Compare commits

...

19 Commits

Author SHA1 Message Date
Lupus590 21961d0049
Merge 8d3e1c5be9 into 00e2e2bd2d 2024-04-26 14:22:02 +01:00
Jonathan Coates 00e2e2bd2d
Switch to vanilla's stillValid implementation 2024-04-25 18:21:23 +01:00
Jonathan Coates 7c1f40031b
Some cleanup to network messages
- Use enums for key and mouse actions, rather than integer ids.
 - Change TerminalState to always contain a terminal. We now make
   TerminalState nullable when we want to skip sending anything.
2024-04-25 18:19:34 +01:00
Lupus590 8d3e1c5be9 Merge branch 'mc-1.20.x' into docs/startup_files 2023-10-10 18:08:12 +01:00
Lupus590 1d5463d2dd Merge branch 'mc-1.16.x' of https://github.com/SquidDev-CC/CC-Tweaked into docs/startup_files 2022-06-09 08:55:38 +01:00
Lupus590 e43314dd35 move mass config to top 2022-06-09 08:54:25 +01:00
Lupus590 67706cfb83 reword a bit 2022-06-09 08:49:53 +01:00
Lupus590 f835bb7f11 Move persistence stuff 2022-06-09 07:46:52 +01:00
Lupus590 f583df3392 add missing note header
off topic change
2022-06-09 07:46:20 +01:00
Lupus590 19e2afc6a6 Move case sensitivity to fs api page 2022-06-09 07:45:52 +01:00
Lupus590 8eb463b6ae Merge branch 'mc-1.16.x' of https://github.com/SquidDev-CC/CC-Tweaked into docs/startup_files 2022-06-07 16:11:56 +01:00
Lupus590 48fcd701ac Merge branch 'mc-1.16.x' of https://github.com/SquidDev-CC/CC-Tweaked into docs/startup_files 2022-06-07 02:07:52 +01:00
Lupus590 71409fac43 Merge branch 'mc-1.16.x' of https://github.com/SquidDev-CC/CC-Tweaked into docs/startup_files 2022-06-01 11:58:06 +01:00
Lupus590 3823202b63
turns on instead of boots
Co-authored-by: Jonathan Coates <git@squiddev.cc>
2022-05-05 17:37:41 +01:00
Lupus590 ae48f5dda9
Changes suggested by grammerly
there's a few more but these are the ones that I think are good changes
2022-04-29 01:24:02 +01:00
Lupus590 cd6fd8e6ca
fix another typo 2022-04-14 16:02:19 +01:00
Lupus590 f3935280d6
fix typos 2022-04-14 15:57:31 +01:00
Lupus590 89899f0ee2
fix typo 2022-04-14 14:34:27 +01:00
Lupus590 190c7c0221 document how to use startup files 2022-04-14 00:53:28 +01:00
20 changed files with 156 additions and 131 deletions

View File

