diff --git a/src/main/java/carpet/CarpetServer.java b/src/main/java/carpet/CarpetServer.java index 554a4ca1..f86cfa31 100644 --- a/src/main/java/carpet/CarpetServer.java +++ b/src/main/java/carpet/CarpetServer.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Random; import carpet.commands.*; +import carpet.helpers.ServerNetworkHandler; import carpet.helpers.TickSpeed; import carpet.logging.LoggerRegistry; import carpet.script.CarpetScriptServer; @@ -17,6 +18,7 @@ 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 { @@ -26,6 +28,7 @@ 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) @@ -45,6 +48,9 @@ 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) @@ -104,6 +110,7 @@ public class CarpetServer // static for now - easier to handle all around the co { LoggerRegistry.playerConnected(player); extensions.forEach(e -> e.onPlayerLoggedIn(player)); + ServerNetworkHandler.onPlayerJoin(player); } public static void onPlayerLoggedOut(ServerPlayerEntity player) diff --git a/src/main/java/carpet/helpers/ClientNetworkHandler.java b/src/main/java/carpet/helpers/ClientNetworkHandler.java new file mode 100644 index 00000000..5e15e6ba --- /dev/null +++ b/src/main/java/carpet/helpers/ClientNetworkHandler.java @@ -0,0 +1,59 @@ +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 new file mode 100644 index 00000000..77b393d3 --- /dev/null +++ b/src/main/java/carpet/helpers/ServerNetworkHandler.java @@ -0,0 +1,66 @@ +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 33d735b7..1c1c4d2b 100644 --- a/src/main/java/carpet/helpers/TickSpeed.java +++ b/src/main/java/carpet/helpers/TickSpeed.java @@ -221,6 +221,7 @@ public class TickSpeed } } } + ServerNetworkHandler.sendTickRateToPlayers(tickrate); } 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 new file mode 100644 index 00000000..0e8fafcf --- /dev/null +++ b/src/main/java/carpet/mixins/ClientPlayNetworkHandlerMixin.java @@ -0,0 +1,44 @@ +package carpet.mixins; + +import carpet.CarpetServer; +import carpet.helpers.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 org.spongepowered.asm.mixin.Mixin; +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(); + } + } + + @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(); + } +} diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index c1356941..041dbaaa 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -177,7 +177,8 @@ "ClientPlayNetworkHandler_smoothClientAnimationsMixin", "ClientPlayerEntity_clientCommandMixin", "WorldRenderer_fogOffMixin", - "WorldRenderer_creativeNoClipMixin" + "WorldRenderer_creativeNoClipMixin", + "ClientPlayNetworkHandlerMixin" ], "server": [