mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-11-04 15:43:00 +00:00 
			
		
		
		
	Merge branch 'mc-1.20.x' into mc-1.21.x
This commit is contained in:
		@@ -24,7 +24,6 @@ import dan200.computercraft.shared.command.CommandComputerCraft;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ComputerState;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerContext;
 | 
			
		||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
 | 
			
		||||
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
 | 
			
		||||
import dan200.computercraft.shared.media.items.DiskItem;
 | 
			
		||||
import net.minecraft.Util;
 | 
			
		||||
import net.minecraft.client.Minecraft;
 | 
			
		||||
@@ -101,15 +100,12 @@ public final class ClientRegistry {
 | 
			
		||||
 | 
			
		||||
    public static void registerMenuScreens(RegisterMenuScreen register) {
 | 
			
		||||
        register.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.COMPUTER.get(), ComputerScreen::new);
 | 
			
		||||
        register.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER.get(), ComputerScreen::new);
 | 
			
		||||
        register.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
 | 
			
		||||
        register.register(ModRegistry.Menus.TURTLE.get(), TurtleScreen::new);
 | 
			
		||||
 | 
			
		||||
        register.register(ModRegistry.Menus.PRINTER.get(), PrinterScreen::new);
 | 
			
		||||
        register.register(ModRegistry.Menus.DISK_DRIVE.get(), DiskDriveScreen::new);
 | 
			
		||||
        register.register(ModRegistry.Menus.PRINTOUT.get(), PrintoutScreen::new);
 | 
			
		||||
 | 
			
		||||
        register.<ViewComputerMenu, ComputerScreen<ViewComputerMenu>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), ComputerScreen::new);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface RegisterMenuScreen {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.integration.jei;
 | 
			
		||||
package dan200.computercraft.client.integration.jei;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleSide;
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.integration.jei;
 | 
			
		||||
package dan200.computercraft.client.integration.jei;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
import dan200.computercraft.shared.integration.RecipeModHelpers;
 | 
			
		||||
@@ -27,12 +27,10 @@ import dan200.computercraft.shared.common.ColourableRecipe;
 | 
			
		||||
import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider;
 | 
			
		||||
import dan200.computercraft.shared.common.HeldItemMenu;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.CommandComputerBlock;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.CommandComputerBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.ComputerBlock;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
 | 
			
		||||
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
 | 
			
		||||
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
 | 
			
		||||
import dan200.computercraft.shared.computer.items.AbstractComputerItem;
 | 
			
		||||
import dan200.computercraft.shared.computer.items.CommandComputerItem;
 | 
			
		||||
import dan200.computercraft.shared.computer.items.ComputerItem;
 | 
			
		||||
@@ -155,8 +153,7 @@ public final class ModRegistry {
 | 
			
		||||
            () -> new ComputerBlock<>(computerProperties().mapColor(MapColor.STONE), BlockEntities.COMPUTER_NORMAL));
 | 
			
		||||
        public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = REGISTRY.register("computer_advanced",
 | 
			
		||||
            () -> new ComputerBlock<>(computerProperties().mapColor(MapColor.GOLD), BlockEntities.COMPUTER_ADVANCED));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<ComputerBlock<CommandComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command",
 | 
			
		||||
        public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command",
 | 
			
		||||
            () -> new CommandComputerBlock<>(computerProperties().strength(-1, 6000000.0F), BlockEntities.COMPUTER_COMMAND));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = REGISTRY.register("turtle_normal",
 | 
			
		||||
@@ -199,8 +196,8 @@ public final class ModRegistry {
 | 
			
		||||
            ofBlock(Blocks.COMPUTER_NORMAL, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_NORMAL.get(), p, s, ComputerFamily.NORMAL));
 | 
			
		||||
        public static final RegistryEntry<BlockEntityType<ComputerBlockEntity>> COMPUTER_ADVANCED =
 | 
			
		||||
            ofBlock(Blocks.COMPUTER_ADVANCED, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_ADVANCED.get(), p, s, ComputerFamily.ADVANCED));
 | 
			
		||||
        public static final RegistryEntry<BlockEntityType<CommandComputerBlockEntity>> COMPUTER_COMMAND =
 | 
			
		||||
            ofBlock(Blocks.COMPUTER_COMMAND, (p, s) -> new CommandComputerBlockEntity(BlockEntities.COMPUTER_COMMAND.get(), p, s));
 | 
			
		||||
        public static final RegistryEntry<BlockEntityType<ComputerBlockEntity>> COMPUTER_COMMAND =
 | 
			
		||||
            ofBlock(Blocks.COMPUTER_COMMAND, (p, s) -> new ComputerBlockEntity(BlockEntities.COMPUTER_COMMAND.get(), p, s, ComputerFamily.COMMAND));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<BlockEntityType<TurtleBlockEntity>> TURTLE_NORMAL =
 | 
			
		||||
            ofBlock(Blocks.TURTLE_NORMAL, (p, s) -> new TurtleBlockEntity(BlockEntities.TURTLE_NORMAL.get(), p, s, () -> Config.turtleFuelLimit, ComputerFamily.NORMAL));
 | 
			
		||||