@ -0,0 +1,62 @@
---
module: [kind=guide] startup_files
---
# Running code when a computer turns on
:::note Use case
You might be aware that CC computers restart when the chunk they are in reloads, startup files provides a way to have the CC computer run arbitrary code after it has finished turning on.
:::
:::note Mass configuration
Unless disabled in the server config, CC computers will look for startup files on disks in attached disk drives. This means that a freshly crafted computer can automatically load a program from that disk startup file.
Apply this to turtles with a nearby chest containing fuel and you can have a turtle factory that automatically programs the turtles after creating them.
:::
CC computers will look for a file or folder with a special name when it finishes loading. Also, CC has a fixed order in which it looks for these files and uses them.
## The magic names
All startup *files* have to be at the root of their drive, this drive is commonly the computer's internal storage, but can be a disk too.
```
startup
startup.lua
```
`startup` may be a file or a folder, the behavior of it changes depending on which it is. If it's a file then it is ran, if it's a folder then each file inside it is ran.
`startup.lua` has to be a file.
Note that these are all lower case, case matters sometimes so keep to the correct one - more info in a note on the @{fs} API page.
## Searching drives for startup files
If `shell.allow_disk_startup` is true (which it is by default), then the CC computer will look for disk drives that have at least one startup file, it only uses the first disk that fulfils these criteria. Disk drives are searched in the order they are found via `peripheral.getNames()`. It then runs the found startup files as described below.
If `shell.allow_startup` is true (which it is by default) and no disk startup file was used, then the computer will look for startup files in its internal storage. Valid files are run as described below.
### Running the startup files
If `startup` is a file then this file and *only* this file is run, even if a `startup.lua` exists on the same device.
If `startup` is not a file (either it's a folder or it doesn't exist) then `startup.lua` is run, assuming it exists. After running `startup.lua` (or not if it didn't exist), the CC computer then runs each file in the `startup` folder one after the other in the order that @{fs.list} returns them.
:::note Example
Let's say that I have a computer with a startup file on its internal storage, and is connected to six disk drives. Two of these drives have disks that have startup files, one has a disk with no files, one with files but none of them are startup files, one has a music disk (the kind that you can place in a jukebox), the remaining drive has no disk in it.
Both of the settings that affect startup are set to allow their respective startup modes.
I turn on my computer, it looks for disk drives. It so happens that the first one it finds is the empty one, since this drive has no disk it goes to the next drive it found. The second drive that it searches for startup files is the jukebox music disk, this one is also skipped as music disks don't have startup files. Third, it finds the disk drive containing the disk without files, it goes to the next drive. Forth is the disk with files but without startup files, it tries the next disk.
We are down to the two disks both with startup files, the computer finds one of them and searches it for startup files, it finds the files and runs them in the order above. When/if these startup files exit without shutting down the computer then the CC computer drops into the interactive prompt. The computer *didn't* look at the last disk drive and *didn't* use the startup files on its internal storage.
:::
:::note Computers don't remember what they were doing when the chunk unloads
You may have heard of the term "persistence", Computercraft computers do not have persistence. Startup files are currently the closest that CC has to persistence.
If you don't know what persistence is, if CC computers were persistent then they would remember what they were doing when the chunk they are in was unloaded, and resume running the task they were doing when the chunk gets reloaded.
However, Computercraft doesn't have persistence and thus restart as if they were just turned on. Mentioning turning on, they will remember that they were running and when the chunk reloads they will turn themselves on and start looking for startup files. Clever use of startup files and recording data to disk can somewhat circumvent the lack of built in persistence.
For most programs (usually running on computers), restarting from the beginning of the program is not an issue. However, turtles commonly have startup complications due to their ability to move. Unless you make sure that the turtle is in a fixed starting position every time (which is not always practical), your turtle programs will need some way to cope with the turtle starting in a different position - perhaps with the @{gps} API.
Incase it's not clear, Minecraft unloads all chunks (including force loaded chunks with chunk loaders) when the server restarts and when the single player world closes. So you may want startup files even if you are chunk loading your computers.
:::

View File

@ -49,31 +49,31 @@ public void queueEvent(String event, @Nullable Object[] arguments) {
@Override
public void keyDown(int key, boolean repeat) {
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key));
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.Action.REPEAT : KeyEventServerMessage.Action.DOWN, key));
}
@Override
public void keyUp(int key) {
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.TYPE_UP, key));
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.Action.UP, key));
}
@Override
public void mouseClick(int button, int x, int y) {
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_CLICK, button, x, y));
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.CLICK, button, x, y));
}
@Override
public void mouseUp(int button, int x, int y) {
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_UP, button, x, y));
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.UP, button, x, y));
}
@Override
public void mouseDrag(int button, int x, int y) {
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_DRAG, button, x, y));
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.DRAG, button, x, y));
}
@Override
public void mouseScroll(int direction, int x, int y) {
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y));
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.SCROLL, direction, x, y));
}
}

View File

@ -49,7 +49,7 @@ public void handleComputerTerminal(int containerId, TerminalState terminal) {
}
@Override
public void handleMonitorData(BlockPos pos, TerminalState terminal) {
public void handleMonitorData(BlockPos pos, @Nullable TerminalState terminal) {
var player = Minecraft.getInstance().player;
if (player == null) return;
@ -67,7 +67,7 @@ public void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable
}
@Override
public void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, TerminalState terminal) {
public void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, @Nullable TerminalState terminal) {
ClientPocketComputers.setState(instanceId, state, lightState, terminal);
}

View File

