diff --git a/src/main/java/dev/technici4n/moderndynamics/client/ber/PipeBlockEntityRenderer.java b/src/main/java/dev/technici4n/moderndynamics/client/ber/PipeBlockEntityRenderer.java index 9cd7d55..dd55a43 100644 --- a/src/main/java/dev/technici4n/moderndynamics/client/ber/PipeBlockEntityRenderer.java +++ b/src/main/java/dev/technici4n/moderndynamics/client/ber/PipeBlockEntityRenderer.java @@ -53,7 +53,7 @@ public void render(PipeBlockEntity pipe, float tickDelta, PoseStack matrices, Mu Vec3 from, to; double ratio; - var distance = Mth.frac(item.traveledDistance()) + ClientTravelingItemSmoothing.getAndUpdateDistanceDelta(item) + var distance = Mth.frac(item.traveledDistance()) + ClientTravelingItemSmoothing.getDistanceDelta(item, tickDelta) + item.speed() * tickDelta; if (distance <= 0.5) { from = findFaceMiddle(item.in().getOpposite()); diff --git a/src/main/java/dev/technici4n/moderndynamics/network/item/ItemHost.java b/src/main/java/dev/technici4n/moderndynamics/network/item/ItemHost.java index 4cc4143..1f4adbc 100644 --- a/src/main/java/dev/technici4n/moderndynamics/network/item/ItemHost.java +++ b/src/main/java/dev/technici4n/moderndynamics/network/item/ItemHost.java @@ -299,11 +299,21 @@ public void tickMovingItems() { return; } + long curTick = getLevel().getGameTime(); + // List of items that moved out of this pipe. List movedOut = new ArrayList<>(); for (var iterator = travelingItems.iterator(); iterator.hasNext();) { var travelingItem = iterator.next(); + + // Make sure we only update items once per tick. + // This makes sure that we don't update items twice if they get moved to another pipe. + if (travelingItem.lastTick == curTick) { + continue; + } + travelingItem.lastTick = curTick; + // Calculate in which path segment the item is now, and in which segment it is after moving it int currentIndex = (int) travelingItem.traveledDistance; travelingItem.traveledDistance += travelingItem.getSpeed(); @@ -538,9 +548,20 @@ public void readClientNbt(CompoundTag tag) { @Override public void clientTick() { + long curTick = getLevel().getGameTime(); + for (var it = clientTravelingItems.iterator(); it.hasNext();) { ClientTravelingItem travelingItem = it.next(); + + // Make sure we only update items once per tick. + // This makes sure that we don't update items twice if they get moved to another pipe. + if (travelingItem.lastTick == curTick) { + continue; + } + travelingItem.lastTick = curTick; + travelingItem.traveledDistance += travelingItem.speed(); + ClientTravelingItemSmoothing.onTickItem(travelingItem); if (Mth.frac(travelingItem.traveledDistance) < travelingItem.speed()) { // Goes out of this pipe! diff --git a/src/main/java/dev/technici4n/moderndynamics/network/item/TravelingItem.java b/src/main/java/dev/technici4n/moderndynamics/network/item/TravelingItem.java index 1f9140c..9cccc10 100644 --- a/src/main/java/dev/technici4n/moderndynamics/network/item/TravelingItem.java +++ b/src/main/java/dev/technici4n/moderndynamics/network/item/TravelingItem.java @@ -34,6 +34,7 @@ public class TravelingItem { public final FailedInsertStrategy strategy; public final double speedMultiplier; public double traveledDistance; + public long lastTick; public TravelingItem(ItemVariant variant, int amount, ItemPath path, FailedInsertStrategy strategy, double speedMultiplier, double traveledDistance) { diff --git a/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItem.java b/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItem.java index 6a01443..1391011 100644 --- a/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItem.java +++ b/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItem.java @@ -30,6 +30,7 @@ public final class ClientTravelingItem { public Direction in; public Direction out; final double speed; + public long lastTick; public ClientTravelingItem(int id, ItemVariant variant, int amount, double totalPathDistance, double traveledDistance, Direction in, Direction out, double speed) { diff --git a/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItemSmoothing.java b/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItemSmoothing.java index e9679de..e173df2 100644 --- a/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItemSmoothing.java +++ b/src/main/java/dev/technici4n/moderndynamics/network/item/sync/ClientTravelingItemSmoothing.java @@ -27,11 +27,14 @@ * Also keeps track of a client tick counter. */ public class ClientTravelingItemSmoothing { - public static void onUnpausedTick() { - // Cleanup items that are not used anymore for (var it = INFOS.values().iterator(); it.hasNext();) { SmoothingInfo info = it.next(); + + // Apply 1 tick worth of smoothing + info.wrongOffset *= smooth(1); + + // Cleanup items that are not used anymore info.deadTimer--; if (info.deadTimer <= 0) { it.remove(); @@ -55,16 +58,30 @@ public static void onReceiveItem(ClientTravelingItem item) { info.resetTimer(); } - public static double getAndUpdateDistanceDelta(ClientTravelingItem item) { + public static void onTickItem(ClientTravelingItem item) { var info = INFOS.get(item.id); if (info == null) { - return 0; + return; } info.resetTimer(); info.lastTraveledDistance = item.traveledDistance; - double offset = info.wrongOffset; - info.wrongOffset *= 0.95; // might want to adjust based on FPS or similar - return offset; + } + + public static double getDistanceDelta(ClientTravelingItem item, float partialTick) { + var info = INFOS.get(item.id); + if (info == null) { + return 0; + } + return info.wrongOffset * smooth(partialTick); + } + + /** + * Smoothing constant. It takes ~1 second to smooth out 95% of the offset. + */ + private static final double SMOOTHING_EXP = 0.15; + + private static double smooth(double ticks) { + return Math.exp(-SMOOTHING_EXP * ticks); } public static long getClientTick() {