Forráskód Böngészése

Add hack to make the standard getValues fast-ish again
Get rid of JS coremod

malte0811 4 éve
szülő
commit
fa16fbe448

+ 51 - 0
common/src/main/java/com/google/common/collect/FerriteCoreEntrySet.java

@@ -0,0 +1,51 @@
+package com.google.common.collect;
+
+import net.minecraft.world.level.block.state.properties.Property;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+
+public class FerriteCoreEntrySet<K, V> extends ImmutableSet<Map.Entry<K, V>> {
+    //TODO tie together properly
+    private final int numProperties;
+    private final Function<Object, V> getValue;
+    private final IntFunction<Map.Entry<K, V>> getIth;
+
+    public FerriteCoreEntrySet(int numProperties, Function<Object, V> getValue, IntFunction<Map.Entry<K, V>> getIth) {
+        this.numProperties = numProperties;
+        this.getValue = getValue;
+        this.getIth = getIth;
+    }
+
+    @Override
+    @NotNull
+    public UnmodifiableIterator<Map.Entry<K, V>> iterator() {
+        return new FerriteCoreIterator<>(getIth, size());
+    }
+
+    @Override
+    public int size() {
+        return numProperties;
+    }
+
+    @Override
+    public boolean contains(@Nullable Object object) {
+        if (!(object instanceof Map.Entry)) {
+            return false;
+        }
+        Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
+        if (!(entry.getKey() instanceof Property<?>)) {
+            return false;
+        }
+        Object valueInMap = getValue.apply(entry.getKey());
+        return valueInMap != null && valueInMap.equals(((Map.Entry<?, ?>) object).getValue());
+    }
+
+    @Override
+    boolean isPartialView() {
+        return false;
+    }
+}

+ 41 - 0
common/src/main/java/com/google/common/collect/FerriteCoreImmutableMap.java

@@ -0,0 +1,41 @@
+package com.google.common.collect;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+
+public class FerriteCoreImmutableMap<K, V> extends ImmutableMap<K, V> {
+    //TODO tie together properly
+    // This is a quite inconvenient "handle" on a FastMap, but we need classloader separation
+    private final int numProperties;
+    private final Function<Object, V> getValue;
+    private final IntFunction<Entry<K, V>> getIth;
+
+    public FerriteCoreImmutableMap(int numProperties, Function<Object, V> getValue, IntFunction<Entry<K, V>> getIth) {
+        this.numProperties = numProperties;
+        this.getValue = getValue;
+        this.getIth = getIth;
+    }
+
+    @Override
+    public int size() {
+        return numProperties;
+    }
+
+    @Override
+    public V get(@Nullable Object key) {
+        return getValue.apply(key);
+    }
+
+    @Override
+    ImmutableSet<Map.Entry<K, V>> createEntrySet() {
+        return new FerriteCoreEntrySet<>(numProperties, getValue, getIth);
+    }
+
+    @Override
+    boolean isPartialView() {
+        return false;
+    }
+}

+ 29 - 0
common/src/main/java/com/google/common/collect/FerriteCoreIterator.java

@@ -0,0 +1,29 @@
+package com.google.common.collect;
+
+import java.util.Map;
+import java.util.function.IntFunction;
+
+public class FerriteCoreIterator<K, V> extends UnmodifiableIterator<Map.Entry<K, V>> {
+    //TODO tie together properly
+    private final IntFunction<Map.Entry<K, V>> getIth;
+    private final int length;
+
+    private int currentIndex;
+
+    public FerriteCoreIterator(IntFunction<Map.Entry<K, V>> getIth, int length) {
+        this.getIth = getIth;
+        this.length = length;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return currentIndex < length;
+    }
+
+    @Override
+    public Map.Entry<K, V> next() {
+        Map.Entry<K, V> next = getIth.apply(currentIndex);
+        ++currentIndex;
+        return next;
+    }
+}

+ 50 - 0
common/src/main/java/malte0811/ferritecore/classloading/ClassDefiner.java

@@ -0,0 +1,50 @@
+package malte0811.ferritecore.classloading;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import net.minecraft.util.LazyLoadedValue;
+
+import java.io.InputStream;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+
+public class ClassDefiner {
+    private static final LazyLoadedValue<MethodHandle> MAKE_IMMUTABLE_FAST_MAP = new LazyLoadedValue<>(() -> {
+        try {
+            define("com.google.common.collect.FerriteCoreIterator");
+            define("com.google.common.collect.FerriteCoreEntrySet");
+            Class<?> map = define("com.google.common.collect.FerriteCoreImmutableMap");
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+            //int numProperties, Function<Object, V> getValue, IntFunction<Entry<K, V>> getIth
+            return lookup.findConstructor(map, MethodType.methodType(
+                    void.class, int.class, Function.class, IntFunction.class
+            ));
+        } catch (Exception x) {
+            throw new RuntimeException(x);
+        }
+    });
+
+    public static <K, V> ImmutableMap<K, V> makeMap(
+            int numProperties, Function<Object, V> getValue, IntFunction<Map.Entry<K, V>> getIth
+    ) throws Throwable {
+        return (ImmutableMap<K, V>) MAKE_IMMUTABLE_FAST_MAP.get().invoke(numProperties, getValue, getIth);
+    }
+
+    private static Class<?> define(String name) throws Exception {
+        ClassLoader loaderToUse = ImmutableMap.class.getClassLoader();
+        InputStream byteInput = ClassDefiner.class.getResourceAsStream('/' + name.replace('.', '/') + ".class");
+        byte[] classBytes = new byte[byteInput.available()];
+        final int bytesRead = byteInput.read(classBytes);
+        Preconditions.checkState(bytesRead == classBytes.length);
+        Method defineClass = ClassLoader.class.getDeclaredMethod(
+                "defineClass", String.class, byte[].class, int.class, int.class
+        );
+        defineClass.setAccessible(true);
+        return (Class<?>) defineClass.invoke(loaderToUse, name, classBytes, 0, classBytes.length);
+    }
+}

