diff --git a/gradle.properties b/gradle.properties index 0633464..ab6b760 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,11 +3,11 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties minecraft_version=1.16.2 -yarn_mappings=1.16.2+build.6 +yarn_mappings=1.16.2+build.9 loader_version=0.9.1+build.205 # Mod Properties -mod_version = 1.0 +mod_version = 1.1 maven_group = net.cavoj archives_base_name = servertick diff --git a/src/main/java/net/cavoj/servertick/NetworkC2S.java b/src/main/java/net/cavoj/servertick/NetworkC2S.java new file mode 100644 index 0000000..485e043 --- /dev/null +++ b/src/main/java/net/cavoj/servertick/NetworkC2S.java @@ -0,0 +1,16 @@ +package net.cavoj.servertick; + +import io.netty.buffer.Unpooled; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; + +public class NetworkC2S { + public static final Identifier PACKET_ENABLED = new Identifier("servertick", "enabled"); + + public static void sendToggle(boolean state) { + PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); + data.writeBoolean(state); + ClientSidePacketRegistry.INSTANCE.sendToServer(PACKET_ENABLED, data); + } +} diff --git a/src/main/java/net/cavoj/servertick/NetworkS2C.java b/src/main/java/net/cavoj/servertick/NetworkS2C.java new file mode 100644 index 0000000..6e0dc3d --- /dev/null +++ b/src/main/java/net/cavoj/servertick/NetworkS2C.java @@ -0,0 +1,25 @@ +package net.cavoj.servertick; + +import io.netty.buffer.Unpooled; +import net.cavoj.servertick.extensions.SerializableMetricsData; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; + +public class NetworkS2C { + public static final Identifier PACKET_FULL_METRICS = new Identifier("servertick", "metrics/full"); + public static final Identifier PACKET_LAST_SAMPLE = new Identifier("servertick", "metrics/sample"); + + public static void sendFullMetrics(SerializableMetricsData metrics, PlayerEntity player) { + PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); + metrics.serialize(data); + ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, PACKET_FULL_METRICS, data); + } + + public static void sendLastSample(long sample, PlayerEntity player) { + PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); + data.writeLong(sample); + ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, PACKET_LAST_SAMPLE, data); + } +} diff --git a/src/main/java/net/cavoj/servertick/Packets.java b/src/main/java/net/cavoj/servertick/Packets.java deleted file mode 100644 index 65394d4..0000000 --- a/src/main/java/net/cavoj/servertick/Packets.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.cavoj.servertick; - -import net.minecraft.util.Identifier; - -public class Packets { - public static final Identifier PACKET_TOGGLE_DEBUG_SCREEN = new Identifier("servertick", "test"); - public static final Identifier PACKET_FULL_METRICS = new Identifier("servertick", "metrics/full"); - public static final Identifier PACKET_SAMPLE_METRICS = new Identifier("servertick", "metrics/sample"); -} diff --git a/src/main/java/net/cavoj/servertick/STServer.java b/src/main/java/net/cavoj/servertick/STServer.java deleted file mode 100644 index b1a1597..0000000 --- a/src/main/java/net/cavoj/servertick/STServer.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.cavoj.servertick; - -import io.netty.buffer.Unpooled; -import net.cavoj.servertick.mixin.server.MinecraftServerAccessor; -import net.fabricmc.api.DedicatedServerModInitializer; -import net.fabricmc.fabric.api.network.PacketContext; -import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.MetricsData; - -import java.util.HashSet; -import java.util.Set; - -public class STServer implements DedicatedServerModInitializer { - private final Set listeners = new HashSet<>(); - private static STServer _instance; - - public STServer() { - if (_instance != null) { - throw new RuntimeException("Cannot have multiple instances"); - } - _instance = this; - } - - @Override - public void onInitializeServer() { - ServerSidePacketRegistry.INSTANCE.register(Packets.PACKET_TOGGLE_DEBUG_SCREEN, this::processTogglePacket); -// ServerTickEvents.END_SERVER_TICK.register(this::onTick); - } - - public static STServer getInstance() { - return _instance; - } - -// private int tickCounter = 0; -// private void onTick(MinecraftServer server) { -// tickCounter++; -// if (tickCounter > 20) { -// tickCounter = 0; -// // Send full metrics every so often to prevent desync -// listeners.forEach(player -> sendMetrics(server, player)); -// } -// } - - private void sendMetrics(MinecraftServer server, PlayerEntity player) { - MetricsData metrics = ((MinecraftServerAccessor)server).getMetricsData(); - PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); - ((SerializableMetricsData)metrics).serialize(data); - ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, Packets.PACKET_FULL_METRICS, data); - } - - private void processTogglePacket(PacketContext ctx, PacketByteBuf data) { - boolean state = data.readBoolean(); - PlayerEntity player = ctx.getPlayer(); - MinecraftServer server = ctx.getPlayer().getServer(); - ctx.getTaskQueue().execute(() -> { - if (state) { - if (player.hasPermissionLevel(4)) { - listeners.add(player); - sendMetrics(server, player); - } - } else { - listeners.remove(player); - } - }); - } - - public void pushSample(long time) { - PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); - data.writeLong(time); - listeners.forEach(player -> ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, Packets.PACKET_SAMPLE_METRICS, data)); - } - - public void onPlayerDisconnected(ServerPlayerEntity player) { - this.listeners.remove(player); - } -} diff --git a/src/main/java/net/cavoj/servertick/ServerTick.java b/src/main/java/net/cavoj/servertick/ServerTick.java new file mode 100644 index 0000000..65eda13 --- /dev/null +++ b/src/main/java/net/cavoj/servertick/ServerTick.java @@ -0,0 +1,39 @@ +package net.cavoj.servertick; + +import net.cavoj.servertick.extensions.MinecraftServerWithST; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.network.PacketContext; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; + +public class ServerTick implements ModInitializer { + @Override + public void onInitialize() { + ServerSidePacketRegistry.INSTANCE.register(NetworkC2S.PACKET_ENABLED, this::processTogglePacket); + ServerTickEvents.END_SERVER_TICK.register((minecraftServer -> { + ((MinecraftServerWithST)minecraftServer).tickST(); + })); + } + + private boolean checkPlayerPrivilege(PlayerEntity player) { + return player.hasPermissionLevel(4) || !player.getServer().isDedicated(); + } + + private void processTogglePacket(PacketContext ctx, PacketByteBuf data) { + boolean state = data.readBoolean(); + ctx.getTaskQueue().execute(() -> { + PlayerEntity player = ctx.getPlayer(); + MinecraftServerWithST server = (MinecraftServerWithST)ctx.getPlayer().getServer(); + assert server != null; + if (state) { + if (checkPlayerPrivilege(player)) { + server.registerSTListener(player); + } + } else { + server.removeSTListener(player); + } + }); + } +} diff --git a/src/main/java/net/cavoj/servertick/STClient.java b/src/main/java/net/cavoj/servertick/ServerTickClient.java similarity index 68% rename from src/main/java/net/cavoj/servertick/STClient.java rename to src/main/java/net/cavoj/servertick/ServerTickClient.java index 45fb3fc..cad57d2 100644 --- a/src/main/java/net/cavoj/servertick/STClient.java +++ b/src/main/java/net/cavoj/servertick/ServerTickClient.java @@ -1,30 +1,30 @@ package net.cavoj.servertick; -import io.netty.buffer.Unpooled; +import net.cavoj.servertick.extensions.SerializableMetricsData; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.network.PacketContext; import net.minecraft.network.PacketByteBuf; import net.minecraft.util.MetricsData; -public class STClient implements ClientModInitializer { - private static STClient _instance; +public class ServerTickClient implements ClientModInitializer { + private static ServerTickClient _instance; - public STClient() { + public ServerTickClient() { if (_instance != null) { throw new RuntimeException("Cannot have multiple instances"); } _instance = this; } - public static STClient getInstance() { + public static ServerTickClient getInstance() { return _instance; } @Override public void onInitializeClient() { - ClientSidePacketRegistry.INSTANCE.register(Packets.PACKET_FULL_METRICS, this::processMetricsFullPacket); - ClientSidePacketRegistry.INSTANCE.register(Packets.PACKET_SAMPLE_METRICS, this::processMetricsSamplePacket); + ClientSidePacketRegistry.INSTANCE.register(NetworkS2C.PACKET_FULL_METRICS, this::processMetricsFullPacket); + ClientSidePacketRegistry.INSTANCE.register(NetworkS2C.PACKET_LAST_SAMPLE, this::processMetricsSamplePacket); } private void processMetricsFullPacket(PacketContext ctx, PacketByteBuf data) { @@ -47,17 +47,15 @@ private void processMetricsSamplePacket(PacketContext ctx, PacketByteBuf data) { public void setTpsEnabled(boolean enabled) { if (this.debugTpsEnabled != enabled) { + if (enabled) { + // To prevent displaying stale data + setMetricsData(null); + } this.debugTpsEnabled = enabled; - updateTpsEnabled(); + NetworkC2S.sendToggle(enabled); } } - private void updateTpsEnabled() { - PacketByteBuf data = new PacketByteBuf(Unpooled.buffer()); - data.writeBoolean(this.debugTpsEnabled); - ClientSidePacketRegistry.INSTANCE.sendToServer(Packets.PACKET_TOGGLE_DEBUG_SCREEN, data); - } - public void setMetricsData(MetricsData data) { this.metrics = data; } diff --git a/src/main/java/net/cavoj/servertick/extensions/LastSampleMetricsData.java b/src/main/java/net/cavoj/servertick/extensions/LastSampleMetricsData.java new file mode 100644 index 0000000..e7b58a6 --- /dev/null +++ b/src/main/java/net/cavoj/servertick/extensions/LastSampleMetricsData.java @@ -0,0 +1,5 @@ +package net.cavoj.servertick.extensions; + +public interface LastSampleMetricsData { + long getLastSample(); +} diff --git a/src/main/java/net/cavoj/servertick/extensions/MinecraftServerWithST.java b/src/main/java/net/cavoj/servertick/extensions/MinecraftServerWithST.java new file mode 100644 index 0000000..b45c501 --- /dev/null +++ b/src/main/java/net/cavoj/servertick/extensions/MinecraftServerWithST.java @@ -0,0 +1,9 @@ +package net.cavoj.servertick.extensions; + +import net.minecraft.entity.player.PlayerEntity; + +public interface MinecraftServerWithST { + void registerSTListener(PlayerEntity player); + void removeSTListener(PlayerEntity player); + void tickST(); +} diff --git a/src/main/java/net/cavoj/servertick/SerializableMetricsData.java b/src/main/java/net/cavoj/servertick/extensions/SerializableMetricsData.java similarity index 80% rename from src/main/java/net/cavoj/servertick/SerializableMetricsData.java rename to src/main/java/net/cavoj/servertick/extensions/SerializableMetricsData.java index 3724200..b5eab5d 100644 --- a/src/main/java/net/cavoj/servertick/SerializableMetricsData.java +++ b/src/main/java/net/cavoj/servertick/extensions/SerializableMetricsData.java @@ -1,4 +1,4 @@ -package net.cavoj.servertick; +package net.cavoj.servertick.extensions; import net.minecraft.network.PacketByteBuf; diff --git a/src/main/java/net/cavoj/servertick/mixin/MetricsDataMixin.java b/src/main/java/net/cavoj/servertick/mixin/MetricsDataMixin.java index 279babf..80a5ce4 100644 --- a/src/main/java/net/cavoj/servertick/mixin/MetricsDataMixin.java +++ b/src/main/java/net/cavoj/servertick/mixin/MetricsDataMixin.java @@ -1,7 +1,7 @@ package net.cavoj.servertick.mixin; -import net.cavoj.servertick.STServer; -import net.cavoj.servertick.SerializableMetricsData; +import net.cavoj.servertick.extensions.LastSampleMetricsData; +import net.cavoj.servertick.extensions.SerializableMetricsData; import net.minecraft.network.PacketByteBuf; import net.minecraft.util.MetricsData; import org.spongepowered.asm.mixin.Final; @@ -12,7 +12,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(MetricsData.class) -public abstract class MetricsDataMixin implements SerializableMetricsData { +public abstract class MetricsDataMixin implements SerializableMetricsData, LastSampleMetricsData { + + private long lastSample; @Shadow @Final private long[] samples; @@ -40,4 +42,13 @@ public void serialize(PacketByteBuf data) { data.writeLong(this.samples[i]); } + @Inject(method = "pushSample", at = @At("HEAD")) + public void pushSample(long sample, CallbackInfo ci) { + this.lastSample = sample; + } + + @Override + public long getLastSample() { + return this.lastSample; + } } diff --git a/src/main/java/net/cavoj/servertick/mixin/MinecraftServerMixin.java b/src/main/java/net/cavoj/servertick/mixin/MinecraftServerMixin.java new file mode 100644 index 0000000..65feb15 --- /dev/null +++ b/src/main/java/net/cavoj/servertick/mixin/MinecraftServerMixin.java @@ -0,0 +1,39 @@ +package net.cavoj.servertick.mixin; + +import net.cavoj.servertick.NetworkS2C; +import net.cavoj.servertick.extensions.LastSampleMetricsData; +import net.cavoj.servertick.extensions.MinecraftServerWithST; +import net.cavoj.servertick.extensions.SerializableMetricsData; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.MetricsData; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.HashSet; + +@Mixin(MinecraftServer.class) +public abstract class MinecraftServerMixin implements MinecraftServerWithST { + @Shadow @Final private MetricsData metricsData; + private final HashSet listeners = new HashSet<>(); + + @Override + public void registerSTListener(PlayerEntity player) { + this.listeners.add(player); + NetworkS2C.sendFullMetrics((SerializableMetricsData) this.metricsData, player); + } + + @Override + public void removeSTListener(PlayerEntity player) { + this.listeners.remove(player); + } + + @Override + public void tickST() { + long sample = ((LastSampleMetricsData)this.metricsData).getLastSample(); + for (PlayerEntity player : this.listeners) { + NetworkS2C.sendLastSample(sample, player); + } + } +} diff --git a/src/main/java/net/cavoj/servertick/mixin/server/ServerPlayNetworkHandlerMixin.java b/src/main/java/net/cavoj/servertick/mixin/ServerPlayNetworkHandlerMixin.java similarity index 66% rename from src/main/java/net/cavoj/servertick/mixin/server/ServerPlayNetworkHandlerMixin.java rename to src/main/java/net/cavoj/servertick/mixin/ServerPlayNetworkHandlerMixin.java index 26e1966..3b3de08 100644 --- a/src/main/java/net/cavoj/servertick/mixin/server/ServerPlayNetworkHandlerMixin.java +++ b/src/main/java/net/cavoj/servertick/mixin/ServerPlayNetworkHandlerMixin.java @@ -1,8 +1,10 @@ -package net.cavoj.servertick.mixin.server; +package net.cavoj.servertick.mixin; -import net.cavoj.servertick.STServer; +import net.cavoj.servertick.extensions.MinecraftServerWithST; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -13,8 +15,10 @@ public abstract class ServerPlayNetworkHandlerMixin { @Shadow public ServerPlayerEntity player; + @Shadow @Final private MinecraftServer server; + @Inject(method = "onDisconnected", at = @At("HEAD")) public void onDisconnected(CallbackInfo ci) { - STServer.getInstance().onPlayerDisconnected(this.player); + ((MinecraftServerWithST)this.server).removeSTListener(this.player); } } diff --git a/src/main/java/net/cavoj/servertick/mixin/client/ClientPlayNetworkHandlerMixin.java b/src/main/java/net/cavoj/servertick/mixin/client/ClientPlayNetworkHandlerMixin.java index d28057b..e1f1f74 100644 --- a/src/main/java/net/cavoj/servertick/mixin/client/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/net/cavoj/servertick/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -1,6 +1,6 @@ package net.cavoj.servertick.mixin.client; -import net.cavoj.servertick.STClient; +import net.cavoj.servertick.ServerTickClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -11,6 +11,6 @@ public abstract class ClientPlayNetworkHandlerMixin { @Inject(method = "onGameJoin", at = @At("HEAD")) public void onGameJoin(CallbackInfo ci) { - STClient.getInstance().joined(); + ServerTickClient.getInstance().joined(); } } diff --git a/src/main/java/net/cavoj/servertick/mixin/client/DebugHudMixin.java b/src/main/java/net/cavoj/servertick/mixin/client/DebugHudMixin.java index 2dbc298..861adee 100644 --- a/src/main/java/net/cavoj/servertick/mixin/client/DebugHudMixin.java +++ b/src/main/java/net/cavoj/servertick/mixin/client/DebugHudMixin.java @@ -1,6 +1,6 @@ package net.cavoj.servertick.mixin.client; -import net.cavoj.servertick.STClient; +import net.cavoj.servertick.ServerTickClient; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.hud.DebugHud; import net.minecraft.client.util.math.MatrixStack; @@ -21,7 +21,7 @@ public abstract class DebugHudMixin { @Inject(method = "render", at = @At("HEAD")) public void render(MatrixStack matrices, CallbackInfo ci) { if (this.client.options.debugTpsEnabled && this.client.getServer() == null) { - MetricsData metrics = STClient.getInstance().getMetricsData(); + MetricsData metrics = ServerTickClient.getInstance().getMetricsData(); if (metrics == null) return; int i = this.client.getWindow().getScaledWidth(); diff --git a/src/main/java/net/cavoj/servertick/mixin/client/KeyboardMixin.java b/src/main/java/net/cavoj/servertick/mixin/client/KeyboardMixin.java index ee4ffb3..a0a101e 100644 --- a/src/main/java/net/cavoj/servertick/mixin/client/KeyboardMixin.java +++ b/src/main/java/net/cavoj/servertick/mixin/client/KeyboardMixin.java @@ -1,6 +1,6 @@ package net.cavoj.servertick.mixin.client; -import net.cavoj.servertick.STClient; +import net.cavoj.servertick.ServerTickClient; import net.minecraft.client.Keyboard; import net.minecraft.client.MinecraftClient; import org.spongepowered.asm.mixin.Final; @@ -16,6 +16,7 @@ public abstract class KeyboardMixin { @Inject(method = "onKey", at = @At("RETURN")) protected void onKey(CallbackInfo ci) { - STClient.getInstance().setTpsEnabled(this.client.options.debugEnabled && this.client.options.debugTpsEnabled); + if (this.client.getServer() != null) return; // Do nothing when playing on integrated + ServerTickClient.getInstance().setTpsEnabled(this.client.options.debugEnabled && this.client.options.debugTpsEnabled); } } diff --git a/src/main/java/net/cavoj/servertick/mixin/server/MetricsDataServerMixin.java b/src/main/java/net/cavoj/servertick/mixin/server/MetricsDataServerMixin.java deleted file mode 100644 index 5a47cb8..0000000 --- a/src/main/java/net/cavoj/servertick/mixin/server/MetricsDataServerMixin.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.cavoj.servertick.mixin.server; - -import net.cavoj.servertick.STServer; -import net.minecraft.util.MetricsData; -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; - -@Mixin(MetricsData.class) -public abstract class MetricsDataServerMixin { - - @Inject(method = "pushSample", at = @At("HEAD")) - public void pushSample(long time, CallbackInfo ci) { - STServer.getInstance().pushSample(time); - } -} diff --git a/src/main/java/net/cavoj/servertick/mixin/server/MinecraftServerAccessor.java b/src/main/java/net/cavoj/servertick/mixin/server/MinecraftServerAccessor.java deleted file mode 100644 index fe67254..0000000 --- a/src/main/java/net/cavoj/servertick/mixin/server/MinecraftServerAccessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.cavoj.servertick.mixin.server; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.MetricsData; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(MinecraftServer.class) -public interface MinecraftServerAccessor { - @Accessor("metricsData") - MetricsData getMetricsData(); -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index f537f70..9e52f97 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -15,11 +15,11 @@ "license": "MIT", "environment": "*", "entrypoints": { - "server": [ - "net.cavoj.servertick.STServer" + "main": [ + "net.cavoj.servertick.ServerTick" ], "client": [ - "net.cavoj.servertick.STClient" + "net.cavoj.servertick.ServerTickClient" ] }, "mixins": [ diff --git a/src/main/resources/servertick.mixins.json b/src/main/resources/servertick.mixins.json index 0455bd0..0b51e4e 100644 --- a/src/main/resources/servertick.mixins.json +++ b/src/main/resources/servertick.mixins.json @@ -12,11 +12,8 @@ "defaultRequire": 1 }, "mixins": [ - "MetricsDataMixin" - ], - "server": [ - "server.MetricsDataServerMixin", - "server.MinecraftServerAccessor", - "server.ServerPlayNetworkHandlerMixin" + "MetricsDataMixin", + "MinecraftServerMixin", + "ServerPlayNetworkHandlerMixin" ] }