@ -43,7 +43,7 @@ public static void remove(UUID id) {
* @param lightColour The current colour of the modem light.
* @param terminalData The current terminal contents.
*/
public static void setState(UUID instanceId, ComputerState state, int lightColour, TerminalState terminalData) {
public static void setState(UUID instanceId, ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
var computer = instances.get(instanceId);
if (computer == null) {
instances.put(instanceId, new PocketComputerData(state, lightColour, terminalData));

View File

@ -26,10 +26,10 @@ public final class PocketComputerData {
private ComputerState state;
private int lightColour;
PocketComputerData(ComputerState state, int lightColour, TerminalState terminalData) {
PocketComputerData(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
this.state = state;
this.lightColour = lightColour;
if (terminalData.hasTerminal()) terminal = terminalData.create();
if (terminalData != null) terminal = terminalData.create();
}
public int getLightState() {
@ -44,11 +44,11 @@ public ComputerState getState() {
return state;
}
void setState(ComputerState state, int lightColour, TerminalState terminalData) {
void setState(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
this.state = state;
this.lightColour = lightColour;
if (terminalData.hasTerminal()) {
if (terminalData != null) {
if (terminal == null) {
terminal = terminalData.create();
} else {

View File

@ -5,9 +5,9 @@
package dan200.computercraft.shared.common;
import dan200.computercraft.shared.container.BasicContainer;
import dan200.computercraft.shared.util.BlockEntityHelpers;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -29,6 +29,6 @@ protected final Component getDefaultName() {
@Override
public boolean stillValid(Player player) {
return BlockEntityHelpers.isUsable(this, player, BlockEntityHelpers.DEFAULT_INTERACT_RANGE);
return Container.stillValidBlockEntity(this, player);
}
}

View File

@ -24,6 +24,7 @@
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.Container;
import net.minecraft.world.LockCode;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.Nameable;
@ -75,13 +76,13 @@ public void setRemoved() {
unload();
}
protected double getInteractRange() {
return BlockEntityHelpers.DEFAULT_INTERACT_RANGE;
protected int getInteractRange() {
return Container.DEFAULT_DISTANCE_LIMIT;
}
public boolean isUsable(Player player) {
return BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName())
&& BlockEntityHelpers.isUsable(this, player, getInteractRange());
&& Container.stillValidBlockEntity(this, player, getInteractRange());
}
protected void serverTick() {

View File

@ -7,6 +7,7 @@
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.network.FriendlyByteBuf;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nullable;
@ -21,68 +22,49 @@ public class TerminalState {
private final boolean colour;
private final int width;
private final int height;
@Nullable
private final ByteBuf buffer;
public TerminalState(@Nullable NetworkedTerminal terminal) {
if (terminal == null) {
colour = false;
width = height = 0;
buffer = null;
} else {
colour = terminal.isColour();
width = terminal.getWidth();
height = terminal.getHeight();
public TerminalState(NetworkedTerminal terminal) {
colour = terminal.isColour();
width = terminal.getWidth();
height = terminal.getHeight();
var buf = buffer = Unpooled.buffer();
terminal.write(new FriendlyByteBuf(buf));
}
var buf = buffer = Unpooled.buffer();
terminal.write(new FriendlyByteBuf(buf));
}
@Contract("null -> null; !null -> !null")
public static @Nullable TerminalState create(@Nullable NetworkedTerminal terminal) {
return terminal == null ? null : new TerminalState(terminal);
}
public TerminalState(FriendlyByteBuf buf) {
colour = buf.readBoolean();
width = buf.readVarInt();
height = buf.readVarInt();
if (buf.readBoolean()) {
width = buf.readVarInt();
height = buf.readVarInt();
var length = buf.readVarInt();
buffer = buf.readBytes(length);
} else {
width = height = 0;
buffer = null;
}
var length = buf.readVarInt();
buffer = buf.readBytes(length);
}
public void write(FriendlyByteBuf buf) {
buf.writeBoolean(colour);
buf.writeBoolean(buffer != null);
if (buffer != null) {
buf.writeVarInt(width);
buf.writeVarInt(height);
buf.writeVarInt(buffer.readableBytes());
buf.writeBytes(buffer, buffer.readerIndex(), buffer.readableBytes());
}
}
public boolean hasTerminal() {
return buffer != null;
buf.writeVarInt(width);
buf.writeVarInt(height);
buf.writeVarInt(buffer.readableBytes());
buf.writeBytes(buffer, buffer.readerIndex(), buffer.readableBytes());
}
public int size() {
return buffer == null ? 0 : buffer.readableBytes();
return buffer.readableBytes();
}
public void apply(NetworkedTerminal terminal) {
if (buffer == null) throw new NullPointerException("buffer");
terminal.resize(width, height);
terminal.read(new FriendlyByteBuf(buffer));
}
public NetworkedTerminal create() {
if (buffer == null) throw new NullPointerException("Terminal does not exist");
var terminal = new NetworkedTerminal(width, height, colour);
terminal.read(new FriendlyByteBuf(buffer));
return terminal;

View File

@ -26,11 +26,11 @@ public interface ClientNetworkContext {
void handleComputerTerminal(int containerId, TerminalState terminal);
void handleMonitorData(BlockPos pos, TerminalState terminal);
void handleMonitorData(BlockPos pos, @Nullable TerminalState terminal);
void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable String name);
void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, TerminalState terminal);
void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, @Nullable TerminalState terminal);
void handlePocketComputerDeleted(UUID instanceId);

View File

@ -11,25 +11,26 @@
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import javax.annotation.Nullable;
public class MonitorClientMessage implements NetworkMessage<ClientNetworkContext> {
private final BlockPos pos;
private final TerminalState state;
private final @Nullable TerminalState state;
public MonitorClientMessage(BlockPos pos, TerminalState state) {
public MonitorClientMessage(BlockPos pos, @Nullable TerminalState state) {
this.pos = pos;
this.state = state;
}
public MonitorClientMessage(FriendlyByteBuf buf) {
pos = buf.readBlockPos();
state = new TerminalState(buf);
state = buf.readNullable(TerminalState::new);
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeBlockPos(pos);
state.write(buf);
buf.writeNullable(state, (b, t) -> t.write(b));
}
@Override

View File

@ -5,7 +5,6 @@
package dan200.computercraft.shared.network.client;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
import dan200.computercraft.shared.computer.terminal.TerminalState;
import dan200.computercraft.shared.network.MessageType;
import dan200.computercraft.shared.network.NetworkMessage;
@ -13,6 +12,7 @@
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
import net.minecraft.network.FriendlyByteBuf;
import javax.annotation.Nullable;
import java.util.UUID;
/**
@ -22,20 +22,20 @@ public class PocketComputerDataMessage implements NetworkMessage<ClientNetworkCo
private final UUID clientId;
private final ComputerState state;
private final int lightState;
private final TerminalState terminal;
private final @Nullable TerminalState terminal;
public PocketComputerDataMessage(PocketServerComputer computer, boolean sendTerminal) {
clientId = computer.getInstanceUUID();
state = computer.getState();
lightState = computer.getLight();
terminal = sendTerminal ? computer.getTerminalState() : new TerminalState((NetworkedTerminal) null);
terminal = sendTerminal ? computer.getTerminalState() : null;
}
public PocketComputerDataMessage(FriendlyByteBuf buf) {
clientId = buf.readUUID();
state = buf.readEnum(ComputerState.class);
lightState = buf.readVarInt();
terminal = new TerminalState(buf);
terminal = buf.readNullable(TerminalState::new);
}
@Override
@ -43,7 +43,7 @@ public void write(FriendlyByteBuf buf) {
buf.writeUUID(clientId);
buf.writeEnum(state);
buf.writeVarInt(lightState);
terminal.write(buf);
buf.writeNullable(terminal, (b, t) -> t.write(b));
}
@Override

View File

@ -12,14 +12,10 @@
public class KeyEventServerMessage extends ComputerServerMessage {
public static final int TYPE_DOWN = 0;
public static final int TYPE_REPEAT = 1;
public static final int TYPE_UP = 2;
private final int type;
private final Action type;
private final int key;
public KeyEventServerMessage(AbstractContainerMenu menu, int type, int key) {
public KeyEventServerMessage(AbstractContainerMenu menu, Action type, int key) {
super(menu);
this.type = type;
this.key = key;
@ -27,24 +23,24 @@ public KeyEventServerMessage(AbstractContainerMenu menu, int type, int key) {
public KeyEventServerMessage(FriendlyByteBuf buf) {
super(buf);
type = buf.readByte();
type = buf.readEnum(Action.class);
key = buf.readVarInt();
}
@Override
public void write(FriendlyByteBuf buf) {
super.write(buf);
buf.writeByte(type);
buf.writeEnum(type);
buf.writeVarInt(key);
}
@Override
protected void handle(ServerNetworkContext context, ComputerMenu container) {
var input = container.getInput();
if (type == TYPE_UP) {
if (type == Action.UP) {
input.keyUp(key);
} else {
input.keyDown(key, type == TYPE_REPEAT);
input.keyDown(key, type == Action.REPEAT);
}
}
@ -52,4 +48,8 @@ protected void handle(ServerNetworkContext context, ComputerMenu container) {
public MessageType<KeyEventServerMessage> type() {
return NetworkMessages.KEY_EVENT;
}
public enum Action {
DOWN, REPEAT, UP
}
}

View File

@ -12,17 +12,12 @@
public class MouseEventServerMessage extends ComputerServerMessage {
public static final int TYPE_CLICK = 0;
public static final int TYPE_DRAG = 1;
public static final int TYPE_UP = 2;
public static final int TYPE_SCROLL = 3;
private final int type;
private final Action type;
private final int x;
private final int y;
private final int arg;
public MouseEventServerMessage(AbstractContainerMenu menu, int type, int arg, int x, int y) {
public MouseEventServerMessage(AbstractContainerMenu menu, Action type, int arg, int x, int y) {
super(menu);
this.type = type;
this.arg = arg;
@ -32,7 +27,7 @@ public MouseEventServerMessage(AbstractContainerMenu menu, int type, int arg, in
public MouseEventServerMessage(FriendlyByteBuf buf) {
super(buf);
type = buf.readByte();
type = buf.readEnum(Action.class);
arg = buf.readVarInt();
x = buf.readVarInt();
y = buf.readVarInt();
@ -41,7 +36,7 @@ public MouseEventServerMessage(FriendlyByteBuf buf) {
@Override
public void write(FriendlyByteBuf buf) {
super.write(buf);
buf.writeByte(type);
buf.writeEnum(type);
buf.writeVarInt(arg);
buf.writeVarInt(x);
buf.writeVarInt(y);
@ -51,10 +46,10 @@ public void write(FriendlyByteBuf buf) {
protected void handle(ServerNetworkContext context, ComputerMenu container) {
var input = container.getInput();
switch (type) {
case TYPE_CLICK -> input.mouseClick(arg, x, y);
case TYPE_DRAG -> input.mouseDrag(arg, x, y);
case TYPE_UP -> input.mouseUp(arg, x, y);
case TYPE_SCROLL -> input.mouseScroll(arg, x, y);
case CLICK -> input.mouseClick(arg, x, y);
case DRAG -> input.mouseDrag(arg, x, y);
case UP -> input.mouseUp(arg, x, y);
case SCROLL -> input.mouseScroll(arg, x, y);
}
}
@ -62,4 +57,8 @@ protected void handle(ServerNetworkContext context, ComputerMenu container) {
public MessageType<MouseEventServerMessage> type() {
return NetworkMessages.MOUSE_EVENT;
}
public enum Action {
CLICK, DRAG, UP, SCROLL,
}
}

View File

@ -54,8 +54,8 @@ public boolean pollTerminalChanged() {
return terminal;
}
void read(TerminalState state) {
if (state.hasTerminal()) {
void read(@Nullable TerminalState state) {
if (state != null) {
if (terminal == null) {
terminal = state.create();
} else {

View File

@ -223,7 +223,7 @@ private void onClientLoad(int oldXIndex, int oldYIndex) {
if (xIndex == 0 && yIndex == 0 && clientMonitor == null) clientMonitor = new ClientMonitor(this);
}
public final void read(TerminalState state) {
public final void read(@Nullable TerminalState state) {
if (xIndex != 0 || yIndex != 0) {
LOG.warn("Receiving monitor state for non-origin terminal at {}", getBlockPos());
return;

View File

@ -68,7 +68,7 @@ public static void onTick() {
var state = getState(tile, monitor);
ServerNetworking.sendToAllTracking(new MonitorClientMessage(pos, state), chunk);
limit -= state.size();
limit -= state == null ? 0 : state.size();
}
}
@ -76,9 +76,9 @@ public static void onTick() {
return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null;
}
private static TerminalState getState(MonitorBlockEntity tile, ServerMonitor monitor) {
private static @Nullable TerminalState getState(MonitorBlockEntity tile, ServerMonitor monitor) {
var state = tile.cached;
if (state == null) state = tile.cached = new TerminalState(monitor.getTerminal());
if (state == null) state = tile.cached = TerminalState.create(monitor.getTerminal());
return state;
}
}

View File

@ -21,6 +21,7 @@ public void write(FriendlyByteBuf buf) {
buf.writeVarInt(charge());
buf.writeVarInt(strength());
buf.writeBoolean(previousBit());
buf.writeVarInt(audio.remaining());
buf.writeBytes(audio().duplicate());
}
@ -29,7 +30,8 @@ public static EncodedAudio read(FriendlyByteBuf buf) {
var strength = buf.readVarInt();
var previousBit = buf.readBoolean();
var bytes = new byte[buf.readableBytes()];
var length = buf.readVarInt();
var bytes = new byte[length];
buf.readBytes(bytes);
return new EncodedAudio(charge, strength, previousBit, ByteBuffer.wrap(bytes));

View File

@ -26,6 +26,7 @@
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
@ -88,8 +89,8 @@ protected void unload() {
}
@Override
protected double getInteractRange() {
return 12.0;
protected int getInteractRange() {
return Container.DEFAULT_DISTANCE_LIMIT + 4;
}
@Override

View File

@ -4,24 +4,14 @@
package dan200.computercraft.shared.util;
import dan200.computercraft.shared.platform.PlatformHelper;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.phys.Vec3;
import javax.annotation.Nullable;
public final class BlockEntityHelpers {
/**
* The maximum limit a player can be away from a block to still have its UI open.
*
* @see #isUsable(BlockEntity, Player, double)
*/
public static final double DEFAULT_INTERACT_RANGE = 8.0;
private BlockEntityHelpers() {
}
@ -33,27 +23,6 @@ public static <E extends BlockEntity, A extends BlockEntity> BlockEntityTicker<A
return actualType == expectedType ? (BlockEntityTicker<A>) ticker : null;
}
/**
* Determine if a block entity is "usable" by a player.
*
* @param blockEntity The current block entity.
* @param player The player who is trying to interact with the block.
* @param range The default distance the player can be away. This typically defaults to {@link #DEFAULT_INTERACT_RANGE},
* but a custom value may be used. If {@link PlatformHelper#getReachDistance(Player)} is larger,
* that will be used instead.
* @return Whether this block entity is usable.
*/
public static boolean isUsable(BlockEntity blockEntity, Player player, double range) {
var level = blockEntity.getLevel();
var pos = blockEntity.getBlockPos();
range = Math.max(range, PlatformHelper.get().getReachDistance(player));
return player.isAlive() && player.getCommandSenderWorld() == level &&
!blockEntity.isRemoved() && level.getBlockEntity(pos) == blockEntity &&
player.distanceToSqr(Vec3.atCenterOf(pos)) <= range * range;
}
/**
* Update a block entity, marking it as changed and propagating changes to the client.
*

View File

@ -52,6 +52,14 @@
* an incredibly large file) will fail. You can see a mount's capacity with {@link #getCapacity} and the remaining
* space with {@link #getFreeSpace}.
*
* :::note Case sensitivity
* CC inherits the case sensitivity of the real world OS that the Minecraft server is running on, so if you are used to
* Microsoft Windows' case insensitivity (e.g. `startup.lua` and `StartUp.Lua` are considered the same when used as
* file names) and play on a server (which will likely be running Linux which is case sensitive) then you should keep
* in mind that programs which work on your machine in singleplayer may not work correctly on the server if you are
* inconsistent with the case that you use for file names.
* :::
*
* @cc.module fs
*/
public class FSAPI implements ILuaAPI {