diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IntList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IntList.java index b08a2bd..9f3b25b 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/list/IntList.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IntList.java @@ -19,6 +19,13 @@ public final class IntList { return this.count; } + public void setMinCapacity(final int len) { + final int[] byIndex = this.byIndex; + if (byIndex.length < len) { + this.byIndex = Arrays.copyOf(byIndex, len); + } + } + public int getRaw(final int index) { return this.byIndex[index]; } diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java new file mode 100644 index 0000000..2bae994 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java @@ -0,0 +1,77 @@ +package ca.spottedleaf.moonrise.common.list; + +import it.unimi.dsi.fastutil.shorts.Short2ShortOpenHashMap; +import java.util.Arrays; + +public final class ShortList { + + private final Short2ShortOpenHashMap map = new Short2ShortOpenHashMap(); + { + this.map.defaultReturnValue(Short.MIN_VALUE); + } + + private static final short[] EMPTY_LIST = new short[0]; + + private short[] byIndex = EMPTY_LIST; + private short count; + + public int size() { + return (int)this.count; + } + + public short getRaw(final int index) { + return this.byIndex[index]; + } + + public void setMinCapacity(final int len) { + final short[] byIndex = this.byIndex; + if (byIndex.length < len) { + this.byIndex = Arrays.copyOf(byIndex, len); + } + } + + public boolean add(final short value) { + final int count = (int)this.count; + final short currIndex = this.map.putIfAbsent(value, (short)count); + + if (currIndex != Short.MIN_VALUE) { + return false; // already in this list + } + + short[] list = this.byIndex; + + if (list.length == count) { + // resize required + list = this.byIndex = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative + } + + list[count] = value; + this.count = (short)(count + 1); + + return true; + } + + public boolean remove(final short value) { + final short index = this.map.remove(value); + if (index == Short.MIN_VALUE) { + return false; + } + + // move the entry at the end to this index + final short endIndex = --this.count; + final short end = this.byIndex[endIndex]; + if (index != endIndex) { + // not empty after this call + this.map.put(end, index); + } + this.byIndex[(int)index] = end; + this.byIndex[(int)endIndex] = (short)0; + + return true; + } + + public void clear() { + this.count = (short)0; + this.map.clear(); + } +} diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/BitStorageMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/BitStorageMixin.java index e416ffa..7705132 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/BitStorageMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/BitStorageMixin.java @@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.block_counting; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.shorts.ShortArrayList; import net.minecraft.util.BitStorage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -18,15 +19,15 @@ interface BitStorageMixin extends BlockCountingBitStorage { // provide default impl in case mods implement this... @Override - public default Int2ObjectOpenHashMap moonrise$countEntries() { - final Int2ObjectOpenHashMap ret = new Int2ObjectOpenHashMap<>(); + public default Int2ObjectOpenHashMap moonrise$countEntries() { + final Int2ObjectOpenHashMap ret = new Int2ObjectOpenHashMap<>(); final int size = this.getSize(); for (int index = 0; index < size; ++index) { final int paletteIdx = this.get(index); ret.computeIfAbsent(paletteIdx, (final int key) -> { - return new IntArrayList(); - }).add(index); + return new ShortArrayList(64); + }).add((short)index); } return ret; diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java index 2de3109..990bd8f 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java @@ -1,13 +1,13 @@ package ca.spottedleaf.moonrise.mixin.block_counting; -import ca.spottedleaf.moonrise.common.list.IntList; +import ca.spottedleaf.moonrise.common.list.ShortList; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage; import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection; import com.llamalad7.mixinextras.sugar.Local; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.shorts.ShortArrayList; import net.minecraft.util.BitStorage; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -48,9 +48,9 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { public abstract boolean maybeHas(Predicate predicate); @Unique - private static final IntArrayList FULL_LIST = new IntArrayList(16*16*16); + private static final ShortArrayList FULL_LIST = new ShortArrayList(16*16*16); static { - for (int i = 0; i < (16*16*16); ++i) { + for (short i = 0; i < (16*16*16); ++i) { FULL_LIST.add(i); } } @@ -65,7 +65,7 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { private short specialCollidingBlocks; @Unique - private final IntList tickingBlocks = new IntList(); + private final ShortList tickingBlocks = new ShortList(); @Override public final boolean moonrise$hasSpecialCollidingBlocks() { @@ -73,7 +73,7 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { } @Override - public final IntList moonrise$getTickingBlockList() { + public final ShortList moonrise$getTickingBlockList() { return this.tickingBlocks; } @@ -100,20 +100,27 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { return; } - if (CollisionUtil.isSpecialCollidingBlock(oldState)) { - --this.specialCollidingBlocks; - } - if (CollisionUtil.isSpecialCollidingBlock(newState)) { - ++this.specialCollidingBlocks; + final boolean isSpecialOld = CollisionUtil.isSpecialCollidingBlock(oldState); + final boolean isSpecialNew = CollisionUtil.isSpecialCollidingBlock(newState); + if (isSpecialOld != isSpecialNew) { + if (isSpecialOld) { + --this.specialCollidingBlocks; + } else { + ++this.specialCollidingBlocks; + } } - final int position = x | (z << 4) | (y << (4+4)); + final boolean oldTicking = oldState.isRandomlyTicking(); + final boolean newTicking = newState.isRandomlyTicking(); + if (oldTicking != newTicking) { + final ShortList tickingBlocks = this.tickingBlocks; + final short position = (short)(x | (z << 4) | (y << (4+4))); - if (oldState.isRandomlyTicking()) { - this.tickingBlocks.remove(position); - } - if (newState.isRandomlyTicking()) { - this.tickingBlocks.add(position); + if (oldTicking) { + tickingBlocks.remove(position); + } else { + tickingBlocks.add(position); + } } } @@ -151,7 +158,7 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { final int paletteSize = palette.getSize(); final BitStorage storage = data.storage; - final Int2ObjectOpenHashMap counts; + final Int2ObjectOpenHashMap counts; if (paletteSize == 1) { counts = new Int2ObjectOpenHashMap<>(1); counts.put(0, FULL_LIST); @@ -159,10 +166,10 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { counts = ((BlockCountingBitStorage)storage).moonrise$countEntries(); } - for (final Iterator> iterator = counts.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) { - final Int2ObjectMap.Entry entry = iterator.next(); + for (final Iterator> iterator = counts.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) { + final Int2ObjectMap.Entry entry = iterator.next(); final int paletteIdx = entry.getIntKey(); - final IntArrayList coordinates = entry.getValue(); + final ShortArrayList coordinates = entry.getValue(); final int paletteCount = coordinates.size(); final BlockState state = palette.valueFor(paletteIdx); @@ -172,16 +179,21 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { } if (CollisionUtil.isSpecialCollidingBlock(state)) { - this.specialCollidingBlocks += paletteCount; + this.specialCollidingBlocks += (short)paletteCount; } - this.nonEmptyBlockCount += paletteCount; + this.nonEmptyBlockCount += (short)paletteCount; if (state.isRandomlyTicking()) { - this.tickingBlockCount += paletteCount; - final int[] raw = coordinates.elements(); + this.tickingBlockCount += (short)paletteCount; + final short[] raw = coordinates.elements(); + final int rawLen = raw.length; - Objects.checkFromToIndex(0, paletteCount, raw.length); + final ShortList tickingBlocks = this.tickingBlocks; + + tickingBlocks.setMinCapacity(Math.min((rawLen + tickingBlocks.size()) * 3 / 2, 16*16*16)); + + Objects.checkFromToIndex(0, paletteCount, rawLen); for (int i = 0; i < paletteCount; ++i) { - this.tickingBlocks.add(raw[i]); + tickingBlocks.add(raw[i]); } } @@ -190,7 +202,7 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection { if (!fluid.isEmpty()) { //this.nonEmptyBlockCount += count; // fix vanilla bug: make non-empty block count correct if (fluid.isRandomlyTicking()) { - this.tickingFluidCount += paletteCount; + this.tickingFluidCount += (short)paletteCount; } } } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/SimpleBitStorageMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/SimpleBitStorageMixin.java index 0de52c9..019d3c1 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/SimpleBitStorageMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/SimpleBitStorageMixin.java @@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.block_counting; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.shorts.ShortArrayList; import net.minecraft.util.BitStorage; import net.minecraft.util.SimpleBitStorage; import org.spongepowered.asm.mixin.Final; @@ -33,14 +34,14 @@ abstract class SimpleBitStorageMixin implements BitStorage, BlockCountingBitStor private int size; @Override - public final Int2ObjectOpenHashMap moonrise$countEntries() { + public final Int2ObjectOpenHashMap moonrise$countEntries() { final int valuesPerLong = this.valuesPerLong; final int bits = this.bits; final long mask = this.mask; final int size = this.size; // we may be backed by global palette, so limit bits for init capacity - final Int2ObjectOpenHashMap ret = new Int2ObjectOpenHashMap<>( + final Int2ObjectOpenHashMap ret = new Int2ObjectOpenHashMap<>( 1 << Math.min(6, bits) ); @@ -53,8 +54,8 @@ abstract class SimpleBitStorageMixin implements BitStorage, BlockCountingBitStor value >>= bits; ret.computeIfAbsent(paletteIdx, (final int key) -> { - return new IntArrayList(); - }).add(index); + return new ShortArrayList(64); + }).add((short)index); ++li; ++index; diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/ZeroBitStorageMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/ZeroBitStorageMixin.java index fdabf2d..1043f64 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/ZeroBitStorageMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/ZeroBitStorageMixin.java @@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.block_counting; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.shorts.ShortArrayList; import net.minecraft.util.BitStorage; import net.minecraft.util.ZeroBitStorage; import org.spongepowered.asm.mixin.Final; @@ -17,17 +18,17 @@ abstract class ZeroBitStorageMixin implements BitStorage, BlockCountingBitStorag private int size; @Override - public final Int2ObjectOpenHashMap moonrise$countEntries() { + public final Int2ObjectOpenHashMap moonrise$countEntries() { final int size = this.size; - final int[] raw = new int[size]; + final short[] raw = new short[size]; for (int i = 0; i < size; ++i) { - raw[i] = i; + raw[i] = (short)i; } - final IntArrayList coordinates = IntArrayList.wrap(raw, size); + final ShortArrayList coordinates = ShortArrayList.wrap(raw, size); - final Int2ObjectOpenHashMap ret = new Int2ObjectOpenHashMap<>(1); + final Int2ObjectOpenHashMap ret = new Int2ObjectOpenHashMap<>(1); ret.put(0, coordinates); return ret; } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/random_ticking/ServerLevelMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/random_ticking/ServerLevelMixin.java index 3baa2cb..0121d1b 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/random_ticking/ServerLevelMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/random_ticking/ServerLevelMixin.java @@ -1,7 +1,7 @@ package ca.spottedleaf.moonrise.mixin.random_ticking; import ca.spottedleaf.moonrise.common.PlatformHooks; -import ca.spottedleaf.moonrise.common.list.IntList; +import ca.spottedleaf.moonrise.common.list.ShortList; import ca.spottedleaf.moonrise.common.util.SimpleRandom; import ca.spottedleaf.moonrise.common.util.WorldUtil; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection; @@ -89,7 +89,7 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel { continue; } - final IntList tickList = ((BlockCountingChunkSection)section).moonrise$getTickingBlockList(); + final ShortList tickList = ((BlockCountingChunkSection)section).moonrise$getTickingBlockList(); for (int i = 0; i < tickSpeed; ++i) { final int tickingBlocks = tickList.size(); @@ -100,7 +100,7 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel { continue; } - final int location = tickList.getRaw(index); + final int location = (int)tickList.getRaw(index) & 0xFFFF; final BlockState state = states.get(location); // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java index aef4fc0..93bc56d 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingBitStorage.java @@ -1,10 +1,10 @@ package ca.spottedleaf.moonrise.patches.block_counting; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.shorts.ShortArrayList; public interface BlockCountingBitStorage { - public Int2ObjectOpenHashMap moonrise$countEntries(); + public Int2ObjectOpenHashMap moonrise$countEntries(); } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java index 7479536..0d1443a 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/block_counting/BlockCountingChunkSection.java @@ -1,11 +1,11 @@ package ca.spottedleaf.moonrise.patches.block_counting; -import ca.spottedleaf.moonrise.common.list.IntList; +import ca.spottedleaf.moonrise.common.list.ShortList; public interface BlockCountingChunkSection { public boolean moonrise$hasSpecialCollidingBlocks(); - public IntList moonrise$getTickingBlockList(); + public ShortList moonrise$getTickingBlockList(); }