aboutsummaryrefslogtreecommitdiffhomepage
path: root/paper-server/patches/features/0023-Lag-compensation-ticks.patch
blob: 0e33a6864f7f65dfba7b42c9daf0d4346037d6cd (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 9c5305b4542483efeeeab19a79eb8eae6d15ef2c..ddd23354d68f5cbdc9f72c11246ab26a6c0bbe16 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
@@ -1663,6 +1664,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 bbb4bb0940765a12c45a99c8234ca82ef1934903..7dbf6113d79ab826ba5bb9b648b557f625e2b438 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() {