@@ -413,9 +410,6 @@ public final class ModRegistry {
 | 
			
		||||
        public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> COMPUTER = REGISTRY.register("computer",
 | 
			
		||||
            () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.COMPUTER.get(), id, inv, data)));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> POCKET_COMPUTER = REGISTRY.register("pocket_computer",
 | 
			
		||||
            () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER.get(), id, inv, data)));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<MenuType<ComputerMenuWithoutInventory>> POCKET_COMPUTER_NO_TERM = REGISTRY.register("pocket_computer_no_term",
 | 
			
		||||
            () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, (id, inv, data) -> new ComputerMenuWithoutInventory(Menus.POCKET_COMPUTER_NO_TERM.get(), id, inv, data)));
 | 
			
		||||
 | 
			
		||||
@@ -433,9 +427,6 @@ public final class ModRegistry {
 | 
			
		||||
                HeldItemContainerData.STREAM_CODEC,
 | 
			
		||||
                (id, inventory, data) -> new HeldItemMenu(Menus.PRINTOUT.get(), id, inventory.player, data.hand())
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<MenuType<ViewComputerMenu>> VIEW_COMPUTER = REGISTRY.register("view_computer",
 | 
			
		||||
            () -> ContainerData.toType(ComputerContainerData.STREAM_CODEC, ViewComputerMenu::new));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class ArgumentTypes {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ import dan200.computercraft.shared.command.text.TableBuilder;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerComputer;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerContext;
 | 
			
		||||
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
 | 
			
		||||
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
 | 
			
		||||
import dan200.computercraft.shared.computer.metrics.basic.Aggregate;
 | 
			
		||||
import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric;
 | 
			
		||||
import dan200.computercraft.shared.computer.metrics.basic.BasicComputerMetricsObserver;
 | 
			
		||||
@@ -268,7 +268,7 @@ public final class CommandComputerCraft {
 | 
			
		||||
 | 
			
		||||
            @Override
 | 
			
		||||
            public AbstractContainerMenu createMenu(int id, Inventory player, Player entity) {
 | 
			
		||||
                return new ViewComputerMenu(id, player, computer);
 | 
			
		||||
                return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, player, p -> true, computer);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,15 +10,19 @@ import dan200.computercraft.api.detail.BlockReference;
 | 
			
		||||
import dan200.computercraft.api.detail.VanillaDetailRegistries;
 | 
			
		||||
import dan200.computercraft.api.lua.*;
 | 
			
		||||
import dan200.computercraft.core.Logging;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.CommandComputerBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerComputer;
 | 
			
		||||
import dan200.computercraft.shared.util.NBTUtil;
 | 
			
		||||
import net.minecraft.commands.CommandSource;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.core.registries.Registries;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.resources.ResourceKey;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.level.GameRules;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.phys.Vec2;
 | 
			
		||||
import net.minecraft.world.phys.Vec3;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
@@ -31,9 +35,10 @@ import java.util.*;
 | 
			
		||||
public class CommandAPI implements ILuaAPI {
 | 
			
		||||
    private static final Logger LOG = LoggerFactory.getLogger(CommandAPI.class);
 | 
			
		||||
 | 
			
		||||
    private final CommandComputerBlockEntity computer;
 | 
			
		||||
    private final ServerComputer computer;
 | 
			
		||||
    private final OutputReceiver receiver = new OutputReceiver();
 | 
			
		||||
 | 
			
		||||
    public CommandAPI(CommandComputerBlockEntity computer) {
 | 
			
		||||
    public CommandAPI(ServerComputer computer) {
 | 
			
		||||
        this.computer = computer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -48,16 +53,15 @@ public class CommandAPI implements ILuaAPI {
 | 
			
		||||
 | 
			
		||||
    private Object[] doCommand(String command) {
 | 
			
		||||
        var server = computer.getLevel().getServer();
 | 
			
		||||
        if (server == null || !server.isCommandBlockEnabled()) {
 | 
			
		||||
        if (!server.isCommandBlockEnabled()) {
 | 
			
		||||
            return new Object[]{ false, createOutput("Command blocks disabled by server") };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var commandManager = server.getCommands();
 | 
			
		||||
        var receiver = computer.getReceiver();
 | 
			
		||||
        try {
 | 
			
		||||
            receiver.clearOutput();
 | 
			
		||||
            var state = new CommandState();
 | 
			
		||||
            var source = computer.getSource().withCallback((success, x) -> {
 | 
			
		||||
            var source = getSource().withCallback((success, x) -> {
 | 
			
		||||
                if (success) state.successes++;
 | 
			
		||||
            });
 | 
			
		||||
            commandManager.performPrefixedCommand(source, command);
 | 
			
		||||
@@ -142,7 +146,6 @@ public class CommandAPI implements ILuaAPI {
 | 
			
		||||
    public final List<String> list(IArguments args) throws LuaException {
 | 
			
		||||
        var server = computer.getLevel().getServer();
 | 
			
		||||
 | 
			
		||||
        if (server == null) return List.of();
 | 
			
		||||
        CommandNode<CommandSourceStack> node = server.getCommands().getDispatcher().getRoot();
 | 
			
		||||
        for (var j = 0; j < args.count(); j++) {
 | 
			
		||||
            var name = args.getString(j);
 | 
			
		||||
@@ -169,7 +172,7 @@ public class CommandAPI implements ILuaAPI {
 | 
			
		||||
    @LuaFunction
 | 
			
		||||
    public final Object[] getBlockPosition() {
 | 
			
		||||
        // This is probably safe to do on the Lua thread. Probably.
 | 
			
		||||
        var pos = computer.getBlockPos();
 | 
			
		||||
        var pos = computer.getPosition();
 | 
			
		||||
        return new Object[]{ pos.getX(), pos.getY(), pos.getZ() };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -194,7 +197,6 @@ public class CommandAPI implements ILuaAPI {
 | 
			
		||||
     * @throws LuaException If trying to get information about more than 4096 blocks.
 | 
			
		||||
     * @cc.since 1.76
 | 
			
		||||
     * @cc.changed 1.99 Added {@code dimension} argument.
 | 
			
		||||
     *
 | 
			
		||||
     * @cc.usage Print out all blocks in a cube around the computer.
 | 
			
		||||
     *
 | 
			
		||||
     * <pre>{@code
 | 
			
		||||
@@ -228,7 +230,7 @@ public class CommandAPI implements ILuaAPI {
 | 
			
		||||
            Math.max(minY, maxY),
 | 
			
		||||
            Math.max(minZ, maxZ)
 | 
			
		||||
        );
 | 
			
		||||
        if (world == null || !world.isInWorldBounds(min) || !world.isInWorldBounds(max)) {
 | 
			
		||||
        if (!world.isInWorldBounds(min) || !world.isInWorldBounds(max)) {
 | 
			
		||||
            throw new LuaException("Co-ordinates out of range");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -273,10 +275,9 @@ public class CommandAPI implements ILuaAPI {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Level getLevel(Optional<String> id) throws LuaException {
 | 
			
		||||
        var currentLevel = (ServerLevel) computer.getLevel();
 | 
			
		||||
        if (currentLevel == null) throw new LuaException("No world exists");
 | 
			
		||||
        var currentLevel = computer.getLevel();
 | 
			
		||||
 | 
			
		||||
        if (!id.isPresent()) return currentLevel;
 | 
			
		||||
        if (id.isEmpty()) return currentLevel;
 | 
			
		||||
 | 
			
		||||
        var dimensionId = ResourceLocation.tryParse(id.get());
 | 
			
		||||
        if (dimensionId == null) throw new LuaException("Invalid dimension name");
 | 
			
		||||
@@ -286,4 +287,52 @@ public class CommandAPI implements ILuaAPI {
 | 
			
		||||
 | 
			
		||||
        return level;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CommandSourceStack getSource() {
 | 
			
		||||
        var name = "@";
 | 
			
		||||
        var label = computer.getLabel();
 | 
			
		||||
        if (label != null) name = label;
 | 
			
		||||
 | 
			
		||||
        return new CommandSourceStack(receiver,
 | 
			
		||||
            Vec3.atCenterOf(computer.getPosition()), Vec2.ZERO,
 | 
			
		||||
            computer.getLevel(), 2,
 | 
			
		||||
            name, Component.literal(name),
 | 
			
		||||
            computer.getLevel().getServer(), null
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A {@link CommandSource} that consumes output messages and stores them to a list.
 | 
			
		||||
     */
 | 
			
		||||
    private final class OutputReceiver implements CommandSource {
 | 
			
		||||
        private final List<String> output = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        void clearOutput() {
 | 
			
		||||
            output.clear();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        List<String> copyOutput() {
 | 
			
		||||
            return List.copyOf(output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void sendSystemMessage(Component textComponent) {
 | 
			
		||||
            output.add(textComponent.getString());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean acceptsSuccess() {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean acceptsFailure() {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean shouldInformAdmins() {
 | 
			
		||||
            return computer.getLevel().getGameRules().getBoolean(GameRules.RULE_COMMANDBLOCKOUTPUT);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,8 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isUsable(Player player) {
 | 
			
		||||
        return BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName())
 | 
			
		||||
        return getFamily().checkUsable(player)
 | 
			
		||||
            && BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName())
 | 
			
		||||
            && Container.stillValidBlockEntity(this, player, getInteractRange());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
 | 
			
		||||
 * @param <T> The type of the computer block entity.
 | 
			
		||||
 * @see dan200.computercraft.shared.computer.items.CommandComputerItem
 | 
			
		||||
 */
 | 
			
		||||
public class CommandComputerBlock<T extends CommandComputerBlockEntity> extends ComputerBlock<T> implements GameMasterBlock {
 | 
			
		||||
public class CommandComputerBlock<T extends ComputerBlockEntity> extends ComputerBlock<T> implements GameMasterBlock {
 | 
			
		||||
    private static final MapCodec<CommandComputerBlock<?>> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
 | 
			
		||||
        BlockCodecs.propertiesCodec(),
 | 
			
		||||
        BlockCodecs.blockEntityCodec(x -> x.type)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,114 +0,0 @@
 | 
			
		||||
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: LicenseRef-CCPL
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.computer.blocks;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.shared.computer.apis.CommandAPI;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerComputer;
 | 
			
		||||
import dan200.computercraft.shared.config.Config;
 | 
			
		||||
import net.minecraft.commands.CommandSource;
 | 
			
		||||
import net.minecraft.commands.CommandSourceStack;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.level.GameRules;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntityType;
 | 
			
		||||
import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import net.minecraft.world.phys.Vec2;
 | 
			
		||||
import net.minecraft.world.phys.Vec3;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class CommandComputerBlockEntity extends ComputerBlockEntity {
 | 
			
		||||
    public class CommandReceiver implements CommandSource {
 | 
			
		||||
        private final List<String> output = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        public void clearOutput() {
 | 
			
		||||
            output.clear();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<String> copyOutput() {
 | 
			
		||||
            return new ArrayList<>(output);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void sendSystemMessage(Component textComponent) {
 | 
			
		||||
            output.add(textComponent.getString());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean acceptsSuccess() {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean acceptsFailure() {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean shouldInformAdmins() {
 | 
			
		||||
            return getLevel().getGameRules().getBoolean(GameRules.RULE_COMMANDBLOCKOUTPUT);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final CommandReceiver receiver;
 | 
			
		||||
 | 
			
		||||
    public CommandComputerBlockEntity(BlockEntityType<? extends ComputerBlockEntity> type, BlockPos pos, BlockState state) {
 | 
			
		||||
        super(type, pos, state, ComputerFamily.COMMAND);
 | 
			
		||||
        receiver = new CommandReceiver();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public CommandReceiver getReceiver() {
 | 
			
		||||
        return receiver;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public CommandSourceStack getSource() {
 | 
			
		||||
        var computer = getServerComputer();
 | 
			
		||||
        var name = "@";
 | 
			
		||||
        if (computer != null) {
 | 
			
		||||
            var label = computer.getLabel();
 | 
			
		||||
            if (label != null) name = label;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new CommandSourceStack(receiver,
 | 
			
		||||
            Vec3.atCenterOf(worldPosition), Vec2.ZERO,
 | 
			
		||||
            (ServerLevel) getLevel(), 2,
 | 
			
		||||
            name, Component.literal(name),
 | 
			
		||||
            getLevel().getServer(), null
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected ServerComputer createComputer(int id) {
 | 
			
		||||
        var computer = super.createComputer(id);
 | 
			
		||||
        computer.addAPI(new CommandAPI(this));
 | 
			
		||||
        return computer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isUsable(Player player) {
 | 
			
		||||
        return isCommandUsable(player) && super.isUsable(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean isCommandUsable(Player player) {
 | 
			
		||||
        var server = player.getServer();
 | 
			
		||||
        if (server == null || !server.isCommandBlockEnabled()) {
 | 
			
		||||
            player.displayClientMessage(Component.translatable("advMode.notEnabled"), true);
 | 
			
		||||
            return false;
 | 
			
		||||
        } else if (!canUseCommandBlock(player)) {
 | 
			
		||||
            player.displayClientMessage(Component.translatable("advMode.notAllowed"), true);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean canUseCommandBlock(Player player) {
 | 
			
		||||
        return Config.commandRequireCreative ? player.canUseGameMasterBlocks() : player.hasPermissions(2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -67,7 +67,7 @@ public class ComputerBlockEntity extends AbstractComputerBlockEntity {
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
 | 
			
		||||
        return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily());
 | 
			
		||||
        return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, inventory, this::isUsableByPlayer, createServerComputer());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IPeripheral peripheral() {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,45 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.computer.core;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.shared.config.Config;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
 | 
			
		||||
public enum ComputerFamily {
 | 
			
		||||
    NORMAL,
 | 
			
		||||
    ADVANCED,
 | 
			
		||||
    COMMAND,
 | 
			
		||||
    COMMAND;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether computers with this family can be used by the provided player.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This method is not pure. On failure, the method may send a message to the player telling them why they cannot
 | 
			
		||||
     * interact with the computer.
 | 
			
		||||
     *
 | 
			
		||||
     * @param player The player trying to use a computer.
 | 
			
		||||
     * @return Whether this computer family can be used.
 | 
			
		||||
     */
 | 
			
		||||
    public boolean checkUsable(Player player) {
 | 
			
		||||
        return switch (this) {
 | 
			
		||||
            case NORMAL, ADVANCED -> true;
 | 
			
		||||
            case COMMAND -> checkCommandUsable(player);
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean checkCommandUsable(Player player) {
 | 
			
		||||
        var server = player.getServer();
 | 
			
		||||
        if (server == null || !server.isCommandBlockEnabled()) {
 | 
			
		||||
            player.displayClientMessage(Component.translatable("advMode.notEnabled"), true);
 | 
			
		||||
            return false;
 | 
			
		||||
        } else if (!canUseCommandBlock(player)) {
 | 
			
		||||
            player.displayClientMessage(Component.translatable("advMode.notAllowed"), true);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean canUseCommandBlock(Player player) {
 | 
			
		||||
        return Config.commandRequireCreative ? player.canUseGameMasterBlocks() : player.hasPermissions(2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,11 +8,12 @@ import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
import dan200.computercraft.api.filesystem.WritableMount;
 | 
			
		||||
import dan200.computercraft.api.lua.ILuaAPI;
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import dan200.computercraft.core.apis.IAPIEnvironment;
 | 
			
		||||
import dan200.computercraft.api.peripheral.WorkMonitor;
 | 
			
		||||
import dan200.computercraft.core.computer.Computer;
 | 
			
		||||
import dan200.computercraft.core.computer.ComputerEnvironment;
 | 
			
		||||
import dan200.computercraft.core.computer.ComputerSide;
 | 
			
		||||
import dan200.computercraft.core.metrics.MetricsObserver;
 | 
			
		||||
import dan200.computercraft.shared.computer.apis.CommandAPI;
 | 
			
		||||
import dan200.computercraft.shared.computer.menu.ComputerMenu;
 | 
			
		||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
 | 
			
		||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
 | 
			
		||||
@@ -23,6 +24,7 @@ import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage;
 | 
			
		||||
import dan200.computercraft.shared.network.server.ServerNetworking;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.inventory.AbstractContainerMenu;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
@@ -58,6 +60,8 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
 | 
			
		||||
 | 
			
		||||
        computer = new Computer(context.computerContext(), this, terminal, computerID);
 | 
			
		||||
        computer.setLabel(label);
 | 
			
		||||
 | 
			
		||||
        if (family == ComputerFamily.COMMAND) addAPI(new CommandAPI(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ComputerFamily getFamily() {
 | 
			
		||||
@@ -68,32 +72,20 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
 | 
			
		||||
        return level;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setLevel(ServerLevel level) {
 | 
			
		||||
        this.level = level;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BlockPos getPosition() {
 | 
			
		||||
        return position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPosition(BlockPos pos) {
 | 
			
		||||
        position = new BlockPos(pos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IAPIEnvironment getAPIEnvironment() {
 | 
			
		||||
        return computer.getAPIEnvironment();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Computer getComputer() {
 | 
			
		||||
        return computer;
 | 
			
		||||
    public void setPosition(ServerLevel level, BlockPos pos) {
 | 
			
		||||
        this.level = level;
 | 
			
		||||
        position = pos.immutable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void markTerminalChanged() {
 | 
			
		||||
        terminalChanged.set(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public void tickServer() {
 | 
			
		||||
    protected void tickServer() {
 | 
			
		||||
        ticksSincePing++;
 | 
			
		||||
        computer.tick();
 | 
			
		||||
        if (terminalChanged.getAndSet(false)) onTerminalChanged();
 | 
			
		||||
@@ -111,10 +103,15 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
 | 
			
		||||
        ticksSincePing = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean hasTimedOut() {
 | 
			
		||||
    boolean hasTimedOut() {
 | 
			
		||||
        return ticksSincePing > 100;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a bitmask returning which sides on the computer have changed, resetting the internal state.
 | 
			
		||||
     *
 | 
			
		||||
     * @return What sides on the computer have changed.
 | 
			
		||||
     */
 | 
			
		||||
    public int pollAndResetChanges() {
 | 
			
		||||
        return computer.pollAndResetChanges();
 | 
			
		||||
    }
 | 
			
		||||
@@ -133,6 +130,17 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
 | 
			
		||||
        ServerContext.get(level.getServer()).registry().remove(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether this computer is usable by a player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param player The player trying to use this computer.
 | 
			
		||||
     * @return Whether this computer can be used.
 | 
			
		||||
     */
 | 
			
		||||
    public final boolean checkUsable(Player player) {
 | 
			
		||||
        return ServerContext.get(level.getServer()).registry().get(instanceUUID) == this
 | 
			
		||||
            && getFamily().checkUsable(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void sendToAllInteracting(Function<AbstractContainerMenu, NetworkMessage<ClientNetworkContext>> createPacket) {
 | 
			
		||||
        var server = level.getServer();
 | 
			
		||||
 | 
			
		||||
@@ -169,25 +177,21 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void turnOn() {
 | 
			
		||||
        // Turn on
 | 
			
		||||
        computer.turnOn();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void shutdown() {
 | 
			
		||||
        // Shutdown
 | 
			
		||||
        computer.shutdown();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void reboot() {
 | 
			
		||||
        // Reboot
 | 
			
		||||
        computer.reboot();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void queueEvent(String event, @Nullable Object[] arguments) {
 | 
			
		||||
        // Queue event
 | 
			
		||||
        computer.queueEvent(event, arguments);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -239,6 +243,10 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
 | 
			
		||||
        return metrics;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public WorkMonitor getMainThreadMonitor() {
 | 
			
		||||
        return computer.getMainThreadMonitor();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable WritableMount createRootMount() {
 | 
			
		||||
        return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + computer.getID(), Config.computerSpaceLimit);
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ public abstract class AbstractComputerMenu extends AbstractContainerMenu impleme
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean stillValid(Player player) {
 | 
			
		||||
        return canUse.test(player);
 | 
			
		||||
        return (computer == null || computer.checkUsable(player)) && canUse.test(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ComputerFamily getFamily() {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.computer.inventory;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerComputer;
 | 
			
		||||
import dan200.computercraft.shared.container.InvisibleSlot;
 | 
			
		||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
 | 
			
		||||
@@ -23,9 +22,9 @@ import java.util.function.Predicate;
 | 
			
		||||
public class ComputerMenuWithoutInventory extends AbstractComputerMenu {
 | 
			
		||||
    public ComputerMenuWithoutInventory(
 | 
			
		||||
        MenuType<? extends AbstractComputerMenu> type, int id, Inventory player, Predicate<Player> canUse,
 | 
			
		||||
        ServerComputer computer, ComputerFamily family
 | 
			
		||||
        ServerComputer computer
 | 
			
		||||
    ) {
 | 
			
		||||
        super(type, id, canUse, family, computer, null);
 | 
			
		||||
        super(type, id, canUse, computer.getFamily(), computer, null);
 | 
			
		||||
        addSlots(player);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.computer.inventory;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry;
 | 
			
		||||
import dan200.computercraft.shared.computer.blocks.CommandComputerBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerComputer;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerContext;
 | 
			
		||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
 | 
			
		||||
import net.minecraft.world.entity.player.Inventory;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class ViewComputerMenu extends ComputerMenuWithoutInventory {
 | 
			
		||||
    public ViewComputerMenu(int id, Inventory player, ServerComputer computer) {
 | 
			
		||||
        super(ModRegistry.Menus.VIEW_COMPUTER.get(), id, player, p -> canInteractWith(computer, p), computer, computer.getFamily());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ViewComputerMenu(int id, Inventory player, ComputerContainerData data) {
 | 
			
		||||
        super(ModRegistry.Menus.VIEW_COMPUTER.get(), id, player, data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean canInteractWith(ServerComputer computer, Player player) {
 | 
			
		||||
        // If this computer no longer exists then discard it.
 | 
			
		||||
        if (ServerContext.get(computer.getLevel().getServer()).registry().get(computer.getInstanceUUID()) != computer) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If we're a command computer then ensure we're in creative
 | 
			
		||||
        if (computer.getFamily() == ComputerFamily.COMMAND && !CommandComputerBlockEntity.isCommandUsable(player)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -138,10 +138,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public synchronized void updateValues(@Nullable Entity entity, ItemStack stack, @Nullable IPocketUpgrade upgrade) {
 | 
			
		||||
        if (entity != null) {
 | 
			
		||||
            setLevel((ServerLevel) entity.getCommandSenderWorld());
 | 
			
		||||
            setPosition(entity.blockPosition());
 | 
			
		||||
        }
 | 
			
		||||
        if (entity != null) setPosition((ServerLevel) entity.level(), entity.blockPosition());
 | 
			
		||||
 | 
			
		||||
        // If a new entity has picked it up then rebroadcast the terminal to them
 | 
			
		||||
        if (entity != this.entity && entity instanceof ServerPlayer) markTerminalChanged();
 | 
			
		||||
@@ -156,7 +153,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void tickServer() {
 | 
			
		||||
    protected void tickServer() {
 | 
			
		||||
        super.tickServer();
 | 
			
		||||
 | 
			
		||||
        // Find any players which have gone missing and remove them from the tracking list.
 | 
			
		||||
 
 | 
			
		||||
@@ -45,12 +45,12 @@ public class PocketComputerMenuProvider implements MenuProvider {
 | 
			
		||||
    @Override
 | 
			
		||||
    public AbstractContainerMenu createMenu(int id, Inventory inventory, Player entity) {
 | 
			
		||||
        return new ComputerMenuWithoutInventory(
 | 
			
		||||
            isTypingOnly ? ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get() : ModRegistry.Menus.POCKET_COMPUTER.get(), id, inventory,
 | 
			
		||||
            isTypingOnly ? ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get() : ModRegistry.Menus.COMPUTER.get(), id, inventory,
 | 
			
		||||
            p -> {
 | 
			
		||||
                var stack = p.getItemInHand(hand);
 | 
			
		||||
                return stack.getItem() == item && PocketComputerItem.getServerComputer(assertNonNull(entity.level().getServer()), stack) == computer;
 | 
			
		||||
            },
 | 
			
		||||
            computer, item.getFamily()
 | 
			
		||||
            computer
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -53,10 +53,9 @@ public class PocketComputerItem extends Item implements IMedia {
 | 
			
		||||
        this.family = family;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean tick(ItemStack stack, Level world, Entity entity, PocketServerComputer computer) {
 | 
			
		||||
    private boolean tick(ItemStack stack, Entity entity, PocketServerComputer computer) {
 | 
			
		||||
        var upgrade = getUpgrade(stack);
 | 
			
		||||
 | 
			
		||||
        computer.setLevel((ServerLevel) world);
 | 
			
		||||
        computer.updateValues(entity, stack, upgrade);
 | 
			
		||||
 | 
			
		||||
        var changed = false;
 | 
			
		||||
@@ -87,7 +86,7 @@ public class PocketComputerItem extends Item implements IMedia {
 | 
			
		||||
        var computer = createServerComputer((ServerLevel) world, entity, inventory, stack);
 | 
			
		||||
        computer.keepAlive();
 | 
			
		||||
 | 
			
		||||
        var changed = tick(stack, world, entity, computer);
 | 
			
		||||
        var changed = tick(stack, entity, computer);
 | 
			
		||||
        if (changed && inventory != null) inventory.setChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -97,7 +96,7 @@ public class PocketComputerItem extends Item implements IMedia {
 | 
			
		||||
        if (level.isClientSide || level.getServer() == null) return false;
 | 
			
		||||
 | 
			
		||||
        var computer = getServerComputer(level.getServer(), stack);
 | 
			
		||||
        if (computer != null && tick(stack, entity.level(), entity, computer)) entity.setItem(stack.copy());
 | 
			
		||||
        if (computer != null && tick(stack, entity, computer)) entity.setItem(stack.copy());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -175,7 +174,7 @@ public class PocketComputerItem extends Item implements IMedia {
 | 
			
		||||
 | 
			
		||||
            if (inventory != null) inventory.setChanged();
 | 
			
		||||
        }
 | 
			
		||||
        computer.setLevel(level);
 | 
			
		||||
 | 
			
		||||
        return computer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ public class PocketModemPeripheral extends WirelessModemPeripheral {
 | 
			
		||||
    void setLocation(IPocketAccess access) {
 | 
			
		||||
        var entity = access.getEntity();
 | 
			
		||||
        if (entity != null) {
 | 
			
		||||
            level = entity.getCommandSenderWorld();
 | 
			
		||||
            level = entity.level();
 | 
			
		||||
            position = entity.getEyePosition(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,9 @@ import dan200.computercraft.api.lua.*;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleCommand;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleCommandResult;
 | 
			
		||||
import dan200.computercraft.api.turtle.TurtleSide;
 | 
			
		||||
import dan200.computercraft.core.apis.IAPIEnvironment;
 | 
			
		||||
import dan200.computercraft.core.metrics.Metrics;
 | 
			
		||||
import dan200.computercraft.core.metrics.MetricsObserver;
 | 
			
		||||
import dan200.computercraft.shared.computer.core.ServerComputer;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods;
 | 
			
		||||
import dan200.computercraft.shared.turtle.core.*;
 | 
			
		||||
 | 
			
		||||
@@ -64,11 +65,11 @@ import java.util.Optional;
 | 
			
		||||
 * @cc.since 1.3
 | 
			
		||||
 */
 | 
			
		||||
public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
    private final IAPIEnvironment environment;
 | 
			
		||||
    private final MetricsObserver metrics;
 | 
			
		||||
    private final TurtleAccessInternal turtle;
 | 
			
		||||
 | 
			
		||||
    public TurtleAPI(IAPIEnvironment environment, TurtleAccessInternal turtle) {
 | 
			
		||||
        this.environment = environment;
 | 
			
		||||
    public TurtleAPI(ServerComputer computer, TurtleAccessInternal turtle) {
 | 
			
		||||
        this.metrics = computer.getMetrics();
 | 
			
		||||
        this.turtle = turtle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -78,7 +79,7 @@ public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private MethodResult trackCommand(TurtleCommand command) {
 | 
			
		||||
        environment.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        metrics.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        return turtle.executeCommand(command);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -169,7 +170,7 @@ public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction
 | 
			
		||||
    public final MethodResult dig(Optional<TurtleSide> side) {
 | 
			
		||||
        environment.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        metrics.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        return trackCommand(TurtleToolCommand.dig(InteractDirection.FORWARD, side.orElse(null)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -184,7 +185,7 @@ public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction
 | 
			
		||||
    public final MethodResult digUp(Optional<TurtleSide> side) {
 | 
			
		||||
        environment.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        metrics.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        return trackCommand(TurtleToolCommand.dig(InteractDirection.UP, side.orElse(null)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -199,7 +200,7 @@ public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction
 | 
			
		||||
    public final MethodResult digDown(Optional<TurtleSide> side) {
 | 
			
		||||
        environment.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        metrics.observe(Metrics.TURTLE_OPS);
 | 
			
		||||
        return trackCommand(TurtleToolCommand.dig(InteractDirection.DOWN, side.orElse(null)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -84,7 +84,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
 | 
			
		||||
            getFamily(), Config.turtleTermWidth,
 | 
			
		||||
            Config.turtleTermHeight
 | 
			
		||||
        );
 | 
			
		||||
        computer.addAPI(new TurtleAPI(computer.getAPIEnvironment(), brain));
 | 
			
		||||
        computer.addAPI(new TurtleAPI(computer, brain));
 | 
			
		||||
        brain.setupComputer(computer);
 | 
			
		||||
        return computer;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -266,8 +266,7 @@ public class TurtleBrain implements TurtleAccessInternal {
 | 
			
		||||
                        newTurtle.transferStateFrom(oldOwner);
 | 
			
		||||
 | 
			
		||||
                        var computer = newTurtle.createServerComputer();
 | 
			
		||||
                        computer.setLevel((ServerLevel) world);
 | 
			
		||||
                        computer.setPosition(pos);
 | 
			
		||||
                        computer.setPosition((ServerLevel) world, pos);
 | 
			
		||||
 | 
			
		||||
                        // Remove the old turtle
 | 
			
		||||
                        oldWorld.removeBlock(oldPos, false);
 | 
			
		||||
@@ -586,7 +585,7 @@ public class TurtleBrain implements TurtleAccessInternal {
 | 
			
		||||
 | 
			
		||||
        // If we've got a computer, ensure that we're allowed to perform work.
 | 
			
		||||
        var computer = owner.getServerComputer();
 | 
			
		||||
        if (computer != null && !computer.getComputer().getMainThreadMonitor().canWork()) return;
 | 
			
		||||
        if (computer != null && !computer.getMainThreadMonitor().canWork()) return;
 | 
			
		||||
 | 
			
		||||
        // Pull a new command
 | 
			
		||||
        var nextCommand = commandQueue.poll();
 | 
			
		||||
@@ -599,7 +598,7 @@ public class TurtleBrain implements TurtleAccessInternal {
 | 
			
		||||
 | 
			
		||||
        // Dispatch the callback
 | 
			
		||||
        if (computer == null) return;
 | 
			
		||||
        computer.getComputer().getMainThreadMonitor().trackWork(end - start, TimeUnit.NANOSECONDS);
 | 
			
		||||
        computer.getMainThreadMonitor().trackWork(end - start, TimeUnit.NANOSECONDS);
 | 
			
		||||
        var callbackID = nextCommand.callbackID();
 | 
			
		||||
        if (callbackID < 0) return;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ public final class TurtlePlayer {
 | 
			
		||||
 | 
			
		||||
        var player = brain.cachedPlayer;
 | 
			
		||||
        if (player == null || player.player.getGameProfile() != getProfile(access.getOwningPlayer())
 | 
			
		||||
            || player.player.getCommandSenderWorld() != access.getLevel()) {
 | 
			
		||||
            || player.player.level() != access.getLevel()) {
 | 
			
		||||
            player = brain.cachedPlayer = create(brain);
 | 
			
		||||
        } else {
 | 
			
		||||
            player.setState(access);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
            "dan200.computercraft.data.FabricDataGenerators"
 | 
			
		||||
        ],
 | 
			
		||||
        "jei_mod_plugin": [
 | 
			
		||||
            "dan200.computercraft.shared.integration.jei.JEIComputerCraft"
 | 
			
		||||
            "dan200.computercraft.client.integration.jei.JEIComputerCraft"
 | 
			
		||||
        ],
 | 
			
		||||
        "rei_client": [
 | 
			
		||||
            "dan200.computercraft.client.integration.rei.REIComputerCraft"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user