Yatopia/patches/server/0064-Port-hydrogen.patch

645 lines
25 KiB
Diff
Raw Normal View History

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
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/BiomeStorage.java b/src/main/java/net/minecraft/server/BiomeStorage.java
index b7f5c932197529c0ea045cfe696fd5da1ccc7202..af6245ba0c6b1389703722596ab7aa50deaf9e9f 100644
--- a/src/main/java/net/minecraft/server/BiomeStorage.java
+++ b/src/main/java/net/minecraft/server/BiomeStorage.java
@@ -1,23 +1,32 @@
package net.minecraft.server;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.Reference2ShortMap;
+import it.unimi.dsi.fastutil.objects.Reference2ShortOpenHashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class BiomeStorage implements BiomeManager.Provider {
private static final Logger LOGGER = LogManager.getLogger();
- private static final int e = (int) Math.round(Math.log(16.0D) / Math.log(2.0D)) - 2;
+ private static final int e = (int) Math.round(Math.log(16.0D) / Math.log(2.0D)) - 2; public static final int HORIZONTAL_SECTION_COUNT = e; // Yatopia - OBFHELPER
private static final int f = (int) Math.round(Math.log(256.0D) / Math.log(2.0D)) - 2;
public static final int a = 1 << BiomeStorage.e + BiomeStorage.e + BiomeStorage.f;
- public static final int b = (1 << BiomeStorage.e) - 1;
- public static final int c = (1 << BiomeStorage.f) - 1;
+ public static final int b = (1 << BiomeStorage.e) - 1; public static final int HORIZONTAL_BIT_MASK = b; // Yatopia - OBFHELPER
+ public static final int c = (1 << BiomeStorage.f) - 1; public static final int VERTICAL_BIT_MASK = c; // Yatopia - OBFHELPER
public final Registry<BiomeBase> registry;
- private final BiomeBase[] h;
+ private BiomeBase[] h; private BiomeBase[] getData() { return h; } // Yatopia - OBFHELPER , remove final
+
+ // Yatopia start - Port hydrogen
+ private BiomeBase[] palette;
+ private DataBits intArray;
+ // Yatopia end
public BiomeStorage(Registry<BiomeBase> registry, BiomeBase[] abiomebase) {
this.registry = registry;
this.h = abiomebase;
+ this.createCompact(); // Yatopia - Port hydrogen
}
private BiomeStorage(Registry<BiomeBase> registry) {
@@ -37,6 +46,7 @@ public class BiomeStorage implements BiomeManager.Provider {
this.h[k] = worldchunkmanager.getBiome(i + l, i1, j + j1);
}
+ this.createCompact(); // Yatopia - Port hydrogen
}
public BiomeStorage(Registry<BiomeBase> registry, ChunkCoordIntPair chunkcoordintpair, WorldChunkManager worldchunkmanager, @Nullable int[] aint) {
@@ -67,9 +77,11 @@ public class BiomeStorage implements BiomeManager.Provider {
}
}
+ this.createCompact(); // Yatopia - Port hydrogen
}
public int[] a() {
+ /* // Yatopia start - Port hydrogen
int[] aint = new int[this.h.length];
for (int i = 0; i < this.h.length; ++i) {
@@ -77,15 +89,33 @@ public class BiomeStorage implements BiomeManager.Provider {
}
return aint;
+ */
+ int size = this.intArray.getSize();
+ int[] array = new int[size];
+
+ for (int i = 0; i < size; ++i) {
+ array[i] = this.registry.a(this.palette[this.intArray.get(i)]);
+ }
+
+ return array;
+ // Yatopia end
}
@Override
public BiomeBase getBiome(int i, int j, int k) {
+ /* // Yatopia start - Port hydrogen
int l = i & BiomeStorage.b;
int i1 = MathHelper.clamp(j, 0, BiomeStorage.c);
int j1 = k & BiomeStorage.b;
return this.h[i1 << BiomeStorage.e + BiomeStorage.e | j1 << BiomeStorage.e | l];
+ */
+ int x = i & HORIZONTAL_BIT_MASK;
+ int y = MathHelper.clamp(j, 0, VERTICAL_BIT_MASK);
+ int z = k & HORIZONTAL_BIT_MASK;
+
+ return this.palette[this.intArray.get(y << HORIZONTAL_SECTION_COUNT + HORIZONTAL_SECTION_COUNT | z << HORIZONTAL_SECTION_COUNT | x)];
+ // Yatopia end
}
// CraftBukkit start
@@ -94,7 +124,74 @@ public class BiomeStorage implements BiomeManager.Provider {
int i1 = MathHelper.clamp(j, 0, BiomeStorage.c);
int j1 = k & BiomeStorage.b;
- this.h[i1 << BiomeStorage.e + BiomeStorage.e | j1 << BiomeStorage.e | l] = biome;
+ this.palette[this.intArray.get(l << HORIZONTAL_SECTION_COUNT + HORIZONTAL_SECTION_COUNT | i1 << HORIZONTAL_SECTION_COUNT | j1)] = biome; // Yatopia - Port Hydrogen
}
// CraftBukkit end
+
+
+ // Yatopia Start - Port Hydrogen
+ private void createCompact() {
+ if (this.intArray != null || this.getData()[0] == null) {
+ return;
+ }
+
+ Reference2ShortOpenHashMap<BiomeBase> paletteTable = this.createPalette();
+ BiomeBase[] paletteIndexed = new BiomeBase[paletteTable.size()];
+
+ for (Reference2ShortMap.Entry<BiomeBase> entry : paletteTable.reference2ShortEntrySet()) {
+ paletteIndexed[entry.getShortValue()] = entry.getKey();
+ }
+
+ int packedIntSize = Math.max(2, MathHelper.e(paletteTable.size()));
+ DataBits integerArray = new DataBits(packedIntSize, a);
+
+ BiomeBase prevBiome = null;
+ short prevId = -1;
+
+ for (int i = 0; i < this.getData().length; i++) {
+ BiomeBase biome = this.getData()[i];
+ short id;
+
+ if (prevBiome == biome) {
+ id = prevId;
+ } else {
+ id = paletteTable.getShort(biome);
+
+ if (id < 0) {
+ throw new IllegalStateException("Palette is missing entry: " + biome);
+ }
+
+ prevId = id;
+ prevBiome = biome;
+ }
+
+ integerArray.set(i, id);
+ }
+
+ this.palette = paletteIndexed;
+ this.intArray = integerArray;
+ this.h = null;
+ }
+
+ private Reference2ShortOpenHashMap<BiomeBase> createPalette() {
+ Reference2ShortOpenHashMap<BiomeBase> map = new Reference2ShortOpenHashMap<>();
+ map.defaultReturnValue(Short.MIN_VALUE);
+
+ BiomeBase prevObj = null;
+ short id = 0;
+
+ for (BiomeBase obj : this.getData()) {
+ if (obj == prevObj) {
+ continue;
+ }
+
+ if (map.getShort(obj) < 0) {
+ map.put(obj, id++);
+ }
+
+ prevObj = obj;
+ }
+
+ return map;
+ } // Yatopia end
}
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index 8b7fd21e6b366196fbc9cd44a340335c4cf9205f..8b8ecc2d8925b3c209d99e101f6e478b08d86db9 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -336,6 +336,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
}
public org.bukkit.Chunk bukkitChunk;
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index 5f04591193d58ba7897194142da5efcbec3763dd..bf4f34b5f4f7473921589b2f001570a38e96c5ce 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() {