1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-10 01:10:30 +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:
Jonathan Coates 2024-06-22 17:18:21 +01:00
parent e81af93043
commit 571ea794a8
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
2 changed files with 64 additions and 79 deletions

View File

@ -10,15 +10,19 @@ import dan200.computercraft.api.detail.BlockReference;
import dan200.computercraft.api.detail.VanillaDetailRegistries; import dan200.computercraft.api.detail.VanillaDetailRegistries;
import dan200.computercraft.api.lua.*; import dan200.computercraft.api.lua.*;
import dan200.computercraft.core.Logging; 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 dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; 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.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -31,9 +35,10 @@ import java.util.*;
public class CommandAPI implements ILuaAPI { public class CommandAPI implements ILuaAPI {
private static final Logger LOG = LoggerFactory.getLogger(CommandAPI.class); 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; this.computer = computer;
} }
@ -48,15 +53,14 @@ public class CommandAPI implements ILuaAPI {
private Object[] doCommand(String command) { private Object[] doCommand(String command) {
var server = computer.getLevel().getServer(); var server = computer.getLevel().getServer();
if (server == null || !server.isCommandBlockEnabled()) { if (!server.isCommandBlockEnabled()) {
return new Object[]{ false, createOutput("Command blocks disabled by server") }; return new Object[]{ false, createOutput("Command blocks disabled by server") };
} }
var commandManager = server.getCommands(); var commandManager = server.getCommands();
var receiver = computer.getReceiver();
try { try {
receiver.clearOutput(); receiver.clearOutput();
var result = commandManager.performPrefixedCommand(computer.getSource(), command); var result = commandManager.performPrefixedCommand(getSource(), command);
return new Object[]{ result > 0, receiver.copyOutput(), result }; return new Object[]{ result > 0, receiver.copyOutput(), result };
} catch (Throwable t) { } catch (Throwable t) {
LOG.error(Logging.JAVA_ERROR, "Error running command.", 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 { public final List<String> list(IArguments args) throws LuaException {
var server = computer.getLevel().getServer(); var server = computer.getLevel().getServer();
if (server == null) return List.of();
CommandNode<CommandSourceStack> node = server.getCommands().getDispatcher().getRoot(); CommandNode<CommandSourceStack> node = server.getCommands().getDispatcher().getRoot();
for (var j = 0; j < args.count(); j++) { for (var j = 0; j < args.count(); j++) {
var name = args.getString(j); var name = args.getString(j);
@ -161,7 +164,7 @@ public class CommandAPI implements ILuaAPI {
@LuaFunction @LuaFunction
public final Object[] getBlockPosition() { public final Object[] getBlockPosition() {
// This is probably safe to do on the Lua thread. Probably. // 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() }; 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. * @throws LuaException If trying to get information about more than 4096 blocks.
* @cc.since 1.76 * @cc.since 1.76
* @cc.changed 1.99 Added {@code dimension} argument. * @cc.changed 1.99 Added {@code dimension} argument.
*
* @cc.usage Print out all blocks in a cube around the computer. * @cc.usage Print out all blocks in a cube around the computer.
* *
* <pre>{@code * <pre>{@code
@ -220,7 +222,7 @@ public class CommandAPI implements ILuaAPI {
Math.max(minY, maxY), Math.max(minY, maxY),
Math.max(minZ, maxZ) 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"); 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 { private Level getLevel(Optional<String> id) throws LuaException {
var currentLevel = (ServerLevel) computer.getLevel(); var currentLevel = computer.getLevel();
if (currentLevel == null) throw new LuaException("No world exists");
if (!id.isPresent()) return currentLevel; if (id.isEmpty()) return currentLevel;
var dimensionId = ResourceLocation.tryParse(id.get()); var dimensionId = ResourceLocation.tryParse(id.get());
if (dimensionId == null) throw new LuaException("Invalid dimension name"); if (dimensionId == null) throw new LuaException("Invalid dimension name");
@ -278,4 +279,52 @@ public class CommandAPI implements ILuaAPI {
return level; 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);
}
}
} }

View File

@ -8,85 +8,21 @@ import dan200.computercraft.shared.computer.apis.CommandAPI;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.config.Config; import dan200.computercraft.shared.config.Config;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player; 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.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; 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 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) { public CommandComputerBlockEntity(BlockEntityType<? extends ComputerBlockEntity> type, BlockPos pos, BlockState state) {
super(type, pos, state, ComputerFamily.COMMAND); 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 @Override
protected ServerComputer createComputer(int id) { protected ServerComputer createComputer(int id) {
var computer = super.createComputer(id); var computer = super.createComputer(id);
computer.addAPI(new CommandAPI(this)); computer.addAPI(new CommandAPI(computer));
return computer; return computer;
} }