mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 05:33:00 +00:00 
			
		
		
		
	Decouple CommandAPI from the command computer BE
All we really need for its implementation is a level and position, which we can get directly from the server block entity!
This commit is contained in:
		| @@ -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,15 +53,14 @@ 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 result = commandManager.performPrefixedCommand(computer.getSource(), command); | ||||
|             var result = commandManager.performPrefixedCommand(getSource(), command); | ||||
|             return new Object[]{ result > 0, receiver.copyOutput(), result }; | ||||
|         } catch (Throwable t) { | ||||
|             LOG.error(Logging.JAVA_ERROR, "Error running command.", t); | ||||
| @@ -134,7 +138,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); | ||||
| @@ -161,7 +164,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() }; | ||||
|     } | ||||
| 
 | ||||
| @@ -186,7 +189,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 | ||||
| @@ -220,7 +222,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"); | ||||
|         } | ||||
| 
 | ||||
| @@ -265,10 +267,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"); | ||||
| @@ -278,4 +279,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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,85 +8,21 @@ 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)); | ||||
|         computer.addAPI(new CommandAPI(computer)); | ||||
|         return computer; | ||||
|     } | ||||
| 
 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates