From 15703cbcefaf37ed7df112074540a7829a3134d4 Mon Sep 17 00:00:00 2001 From: Taiyou06 Date: Sat, 6 Jul 2024 21:34:19 +0300 Subject: [PATCH] improve blockstate lookups --- .../collections/Object2BooleanCacheTable.java | 74 +++++++++++++++++++ .../BlockNeighborGroupMixin.java | 64 ++++++++++++++++ .../shapes/blockstate_cache/BlockMixin.java | 40 ++++++++++ src/main/resources/mixins.core.json | 4 +- 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/gensokyoreimagined/nitori/common/util/collections/Object2BooleanCacheTable.java create mode 100644 src/main/java/net/gensokyoreimagined/nitori/mixin/cached_hashcode/BlockNeighborGroupMixin.java create mode 100644 src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/blockstate_cache/BlockMixin.java diff --git a/src/main/java/net/gensokyoreimagined/nitori/common/util/collections/Object2BooleanCacheTable.java b/src/main/java/net/gensokyoreimagined/nitori/common/util/collections/Object2BooleanCacheTable.java new file mode 100644 index 0000000..2026baf --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/common/util/collections/Object2BooleanCacheTable.java @@ -0,0 +1,74 @@ +// Nitori Copyright (C) 2024 Gensokyo Reimagined +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package net.gensokyoreimagined.nitori.common.util.collections; + +import it.unimi.dsi.fastutil.HashCommon; +import net.minecraft.util.Mth; + +import java.util.function.Predicate; + +/** + * A lossy hashtable implementation that stores a mapping between an object and a boolean. + *

+ * Any hash collisions will result in an overwrite: this is safe because the correct value can always be recomputed, + * given that the given operator is deterministic. + *

+ * This implementation is safe to use from multiple threads + */ +public final class Object2BooleanCacheTable { + private final int mask; + + private final Node[] nodes; + + private final Predicate operator; + + @SuppressWarnings("unchecked") + public Object2BooleanCacheTable(int capacity, Predicate operator) { + int capacity1 = Mth.smallestEncompassingPowerOfTwo(capacity); + this.mask = capacity1 - 1; + + this.nodes = (Node[]) new Node[capacity1]; + + this.operator = operator; + } + + private static int hash(T key) { + return HashCommon.mix(key.hashCode()); + } + + public boolean get(T key) { + int idx = hash(key) & this.mask; + + Node node = this.nodes[idx]; + if (node != null && key.equals(node.key)) { + return node.value; + } + + boolean test = this.operator.test(key); + this.nodes[idx] = new Node<>(key, test); + + return test; + } + + static class Node { + final T key; + final boolean value; + + Node(T key, boolean value) { + this.key = key; + this.value = value; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/cached_hashcode/BlockNeighborGroupMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/cached_hashcode/BlockNeighborGroupMixin.java new file mode 100644 index 0000000..a422960 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/cached_hashcode/BlockNeighborGroupMixin.java @@ -0,0 +1,64 @@ +// Nitori Copyright (C) 2024 Gensokyo Reimagined +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package net.gensokyoreimagined.nitori.mixin.cached_hashcode; + +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +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; + +@Mixin(Block.BlockStatePairKey.class) +public class BlockNeighborGroupMixin { + @Shadow + @Final + private BlockState first; + + @Shadow + @Final + private BlockState second; + + @Shadow + @Final + private Direction direction; + + private int hash; + + /** + * @reason Initialize the object's hashcode and cache it + */ + @Inject(method = "", at = @At("RETURN")) + private void generateHash(BlockState blockState_1, BlockState blockState_2, Direction direction_1, CallbackInfo ci) { + int hash = this.first.hashCode(); + hash = 31 * hash + this.second.hashCode(); + hash = 31 * hash + this.direction.hashCode(); + + this.hash = hash; + } + + /** + * @reason Uses the cached hashcode + * @author JellySquid + */ + @Overwrite(remap = false) + public int hashCode() { + return this.hash; + } +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/blockstate_cache/BlockMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/blockstate_cache/BlockMixin.java new file mode 100644 index 0000000..57c0d01 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/blockstate_cache/BlockMixin.java @@ -0,0 +1,40 @@ +// Nitori Copyright (C) 2024 Gensokyo Reimagined +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +package net.gensokyoreimagined.nitori.mixin.shapes.blockstate_cache; + +import net.gensokyoreimagined.nitori.common.util.collections.Object2BooleanCacheTable; +import net.minecraft.world.phys.shapes.BooleanOp; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.level.block.Block; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(Block.class) +public class BlockMixin { + private static final Object2BooleanCacheTable FULL_CUBE_CACHE = new Object2BooleanCacheTable<>( + 512, + shape -> !Shapes.joinIsNotEmpty(Shapes.block(), shape, BooleanOp.NOT_SAME) + ); + + /** + * @reason Use a faster cache implementation + * @author gegy1000 + */ + @Overwrite + public static boolean isShapeFullBlock(VoxelShape shape) { + return FULL_CUBE_CACHE.get(shape); + } +} \ No newline at end of file diff --git a/src/main/resources/mixins.core.json b/src/main/resources/mixins.core.json index 35130c6..c89a3af 100755 --- a/src/main/resources/mixins.core.json +++ b/src/main/resources/mixins.core.json @@ -32,6 +32,8 @@ "MixinWorldGenRegion", "alloc.ServerChunkManagerMixin", "alloc.StateMixin", - "util.MixinLevelBlockEntityRetrieval" + "util.MixinLevelBlockEntityRetrieval", + "cached_hashcode.BlockNeighborGroupMixin", + "shapes.blockstate_cache.BlockMixin" ] }