diff --git a/src/main/java/net/minecraft/world/chunk/Chunk.java b/src/main/java/net/minecraft/world/chunk/Chunk.java index a8022ae..73b360c 100644 --- a/src/main/java/net/minecraft/world/chunk/Chunk.java +++ b/src/main/java/net/minecraft/world/chunk/Chunk.java @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -19,7 +18,6 @@ import gnu.trove.set.TByteSet; import gnu.trove.set.hash.TByteHashSet; import net.minecraft.block.Block; -import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.command.IEntitySelector; import net.minecraft.crash.CrashReport; @@ -54,6 +52,8 @@ import org.ultramine.server.chunk.ChunkHash; import org.ultramine.server.chunk.IChunkDependency; import org.ultramine.server.chunk.PendingBlockUpdate; +import org.ultramine.server.internal.LambdaHolder; +import org.ultramine.server.util.WeakObjectPool; public class Chunk implements IChunkDependency { @@ -1541,12 +1541,15 @@ } } - /* ======================================== ULTRAMINE START =====================================*/ - + /*======================================== ULTRAMINE START =====================================*/ + + private static final WeakObjectPool> shortObjMapPool = new WeakObjectPool<>(LambdaHolder.newShortObjMap()); + private static final WeakObjectPool> treeSetPool = new WeakObjectPool<>(LambdaHolder.newTreeSet()); + private final ShortObjMap fastTileEntityMap = HashShortObjMaps.newMutableMap(); private final TByteSet updateLightCoords = new TByteHashSet(); - private Set pendingUpdatesSet; + private ShortObjMap pendingUpdatesSet; private TreeSet pendingUpdatesQueue; private ChunkBindState bindState = ChunkBindState.NONE; @@ -1562,6 +1565,23 @@ private short entityWaterCount; private short entityItemCount; private short entityXPOrbCount; + + private void releasePendingUpdatesSets() + { + if(pendingUpdatesQueue != null) + { + if(!pendingUpdatesSet.isEmpty()) + pendingUpdatesSet.clear(); + if(!pendingUpdatesQueue.isEmpty()) + pendingUpdatesQueue.clear(); + + shortObjMapPool.release(pendingUpdatesSet); + treeSetPool.release(pendingUpdatesQueue); + + pendingUpdatesSet = null; + pendingUpdatesQueue = null; + } + } private void convertTileEntityMap() { @@ -1582,14 +1602,11 @@ PendingBlockUpdate p = pendingUpdatesQueue.first(); if(p.scheduledTime <= time) { - pendingUpdatesSet.remove(p); + pendingUpdatesSet.remove(p.getChunkCoordHash()); pendingUpdatesQueue.remove(p); - if(pendingUpdatesQueue.size() == 0) - { - pendingUpdatesSet = null; - pendingUpdatesQueue = null; - } + if(pendingUpdatesQueue.isEmpty()) + releasePendingUpdatesSets(); isModified = true; return p; @@ -1602,13 +1619,16 @@ { if(pendingUpdatesQueue == null) { - pendingUpdatesSet = new HashSet(); - pendingUpdatesQueue = new TreeSet(); + pendingUpdatesSet = shortObjMapPool.getOrCreateInstance(); + pendingUpdatesQueue = treeSetPool.getOrCreateInstance(); } - - if(!check || !pendingUpdatesSet.contains(p)) + + PendingBlockUpdate prev = null; + if(!check || (prev = pendingUpdatesSet.get(p.getChunkCoordHash())) == null || !Block.isEqualTo(p.getBlock(), prev.getBlock())) { - pendingUpdatesSet.add(p); + if(prev != null) + pendingUpdatesQueue.remove(prev); + pendingUpdatesSet.put(p.getChunkCoordHash(), p); pendingUpdatesQueue.add(p); isModified = true; } @@ -1810,5 +1830,6 @@ if(exbs != null) exbs.free(); } + releasePendingUpdatesSets(); } } diff --git a/src/main/java/org/ultramine/server/chunk/PendingBlockUpdate.java b/src/main/java/org/ultramine/server/chunk/PendingBlockUpdate.java index adf1b52..dabc9d2 100644 --- a/src/main/java/org/ultramine/server/chunk/PendingBlockUpdate.java +++ b/src/main/java/org/ultramine/server/chunk/PendingBlockUpdate.java @@ -40,6 +40,11 @@ PendingBlockUpdate p = (PendingBlockUpdate)o; return this.hash == p.hash && Block.isEqualTo(this.block, p.block); } + + public short getChunkCoordHash() + { + return hash; + } public int hashCode() { diff --git a/src/main/java/org/ultramine/server/internal/LambdaHolder.java b/src/main/java/org/ultramine/server/internal/LambdaHolder.java index a6416e9..d34b795 100644 --- a/src/main/java/org/ultramine/server/internal/LambdaHolder.java +++ b/src/main/java/org/ultramine/server/internal/LambdaHolder.java @@ -2,11 +2,31 @@ import net.minecraft.entity.Entity; import net.minecraft.tileentity.TileEntity; +import net.openhft.koloboke.collect.map.ShortObjMap; +import net.openhft.koloboke.collect.map.hash.HashShortObjMaps; +import java.util.TreeSet; import java.util.function.Predicate; +import java.util.function.Supplier; +/** Java 8 features like lambdas must not be used in net.minecraft classes, so all lambdas used there, located here*/ public class LambdaHolder { public static final Predicate ENTITY_REMOVAL_PREDICATE = o -> ((Entity)o).removeThisTick; public static final Predicate TILE_ENTITY_REMOVAL_PREDICATE = o -> ((TileEntity)o).removeThisTick; + + private static final Supplier> NEW_TREE_SET = TreeSet::new; + private static final Supplier> NEW_SHORT_OBJ_MAP = HashShortObjMaps::newMutableMap; + + @SuppressWarnings("unchecked") + public static Supplier> newTreeSet() + { + return (Supplier>) (Object) NEW_TREE_SET; + } + + @SuppressWarnings("unchecked") + public static Supplier> newShortObjMap() + { + return (Supplier>) (Object) NEW_SHORT_OBJ_MAP; + } } diff --git a/src/main/java/org/ultramine/server/util/WeakObjectPool.java b/src/main/java/org/ultramine/server/util/WeakObjectPool.java new file mode 100644 index 0000000..e86c4ce --- /dev/null +++ b/src/main/java/org/ultramine/server/util/WeakObjectPool.java @@ -0,0 +1,42 @@ +package org.ultramine.server.util; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class WeakObjectPool +{ + private final List> pool = new ArrayList<>(); + private final Supplier factory; + private final int limit; + + public WeakObjectPool(Supplier factory, int limit) + { + this.factory = factory; + this.limit = limit; + } + + public WeakObjectPool(Supplier factory) + { + this(factory, Integer.MAX_VALUE); + } + + public T getOrCreateInstance() + { + for(int size; (size = pool.size()) != 0;) + { + T val = pool.remove(size - 1).get(); + if(val != null) + return val; + } + + return factory.get(); + } + + public void release(T val) + { + if(pool.size() < limit) + pool.add(new WeakReference<>(val)); + } +}