diff --git a/src/main/java/carpet/CarpetServer.java b/src/main/java/carpet/CarpetServer.java index f86cfa31..7cc7f021 100644 --- a/src/main/java/carpet/CarpetServer.java +++ b/src/main/java/carpet/CarpetServer.java @@ -6,7 +6,7 @@ import java.util.List; import java.util.Random; import carpet.commands.*; -import carpet.helpers.ServerNetworkHandler; +import carpet.network.ServerNetworkHandler; import carpet.helpers.TickSpeed; import carpet.logging.LoggerRegistry; import carpet.script.CarpetScriptServer; @@ -18,7 +18,6 @@ import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Identifier; public class CarpetServer // static for now - easier to handle all around the code, its one anyways { @@ -28,7 +27,6 @@ public class CarpetServer // static for now - easier to handle all around the co public static CarpetScriptServer scriptServer; public static SettingsManager settingsManager; public static final List extensions = new ArrayList<>(); - public static final Identifier CARPET_CHANNEL = new Identifier("carpet:info"); // Separate from onServerLoaded, because a server can be loaded multiple times in singleplayer public static void manageExtension(CarpetExtension extension) @@ -48,9 +46,6 @@ public class CarpetServer // static for now - easier to handle all around the co settingsManager = new SettingsManager(CarpetSettings.carpetVersion, "carpet", "Carpet Mod"); settingsManager.parseSettingsClass(CarpetSettings.class); extensions.forEach(CarpetExtension::onGameStarted); - CarpetServer.settingsManager.addRuleObserver((source, parsedRule, s) -> { - ServerNetworkHandler.sendUpdateToClient(parsedRule.name, parsedRule.getAsString(), source); - }); } public static void onServerLoaded(MinecraftServer server) @@ -66,6 +61,7 @@ public class CarpetServer // static for now - easier to handle all around the co scriptServer.loadAllWorldScripts(); MobAI.resetTrackers(); LoggerRegistry.initLoggers(); + //TickSpeed.reset(); } public static void tick(MinecraftServer server) @@ -108,31 +104,41 @@ public class CarpetServer // static for now - easier to handle all around the co public static void onPlayerLoggedIn(ServerPlayerEntity player) { + ServerNetworkHandler.onPlayerJoin(player); LoggerRegistry.playerConnected(player); extensions.forEach(e -> e.onPlayerLoggedIn(player)); - ServerNetworkHandler.onPlayerJoin(player); + } public static void onPlayerLoggedOut(ServerPlayerEntity player) { + ServerNetworkHandler.onPlayerLoggedOut(player); LoggerRegistry.playerDisconnected(player); extensions.forEach(e -> e.onPlayerLoggedOut(player)); } public static void onServerClosed(MinecraftServer server) { + ServerNetworkHandler.close(); currentCommandDispatcher = null; if (scriptServer != null) scriptServer.onClose(); - settingsManager.detachServer(); + LoggerRegistry.stopLoggers(); - TickSpeed.reset(); extensions.forEach(e -> e.onServerClosed(server)); minecraft_server = null; + disconnect(); } public static void registerExtensionLoggers() { extensions.forEach(CarpetExtension::registerLoggers); } + + public static void disconnect() + { + // this for whatever reason gets called multiple times even when joining; + TickSpeed.reset(); + settingsManager.detachServer(); + } } diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java index 4913bb1f..a198b438 100644 --- a/src/main/java/carpet/CarpetSettings.java +++ b/src/main/java/carpet/CarpetSettings.java @@ -44,7 +44,7 @@ public class CarpetSettings private static class LanguageValidator extends Validator { @Override public String validate(ServerCommandSource source, ParsedRule currentRule, String newValue, String string) { - if (currentRule.get().equals(newValue)) + if (currentRule.get().equals(newValue) || source == null) { return newValue; } @@ -487,7 +487,7 @@ public class CarpetSettings { @Override public Integer validate(ServerCommandSource source, ParsedRule currentRule, Integer newValue, String string) { - if (currentRule.get().equals(newValue)) + if (currentRule.get().equals(newValue) || source == null) { return newValue; } @@ -538,6 +538,7 @@ public class CarpetSettings } } @Override public Integer validate(ServerCommandSource source, ParsedRule currentRule, Integer newValue, String string) { + if (source == null) return newValue; if (newValue < 0 || newValue > 32) { Messenger.m(source, "r spawn chunk size has to be between 0 and 32"); diff --git a/src/main/java/carpet/commands/TickCommand.java b/src/main/java/carpet/commands/TickCommand.java index cc7dc38c..0b559f38 100644 --- a/src/main/java/carpet/commands/TickCommand.java +++ b/src/main/java/carpet/commands/TickCommand.java @@ -67,7 +67,7 @@ public class TickCommand private static int setTps(ServerCommandSource source, float tps) { - TickSpeed.tickrate(tps); + TickSpeed.tickrate(tps, true); queryTps(source); return (int)tps; } diff --git a/src/main/java/carpet/fakes/CustomPayloadC2SPacketInterface.java b/src/main/java/carpet/fakes/CustomPayloadC2SPacketInterface.java new file mode 100644 index 00000000..baa636e7 --- /dev/null +++ b/src/main/java/carpet/fakes/CustomPayloadC2SPacketInterface.java @@ -0,0 +1,10 @@ +package carpet.fakes; + +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +public interface CustomPayloadC2SPacketInterface +{ + Identifier getPacketChannel(); + PacketByteBuf getPacketData(); +} diff --git a/src/main/java/carpet/helpers/ClientNetworkHandler.java b/src/main/java/carpet/helpers/ClientNetworkHandler.java deleted file mode 100644 index 5e15e6ba..00000000 --- a/src/main/java/carpet/helpers/ClientNetworkHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -package carpet.helpers; - -import carpet.CarpetServer; -import carpet.CarpetSettings; -import carpet.settings.ParsedRule; -import net.minecraft.client.MinecraftClient; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.util.Identifier; -import net.minecraft.util.PacketByteBuf; - -public class ClientNetworkHandler -{ - public static void handleData(Identifier channel, PacketByteBuf data) - { - if (CarpetServer.CARPET_CHANNEL.equals(channel) && data != null) - { - int id = data.readVarInt(); - - if (id == 1) - setOnJoinInfo(data); - else if (id == 2) - updateRule(data); - else if (id == 3) - updateTickRateClient(data); - } - } - - private static void setOnJoinInfo(PacketByteBuf data) - { - CompoundTag compound = data.readCompoundTag(); - if (compound == null) return; - - TickSpeed.tickrate(compound.getFloat("Tickrate")); - - ListTag rulesList = compound.getList("rules", 10); - for (Tag tag : rulesList) - { - CompoundTag ruleNBT = (CompoundTag) tag; - String rule = ruleNBT.getString("rule"); - String value = ruleNBT.getString("value"); - CarpetServer.settingsManager.getRule(rule).set(null, value); - } - } - - private static void updateRule(PacketByteBuf data) - { - String rule = data.readString(); - String newValue = data.readString(); - CarpetServer.settingsManager.getRule(rule).set(null, newValue); - } - - private static void updateTickRateClient(PacketByteBuf data) - { - float rate = data.readFloat(); - TickSpeed.tickrate(rate); - } -} diff --git a/src/main/java/carpet/helpers/ServerNetworkHandler.java b/src/main/java/carpet/helpers/ServerNetworkHandler.java deleted file mode 100644 index 77b393d3..00000000 --- a/src/main/java/carpet/helpers/ServerNetworkHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -package carpet.helpers; - -import carpet.CarpetServer; -import carpet.CarpetSettings; -import carpet.settings.ParsedRule; -import io.netty.buffer.Unpooled; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.PacketByteBuf; - -public class ServerNetworkHandler -{ - public static void onPlayerJoin(ServerPlayerEntity playerEntity) - { - CompoundTag data = new CompoundTag(); - - data.putFloat("Tickrate", TickSpeed.tickrate); - - ListTag rulesList = new ListTag(); - for (ParsedRule rule : CarpetServer.settingsManager.getRules()) - { - CompoundTag ruleNBT = new CompoundTag(); - - ruleNBT.putString("rule" ,rule.name); - ruleNBT.putString("value", rule.getAsString()); - ruleNBT.putString("default", rule.defaultAsString); - rulesList.add(ruleNBT); - } - data.put("rules", rulesList); - PacketByteBuf packetBuf = new PacketByteBuf(Unpooled.buffer()); - packetBuf.writeVarInt(1); - packetBuf.writeCompoundTag(data); - playerEntity.networkHandler.sendPacket(new CustomPayloadS2CPacket(CarpetServer.CARPET_CHANNEL, packetBuf)); - } - - public static void sendUpdateToClient(String rule, String newValue, ServerCommandSource source) - { - PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); - - data.writeVarInt(2); - data.writeString(rule); - data.writeString(newValue); - for (ServerPlayerEntity player : source.getMinecraftServer().getPlayerManager().getPlayerList()) - { - player.networkHandler.sendPacket(new CustomPayloadS2CPacket(CarpetServer.CARPET_CHANNEL, data)); - } - } - - public static void sendTickRateToPlayers(float rate) - { - PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); - data.writeVarInt(3); - data.writeFloat(rate); - if (CarpetServer.minecraft_server != null) - { - for (ServerPlayerEntity player : CarpetServer.minecraft_server.getPlayerManager().getPlayerList()) - { - player.networkHandler.sendPacket(new CustomPayloadS2CPacket(CarpetServer.CARPET_CHANNEL, data)); - } - } - } -} diff --git a/src/main/java/carpet/helpers/TickSpeed.java b/src/main/java/carpet/helpers/TickSpeed.java index 1c1c4d2b..091c7c73 100644 --- a/src/main/java/carpet/helpers/TickSpeed.java +++ b/src/main/java/carpet/helpers/TickSpeed.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.function.BiConsumer; import carpet.CarpetServer; +import carpet.network.ServerNetworkHandler; import carpet.utils.Messenger; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; @@ -177,7 +178,7 @@ public class TickSpeed } } - public static void tickrate(float rate) + public static void tickrate(float rate, boolean update) { tickrate = rate; long mspt = (long)(1000.0 / tickrate); @@ -189,7 +190,7 @@ public class TickSpeed TickSpeed.mspt = (float)mspt; - notifyTickrateListeners("carpet"); + if (update) notifyTickrateListeners("carpet"); } private static void tickrateChanged(String modId, float rate) @@ -221,7 +222,7 @@ public class TickSpeed } } } - ServerNetworkHandler.sendTickRateToPlayers(tickrate); + ServerNetworkHandler.updateTickSpeedToConnectedPlayers(); } public static BiConsumer addTickrateListener(String modId, BiConsumer tickrateListener) diff --git a/src/main/java/carpet/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/carpet/mixins/ClientPlayNetworkHandlerMixin.java index 0e8fafcf..362828ea 100644 --- a/src/main/java/carpet/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/carpet/mixins/ClientPlayNetworkHandlerMixin.java @@ -1,44 +1,43 @@ package carpet.mixins; -import carpet.CarpetServer; -import carpet.helpers.ClientNetworkHandler; +import carpet.network.CarpetClient; +import carpet.network.ClientNetworkHandler; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.util.Identifier; -import net.minecraft.util.PacketByteBuf; +import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; +import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(ClientPlayNetworkHandler.class) public abstract class ClientPlayNetworkHandlerMixin { - @Inject(method = "onCustomPayload", at = @At(value = "CONSTANT", args = "stringValue=Unknown custom packed identifier: {}"), cancellable = true, locals = LocalCapture.CAPTURE_FAILSOFT, require = 0) - private void onCustomPayloadNotFound(CustomPayloadS2CPacket packet, CallbackInfo ci, Identifier id, PacketByteBuf buf) - { - if (CarpetServer.CARPET_CHANNEL.equals(id)) - { - if (buf.refCnt() > 0) - { - buf.release(); - } - - ci.cancel(); - } - } - + @Shadow private MinecraftClient client; + @Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true) private void onOnCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { - Identifier channel = packet.getChannel(); - PacketByteBuf buf = packet.getData(); - ClientNetworkHandler.handleData(channel, buf); - ci.cancel(); + if (CarpetClient.CARPET_CHANNEL.equals(packet.getChannel())) + { + ClientNetworkHandler.handleData(packet.getData(), client.player); + ci.cancel(); + } } + + @Inject(method = "onGameJoin", at = @At("RETURN")) + private void onGameJoined(GameJoinS2CPacket packet, CallbackInfo info) + { + CarpetClient.gameJoined(client.player); + } + + @Inject(method = "onDisconnected", at = @At("HEAD")) + private void onCMDisconnected(Text reason, CallbackInfo ci) + { + CarpetClient.disconnect(); + } + } diff --git a/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java b/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java index a0347524..16a41708 100644 --- a/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java +++ b/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java @@ -1,6 +1,7 @@ package carpet.mixins; import carpet.CarpetServer; +import carpet.network.CarpetClient; import net.minecraft.client.network.ClientPlayerEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -13,8 +14,10 @@ public class ClientPlayerEntity_clientCommandMixin @Inject(method = "sendChatMessage", at = @At("HEAD")) private void inspectMessage(String string, CallbackInfo ci) { - ClientPlayerEntity playerSource = (ClientPlayerEntity)(Object) this; - if (CarpetServer.minecraft_server == null) + if (CarpetServer.minecraft_server == null && !CarpetClient.isCarpet()) + { + ClientPlayerEntity playerSource = (ClientPlayerEntity)(Object) this; CarpetServer.settingsManager.inspectClientsideCommand(playerSource.getCommandSource(), string); + } } } diff --git a/src/main/java/carpet/mixins/CustomPayloadC2SPacketMixin.java b/src/main/java/carpet/mixins/CustomPayloadC2SPacketMixin.java new file mode 100644 index 00000000..0465c72e --- /dev/null +++ b/src/main/java/carpet/mixins/CustomPayloadC2SPacketMixin.java @@ -0,0 +1,27 @@ +package carpet.mixins; + +import carpet.fakes.CustomPayloadC2SPacketInterface; +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(CustomPayloadC2SPacket.class) +public class CustomPayloadC2SPacketMixin implements CustomPayloadC2SPacketInterface +{ + @Shadow + private Identifier channel; + @Shadow + private PacketByteBuf data; + + @Override + public Identifier getPacketChannel() { + return channel; + } + + @Override + public PacketByteBuf getPacketData() { + return new PacketByteBuf(this.data.copy()); + } +} diff --git a/src/main/java/carpet/mixins/MinecraftClientMixin.java b/src/main/java/carpet/mixins/MinecraftClientMixin.java index 2598239a..c2c9be06 100644 --- a/src/main/java/carpet/mixins/MinecraftClientMixin.java +++ b/src/main/java/carpet/mixins/MinecraftClientMixin.java @@ -1,7 +1,9 @@ package carpet.mixins; import carpet.CarpetServer; +import carpet.network.CarpetClient; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -18,4 +20,10 @@ public class MinecraftClientMixin //CM start game hook CarpetServer.onGameStarted(); } + + @Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At("HEAD")) + private void onCloseGame(Screen screen, CallbackInfo ci) + { + CarpetClient.disconnect(); + } } diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandlerMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 00000000..bec53d32 --- /dev/null +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandlerMixin.java @@ -0,0 +1,31 @@ +package carpet.mixins; + +import carpet.fakes.CustomPayloadC2SPacketInterface; +import carpet.network.CarpetClient; +import carpet.network.ServerNetworkHandler; +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayNetworkHandler.class) +public class ServerPlayNetworkHandlerMixin +{ + @Shadow public ServerPlayerEntity player; + + @Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true) + private void onCustomCarpetPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) + { + Identifier channel = ((CustomPayloadC2SPacketInterface) packet).getPacketChannel(); + if (CarpetClient.CARPET_CHANNEL.equals(channel)) + { + ServerNetworkHandler.handleData(((CustomPayloadC2SPacketInterface) packet).getPacketData(), player); + ci.cancel(); + } + } +} diff --git a/src/main/java/carpet/network/CarpetClient.java b/src/main/java/carpet/network/CarpetClient.java new file mode 100644 index 00000000..0846a9d0 --- /dev/null +++ b/src/main/java/carpet/network/CarpetClient.java @@ -0,0 +1,52 @@ +package carpet.network; + +import carpet.CarpetServer; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.util.Identifier; + +public class CarpetClient +{ + public static final Object sync = new Object(); + public static final int HI = 69; + public static final int HELLO = 420; + public static final int DATA = 1; + + private static ClientPlayerEntity clientPlayer = null; + private static boolean isServerCarpet = false; + public static String serverCarpetVersion; + public static final Identifier CARPET_CHANNEL = new Identifier("carpet:hello"); + + public static void gameJoined(ClientPlayerEntity player) + { + synchronized (sync) + { + clientPlayer = player; + // client didn't say hi back yet + if (isServerCarpet) + ClientNetworkHandler.respondHello(); + + } + } + + public static void disconnect() + { + isServerCarpet = false; + clientPlayer = null; + CarpetServer.disconnect(); + } + + public static void setCarpet() + { + isServerCarpet = true; + } + + public static ClientPlayerEntity getPlayer() + { + return clientPlayer; + } + + public static boolean isCarpet() + { + return isServerCarpet; + } +} diff --git a/src/main/java/carpet/network/ClientNetworkHandler.java b/src/main/java/carpet/network/ClientNetworkHandler.java new file mode 100644 index 00000000..68e2349a --- /dev/null +++ b/src/main/java/carpet/network/ClientNetworkHandler.java @@ -0,0 +1,93 @@ +package carpet.network; + +import carpet.CarpetServer; +import carpet.CarpetSettings; +import carpet.helpers.TickSpeed; +import carpet.settings.ParsedRule; +import io.netty.buffer.Unpooled; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.nbt.AbstractNumberTag; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.util.PacketByteBuf; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; + +public class ClientNetworkHandler +{ + private static Map> dataHandlers = new HashMap>(){{ + put("Rules", (p, t) -> { + CompoundTag ruleset = (CompoundTag)t; + for (String ruleName: ruleset.getKeys()) + { + ParsedRule rule = CarpetServer.settingsManager.getRule(ruleName); + if (rule == null) + CarpetSettings.LOG.error("Received unknown rule: "+ruleName); + else + { + CompoundTag ruleNBT = (CompoundTag) ruleset.get(ruleName); + String value = ruleNBT.getString("Value"); + rule.set(null, value); + } + } + }); + put("TickRate", (p, t) -> TickSpeed.tickrate(((AbstractNumberTag)t).getFloat(), false)); + }}; + + + public static void handleData(PacketByteBuf data, ClientPlayerEntity player) + { + if (data != null) + { + int id = data.readVarInt(); + if (id == CarpetClient.HI) + onHi(data); + if (id == CarpetClient.DATA) + onSyncData(data, player); + } + } + + private static void onHi(PacketByteBuf data) + { + synchronized (CarpetClient.sync) + { + CarpetClient.setCarpet(); + CarpetClient.serverCarpetVersion = data.readString(64); + if (CarpetSettings.carpetVersion.equals(CarpetClient.serverCarpetVersion)) + { + CarpetSettings.LOG.info("Joined carpet server with matching carpet version"); + } + else + { + CarpetSettings.LOG.warn("Joined carpet server with another carpet version: "+CarpetClient.serverCarpetVersion); + } + if (CarpetClient.getPlayer() != null) + respondHello(); + + } + } + + public static void respondHello() + { + CarpetClient.getPlayer().networkHandler.sendPacket(new CustomPayloadC2SPacket( + CarpetClient.CARPET_CHANNEL, + (new PacketByteBuf(Unpooled.buffer())).writeVarInt(CarpetClient.HELLO).writeString(CarpetSettings.carpetVersion) + )); + } + + private static void onSyncData(PacketByteBuf data, ClientPlayerEntity player) + { + 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.error("Unknown carpet data: "+key); + } + } +} diff --git a/src/main/java/carpet/network/ServerNetworkHandler.java b/src/main/java/carpet/network/ServerNetworkHandler.java new file mode 100644 index 00000000..152fcc37 --- /dev/null +++ b/src/main/java/carpet/network/ServerNetworkHandler.java @@ -0,0 +1,123 @@ +package carpet.network; + +import carpet.CarpetServer; +import carpet.CarpetSettings; +import carpet.helpers.TickSpeed; +import carpet.settings.ParsedRule; +import io.netty.buffer.Unpooled; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.PacketByteBuf; + +import java.util.ArrayList; +import java.util.List; + +public class ServerNetworkHandler +{ + private static List carpetPlayers = new ArrayList<>(); + + public static void handleData(PacketByteBuf data, ServerPlayerEntity player) + { + if (data != null) + { + int id = data.readVarInt(); + if (id == CarpetClient.HELLO) + onHello(player, data); + } + } + public static void onPlayerJoin(ServerPlayerEntity playerEntity) + { + if (!playerEntity.networkHandler.connection.isLocal()) + { + playerEntity.networkHandler.sendPacket(new CustomPayloadS2CPacket( + CarpetClient.CARPET_CHANNEL, + (new PacketByteBuf(Unpooled.buffer())).writeVarInt(CarpetClient.HI).writeString(CarpetSettings.carpetVersion) + )); + } + } + + public static void onHello(ServerPlayerEntity playerEntity, PacketByteBuf packetData) + { + carpetPlayers.add(playerEntity); + String clientVersion = packetData.readString(64); + if (clientVersion.equals(CarpetSettings.carpetVersion)) + CarpetSettings.LOG.info("Player "+playerEntity.getName().getString()+" joined with a matching carpet client"); + else + CarpetSettings.LOG.warn("Player "+playerEntity.getName().getString()+" joined with another carpet version: "+clientVersion); + DataBuilder data = DataBuilder.create().withTickRate(); + CarpetServer.settingsManager.getRules().forEach(data::withRule); + playerEntity.networkHandler.sendPacket(new CustomPayloadS2CPacket(CarpetClient.CARPET_CHANNEL, data.build() )); + } + + public static void updateRuleWithConnectedClients(ParsedRule rule) + { + for (ServerPlayerEntity player : carpetPlayers) + { + player.networkHandler.sendPacket(new CustomPayloadS2CPacket( + CarpetClient.CARPET_CHANNEL, + DataBuilder.create().withRule(rule).build() + )); + } + } + + public static void updateTickSpeedToConnectedPlayers() + { + for (ServerPlayerEntity player : carpetPlayers) + { + player.networkHandler.sendPacket(new CustomPayloadS2CPacket( + CarpetClient.CARPET_CHANNEL, + DataBuilder.create().withTickRate().build() + )); + } + } + + public static void onPlayerLoggedOut(ServerPlayerEntity player) + { + if (!player.networkHandler.connection.isLocal()) + carpetPlayers.remove(player); + } + + public static void close() + { + carpetPlayers.clear(); + } + + private static class DataBuilder + { + private CompoundTag tag; + private static DataBuilder create() + { + return new DataBuilder(); + } + private DataBuilder() + { + tag = new CompoundTag(); + } + private DataBuilder withTickRate() + { + tag.putFloat("TickRate", TickSpeed.tickrate); + return this; + } + private DataBuilder withRule(ParsedRule rule) + { + CompoundTag rules = (CompoundTag) tag.get("Rules"); + if (rules == null) + { + rules = new CompoundTag(); + tag.put("Rules", rules); + } + CompoundTag ruleNBT = new CompoundTag(); + ruleNBT.putString("Value", rule.getAsString()); + rules.put(rule.name, ruleNBT); + return this; + } + private PacketByteBuf build() + { + PacketByteBuf packetBuf = new PacketByteBuf(Unpooled.buffer()); + packetBuf.writeVarInt(CarpetClient.DATA); + packetBuf.writeCompoundTag(tag); + return packetBuf; + } + } +} diff --git a/src/main/java/carpet/settings/SettingsManager.java b/src/main/java/carpet/settings/SettingsManager.java index 93aac4df..5765f422 100644 --- a/src/main/java/carpet/settings/SettingsManager.java +++ b/src/main/java/carpet/settings/SettingsManager.java @@ -2,6 +2,7 @@ package carpet.settings; import carpet.CarpetServer; import carpet.CarpetSettings; +import carpet.network.ServerNetworkHandler; import carpet.utils.Translations; import carpet.utils.Messenger; import com.google.common.collect.ImmutableList; @@ -80,7 +81,7 @@ public class SettingsManager public void detachServer() { - for (ParsedRule rule : rules.values()) rule.resetToDefault(server.getCommandSource()); + for (ParsedRule rule : rules.values()) rule.resetToDefault(null); server = null; } @@ -103,6 +104,7 @@ public class SettingsManager void notifyRuleChanged(ServerCommandSource source, ParsedRule rule, String userTypedValue) { observers.forEach(observer -> observer.accept(source, rule, userTypedValue)); + ServerNetworkHandler.updateRuleWithConnectedClients(rule); } public Iterable getCategories() @@ -584,8 +586,6 @@ public class SettingsManager rules.get(setting).set(source, strOption); } } - - } } } diff --git a/src/main/java/carpet/settings/Validator.java b/src/main/java/carpet/settings/Validator.java index 8b561ff6..3f48fff0 100644 --- a/src/main/java/carpet/settings/Validator.java +++ b/src/main/java/carpet/settings/Validator.java @@ -22,7 +22,7 @@ public abstract class Validator @Override public T validate(ServerCommandSource source, ParsedRule currentRule, T newValue, String string) { - if (CarpetServer.settingsManager != null) + if (CarpetServer.settingsManager != null && source != null) CarpetServer.settingsManager.notifyPlayersCommandsChanged(); return newValue; } diff --git a/src/main/java/carpet/utils/Messenger.java b/src/main/java/carpet/utils/Messenger.java index 78e7fddc..7aa4f7b5 100644 --- a/src/main/java/carpet/utils/Messenger.java +++ b/src/main/java/carpet/utils/Messenger.java @@ -231,7 +231,8 @@ public class Messenger //message source public static void m(ServerCommandSource source, Object ... fields) { - source.sendFeedback(Messenger.c(fields),source.getMinecraftServer() != null && source.getMinecraftServer().getWorld(DimensionType.OVERWORLD) != null); + if (source != null) + source.sendFeedback(Messenger.c(fields),source.getMinecraftServer() != null && source.getMinecraftServer().getWorld(DimensionType.OVERWORLD) != null); } public static void m(PlayerEntity player, Object ... fields) { diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 041dbaaa..247b24d1 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -6,6 +6,9 @@ "mixins": [ "CommandManagerMixin", + "ServerPlayNetworkHandlerMixin", + "CustomPayloadC2SPacketMixin", + "FillCommandMixin", "CloneCommandMixin", "SetBlockCommandMixin",