diff --git a/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java b/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java index 16a41708..94bd965b 100644 --- a/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java +++ b/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java @@ -14,6 +14,11 @@ public class ClientPlayerEntity_clientCommandMixin @Inject(method = "sendChatMessage", at = @At("HEAD")) private void inspectMessage(String string, CallbackInfo ci) { + if (string.startsWith("/call")) + { + String command = string.substring(6); + CarpetClient.sendClientCommand(command); + } if (CarpetServer.minecraft_server == null && !CarpetClient.isCarpet()) { ClientPlayerEntity playerSource = (ClientPlayerEntity)(Object) this; diff --git a/src/main/java/carpet/network/CarpetClient.java b/src/main/java/carpet/network/CarpetClient.java index 7010eb31..47f74fd4 100644 --- a/src/main/java/carpet/network/CarpetClient.java +++ b/src/main/java/carpet/network/CarpetClient.java @@ -1,8 +1,13 @@ package carpet.network; import carpet.CarpetServer; +import carpet.CarpetSettings; import carpet.script.utils.ShapesRenderer; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; public class CarpetClient @@ -51,4 +56,26 @@ public class CarpetClient { return isServerCarpet; } + + public static boolean sendClientCommand(String command) + { + if (!isServerCarpet && CarpetServer.minecraft_server == null) return false; + ClientNetworkHandler.clientCommand(command); + return true; + } + + public static void onClientCommand(Tag t) + { + CarpetSettings.LOG.info("Server Response:"); + CompoundTag tag = (CompoundTag)t; + CarpetSettings.LOG.info(" - id: "+tag.getString("id")); + CarpetSettings.LOG.info(" - code: "+tag.getInt("code")); + if (tag.contains("error")) CarpetSettings.LOG.warn(" - error: "+tag.getString("error")); + if (tag.contains("output")) + { + ListTag outputTag = (ListTag) tag.get("output"); + for (int i = 0; i < outputTag.size(); i++) + CarpetSettings.LOG.info(" - response: " + Text.Serializer.fromJson(outputTag.getString(i)).getString()); + } + } } diff --git a/src/main/java/carpet/network/ClientNetworkHandler.java b/src/main/java/carpet/network/ClientNetworkHandler.java index c65e2ac6..e105069d 100644 --- a/src/main/java/carpet/network/ClientNetworkHandler.java +++ b/src/main/java/carpet/network/ClientNetworkHandler.java @@ -44,6 +44,9 @@ public class ClientNetworkHandler if (CarpetClient.shapes != null) CarpetClient.shapes.addShapes((ListTag) t); }); + put("clientCommand", (p, t) -> { + CarpetClient.onClientCommand(t); + }); }}; @@ -99,4 +102,17 @@ public class ClientNetworkHandler CarpetSettings.LOG.error("Unknown carpet data: "+key); } } + + public static void clientCommand(String command) + { + CompoundTag tag = new CompoundTag(); + tag.putString("id", command); + tag.putString("command", command); + CompoundTag outer = new CompoundTag(); + outer.put("clientCommand", tag); + CarpetClient.getPlayer().networkHandler.sendPacket(new CustomPayloadC2SPacket( + CarpetClient.CARPET_CHANNEL, + (new PacketByteBuf(Unpooled.buffer())).writeVarInt(CarpetClient.DATA).writeCompoundTag(outer) + )); + } } diff --git a/src/main/java/carpet/network/ServerNetworkHandler.java b/src/main/java/carpet/network/ServerNetworkHandler.java index 6de0b77b..b5427e6f 100644 --- a/src/main/java/carpet/network/ServerNetworkHandler.java +++ b/src/main/java/carpet/network/ServerNetworkHandler.java @@ -6,21 +6,35 @@ import carpet.helpers.TickSpeed; import carpet.settings.ParsedRule; import io.netty.buffer.Unpooled; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; import net.minecraft.util.PacketByteBuf; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BiConsumer; public class ServerNetworkHandler { private static Map remoteCarpetPlayers = new HashMap<>(); private static Set validCarpetPlayers = new HashSet<>(); + private static Map> dataHandlers = new HashMap>(){{ + put("clientCommand", (p, t) -> { + handleClientCommand(p, (CompoundTag)t); + }); + }}; + public static void handleData(PacketByteBuf data, ServerPlayerEntity player) { if (data != null) @@ -28,8 +42,13 @@ public class ServerNetworkHandler int id = data.readVarInt(); if (id == CarpetClient.HELLO) onHello(player, data); + if (id == CarpetClient.DATA) + onClientData(player, data); } } + + + public static void onPlayerJoin(ServerPlayerEntity playerEntity) { if (!playerEntity.networkHandler.connection.isLocal()) @@ -60,6 +79,67 @@ public class ServerNetworkHandler CarpetServer.settingsManager.getRules().forEach(data::withRule); playerEntity.networkHandler.sendPacket(new CustomPayloadS2CPacket(CarpetClient.CARPET_CHANNEL, data.build() )); } + + private static void handleClientCommand(ServerPlayerEntity player, CompoundTag commandData) + { + String command = commandData.getString("command"); + String id = commandData.getString("id"); + List output = new ArrayList<>(); + String[] error = {null}; + int resultCode = -1; + if (player.getServer() == null) + { + error[0] = "No Server"; + } + else + { + resultCode = player.getServer().getCommandManager().execute( + new ServerCommandSource(player, player.getPos(), player.getRotationClient(), + player.world instanceof ServerWorld ? (ServerWorld) player.world : null, + player.server.getPermissionLevel(player.getGameProfile()), player.getName().getString(), player.getDisplayName(), + player.world.getServer(), player) + { + @Override + public void sendError(Text message) + { + error[0] = message.getString(); + } + @Override + public void sendFeedback(Text message, boolean broadcastToOps) + { + output.add(message); + } + }, + command + ); + }; + CompoundTag result = new CompoundTag(); + result.putString("id", id); + result.putInt("code", resultCode); + if (error[0] != null) result.putString("error", error[0]); + ListTag outputResult = new ListTag(); + for (Text line: output) outputResult.add(StringTag.of(Text.Serializer.toJson(line))); + if (!output.isEmpty()) result.put("output", outputResult); + player.networkHandler.sendPacket(new CustomPayloadS2CPacket( + CarpetClient.CARPET_CHANNEL, + DataBuilder.create().withCustomNbt("clientCommand", result).build() + )); + // run command plug to command output, + } + + + private static void onClientData(ServerPlayerEntity player, PacketByteBuf data) + { + CompoundTag compound = data.readCompoundTag(); + if (compound == null) return; + for (String key: compound.getKeys()) + { + if (dataHandlers.containsKey(key)) + dataHandlers.get(key).accept(player, compound.get(key)); + else + CarpetSettings.LOG.warn("Unknown carpet client data: "+key); + } + } public static void updateRuleWithConnectedClients(ParsedRule rule) {