diff --git a/common/src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java b/common/src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java index ff7cc745..7cc8f22c 100644 --- a/common/src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java +++ b/common/src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix.blockstate; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.world.level.block.state.properties.Property; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,6 +15,7 @@ import java.util.*; */ public class FakeStateMap implements Map, Comparable>, S> { private final Map, Comparable>[] keys; + private Map, Comparable>, S> fastLookup; private final Object[] values; private int usedSlots; public FakeStateMap(int numStates) { @@ -34,22 +36,39 @@ public class FakeStateMap implements Map, Comparable>, S> @Override public boolean containsKey(Object o) { - throw new UnsupportedOperationException(); + return getFastLookup().containsKey(o); } @Override public boolean containsValue(Object o) { - throw new UnsupportedOperationException(); + return getFastLookup().containsValue(o); + } + + @SuppressWarnings("unchecked") + private Map, Comparable>, S> getFastLookup() { + if(fastLookup == null) { + var map = new Object2ObjectOpenHashMap, Comparable>, S>(usedSlots); + Map, Comparable>[] keys = this.keys; + Object[] values = this.values; + for(int i = 0; i < usedSlots; i++) { + map.put(keys[i], (S)values[i]); + } + fastLookup = map; + } + return fastLookup; } @Override public S get(Object o) { - throw new UnsupportedOperationException(); + return getFastLookup().get(o); } @Nullable @Override public S put(Map, Comparable> propertyComparableMap, S s) { + if(fastLookup != null) { + throw new IllegalStateException("Cannot populate map after fast lookup is built"); + } keys[usedSlots] = propertyComparableMap; values[usedSlots] = s; usedSlots++; @@ -70,7 +89,7 @@ public class FakeStateMap implements Map, Comparable>, S> @Override public void clear() { - for(int i = 0; i < this.keys.length; i++) { + for(int i = 0; i < usedSlots; i++) { this.keys[i] = null; this.values[i] = null; } diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/state_definition_construct/StateDefinitionMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/state_definition_construct/StateDefinitionMixin.java index 70210f7b..b24ed70d 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/state_definition_construct/StateDefinitionMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/state_definition_construct/StateDefinitionMixin.java @@ -6,23 +6,25 @@ import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.block.state.properties.Property; import org.embeddedt.modernfix.annotation.RequiresMod; import org.embeddedt.modernfix.blockstate.FakeStateMap; -import org.embeddedt.modernfix.blockstate.FerriteCorePostProcess; -import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; 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.ModifyVariable; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.Map; +// This optimization requires FerriteCore to be worthwhile, otherwise the FakeStateMap degrades to hash internally @Mixin(StateDefinition.class) @RequiresMod("ferritecore") public class StateDefinitionMixin> { @Shadow @Final private ImmutableSortedMap> propertiesByName; + /** + * @author embeddedt + * @reason write states into a custom array map for fast iteration by FerriteCore, no need to waste time hashing + * and growing + */ @ModifyVariable(method = "", at = @At(value = "STORE", ordinal = 0), ordinal = 1, index = 8) private Map, Comparable>, S> useArrayMap(Map, Comparable>, S> in) { int numStates = 1; @@ -31,11 +33,4 @@ public class StateDefinitionMixin> { } return new FakeStateMap<>(numStates); } - - @Inject(method = "", at = @At("TAIL")) - private void postProcess(CallbackInfo ci) { - // keep in dev only until upstream FC releases - if(ModernFixPlatformHooks.INSTANCE.isDevEnv()) - FerriteCorePostProcess.postProcess((StateDefinition)(Object)this); - } }