mirror of
https://github.com/YatopiaMC/Yatopia.git
synced 2024-11-29 14:15:43 +01:00
476 lines
19 KiB
Diff
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 0924f6b484468f3cf3c2d405101c0158c12d69e6..bcf94f13414b1e8cb7438af81448e74f42a24768 100644
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
@@ -298,6 +298,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.entitySlicesManager = new com.tuinity.tuinity.world.ChunkEntitySlices(this.world, this.loc.x, this.loc.z, 0, 15); // TODO update for 1.17 // Tuinity
|
|
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() {
|