Skip to content

Commit 5ef599c

Browse files
committed
Add /ctick command
1 parent e1decf9 commit 5ef599c

File tree

4 files changed

+301
-1
lines changed

4 files changed

+301
-1
lines changed

src/main/java/net/earthcomputer/clientcommands/ClientCommandsMod.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import net.earthcomputer.clientcommands.command.CommandNote;
1818
import net.earthcomputer.clientcommands.command.CommandRelog;
1919
import net.earthcomputer.clientcommands.command.CommandTempRule;
20+
import net.earthcomputer.clientcommands.command.CommandTick;
2021
import net.earthcomputer.clientcommands.cvw.ServerConnector;
2122
import net.minecraftforge.client.ClientCommandHandler;
2223
import net.minecraftforge.common.MinecraftForge;
@@ -64,6 +65,7 @@ private void registerCommands() {
6465
ClientCommandHandler.instance.registerCommand(new CommandCTime());
6566
// ClientCommandHandler.instance.registerCommand(new CommandCVW());
6667
ClientCommandHandler.instance.registerCommand(new CommandCWeather());
68+
ClientCommandHandler.instance.registerCommand(new CommandTick());
6769
}
6870

6971
private void registerEventStuff() {

src/main/java/net/earthcomputer/clientcommands/EventManager.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
3333
import net.minecraftforge.fml.common.gameevent.TickEvent;
3434
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
35+
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
3536
import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent;
37+
import net.minecraftforge.fml.common.gameevent.TickEvent.ServerTickEvent;
3638
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;
3739
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent;
3840
import net.minecraftforge.fml.relauncher.Side;
@@ -105,13 +107,46 @@ public void onConnect(EntityJoinWorldEvent e) {
105107

106108
private static Listeners<ClientTickEvent> tickListeners = new Listeners<>();
107109

110+
private static Listeners<ClientTickEvent> endTickListeners = new Listeners<>();
111+
108112
public static void addTickListener(Listener<ClientTickEvent> listener) {
109113
tickListeners.add(listener);
110114
}
111115

116+
public static void addEndTickListener(Listener<ClientTickEvent> listener) {
117+
endTickListeners.add(listener);
118+
}
119+
112120
@SubscribeEvent
113121
public void onTick(ClientTickEvent e) {
114-
tickListeners.invoke(e);
122+
if (e.phase == Phase.START) {
123+
tickListeners.invoke(e);
124+
} else {
125+
endTickListeners.invoke(e);
126+
}
127+
}
128+
129+
// SERVER TICK
130+
131+
private static Listeners<ServerTickEvent> serverTickListeners = new Listeners<>();
132+
133+
private static Listeners<ServerTickEvent> serverEndTickListeners = new Listeners<>();
134+
135+
public static void addServerTickListener(Listener<ServerTickEvent> listener) {
136+
serverTickListeners.add(listener);
137+
}
138+
139+
public static void addServerEndTickListener(Listener<ServerTickEvent> listener) {
140+
serverEndTickListeners.add(listener);
141+
}
142+
143+
@SubscribeEvent
144+
public void onServerTick(ServerTickEvent e) {
145+
if (e.phase == Phase.START) {
146+
serverTickListeners.invoke(e);
147+
} else {
148+
serverEndTickListeners.invoke(e);
149+
}
115150
}
116151

117152
// OUTBOUND PACKET PRE
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
package net.earthcomputer.clientcommands.command;
2+
3+
import java.text.DecimalFormat;
4+
import java.util.Collections;
5+
import java.util.List;
6+
7+
import net.earthcomputer.clientcommands.EventManager;
8+
import net.earthcomputer.clientcommands.EventManager.Listener;
9+
import net.earthcomputer.clientcommands.network.PacketEvent;
10+
import net.earthcomputer.clientcommands.task.LongTask;
11+
import net.earthcomputer.clientcommands.task.TaskManager;
12+
import net.minecraft.client.Minecraft;
13+
import net.minecraft.command.CommandException;
14+
import net.minecraft.command.ICommandSender;
15+
import net.minecraft.command.WrongUsageException;
16+
import net.minecraft.network.play.server.SPacketTimeUpdate;
17+
import net.minecraft.server.MinecraftServer;
18+
import net.minecraft.util.math.BlockPos;
19+
import net.minecraft.util.text.TextComponentTranslation;
20+
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
21+
import net.minecraftforge.fml.common.gameevent.TickEvent.ServerTickEvent;
22+
23+
public class CommandTick extends ClientCommandBase {
24+
25+
private static final DecimalFormat DEC_FMT = new DecimalFormat("0.00");
26+
27+
@Override
28+
public String getName() {
29+
return "ctick";
30+
}
31+
32+
@Override
33+
public String getUsage(ICommandSender sender) {
34+
return "commands.ctick.usage";
35+
}
36+
37+
@Override
38+
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
39+
if (args.length < 2) {
40+
throw new WrongUsageException(getUsage(sender));
41+
}
42+
43+
switch (args[0]) {
44+
case "client":
45+
ctickClient(sender, args);
46+
break;
47+
case "server":
48+
if (Minecraft.getMinecraft().isIntegratedServerRunning())
49+
ctickIntegratedServer(sender, args);
50+
else
51+
ctickServer(sender, args);
52+
break;
53+
default:
54+
throw new WrongUsageException(getUsage(sender));
55+
}
56+
}
57+
58+
private void ctickClient(ICommandSender sender, String[] args) throws CommandException {
59+
switch (args[1]) {
60+
case "tps":
61+
case "mspt":
62+
TaskManager.ensureNoTasks();
63+
TickMeasuringTask measurer = new TickMeasuringTask(sender, "tps".equals(args[1]), false);
64+
TaskManager.addLongTask(measurer);
65+
EventManager.addTickListener(new Listener<ClientTickEvent>() {
66+
@Override
67+
public void accept(ClientTickEvent e) {
68+
measurer.startTick();
69+
}
70+
71+
@Override
72+
public boolean wasFinalAction() {
73+
return measurer.isFinished();
74+
}
75+
});
76+
EventManager.addEndTickListener(new Listener<ClientTickEvent>() {
77+
@Override
78+
public void accept(ClientTickEvent e) {
79+
measurer.endTick();
80+
}
81+
82+
@Override
83+
public boolean wasFinalAction() {
84+
return measurer.isFinished();
85+
}
86+
});
87+
break;
88+
default:
89+
throw new WrongUsageException(getUsage(sender));
90+
}
91+
}
92+
93+
private void ctickIntegratedServer(ICommandSender sender, String[] args) throws CommandException {
94+
switch (args[1]) {
95+
case "tps":
96+
case "mspt":
97+
TaskManager.ensureNoTasks();
98+
TickMeasuringTask measurer = new TickMeasuringTask(sender, "tps".equals(args[1]), false);
99+
TaskManager.addLongTask(measurer);
100+
EventManager.addServerTickListener(new Listener<ServerTickEvent>() {
101+
@Override
102+
public void accept(ServerTickEvent e) {
103+
measurer.startTick();
104+
}
105+
106+
@Override
107+
public boolean wasFinalAction() {
108+
return measurer.isFinished();
109+
}
110+
});
111+
EventManager.addServerEndTickListener(new Listener<ServerTickEvent>() {
112+
@Override
113+
public void accept(ServerTickEvent e) {
114+
measurer.endTick();
115+
}
116+
117+
@Override
118+
public boolean wasFinalAction() {
119+
return measurer.isFinished();
120+
}
121+
});
122+
break;
123+
default:
124+
throw new WrongUsageException(getUsage(sender));
125+
}
126+
}
127+
128+
private void ctickServer(ICommandSender sender, String[] args) throws CommandException {
129+
switch (args[1]) {
130+
case "tps":
131+
case "mspt":
132+
TaskManager.ensureNoTasks();
133+
TickMeasuringTask measurer = new TickMeasuringTask(sender, "tps".equals(args[1]), true);
134+
TaskManager.addLongTask(measurer);
135+
EventManager.addInboundPacketPreListener(new Listener<PacketEvent.Inbound.Pre>() {
136+
long lastTick = -1;
137+
138+
@Override
139+
public void accept(PacketEvent.Inbound.Pre e) {
140+
if (e.getPacket() instanceof SPacketTimeUpdate) {
141+
long tick = ((SPacketTimeUpdate) e.getPacket()).getTotalWorldTime();
142+
if (lastTick != -1) {
143+
int deltaTick = (int) (tick - lastTick);
144+
measurer.incrTickCount(deltaTick);
145+
}
146+
lastTick = tick;
147+
}
148+
}
149+
150+
@Override
151+
public boolean wasFinalAction() {
152+
return measurer.isFinished();
153+
}
154+
});
155+
break;
156+
default:
157+
throw new WrongUsageException(getUsage(sender));
158+
}
159+
}
160+
161+
@Override
162+
public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args,
163+
BlockPos targetPos) {
164+
if (args.length == 0) {
165+
return Collections.emptyList();
166+
} else if (args.length == 1) {
167+
return getListOfStringsMatchingLastWord(args, "client", "server");
168+
} else if (args.length == 2) {
169+
return getListOfStringsMatchingLastWord(args, "tps", "mspt");
170+
} else {
171+
return Collections.emptyList();
172+
}
173+
}
174+
175+
private static class TickMeasuringTask extends LongTask {
176+
177+
private static final int PERIOD = 100;
178+
179+
private int tickCount = 0;
180+
private long totalTickTime = 0;
181+
private long startTickTime;
182+
private boolean hadFirstTick = false;
183+
private long firstTickStart;
184+
private long lastTickStart;
185+
186+
private ICommandSender sender;
187+
private boolean tps;
188+
private boolean forceInaccurate;
189+
190+
public TickMeasuringTask(ICommandSender sender, boolean tps, boolean forceInaccurate) {
191+
this.sender = sender;
192+
this.tps = tps;
193+
this.forceInaccurate = forceInaccurate;
194+
}
195+
196+
public void incrTickCount(int count) {
197+
if (!hadFirstTick) {
198+
firstTickStart = System.nanoTime();
199+
hadFirstTick = true;
200+
} else {
201+
tickCount += count;
202+
}
203+
}
204+
205+
public void startTick() {
206+
startTickTime = System.nanoTime();
207+
if (!hadFirstTick) {
208+
firstTickStart = startTickTime;
209+
hadFirstTick = true;
210+
}
211+
}
212+
213+
public void endTick() {
214+
if (hadFirstTick) {
215+
totalTickTime += System.nanoTime() - startTickTime;
216+
tickCount++;
217+
}
218+
}
219+
220+
@Override
221+
protected void taskTick() {
222+
if (tickCount >= PERIOD) {
223+
lastTickStart = System.nanoTime();
224+
setFinished();
225+
}
226+
}
227+
228+
@Override
229+
public void start() {
230+
sender.sendMessage(new TextComponentTranslation("commands.ctick.measuring"));
231+
}
232+
233+
@Override
234+
public void cleanup() {
235+
if (tps) {
236+
long totalTime = lastTickStart - firstTickStart;
237+
double tps = 1000000000D * tickCount / totalTime;
238+
sender.sendMessage(new TextComponentTranslation("commands.ctick.tps",
239+
totalTime == 0 ? "Immeasurable" : DEC_FMT.format(tps)));
240+
} else if (forceInaccurate) {
241+
long totalTime = lastTickStart - firstTickStart;
242+
double mspt = totalTime / (1000000D * tickCount);
243+
sender.sendMessage(new TextComponentTranslation("commands.ctick.mspt", DEC_FMT.format(mspt)));
244+
sender.sendMessage(new TextComponentTranslation("commands.ctick.mspt.inaccurate"));
245+
} else {
246+
double mspt = totalTickTime / (1000000D * tickCount);
247+
sender.sendMessage(new TextComponentTranslation("commands.ctick.mspt", DEC_FMT.format(mspt)));
248+
}
249+
}
250+
251+
@Override
252+
public int getTimeout() {
253+
return 1200;
254+
}
255+
}
256+
257+
}

src/main/resources/assets/clientcommands/lang/en_us.lang

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ commands.ctemprule.reset.success=TempRule %s has been reset to %s
148148
commands.ctemprule.reset.usage=/ctemprule reset <rule>
149149
commands.ctemprule.usage=/ctemprule <get|set|reset|list> ...
150150

151+
commands.ctick.usage=/ctick <client|server> <health>
152+
commands.ctick.measuring=Measuring...
153+
commands.ctick.tps=Ticks per second = %s
154+
commands.ctick.mspt=Milliseconds per tick = %s
155+
commands.ctick.mspt.inaccurate=MSPT is inaccurate above 20TPS
156+
151157
commands.cvw.usage=/cvw <start|stop> [gamemode]
152158
commands.cvw.stop.notRunning=There is no CVW running
153159

0 commit comments

Comments
 (0)