c5a10665b8
Spigot still maintains some partial implementation of "tick skipping", a practice in which the MinecraftServer.currentTick field is updated not by an increment of one per actual tick, but instead set to System.currentTimeMillis() / 50. This behaviour means that the tracked tick may "skip" a tick value in case a previous tick took more than the expected 50ms. To compensate for this in important paths, spigot/craftbukkit implements "wall-time". Instead of incrementing/decrementing ticks on block entities/entities by one for each call to their tick() method, they instead increment/decrement important values, like an ItemEntity's age or pickupDelay, by the difference of `currentTick - lastTick`, where `lastTick` is the value of `currentTick` during the last tick() call. These "fixes" however do not play nicely with minecraft's simulation distance as entities/block entities implementing the above behaviour would "catch up" their values when moving from a non-ticking chunk to a ticking one as their `lastTick` value remains stuck on the last tick in a ticking chunk and hence lead to a large "catch up" once ticked again. Paper completely removes the "tick skipping" behaviour (See patch "Further-improve-server-tick-loop"), making the above precautions completely unnecessary, which also rids paper of the previous described incompatibility with non-ticking chunks.
58 Zeilen
3.3 KiB
Diff
58 Zeilen
3.3 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: stonar96 <minecraft.stonar96@gmail.com>
|
|
Date: Sun, 17 Jan 2021 01:11:36 +0100
|
|
Subject: [PATCH] Optimize HashMapPalette
|
|
|
|
HashMapPalette uses an instance of CrudeIncrementalIntIdentityHashBiMap
|
|
internally. A Palette has a preset maximum size = 1 << bits.
|
|
CrudeIncrementalIntIdentityHashBiMap has an initial size but is
|
|
automatically resized. The CrudeIncrementalIntIdentityHashBiMap is created
|
|
with the maximum size in the constructor of HashMapPalette, with the aim
|
|
that it doesn't need to be resized anymore. However, there are two things
|
|
that I think Mojang hasn't considered here:
|
|
1) The CrudeIncrementalIntIdentityHashBiMap is resized, when its initial
|
|
size is reached and not the next time, when a further object is added.
|
|
2) HashMapPalette adds objects (unnecessarily) before checking if the
|
|
initial size of CrudeIncrementalIntIdentityHashBiMap is reached.
|
|
This means to actually avoid resize operations in
|
|
CrudeIncrementalIntIdentityHashBiMap, one has to add 2 to the initial size
|
|
or add 1 and check the size before adding objects. This commit implements
|
|
the second approach. Note that this isn't only an optimization but also
|
|
makes async reads of Palettes fail-safe. An async read while the
|
|
CrudeIncrementalIntIdentityHashBiMap is resized is fatal and can even lead
|
|
to corrupted data. This is also something that Anti-Xray is currently
|
|
relying on.
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
|
|
index f80cde264393f3606bc0c54ba2fd6a467f4bcb5a..c5e1040c239874dcf20b79472bf690ee7f0a9e5f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
|
|
@@ -20,7 +20,7 @@ public class HashMapPalette<T> implements Palette<T> {
|
|
}
|
|
|
|
public HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener) {
|
|
- this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create(1 << indexBits));
|
|
+ this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create((1 << indexBits) + 1)); // Paper - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap
|
|
}
|
|
|
|
private HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener, CrudeIncrementalIntIdentityHashBiMap<T> map) {
|
|
@@ -38,10 +38,16 @@ public class HashMapPalette<T> implements Palette<T> {
|
|
public int idFor(T object) {
|
|
int i = this.values.getId(object);
|
|
if (i == -1) {
|
|
- i = this.values.add(object);
|
|
- if (i >= 1 << this.bits) {
|
|
+ // Paper start - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
|
|
+ // We use size() instead of the result from add(K)
|
|
+ // This avoids adding another object unnecessarily
|
|
+ // Without this change, + 2 would be required in the constructor
|
|
+ if (this.values.size() >= 1 << this.bits) {
|
|
i = this.resizeHandler.onResize(this.bits + 1, object);
|
|
+ } else {
|
|
+ i = this.values.add(object);
|
|
}
|
|
+ // Paper end - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
|
|
}
|
|
|
|
return i;
|