Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 93 additions & 30 deletions src/main/java/com/minecrafttas/tasmod/mixin/MixinTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,59 +15,122 @@

@Mixin(Timer.class)
/**
* Rewrites updateTimer to make it possible to interpolate ticks.
* <p>Rewrites updateTimer, to add a tickratechanger and apply ticksync.
* <p>Dynamically speeds up or slows down the tickrate depending on the time between {@link TickSyncClient TickSync} packages.
* @author Pancake
*
*/
public class MixinTimer {

/**
* <p>How many ticks elapsed since the {@link Timer#updateTimer()} method was called.
* <p>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;

/**
* <p>Overwrites {@link Timer#updateTimer()} in a way,<br>
* so that the tickrate matches the tickrate of the server.
*
* <p>It does this by removing {@link Timer#tickLength} from the equasion.<br>
* 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.
*
* <p>If no packet is present, it stops the client.<br>
* This can happen when:
* <ol>
* <li>The packet did not reach it's destination</li>
* <li>The tickrate on the server is 0</li>
* <li>The server is lagging and unable to send packets</li>
* <li>Another player is taking too long to send a packet</li>
* </ol>
*
* @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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public class PlaybackControllerClient implements
EventVirtualInput.EventVirtualCameraAngleTick,

EventVirtualInput.EventVirtualMouseSubtick
//@formatter:on
//@formatter:on
{
private Logger logger = TASmod.LOGGER;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
* <p>Synchronizes the client tickrate with the server tickrate
*
* @author Pancake
* @see TickSyncServer
*/
public class TickSyncClient implements ClientPacketHandler, EventClientTickPost {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
* <p>Synchronizes the server tickrate with all clients
*
* @author Pancake
* @see TickSyncClient
*/
public class TickSyncServer implements ServerPacketHandler, EventServerTickPost, EventClientCompleteAuthentication {

Expand Down
Loading