Yatopia/patches/server/0060-Port-hydrogen.patch
Simon Gardling 9f3986a30b
Updated Upstream and Sidestream(s) (Paper/Purpur) (#404)
* Updated Upstream and Sidestream(s) (Paper/Purpur)

Upstream/An Sidestream has released updates that appears to apply and compile correctly
This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing.

Paper Changes:
088fa6f28 [Auto] Updated Upstream (Bukkit/CraftBukkit/Spigot)

Purpur Changes:
a8c9e3d Add unsafe Entity serialization API (#139)
631520c Add ender crystal explosion options (#168)
3880ddf Config to always tame in Creative (#166)
9ae031c Updated Upstream (Paper)
006e47f Fix #167 `persistent-droppable-entity-display-names` renames lead on named mobs
ec81b87 Update Gradle to 6.8.2

* Updated Upstream and Sidestream(s) (Purpur)

Upstream/An Sidestream has released updates that appears to apply and compile correctly
This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing.

Purpur Changes:
b15a2e9 Add ghast allow-griefing option

* Updated Upstream and Sidestream(s) (Purpur)

Upstream/An Sidestream has released updates that appears to apply and compile correctly
This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing.

Purpur Changes:
9537c77 Add phantom allow-griefing option
2021-02-15 10:10:34 -06:00

476 lines
19 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JellySquid <jellysquid+atwork@protonmail.com>
Date: Wed, 20 Jan 2021 20:14:55 +0100
Subject: [PATCH] Port hydrogen
Original code by JellySquid, licensed under GNU Lesser General Public License v3.0
you can find the original code on https://github.com/CaffeineMC/hydrogen-fabric/ (Yarn mappings)
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/cache/StatePropertyTableCache.java b/src/main/java/me/jellysquid/mods/lithium/common/cache/StatePropertyTableCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd18bb8b3550d0fe9ba2589151baceb9100ae6f2
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/cache/StatePropertyTableCache.java
@@ -0,0 +1,38 @@
+package me.jellysquid.mods.lithium.common.cache;
+
+import me.jellysquid.mods.lithium.common.collections.FastImmutableTableCache;
+import net.minecraft.server.Block;
+import net.minecraft.server.Fluid;
+import net.minecraft.server.FluidType;
+import net.minecraft.server.IBlockData;
+import net.minecraft.server.IBlockState;
+
+/**
+ * Many of the column and row key arrays in block state tables will be duplicated, leading to an unnecessary waste of
+ * memory. Since we have very limited options for trying to construct more optimized table types without throwing
+ * maintainability or mod compatibility out the window, this class acts as a dirty way to find and de-duplicate arrays
+ * after we construct our table types.
+ * <p>
+ * While this global cache does not provide the ability to remove or clear entries from it, the reality is that it
+ * shouldn't matter because block state tables are only initialized once and remain loaded for the entire lifetime of
+ * the game. Even in the event of classloader pre-boot shenanigans, we still shouldn't leak memory as our cache will be
+ * dropped along with the rest of the loaded classes when the class loader is reaped.
+ */
+public class StatePropertyTableCache {
+ public static final FastImmutableTableCache<IBlockState<?>, Comparable<?>, IBlockData> BLOCK_STATE_TABLE =
+ new FastImmutableTableCache<>();
+
+ public static final FastImmutableTableCache<IBlockState<?>, Comparable<?>, Fluid> FLUID_STATE_TABLE =
+ new FastImmutableTableCache<>();
+
+ @SuppressWarnings("unchecked")
+ public static <S, O> FastImmutableTableCache<IBlockState<?>, Comparable<?>, S> getTableCache(O owner) {
+ if (owner instanceof Block) {
+ return (FastImmutableTableCache<IBlockState<?>, Comparable<?>, S>) BLOCK_STATE_TABLE;
+ } else if (owner instanceof FluidType) {
+ return (FastImmutableTableCache<IBlockState<?>, Comparable<?>, S>) FLUID_STATE_TABLE;
+ } else {
+ throw new IllegalArgumentException("");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/collections/FastImmutableTable.java b/src/main/java/me/jellysquid/mods/lithium/common/collections/FastImmutableTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..9aa45ecdff223258c4f3252a61b9ccbbed6151d2
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/collections/FastImmutableTable.java
@@ -0,0 +1,227 @@
+package me.jellysquid.mods.lithium.common.collections;
+
+import com.google.common.collect.Table;
+import it.unimi.dsi.fastutil.Hash;
+import it.unimi.dsi.fastutil.HashCommon;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import static it.unimi.dsi.fastutil.HashCommon.arraySize;
+
+public class FastImmutableTable<R, C, V> implements Table<R, C, V> {
+ private R[] rowKeys;
+ private int[] rowIndices;
+ private final int rowMask;
+ private final int rowCount;
+
+ private C[] colKeys;
+ private int[] colIndices;
+ private final int colMask;
+ private final int colCount;
+
+ private V[] values;
+ private final int size;
+
+ @SuppressWarnings("unchecked")
+ public FastImmutableTable(Table<R, C, V> table, FastImmutableTableCache<R, C, V> cache) {
+ if (cache == null) {
+ throw new IllegalArgumentException("Cache must not be null");
+ }
+
+ float loadFactor = Hash.DEFAULT_LOAD_FACTOR;
+
+ Set<R> rowKeySet = table.rowKeySet();
+ Set<C> colKeySet = table.columnKeySet();
+
+ this.rowCount = rowKeySet.size();
+ this.colCount = colKeySet.size();
+
+ int rowN = arraySize(this.rowCount, loadFactor);
+ int colN = arraySize(this.colCount, loadFactor);
+
+ this.rowMask = rowN - 1;
+ this.rowKeys = (R[]) new Object[rowN];
+ this.rowIndices = new int[rowN];
+
+ this.colMask = colN - 1;
+ this.colKeys = (C[]) new Object[colN];
+ this.colIndices = new int[colN];
+
+ this.createIndex(this.colKeys, this.colIndices, this.colMask, colKeySet);
+ this.createIndex(this.rowKeys, this.rowIndices, this.rowMask, rowKeySet);
+
+ this.values = (V[]) new Object[this.rowCount * this.colCount];
+
+ for (Cell<R, C, V> cell : table.cellSet()) {
+ int colIdx = this.getIndex(this.colKeys, this.colIndices, this.colMask, cell.getColumnKey());
+ int rowIdx = this.getIndex(this.rowKeys, this.rowIndices, this.rowMask, cell.getRowKey());
+
+ if (colIdx < 0 || rowIdx < 0) {
+ throw new IllegalStateException("Missing index for " + cell);
+ }
+
+ this.values[this.colCount * rowIdx + colIdx] = cell.getValue();
+ }
+
+ this.size = table.size();
+
+ this.rowKeys = cache.dedupRows(this.rowKeys);
+ this.rowIndices = cache.dedupIndices(this.rowIndices);
+
+ this.colIndices = cache.dedupIndices(this.colIndices);
+ this.colKeys = cache.dedupColumns(this.colKeys);
+
+ this.values = cache.dedupValues(this.values);
+ }
+
+ private <T> void createIndex(T[] keys, int[] indices, int mask, Collection<T> iterable) {
+ int index = 0;
+
+ for (T obj : iterable) {
+ int i = this.find(keys, mask, obj);
+
+ if (i < 0) {
+ int pos = -i - 1;
+
+ keys[pos] = obj;
+ indices[pos] = index++;
+ }
+ }
+ }
+
+ private <T> int getIndex(T[] keys, int[] indices, int mask, T key) {
+ int pos = this.find(keys, mask, key);
+
+ if (pos < 0) {
+ return -1;
+ }
+
+ return indices[pos];
+ }
+
+ @Override
+ public boolean contains(Object rowKey, Object columnKey) {
+ return this.get(rowKey, columnKey) != null;
+ }
+
+ @Override
+ public boolean containsRow(Object rowKey) {
+ return this.find(this.rowKeys, this.rowMask, rowKey) >= 0;
+ }
+
+ @Override
+ public boolean containsColumn(Object columnKey) {
+ return this.find(this.colKeys, this.colMask, columnKey) >= 0;
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return ArrayUtils.contains(this.values, value);
+ }
+
+ @Override
+ public V get(Object rowKey, Object columnKey) {
+ final int row = this.getIndex(this.rowKeys, this.rowIndices, this.rowMask, rowKey);
+ final int col = this.getIndex(this.colKeys, this.colIndices, this.colMask, columnKey);
+
+ if (row < 0 || col < 0) {
+ return null;
+ }
+
+ return this.values[this.colCount * row + col];
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.size() == 0;
+ }
+
+ @Override
+ public int size() {
+ return this.size;
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V put(R rowKey, C columnKey, V val) {
+ throw new UnsupportedOperationException();
+ }
+
+ private <T> int find(T[] key, int mask, T value) {
+ T curr;
+ int pos;
+ // The starting point.
+ if ((curr = key[pos = HashCommon.mix(value.hashCode()) & mask]) == null) {
+ return -(pos + 1);
+ }
+ if (value.equals(curr)) {
+ return pos;
+ }
+ // There's always an unused entry.
+ while (true) {
+ if ((curr = key[pos = pos + 1 & mask]) == null) {
+ return -(pos + 1);
+ }
+ if (value.equals(curr)) {
+ return pos;
+ }
+ }
+ }
+
+ @Override
+ public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V remove(Object rowKey, Object columnKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<C, V> row(R rowKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<R, V> column(C columnKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<Cell<R, C, V>> cellSet() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<R> rowKeySet() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<C> columnKeySet() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Collection<V> values() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<R, Map<C, V>> rowMap() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<C, Map<R, V>> columnMap() {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/collections/FastImmutableTableCache.java b/src/main/java/me/jellysquid/mods/lithium/common/collections/FastImmutableTableCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5314a0396f4a8f373d855e873820ddddd635a4a
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/collections/FastImmutableTableCache.java
@@ -0,0 +1,44 @@
+package me.jellysquid.mods.lithium.common.collections;
+
+import it.unimi.dsi.fastutil.Hash;
+import it.unimi.dsi.fastutil.ints.IntArrays;
+import it.unimi.dsi.fastutil.objects.ObjectArrays;
+import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
+
+/**
+ * @param <R> The type used by the
+ * @param <C>
+ * @param <V>
+ */
+public class FastImmutableTableCache<R, C, V> {
+ private final ObjectOpenCustomHashSet<R[]> rows;
+ private final ObjectOpenCustomHashSet<C[]> columns;
+ private final ObjectOpenCustomHashSet<V[]> values;
+
+ private final ObjectOpenCustomHashSet<int[]> indices;
+
+ @SuppressWarnings("unchecked")
+ public FastImmutableTableCache() {
+ this.rows = new ObjectOpenCustomHashSet<>((Hash.Strategy<R[]>) ObjectArrays.HASH_STRATEGY);
+ this.columns = new ObjectOpenCustomHashSet<>((Hash.Strategy<C[]>) ObjectArrays.HASH_STRATEGY);
+ this.values = new ObjectOpenCustomHashSet<>((Hash.Strategy<V[]>) ObjectArrays.HASH_STRATEGY);
+
+ this.indices = new ObjectOpenCustomHashSet<>(IntArrays.HASH_STRATEGY);
+ }
+
+ public synchronized V[] dedupValues(V[] values) {
+ return this.values.addOrGet(values);
+ }
+
+ public synchronized R[] dedupRows(R[] rows) {
+ return this.rows.addOrGet(rows);
+ }
+
+ public synchronized C[] dedupColumns(C[] columns) {
+ return this.columns.addOrGet(columns);
+ }
+
+ public synchronized int[] dedupIndices(int[] ints) {
+ return this.indices.addOrGet(ints);
+ }
+}
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index fa1d559a07199bf52d8ae04b2c34261efdebdcdb..a3c86e6b56f744b340bc486b9d728114f884d28f 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -337,6 +337,14 @@ public class Chunk implements IChunkAccess {
// CraftBukkit start
this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
+ // Yatopia start - Port hydrogen
+ // Upgrading a ProtoChunk to a Chunk might result in empty sections being copied over
+ // These simply waste memory, and the Chunk will return air blocks for any absent section without issue.
+ for (int i2 = 0; i2 < this.sections.length; i2++) {
+ if (ChunkSection.isEmpty(this.sections[i2])) {
+ this.sections[i2] = null;
+ }
+ } // Yatopia end
this.lightningTick = this.world.random.nextInt(100000) << 1; // Airplane - initialize lightning tick
}
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index e77da341b765725771726283d3a8249b514b40da..c44333ec5b0c1914f7cb9f4b3b39626069136c22 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -70,8 +70,10 @@ public class ChunkRegionLoader {
private static final String UNINITIALISED_SKYLIGHT_TAG = "starlight.skylight_uninit";
private static final String STARLIGHT_VERSION_TAG = "starlight.light_version";
// Tuinity end - rewrite light engine
+ private static final ThreadLocal<NBTTagCompound> CAPTURED_TAGS = new ThreadLocal<>(); // Yatopia - Port Hydrogen
public static InProgressChunkHolder loadChunk(WorldServer worldserver, DefinedStructureManager definedstructuremanager, VillagePlace villageplace, ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound, boolean distinguish) {
+ CAPTURED_TAGS.set(nbttagcompound); // Yatopia
ArrayDeque<Runnable> tasksToExecuteOnMain = new ArrayDeque<>();
// Paper end
ChunkGenerator chunkgenerator = worldserver.getChunkProvider().getChunkGenerator();
@@ -190,10 +192,22 @@ public class ChunkRegionLoader {
} else {
object2 = protochunkticklist1;
}
+ // Yatopia start
+ NBTTagCompound strippedTag = new NBTTagCompound();
+ strippedTag.set("Entities", nbttagcompound1.getList("Entities", 10));
+ strippedTag.set("TileEntities", nbttagcompound1.getList("TileEntities", 10));
+ strippedTag.set("ChunkBukkitValues", nbttagcompound1.get("ChunkBukkitValues"));
+ // Yatopia end
object = new Chunk(worldserver.getMinecraftWorld(), chunkcoordintpair, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, j, achunksection, // Paper start - fix massive nbt memory leak due to lambda. move lambda into a container method to not leak scope. Only clone needed NBT keys.
+ // Yatopia start - Port hydrogen
+ /*
createLoadEntitiesConsumer(new SafeNBTCopy(nbttagcompound1, "TileEntities", "Entities", "ChunkBukkitValues")) // Paper - move CB Chunk PDC into here
+ */
+ createLoadEntitiesConsumer(strippedTag)
+ // Yatopia end
);// Paper end
+ CAPTURED_TAGS.remove(); // Yatopia
((Chunk)object).setBlockNibbles(blockNibbles); // Tuinity - replace light impl
((Chunk)object).setSkyNibbles(skyNibbles); // Tuinity - replace light impl
} else {
diff --git a/src/main/java/net/minecraft/server/DataBits.java b/src/main/java/net/minecraft/server/DataBits.java
index f0c9009fb808ca664a7c3ebaeb8cfa8e2ba7b97e..40e3001bc1742231dcd02cee4423c57d0fd9a991 100644
--- a/src/main/java/net/minecraft/server/DataBits.java
+++ b/src/main/java/net/minecraft/server/DataBits.java
@@ -64,6 +64,7 @@ public class DataBits {
return j1;
}
+ public final void set(int i, int j){ b(i, j); } // Yatopia - OBFHELPER
public final void b(int i, int j) { // Paper - make final for inline
//Validate.inclusiveBetween(0L, (long) (this.e - 1), (long) i); // Paper
//Validate.inclusiveBetween(0L, this.d, (long) j); // Paper
@@ -74,6 +75,7 @@ public class DataBits {
this.b[k] = l & ~(this.d << i1) | ((long) j & this.d) << i1;
}
+ public final int get(int i) { return this.a(i); } // Yatopia - OBFHELPER
public final int a(int i) { // Paper - make final for inline
//Validate.inclusiveBetween(0L, (long) (this.e - 1), (long) i); // Paper
int j = this.b(i);
@@ -88,6 +90,7 @@ public class DataBits {
return this.b;
}
+ public int getSize(){ return b(); } // Yatopia - OBFHELPER
public int b() {
return this.e;
}
diff --git a/src/main/java/net/minecraft/server/IBlockDataHolder.java b/src/main/java/net/minecraft/server/IBlockDataHolder.java
index b19c694cf01bc868dd7c4ec6432b613d19f2ca40..865fd6ef879943634ee2861c6da21ead31306eb2 100644
--- a/src/main/java/net/minecraft/server/IBlockDataHolder.java
+++ b/src/main/java/net/minecraft/server/IBlockDataHolder.java
@@ -8,6 +8,10 @@ import com.google.common.collect.Table;
import com.google.common.collect.UnmodifiableIterator;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
+// Yatopia start
+import me.jellysquid.mods.lithium.common.cache.StatePropertyTableCache;
+import me.jellysquid.mods.lithium.common.collections.FastImmutableTable;
+// Yatopia end
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -143,7 +147,12 @@ public abstract class IBlockDataHolder<O, S> {
}
}
+ // Yatopia start - Port hydrogen
+ /*
this.e = (Table) (table.isEmpty() ? table : ArrayTable.create(table));
+ */
+ this.e = new FastImmutableTable<>((table.isEmpty() ? table : ArrayTable.create(table)), StatePropertyTableCache.getTableCache(this.c));
+ // Yatopia end
}
}
diff --git a/src/main/java/net/minecraft/server/NBTTagCompound.java b/src/main/java/net/minecraft/server/NBTTagCompound.java
index 06d5acab794e3ee139a11f9b068e8a359c46db2c..2bc71833fea91f1b7b35a431b1d6905a5738e83c 100644
--- a/src/main/java/net/minecraft/server/NBTTagCompound.java
+++ b/src/main/java/net/minecraft/server/NBTTagCompound.java
@@ -20,6 +20,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap; // Yatopia
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; // Paper
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -74,7 +75,12 @@ public class NBTTagCompound implements NBTBase {
public final Map<String, NBTBase> map; // Paper
protected NBTTagCompound(Map<String, NBTBase> map) {
+ // Yatopia start - Port hydrogen
+ /*
this.map = map;
+ */
+ this.map = map instanceof Object2ObjectMap ? map : new Object2ObjectOpenHashMap<>(map);
+ // Yatopia end
}
public NBTTagCompound() {