diff --git a/src/main/java/de/shiewk/widgets/client/WidgetsModClient.java b/src/main/java/de/shiewk/widgets/client/WidgetsModClient.java index 217eca4..3349bcf 100644 --- a/src/main/java/de/shiewk/widgets/client/WidgetsModClient.java +++ b/src/main/java/de/shiewk/widgets/client/WidgetsModClient.java @@ -58,5 +58,6 @@ public class WidgetsModClient implements ClientModInitializer { WidgetManager.register(new MemoryUsageWidget(Identifier.of(WidgetsMod.MOD_ID, "memory"))); WidgetManager.register(new KeyStrokesWidget(Identifier.of(WidgetsMod.MOD_ID, "keystrokes"))); WidgetManager.register(new PlainTextWidget(Identifier.of(WidgetsMod.MOD_ID, "plaintext"))); + WidgetManager.register(new TPSWidget(Identifier.of(WidgetsMod.MOD_ID, "tps"))); } } diff --git a/src/main/java/de/shiewk/widgets/mixin/MixinClientPlayNetworkHandler.java b/src/main/java/de/shiewk/widgets/mixin/MixinClientPlayNetworkHandler.java new file mode 100644 index 0000000..9e013c6 --- /dev/null +++ b/src/main/java/de/shiewk/widgets/mixin/MixinClientPlayNetworkHandler.java @@ -0,0 +1,21 @@ +package de.shiewk.widgets.mixin; + +import de.shiewk.widgets.widgets.TPSWidget; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket; +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(ClientPlayNetworkHandler.class) +public class MixinClientPlayNetworkHandler { + + @Inject(at = @At("HEAD"), method = "onWorldTimeUpdate") + public void onWorldTimeUpdate(WorldTimeUpdateS2CPacket packet, CallbackInfo ci){ + if (MinecraftClient.getInstance().isOnThread()) return; // run this on the networking thread as soon as possible + // server sends this packet every 20 ticks + TPSWidget.worldTimeUpdated(System.nanoTime()); + } +} diff --git a/src/main/java/de/shiewk/widgets/widgets/TPSWidget.java b/src/main/java/de/shiewk/widgets/widgets/TPSWidget.java new file mode 100644 index 0000000..e33eb34 --- /dev/null +++ b/src/main/java/de/shiewk/widgets/widgets/TPSWidget.java @@ -0,0 +1,100 @@ +package de.shiewk.widgets.widgets; + +import de.shiewk.widgets.WidgetSettings; +import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting; +import net.minecraft.client.MinecraftClient; +import net.minecraft.server.ServerTickManager; +import net.minecraft.server.integrated.IntegratedServer; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.util.List; + +public class TPSWidget extends BasicTextWidget { + public TPSWidget(Identifier id) { + super(id, List.of( + new ToggleWidgetSetting("dynamic_color", Text.translatable("widgets.widgets.tps.dynamicColor"), true) + )); + getSettings().optionById("textcolor").setShowCondition(() -> !this.dynamicColor); + INSTANCE = this; + } + + private static TPSWidget INSTANCE; + + private static final long[] lastUpdates = new long[5]; + private static int updatePointer = 0; + + private boolean dynamicColor = true; + + public static void worldTimeUpdated(long nanoTime) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.isInSingleplayer()){ + IntegratedServer server = client.getServer(); + if (server != null) { + ServerTickManager tickManager = server.getTickManager(); + float tps = 1000f / server.getAverageTickTime(); + float targetTickRate = tickManager.getTickRate(); + if (tickManager.isSprinting()){ + INSTANCE.updateTPS(tps, targetTickRate); + } else { + INSTANCE.updateTPS(Math.min(tps, targetTickRate), targetTickRate); + } + } + } else { + lastUpdates[updatePointer] = nanoTime; + updatePointer++; + if (updatePointer >= lastUpdates.length) updatePointer = 0; + + long totalDifference = 0; + for (int i = 0; i < lastUpdates.length-1; i++){ + long difference = lastUpdates[(updatePointer + i + 1) % lastUpdates.length] - lastUpdates[(updatePointer + i) % lastUpdates.length]; + totalDifference += difference; + } + + long avgDifference = totalDifference / (lastUpdates.length-1); // this is how long 20 ticks took on the server on average + float mspt = avgDifference / 20000000f; + float ticksPerSecond = 1000f / mspt; + + if (client.world != null) { + INSTANCE.updateTPS(ticksPerSecond, client.world.getTickManager().getTickRate()); + } else { + INSTANCE.updateTPS(ticksPerSecond, 20); + } + } + } + + private void updateTPS(float tps, float targetTickRate) { + tps = Math.round(tps * 10f) / 10f; + this.renderText = Text.literal(Text.translatable("widgets.widgets.tps.tps", tps).getString()); + if (dynamicColor){ + if (tps >= targetTickRate * 0.995){ + this.textColor = 0x00ff00; + } else if (tps >= targetTickRate * 0.745){ + this.textColor = 0xffff00; + } else { + this.textColor = 0xff0000; + } + } + } + + @Override + public void tickWidget() { + + } + + @Override + public Text getName() { + return Text.translatable("widgets.widgets.tps"); + } + + @Override + public Text getDescription() { + return Text.translatable("widgets.widgets.tps.description"); + } + + @Override + public void onSettingsChanged(WidgetSettings settings) { + super.onSettingsChanged(settings); + this.dynamicColor = ((ToggleWidgetSetting) settings.optionById("dynamic_color")).getValue(); + } +} diff --git a/src/main/resources/assets/widgets/lang/de_de.json b/src/main/resources/assets/widgets/lang/de_de.json index 7afc292..ac7af43 100644 --- a/src/main/resources/assets/widgets/lang/de_de.json +++ b/src/main/resources/assets/widgets/lang/de_de.json @@ -87,5 +87,9 @@ "widgets.widgets.plaintext.description": "Zeigt einen festgelegten Text an", "widgets.widgets.plaintext.text": "Text", "widgets.widgets.plaintext.initial": "Ändere dies in den Widget-Einstellungen", - "widgets.widgets.plaintext.placeholder": "Gib hier deinen Text ein..." + "widgets.widgets.plaintext.placeholder": "Gib hier deinen Text ein...", + "widgets.widgets.tps.tps": "%s TPS", + "widgets.widgets.tps.dynamicColor": "Farbe dynamisch anzeigen", + "widgets.widgets.tps": "TPS", + "widgets.widgets.tps.description": "Zeigt die TPS im Einzelspielermodus an oder schätzt die TPS im Mehrspielermodus" } diff --git a/src/main/resources/assets/widgets/lang/en_us.json b/src/main/resources/assets/widgets/lang/en_us.json index 368cec0..abcf59c 100644 --- a/src/main/resources/assets/widgets/lang/en_us.json +++ b/src/main/resources/assets/widgets/lang/en_us.json @@ -87,5 +87,9 @@ "widgets.widgets.plaintext.description": "Input a text to display on screen", "widgets.widgets.plaintext.text": "Text", "widgets.widgets.plaintext.initial": "Change this in the widget settings", - "widgets.widgets.plaintext.placeholder": "Type your text here..." + "widgets.widgets.plaintext.placeholder": "Type your text here...", + "widgets.widgets.tps.tps": "%s TPS", + "widgets.widgets.tps.dynamicColor": "Dynamic Color", + "widgets.widgets.tps": "TPS", + "widgets.widgets.tps.description": "Shows the current TPS when in singleplayer or estimates server TPS when in multiplayer" } \ No newline at end of file diff --git a/src/main/resources/widgets.mixins.json b/src/main/resources/widgets.mixins.json index f97a76f..989f06a 100644 --- a/src/main/resources/widgets.mixins.json +++ b/src/main/resources/widgets.mixins.json @@ -6,6 +6,7 @@ "mixins": [ ], "client": [ + "MixinClientPlayNetworkHandler", "MixinMouse" ], "injectors": {