aboutsummaryrefslogtreecommitdiffhomepage
path: root/paper-server/patches/features/0023-Lag-compensation-ticks.patch
blob: c764bdee4a6ffbc3694435ca1638b689319dec01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 23 Sep 2023 22:05:35 -0700
Subject: [PATCH] Lag compensation ticks

Areas affected by lag comepnsation:
 - Block breaking and destroying
 - Eating food items

diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 0c35921acebd88f3a9a37676e47e7482dfea6d9c..1ff57c17f7fe3af3fb7fc5fbc5148ca333b5e618 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -301,6 +301,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
     public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
     public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
     private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
+    public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
 
     public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
         ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
@@ -1643,6 +1644,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
         for (ServerLevel serverLevel : this.getAllLevels()) {
             serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
             serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
+            serverLevel.updateLagCompensationTick(); // Paper - lag compensation
             profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
             /* Drop global time updates
             if (this.tickCount % 20 == 0) {
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index ffb5bfdd76a92bac61c7c352fdded4200d13b3ae..651a65aaa37f2cf26d54f75529cbda71e6fc2bc4 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -2678,4 +2678,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
         return this.server.getPlayerList().getPlayer(uuid);
     }
     // Paper end - check global player list where appropriate
+
+    // Paper start - lag compensation
+    private long lagCompensationTick = MinecraftServer.SERVER_INIT;
+
+    public long getLagCompensationTick() {
+        return this.lagCompensationTick;
+    }
+
+    public void updateLagCompensationTick() {
+        this.lagCompensationTick = (System.nanoTime() - MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L));
+    }
+    // Paper end - lag compensation
 }
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
index bf2a4c03afb73367a6d2530c78ff9f7c06f7f6a6..6207f45e7b84af4e6a2e4eb7b9fabf6b1e22a63a 100644
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -111,7 +111,7 @@ public class ServerPlayerGameMode {
     }
 
     public void tick() {
-        this.gameTicks = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit
+        this.gameTicks = (int) this.level.getLagCompensationTick(); // Paper - lag compensation
         if (this.hasDelayedDestroy) {
             BlockState blockState = this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks
             if (blockState == null || blockState.isAir()) { // Paper - Don't allow digging into unloaded chunks
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 635e6e49483194c43b0ab47b5e1bacfe84613c3a..195e1151f7b2a32d6c4eb67edd1952e38f58b266 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3828,6 +3828,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
         this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
     }
     // Paper end - Properly cancel usable items
+    // Paper start - lag compensate eating
+    protected long eatStartTime;
+    protected int totalEatTimeTicks;
+    // Paper end - lag compensate eating
     private void updatingUsingItem() {
         if (this.isUsingItem()) {
             if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
@@ -3841,7 +3845,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
 
     protected void updateUsingItem(ItemStack usingItem) {
         usingItem.onUseTick(this.level(), this, this.getUseItemRemainingTicks());
-        if (--this.useItemRemaining == 0 && !this.level().isClientSide && !usingItem.useOnRelease()) {
+        // Paper start - lag compensate eating
+        // we add 1 to the expected time to avoid lag compensating when we should not
+        final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
+        if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide && !usingItem.useOnRelease()) {
+            this.useItemRemaining = 0;
+            // Paper end - lag compensate eating
             this.completeUsingItem();
         }
     }
@@ -3875,7 +3884,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
         ItemStack itemInHand = this.getItemInHand(hand);
         if (!itemInHand.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack
             this.useItem = itemInHand;
-            this.useItemRemaining = itemInHand.getUseDuration(this);
+            // Paper start - lag compensate eating
+            this.useItemRemaining = this.totalEatTimeTicks = itemInHand.getUseDuration(this);
+            this.eatStartTime = System.nanoTime();
+            // Paper end - lag compensate eating
             if (!this.level().isClientSide) {
                 this.setLivingEntityFlag(1, true);
                 this.setLivingEntityFlag(2, hand == InteractionHand.OFF_HAND);
@@ -3899,7 +3911,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
                 }
             } else if (!this.isUsingItem() && !this.useItem.isEmpty()) {
                 this.useItem = ItemStack.EMPTY;
-                this.useItemRemaining = 0;
+                // Paper start - lag compensate eating
+                this.useItemRemaining = this.totalEatTimeTicks = 0;
+                this.eatStartTime = -1L;
+                // Paper end - lag compensate eating
             }
         }
     }
@@ -4023,7 +4038,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
         }
 
         this.useItem = ItemStack.EMPTY;
-        this.useItemRemaining = 0;
+        // Paper start - lag compensate eating
+        this.useItemRemaining = this.totalEatTimeTicks = 0;
+        this.eatStartTime = -1L;
+        // Paper end - lag compensate eating
     }
 
     public boolean isBlocking() {