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.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);
}
}
}

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.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;
}