From 0a68a6923a5f28a97fbc59cbbac1bb8ec87a370f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:02:46 -0500 Subject: [PATCH] Reimplement deduplicate_wall_shapes --- TODO.txt | 1 - .../WallBlockMixin.java | 54 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/embeddedt/modernfix/common/mixin/perf/deduplicate_wall_shapes/WallBlockMixin.java diff --git a/TODO.txt b/TODO.txt index 93057ed1..4807259e 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,4 +4,3 @@ - Check if BlockStateData patch is still needed in compact_mojang_registries - Check if faster_texture_stitching is still worthwhile with 21.x changes to the stitcher - Sculk deadlock fix looks unnecessary since Mojang is careful about when they send the event -- Rewrite deduplicate_wall_shapes diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/deduplicate_wall_shapes/WallBlockMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/deduplicate_wall_shapes/WallBlockMixin.java new file mode 100644 index 00000000..14ecba4c --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/deduplicate_wall_shapes/WallBlockMixin.java @@ -0,0 +1,54 @@ +package org.embeddedt.modernfix.common.mixin.perf.deduplicate_wall_shapes; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.datafixers.util.Pair; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.WallBlock; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.joml.Vector3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author embeddedt + * @reason Avoid excessive memory usage in modpacks that add many variations of wall blocks. The strategy here requires + * multiple memoization maps, but is also the simplest way to do it without having to literally replicate the vanilla + * logic (as that uses blockstates rather than property maps). + */ +@Mixin(WallBlock.class) +public class WallBlockMixin { + @Unique + private static final ConcurrentHashMap COLUMN_CACHE = new ConcurrentHashMap<>(); + @Unique + private static final ConcurrentHashMap, VoxelShape> BOX_Z_CACHE = new ConcurrentHashMap<>(); + @Unique + private static final ConcurrentHashMap> ROTATE_HORZ_CACHE = new ConcurrentHashMap<>(); + @Unique + private static final ConcurrentHashMap, VoxelShape> OR_CACHE = new ConcurrentHashMap<>(); + + @WrapOperation(method = "makeShapes", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Block;column(DDD)Lnet/minecraft/world/phys/shapes/VoxelShape;")) + private VoxelShape memoizeColumn(double sizeXZ, double minY, double postHeight, Operation original) { + return COLUMN_CACHE.computeIfAbsent(new Vector3d(sizeXZ, minY, postHeight), l -> original.call(sizeXZ, minY, postHeight)); + } + + @WrapOperation(method = "makeShapes", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Block;boxZ(DDDDD)Lnet/minecraft/world/phys/shapes/VoxelShape;")) + private VoxelShape memoizeBoxZ(double sizeX, double minY, double maxY, double minZ, double maxZ, Operation original) { + return BOX_Z_CACHE.computeIfAbsent(List.of(sizeX, minY, maxY, minZ, maxZ), l -> original.call(sizeX, minY, maxY, minZ, maxZ)); + } + + @WrapOperation(method = "makeShapes", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/shapes/Shapes;rotateHorizontal(Lnet/minecraft/world/phys/shapes/VoxelShape;)Ljava/util/Map;")) + private Map memoizeRotateHorizontal(VoxelShape north, Operation> original) { + return ROTATE_HORZ_CACHE.computeIfAbsent(north, l -> original.call(north)); + } + + @WrapOperation(method = "lambda$makeShapes$0", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/shapes/Shapes;or(Lnet/minecraft/world/phys/shapes/VoxelShape;Lnet/minecraft/world/phys/shapes/VoxelShape;)Lnet/minecraft/world/phys/shapes/VoxelShape;")) + private static VoxelShape memoizeOr(VoxelShape one, VoxelShape two, Operation original) { + return OR_CACHE.computeIfAbsent(Pair.of(one, two), l -> original.call(one, two)); + } +}