+ 25 - 4
common/src/main/java/malte0811/ferritecore/fastmap/FastMap.java

@@ -2,10 +2,13 @@ package malte0811.ferritecore.fastmap;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import malte0811.ferritecore.classloading.ClassDefiner;
 import net.minecraft.world.level.block.state.properties.Property;
 
 import javax.annotation.Nullable;
 import java.util.*;
+import java.util.function.Function;
+import java.util.function.IntFunction;
 
 public class FastMap<Value> {
     private final List<FastMapKey<?>> keys;
@@ -76,11 +79,29 @@ public class FastMap<Value> {
     }
 
     public ImmutableMap<Property<?>, Comparable<?>> makeValuesFor(int index) {
-        ImmutableMap.Builder<Property<?>, Comparable<?>> result = ImmutableMap.builder();
-        for (Property<?> p : getProperties()) {
-            result.put(p, Objects.requireNonNull(getValue(index, p)));
+        try {
+            class MapAccessor implements Function<Object, Comparable<?>>, IntFunction<Map.Entry<Property<?>, Comparable<?>>> {
+                @Override
+                public Comparable<?> apply(Object obj) {
+                    if (obj instanceof Property<?>) {
+                        return getValue(index, (Property<?>) obj);
+                    } else {
+                        return null;
+                    }
+                }
+
+                @Override
+                public Map.Entry<Property<?>, Comparable<?>> apply(int subIndex) {
+                    return new AbstractMap.SimpleImmutableEntry<>(
+                            getKey(subIndex).getProperty(), getKey(subIndex).getValue(index)
+                    );
+                }
+            }
+            MapAccessor func = new MapAccessor();
+            return ClassDefiner.makeMap(numProperties(), func, func);
+        } catch (Throwable throwable) {
+            throw new RuntimeException(throwable);
         }
-        return result.build();
     }
 
     public <T extends Comparable<T>>

+ 3 - 7
common/src/main/java/malte0811/ferritecore/mixin/nopropertymap/Config.java

@@ -9,20 +9,16 @@ import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
 import java.util.List;
 
 public class Config extends FerriteMixinConfig {
-    private static final String DUMMY_MIXIN = "DummyFerriteValuesMixin";
-
     @Override
     protected List<String> getAllMixins() {
-        return ImmutableList.of("NoPropertyStateHolderMixin", DUMMY_MIXIN);
+        return ImmutableList.of("NoPropertyStateHolderMixin");
     }
 
     @Override
     protected boolean isEnabled(String mixin) {
-        return FerriteConfig.PROPERTY_MAP.isEnabled() != DUMMY_MIXIN.equals(mixin);
+        return FerriteConfig.PROPERTY_MAP.isEnabled();
     }
 
     @Override
-    public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
-        //TODO replace JS coremod with this?
-    }
+    public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {}
 }

+ 0 - 24
common/src/main/java/malte0811/ferritecore/mixin/nopropertymap/DummyFerriteValuesMixin.java

@@ -1,24 +0,0 @@
-package malte0811.ferritecore.mixin.nopropertymap;
-
-import com.google.common.collect.ImmutableMap;
-import net.minecraft.world.level.block.state.StateHolder;
-import net.minecraft.world.level.block.state.properties.Property;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-
-import java.util.Map;
-
-/**
- * Mostly useless. It's not possible to add config options for JS coremods, so I need to supply getValues_Ferrite even
- * if the nopropertymap code is disabled
- */
-@Mixin(StateHolder.class)
-public abstract class DummyFerriteValuesMixin {
-    @Shadow
-    public abstract ImmutableMap<Property<?>, Comparable<?>> getValues();
-
-    // Used by JS coremod
-    public Map<Property<?>, Comparable<?>> getValues_Ferrite() {
-        return getValues();
-    }
-}

+ 0 - 13
common/src/main/java/malte0811/ferritecore/mixin/nopropertymap/NoPropertyStateHolderMixin.java

@@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableMap;
 import malte0811.ferritecore.ducks.FastMapStateHolder;
 import malte0811.ferritecore.ducks.NoPropertyStateHolder;
 import malte0811.ferritecore.fastmap.FastMap;
-import malte0811.ferritecore.fastmap.FastSubMap;
 import net.minecraft.world.level.block.state.StateHolder;
 import net.minecraft.world.level.block.state.properties.Property;
 import org.spongepowered.asm.mixin.Mixin;
@@ -16,7 +15,6 @@ import org.spongepowered.asm.mixin.injection.Redirect;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
 import java.util.Collection;
-import java.util.Map;
 
 @Mixin(StateHolder.class)
 public abstract class NoPropertyStateHolderMixin implements NoPropertyStateHolder {
@@ -75,15 +73,4 @@ public abstract class NoPropertyStateHolderMixin implements NoPropertyStateHolde
             cir.cancel();
         }
     }
