diff --git a/src/main/java/com/minecrafttas/tasmod/mixin/MixinTimer.java b/src/main/java/com/minecrafttas/tasmod/mixin/MixinTimer.java index 518e3483..2885fb65 100644 --- a/src/main/java/com/minecrafttas/tasmod/mixin/MixinTimer.java +++ b/src/main/java/com/minecrafttas/tasmod/mixin/MixinTimer.java @@ -15,59 +15,122 @@ @Mixin(Timer.class) /** - * Rewrites updateTimer to make it possible to interpolate ticks. + *

Rewrites updateTimer, to add a tickratechanger and apply ticksync. + *

Dynamically speeds up or slows down the tickrate depending on the time between {@link TickSyncClient TickSync} packages. * @author Pancake * */ public class MixinTimer { + /** + *

How many ticks elapsed since the {@link Timer#updateTimer()} method was called. + *

Used in Minecraft#runGameLoop to call {@link Minecraft#runTick()} in the for loop + */ @Shadow private int elapsedTicks; - @Shadow - private float renderPartialTicks; + /** + * How many "frames" elapsed since the {@link Timer#updateTimer()} method was called + */ @Shadow private float elapsedPartialTicks; + /** + * Value between 0-1 of how many frames have elapsed inbetween ticks + */ @Shadow - private long lastSyncSysClock; + private float renderPartialTicks; + /** + * The last time the {@link Timer#updateTimer()} method was called + */ @Shadow - private float tickLength; + private long lastSyncSysClock; + // ========================================================== + + /** + * System time the last time a tick has run and ticksync has triggered + */ @Unique - private long millisLastTick; - @Unique - private long lastGameLoop; + private long timeSinceLastTick; + /** + * The tick length in the last tick + */ @Unique - private float lastTickDuration; + private float lastTickLength; + /** + *

Overwrites {@link Timer#updateTimer()} in a way,
+ * so that the tickrate matches the tickrate of the server. + * + *

It does this by removing {@link Timer#tickLength} from the equasion.
+ * Takes the time between incoming packets from {@link TickSyncClient#onClientPacket(com.minecrafttas.mctcommon.networking.interfaces.PacketID, java.nio.ByteBuffer, String) TickSyncClient.onClientPacket()} + * and calculates the tickrate dynamically. + * + *

If no packet is present, it stops the client.
+ * This can happen when: + *

    + *
  1. The packet did not reach it's destination
  2. + *
  3. The tickrate on the server is 0
  4. + *
  5. The server is lagging and unable to send packets
  6. + *
  7. Another player is taking too long to send a packet
  8. + *
+ * + * @param ci + */ @Inject(method = "updateTimer", at = @At("HEAD"), cancellable = true) public void inject_tick(CallbackInfo ci) { - if (TASmodClient.client != null && !TASmodClient.client.isClosed()) { - lastSyncSysClock = Minecraft.getSystemTime(); // update the tick tracker so that after returning to scheduling the client won't catch up all ticks (max 10) - this.elapsedTicks = 0; // do not do any ticks - long newGameLoop = Minecraft.getSystemTime(); + /* + * Run overriden updateTimer method + * + * Only runs when there is a connection to the custom networking server and the player is in a world + */ + if (TASmodClient.client != null && !TASmodClient.client.isClosed() && Minecraft.getMinecraft().world != null) { + + long currentTime = Minecraft.getSystemTime(); // The current system time as of calling this method + /* + * The length of the tick in milliseconds. + * Set to 50 in vanilla, but in this instance, + * it is set to the duration of when Ticksync.shouldTick was true + */ + float tickLength = lastTickLength; + + this.elapsedTicks = 0; // Prevent the client from ticking + + /* + * Ticksync block. + * Allows the client to run for 1 tick if TickSyncClient.shouldTick is true + */ if (TickSyncClient.shouldTick.compareAndSet(true, false)) { - this.elapsedTicks++; - this.lastTickDuration = newGameLoop - this.millisLastTick; + + this.elapsedTicks++; // Allow the client to tick once + tickLength = currentTime - timeSinceLastTick; // Check the time between ticks if (TASmodClient.tickratechanger.advanceTick) { - lastTickDuration = TASmodClient.tickratechanger.millisecondsPerTick; // Keep the lastTick duration steady during tickadvance, since it grows larger the longer you wait in tickrate 0 + tickLength = TASmodClient.tickratechanger.millisecondsPerTick; // Keep the lastTick duration steady during tickadvance, since it grows larger the longer you wait in tickrate 0 } - this.millisLastTick = newGameLoop; // Update millisLastTick - this.renderPartialTicks = 0; // Reset after the tick + timeSinceLastTick = currentTime; + this.renderPartialTicks = 0; // Reset render partial ticks after a new tick } - // Interpolating - this.elapsedPartialTicks = (newGameLoop - this.lastGameLoop) / this.lastTickDuration; - float newPartialTicks = this.renderPartialTicks; - newPartialTicks += this.elapsedPartialTicks; - newPartialTicks -= (int) this.renderPartialTicks; - if (newPartialTicks > this.renderPartialTicks) { - this.renderPartialTicks = newPartialTicks; + + /* + * Vanilla calculation from updateTimer, + * with added interpolation calculation + */ + this.elapsedPartialTicks = (currentTime - this.lastSyncSysClock) / tickLength; // Use the calculated tickLength instead of the vanill tickLength + float newRenderPartialTicks = this.renderPartialTicks; + newRenderPartialTicks += this.elapsedPartialTicks; + newRenderPartialTicks -= (int) this.renderPartialTicks; + + if (newRenderPartialTicks > this.renderPartialTicks) { // Fixes stuttering when the renderPartialTicks stay the same during tickrate 0 + this.renderPartialTicks = newRenderPartialTicks; } - this.lastGameLoop = newGameLoop; + + this.lastSyncSysClock = currentTime; // Update vanilla variable + lastTickLength = tickLength; // Update last tick length ci.cancel(); - } else { - this.millisLastTick = Minecraft.getSystemTime(); - this.lastGameLoop = Minecraft.getSystemTime(); - TickSyncClient.shouldTick.set(true); // The client should always tick if it once thrown out of the vanilla scheduling part, to make the server tick, etc. + } + // Run vanilla updateTimer + else { + this.timeSinceLastTick = Minecraft.getSystemTime(); + TickSyncClient.shouldTick.set(true); // Client should always tick, when in the main menu } } } diff --git a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java index 4b3e1714..4d372071 100644 --- a/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java +++ b/src/main/java/com/minecrafttas/tasmod/playback/PlaybackControllerClient.java @@ -103,7 +103,7 @@ public class PlaybackControllerClient implements EventVirtualInput.EventVirtualCameraAngleTick, EventVirtualInput.EventVirtualMouseSubtick - //@formatter:on +//@formatter:on { private Logger logger = TASmod.LOGGER; diff --git a/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncClient.java b/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncClient.java index 2faddab1..8896e4b1 100644 --- a/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncClient.java +++ b/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncClient.java @@ -15,11 +15,10 @@ import net.minecraft.client.Minecraft; /** - * This class manages tick sync - * German: https://1drv.ms/p/s!Av_ysXerhm5CphLvLvguvL5QYe1A?e=MHPldP - * English: https://1drv.ms/p/s!Av_ysXerhm5Cpha7Qq2tiVebd4DY?e=pzxOva - * + *

Synchronizes the client tickrate with the server tickrate + * * @author Pancake + * @see TickSyncServer */ public class TickSyncClient implements ClientPacketHandler, EventClientTickPost { diff --git a/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncServer.java b/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncServer.java index 18d3ec4d..27fc8df3 100644 --- a/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncServer.java +++ b/src/main/java/com/minecrafttas/tasmod/ticksync/TickSyncServer.java @@ -19,11 +19,10 @@ import net.minecraft.server.MinecraftServer; /** - * This class manages tick sync - * German: https://1drv.ms/p/s!Av_ysXerhm5CphLvLvguvL5QYe1A?e=MHPldP - * English: https://1drv.ms/p/s!Av_ysXerhm5Cpha7Qq2tiVebd4DY?e=pzxOva - * + *

Synchronizes the server tickrate with all clients + * * @author Pancake + * @see TickSyncClient */ public class TickSyncServer implements ServerPacketHandler, EventServerTickPost, EventClientCompleteAuthentication {