mirror of
https://github.com/YatopiaMC/Yatopia.git
synced 2024-11-25 12:05:14 +01:00
b774a5d8a8
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: 5cff60d Toggle for water sensitive mobs getting damaged by... water (#161) AirplaneLite Changes: 1b11269 This works, last time f763e5b Keep one patch ca87ae0 Keep empty API directory 53d0334 Rebrand as "Airplane" 1e153e0 Merge pull request #3 from DeadSteve51/patch-1 0829860 Remove actions links 12cc4d7 Adds more info to the README, mostly from the Discord a78a63c Add new downloads URL 2a05c35 Force workflow run
474 lines
18 KiB
Diff
474 lines
18 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
|
|
|
|
|
|
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 7b8036840dcca16904b3063c209d5ff10ab8a6af..6bc5fedc4d8effa530799eac814f626dfeed2105 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() {
|