mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +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
	 Jonathan Coates
					Jonathan Coates