From 6b28cb5ebcc14c616a60a8cc512cf167cfe3c485 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 22 Jan 2023 20:11:03 -0500 Subject: [PATCH] Port biome palette and chunk section optimizations from Hydrogen --- .../core/config/ModernFixEarlyConfig.java | 2 + .../MixinBiomeContainer.java | 148 ++++++++++++++++++ .../nuke_empty_chunk_sections/MixinChunk.java | 38 +++++ src/main/resources/modernfix.mixins.json | 4 +- 4 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/nuke_empty_chunk_sections/MixinChunk.java diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index dc794b9d..2b6c451c 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -33,6 +33,8 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.sync_executor_sleep", true); this.addMixinRule("perf.scan_cache", true); this.addMixinRule("perf.parallel_blockstate_cache_rebuild", true); + this.addMixinRule("perf.compress_biome_container", true); + this.addMixinRule("perf.nuke_empty_chunk_sections", true); this.addMixinRule("perf.deduplicate_location", true); this.addMixinRule("safety", true); this.addMixinRule("launch.transformer_cache", false); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java new file mode 100644 index 00000000..af58cf0d --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_biome_container/MixinBiomeContainer.java @@ -0,0 +1,148 @@ +package org.embeddedt.modernfix.mixin.perf.compress_biome_container; + +import it.unimi.dsi.fastutil.objects.Reference2ShortMap; +import it.unimi.dsi.fastutil.objects.Reference2ShortOpenHashMap; +import net.minecraft.util.BitArray; +import net.minecraft.util.IObjectIntIterable; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.biome.provider.BiomeProvider; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BiomeContainer.class) +public class MixinBiomeContainer { + @Mutable + @Shadow + @Final + private Biome[] biomes; + + @Shadow + @Final + private IObjectIntIterable biomeRegistry; + + @Shadow + @Final + private static int WIDTH_BITS; + + private Biome[] palette; + private BitArray intArray; + + @Inject(method = "(Lnet/minecraft/util/IObjectIntIterable;[I)V", at = @At("RETURN")) + private void reinit1(IObjectIntIterable p_i241970_1_, int[] p_i241970_2_, CallbackInfo ci) { + this.createCompact(); + } + + @Inject(method = "(Lnet/minecraft/util/IObjectIntIterable;[Lnet/minecraft/world/biome/Biome;)V", at = @At("RETURN")) + private void reinit2(IObjectIntIterable p_i241971_1_, Biome[] p_i241971_2_, CallbackInfo ci) { + this.createCompact(); + } + + @Inject(method = "(Lnet/minecraft/util/IObjectIntIterable;Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/biome/provider/BiomeProvider;)V", at = @At("RETURN")) + private void reinit3(IObjectIntIterable p_i241968_1_, ChunkPos p_i241968_2_, BiomeProvider p_i241968_3_, CallbackInfo ci) { + this.createCompact(); + } + + @Inject(method = "(Lnet/minecraft/util/IObjectIntIterable;Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/biome/provider/BiomeProvider;[I)V", at = @At("RETURN")) + private void reinit4(IObjectIntIterable p_i241969_1_, ChunkPos p_i241969_2_, BiomeProvider p_i241969_3_, int[] p_i241969_4_, CallbackInfo ci) { + this.createCompact(); + } + + private void createCompact() { + if (this.intArray != null || this.biomes[0] == null) { + return; + } + + Reference2ShortOpenHashMap paletteTable = this.createPalette(); + Biome[] paletteIndexed = new Biome[paletteTable.size()]; + + for (Reference2ShortMap.Entry entry : paletteTable.reference2ShortEntrySet()) { + paletteIndexed[entry.getShortValue()] = entry.getKey(); + } + + int packedIntSize = Math.max(2, MathHelper.ceillog2(paletteTable.size())); + BitArray integerArray = new BitArray(packedIntSize, BiomeContainer.BIOMES_SIZE); + + Biome prevBiome = null; + short prevId = -1; + + for (int i = 0; i < this.biomes.length; i++) { + Biome biome = this.biomes[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.biomes = null; + } + + private Reference2ShortOpenHashMap createPalette() { + Reference2ShortOpenHashMap map = new Reference2ShortOpenHashMap<>(); + map.defaultReturnValue(Short.MIN_VALUE); + + Biome prevObj = null; + short id = 0; + + for (Biome obj : this.biomes) { + if (obj == prevObj) { + continue; + } + + if (map.getShort(obj) < 0) { + map.put(obj, id++); + } + + prevObj = obj; + } + + return map; + } + + /** + * @author JellySquid + * @reason Use paletted lookup + */ + @Overwrite + public int[] writeBiomes() { + int size = this.intArray.getSize(); + int[] array = new int[size]; + + for(int i = 0; i < size; ++i) { + array[i] = this.biomeRegistry.getId(this.palette[this.intArray.get(i)]); + } + + return array; + } + + /** + * @author JellySquid + * @reason Use paletted lookup + */ + @Overwrite + public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) { + int x = biomeX & BiomeContainer.HORIZONTAL_MASK; + int y = MathHelper.clamp(biomeY, 0, BiomeContainer.VERTICAL_MASK); + int z = biomeZ & BiomeContainer.HORIZONTAL_MASK; + + return this.palette[this.intArray.get(y << WIDTH_BITS + WIDTH_BITS | z << WIDTH_BITS | x)]; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/nuke_empty_chunk_sections/MixinChunk.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/nuke_empty_chunk_sections/MixinChunk.java new file mode 100644 index 00000000..e2e389db --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/nuke_empty_chunk_sections/MixinChunk.java @@ -0,0 +1,38 @@ +package org.embeddedt.modernfix.mixin.perf.nuke_empty_chunk_sections; + +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.palette.UpgradeData; +import net.minecraft.world.ITickList; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkSection; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.function.Consumer; + +@Mixin(Chunk.class) +public class MixinChunk { + @Shadow @Final private ChunkSection[] sections; + + @Inject(method = "(Lnet/minecraft/world/World;" + + "Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/biome/BiomeContainer;" + + "Lnet/minecraft/util/palette/UpgradeData;Lnet/minecraft/world/ITickList;" + + "Lnet/minecraft/world/ITickList;J[Lnet/minecraft/world/chunk/ChunkSection;Ljava/util/function/Consumer;)V", + at = @At("RETURN")) + private void reinit(World world, ChunkPos pos, BiomeContainer container, UpgradeData data, + ITickList list1, ITickList list2, long inhabited, + ChunkSection[] oldSections, Consumer consumer, CallbackInfo ci) { + /* taken from Hydrogen */ + for(int i = 0; i < this.sections.length; i++) { + if(ChunkSection.isEmpty(this.sections[i])) { + this.sections[i] = null; + } + } + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index f1b0a649..7beab9d1 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -23,7 +23,9 @@ "perf.parallel_blockstate_cache_rebuild.BlockCallbacksMixin", "perf.parallel_blockstate_cache_rebuild.ShapeCacheMixin", "perf.deduplicate_location.MixinResourceLocation", - "perf.sync_executor_sleep.SyncExecutorMixin" + "perf.sync_executor_sleep.SyncExecutorMixin", + "perf.compress_biome_container.MixinBiomeContainer", + "perf.nuke_empty_chunk_sections.MixinChunk" ], "client": [ "perf.skip_first_datapack_reload.MinecraftMixin",