-
-    // Used by JS coremod
-    public Map<Property<?>, Comparable<?>> getValues_Ferrite() {
-        final FastMap<?> globalTable = ((FastMapStateHolder<?>) this).getStateMap();
-        if (globalTable != null) {
-            final int globalIndex = ((FastMapStateHolder<?>) this).getStateIndex();
-            return new FastSubMap(globalTable, globalIndex);
-        } else {
-            return getValues();
-        }
-    }
 }

+ 0 - 3
common/src/main/resources/META-INF/coremods.json

@@ -1,3 +0,0 @@
-{
-  "ImmutableMap to plain map": "asm/immutable_to_plain_map.js"
-}

+ 0 - 88
common/src/main/resources/asm/immutable_to_plain_map.js

@@ -1,88 +0,0 @@
-var StateHolderDot = 'net.minecraft.state.StateHolder';
-var StateHolderSlash = StateHolderDot.replaceAll("\\.", "/");
-var ImmutableMap = "com/google/common/collect/ImmutableMap";
-var MapName = "java/util/Map";
-
-//TODO make this not fail when fast is disabled. Maybe using a replacement mixin?
-function getReplacement(type) {
-    if (ImmutableMap.equals(type)) {
-        return MapName;
-    } else if ("com/google/common/collect/ImmutableSet".equals(type)) {
-        return "java/util/Set";
-    } else if ("com/google/common/collect/UnmodifiableIterator".equals(type)) {
-        return "java/util/Iterator";
-    } else {
-        return type;
-    }
-}
-
-function isGetValuesOwner(type) {
-    return type.equals(StateHolderSlash) ||
-        type.equals("net/minecraft/block/AbstractBlock/AbstractBlockState") ||
-        type.equals("net/minecraft/block/BlockState") ||
-        type.equals("net/minecraft/fluid/FluidState");
-}
-
-function replaceImmutableMapWithMap(method) {
-    var Opcodes = Java.type('org.objectweb.asm.Opcodes');
-    var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI');
-    var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode');
-    var replaceTarget = ASMAPI.mapMethod("func_206871_b");
-    for (var i = 0; i < method.instructions.size(); ++i) {
-        var node = method.instructions.get(i);
-        if (node.getOpcode() === Opcodes.INVOKEVIRTUAL) {
-            if (
-                isGetValuesOwner(node.owner) &&
-                node.name.equals(replaceTarget) &&
-                node.desc.equals("()L" + ImmutableMap + ";")
-            ) {
-                node.name = "getValues_Ferrite";
-                node.desc = "()L" + MapName + ";";
-            } else {
-                var newOwner = getReplacement(node.owner);
-                if (newOwner !== node.owner) {
-                    node.owner = newOwner;
-                    var splitPoint = node.desc.indexOf(")") + 1;
-                    var args = node.desc.substring(0, splitPoint);
-                    var result = node.desc.substring(splitPoint);
-                    if (result.charAt(0) === 'L') {
-                        var returnTypeOriginal = result.substring(1, result.length - 1);
-                        node.desc = args + "L" + getReplacement(returnTypeOriginal) + ";";
-                    }
-                    method.instructions.set(node, new MethodInsnNode(
-                        Opcodes.INVOKEINTERFACE, node.owner, node.name, node.desc
-                    ));
-                }
-            }
-        }
-    }
-    return method;
-}
-
-function addCoremodFor(owner, method, desc, list) {
-    var targetDesc = owner.substring(owner.lastIndexOf(".") + 1) + "::" + method;
-    list['Replace StateHolder::getValues in ' + targetDesc] = {
-        'target': {
-            'type': 'METHOD',
-            'class': owner,
-            'methodName': method,
-            'methodDesc': desc
-        },
-        'transformer': replaceImmutableMapWithMap
-    };
-}
-
-function initializeCoreMod() {
-    var coremods = {};
-    addCoremodFor(StateHolderDot, 'toString', '()Ljava/lang/String;', coremods);
-    addCoremodFor(
-        "net.minecraft.client.gui.overlay.DebugOverlayGui", 'func_175238_c', '()Ljava/util/List;', coremods
-    );
-    addCoremodFor(
-        "net.minecraft.client.renderer.BlockModelShapes",
-        "func_209553_a",
-        "(Lnet/minecraft/util/ResourceLocation;Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/renderer/model/ModelResourceLocation;",
-        coremods
-    );
-    return coremods;
-}