-
-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
224 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
210 changes: 210 additions & 0 deletions
210
src/main/java/net/earthcomputer/clientcommands/command/CTickCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
package net.earthcomputer.clientcommands.command; | ||
|
||
import com.mojang.brigadier.CommandDispatcher; | ||
import com.mojang.brigadier.exceptions.CommandSyntaxException; | ||
import net.earthcomputer.clientcommands.event.MoreClientEvents; | ||
import net.earthcomputer.clientcommands.task.SimpleTask; | ||
import net.earthcomputer.clientcommands.task.TaskManager; | ||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; | ||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; | ||
import net.minecraft.client.Minecraft; | ||
import net.minecraft.network.chat.Component; | ||
import net.minecraft.network.protocol.game.ClientboundSetTimePacket; | ||
import net.minecraft.util.TimeUtil; | ||
|
||
import java.text.DecimalFormat; | ||
|
||
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; | ||
|
||
public class CTickCommand { | ||
|
||
private static final DecimalFormat DEC_FMT = new DecimalFormat("0.00"); | ||
|
||
private static final String TASK_NAME = "ctick"; | ||
|
||
private static TickMeasuringTask currentMeasurer = null; | ||
|
||
public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) { | ||
dispatcher.register(literal("ctick") | ||
.then(literal("client") | ||
.then(literal("tps") | ||
.executes(ctx -> getTpsClient(ctx.getSource()))) | ||
.then(literal("mspt") | ||
.executes(ctx -> getMsptClient(ctx.getSource())))) | ||
.then(literal("server") | ||
.then(literal("tps") | ||
.executes(ctx -> getTpsServer(ctx.getSource()))) | ||
.then(literal("mspt") | ||
.executes(ctx -> getMsptServer(ctx.getSource()))))); | ||
} | ||
|
||
private static int getTpsClient(FabricClientCommandSource source) throws CommandSyntaxException { | ||
stopPreviousTask(); | ||
|
||
TickMeasuringTask measurer = new TickMeasuringTask(true, false); | ||
TaskManager.addTask(TASK_NAME, measurer); | ||
currentMeasurer = measurer; | ||
|
||
float tps = source.getWorld().tickRateManager().tickrate(); | ||
source.sendFeedback(Component.translatable("commands.ctick.client.tps.expectedTps", tps)); | ||
return (int) tps; | ||
} | ||
|
||
private static int getMsptClient(FabricClientCommandSource source) throws CommandSyntaxException { | ||
stopPreviousTask(); | ||
|
||
TickMeasuringTask measurer = new TickMeasuringTask(false, false); | ||
TaskManager.addTask(TASK_NAME, measurer); | ||
currentMeasurer = measurer; | ||
|
||
float mspt = TimeUtil.MILLISECONDS_PER_SECOND / source.getWorld().tickRateManager().tickrate(); | ||
source.sendFeedback(Component.translatable("commands.ctick.client.mspt.expectedMspt", mspt)); | ||
return (int) mspt; | ||
} | ||
|
||
private static int getTpsServer(FabricClientCommandSource source) throws CommandSyntaxException { | ||
stopPreviousTask(); | ||
|
||
boolean isIntegratedServer = source.getClient().hasSingleplayerServer(); | ||
TickMeasuringTask measurer = new TickMeasuringTask(true, !isIntegratedServer); | ||
TaskManager.addTask(TASK_NAME, measurer); | ||
currentMeasurer = measurer; | ||
|
||
float tps = source.getWorld().tickRateManager().tickrate(); | ||
source.sendFeedback(Component.translatable("commands.ctick.server.tps.expectedTps", tps)); | ||
return (int) tps; | ||
} | ||
|
||
private static int getMsptServer(FabricClientCommandSource source) throws CommandSyntaxException { | ||
stopPreviousTask(); | ||
|
||
boolean isIntegratedServer = source.getClient().hasSingleplayerServer(); | ||
TickMeasuringTask measurer = new TickMeasuringTask(false, !isIntegratedServer); | ||
TaskManager.addTask(TASK_NAME, measurer); | ||
currentMeasurer = measurer; | ||
|
||
float mspt = TimeUtil.MILLISECONDS_PER_SECOND / source.getWorld().tickRateManager().tickrate(); | ||
source.sendFeedback(Component.translatable("commands.ctick.server.mspt.expectedMspt", mspt)); | ||
return (int) mspt; | ||
} | ||
|
||
private static void stopPreviousTask() { | ||
if (currentMeasurer != null) { | ||
currentMeasurer._break(); | ||
TaskManager.removeTask(TASK_NAME); | ||
currentMeasurer = null; | ||
} | ||
} | ||
|
||
// see https://github.com/Earthcomputer/clientcommands/blob/c1e37665739f0e1d6aeb826b9d4e45b7adb5d876/src/main/java/net/earthcomputer/clientcommands/command/CommandTick.java#L175-L255 | ||
private static class TickMeasuringTask extends SimpleTask { | ||
|
||
private static final int PERIOD = 100; | ||
|
||
private static final Minecraft minecraft = Minecraft.getInstance(); | ||
|
||
private int tickCount = 0; | ||
private long totalTickTime = 0; | ||
private long startTickTime; | ||
private boolean hadFirstTick = false; | ||
private long firstTickStart; | ||
private long lastTickStart; | ||
|
||
private final boolean tps; | ||
private final boolean forceInaccurate; | ||
|
||
public TickMeasuringTask(boolean tps, boolean forceInaccurate) { | ||
this.tps = tps; | ||
this.forceInaccurate = forceInaccurate; | ||
} | ||
|
||
public void incrTickCount(int count) { | ||
if (!hadFirstTick) { | ||
firstTickStart = System.nanoTime(); | ||
hadFirstTick = true; | ||
} else { | ||
tickCount += count; | ||
} | ||
} | ||
|
||
public void startTick() { | ||
startTickTime = System.nanoTime(); | ||
if (!hadFirstTick) { | ||
firstTickStart = startTickTime; | ||
hadFirstTick = true; | ||
} | ||
} | ||
|
||
public void endTick() { | ||
if (hadFirstTick) { | ||
totalTickTime += System.nanoTime() - startTickTime; | ||
tickCount++; | ||
} | ||
} | ||
|
||
@Override | ||
protected void onTick() { | ||
if (tickCount >= PERIOD) { | ||
lastTickStart = System.nanoTime(); | ||
_break(); | ||
} | ||
} | ||
|
||
@Override | ||
public void initialize() { | ||
minecraft.player.displayClientMessage(Component.translatable("commands.ctick.measuring"), false); | ||
} | ||
|
||
@Override | ||
public void onCompleted() { | ||
if (tps) { | ||
long totalTime = lastTickStart - firstTickStart; | ||
double tps = 1_000_000_000D * tickCount / totalTime; | ||
minecraft.player.displayClientMessage(Component.translatable("commands.ctick.tps", totalTime == 0 ? Component.translatable("commands.ctick.tps.immeasurable") : DEC_FMT.format(tps)), false); | ||
} else if (forceInaccurate) { | ||
long totalTime = lastTickStart - firstTickStart; | ||
double mspt = totalTime / (1_000_000D * tickCount); | ||
minecraft.player.displayClientMessage(Component.translatable("commands.ctick.mspt", DEC_FMT.format(mspt)), false); | ||
minecraft.player.displayClientMessage(Component.translatable("commands.ctick.mspt.inaccurate"), false); | ||
} else { | ||
double mspt = totalTickTime / (1_000_000D * tickCount); | ||
minecraft.player.displayClientMessage(Component.translatable("commands.ctick.mspt", DEC_FMT.format(mspt)), false); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean condition() { | ||
return tickCount <= 1200; | ||
} | ||
} | ||
|
||
public static void registerEvents() { | ||
ClientTickEvents.START_CLIENT_TICK.register(minecraft -> { | ||
if (currentMeasurer != null && !currentMeasurer.isCompleted() && !currentMeasurer.forceInaccurate) { | ||
currentMeasurer.startTick(); | ||
} | ||
}); | ||
|
||
ClientTickEvents.END_CLIENT_TICK.register(minecraft -> { | ||
if (currentMeasurer != null && !currentMeasurer.isCompleted() && !currentMeasurer.forceInaccurate) { | ||
currentMeasurer.endTick(); | ||
} | ||
}); | ||
|
||
MoreClientEvents.TIME_SYNC.register(new MoreClientEvents.TimeSync() { | ||
private long lastTick = -1; | ||
|
||
@Override | ||
public void onTimeSync(ClientboundSetTimePacket packet) { | ||
if (currentMeasurer != null && !currentMeasurer.isCompleted() && currentMeasurer.forceInaccurate) { | ||
long tick = packet.gameTime(); | ||
if (lastTick != -1) { | ||
int deltaTick = (int) (tick - lastTick); | ||
currentMeasurer.incrTickCount(deltaTick); | ||
} | ||
lastTick = tick; | ||
} | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters