Ver Fonte

Better config options, add JS coremod to replace calls to StateHolder#getValues with calls to getValues_Ferrite

malte0811 há 4 anos atrás
pai
commit
6f8939199b

+ 15 - 4
build.gradle

@@ -1,3 +1,5 @@
+import java.util.stream.Collectors
+
 buildscript {
     repositories {
         maven { url = 'https://files.minecraftforge.net/maven' }
@@ -20,6 +22,16 @@ version = "${mod_version}"
 group = "malte0811.${modid}" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
 archivesBaseName = "${modid}"
 
+def mixinConfigs = ["predicates", "fastmap", "nopropertymap"].stream()
+        .map({s -> archivesBaseName+"."+s+".mixin.json"})
+        .collect(Collectors.toList())
+
+def mixinConfigArg = mixinConfigs.stream()
+    .map({s -> "-mixin.config="+s})
+        .collect(Collectors.toList())
+
+def mixinConfigManifestEntry = mixinConfigs.join(",");
+
 sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
 
 minecraft {
@@ -38,7 +50,7 @@ minecraft {
     runs {
         client {
             workingDirectory project.file('run')
-            arg "-mixin.config="+archivesBaseName+".mixins.json"
+            args mixinConfigArg
             property 'mixin.env.disableRefMap', 'true'
             property 'mixin.debug.export', 'true'
 
@@ -55,7 +67,7 @@ minecraft {
 
         server {
             workingDirectory project.file('run')
-            arg "-mixin.config="+archivesBaseName+".mixins.json"
+            args mixinConfigArg
             arg "-nogui"
             property 'mixin.env.disableRefMap', 'true'
 
@@ -99,7 +111,6 @@ repositories{
 
 dependencies {
     minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
-    compile fg.deobf("blusunrize.immersiveengineering:ImmersiveEngineering:1.16.3-+")
     runtimeOnly fg.deobf("mezz.jei:jei-1.16.3:7.6.0.49")
 }
 
@@ -112,7 +123,7 @@ jar {
                 "Implementation-Title": project.name,
                 "Implementation-Version": "${version}",
                 "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
-                "MixinConfigs": "${modid}.mixins.json"
+                "MixinConfigs": mixinConfigManifestEntry
         ])
     }
 }

+ 49 - 0
src/main/java/malte0811/ferritecore/FastMapEntry.java

@@ -0,0 +1,49 @@
+package malte0811.ferritecore;
+
+import net.minecraft.state.Property;
+import org.apache.commons.lang3.tuple.Pair;
+
+import javax.annotation.Nonnull;
+import java.util.*;
+
+public class FastMapEntry extends AbstractMap<Property<?>, Comparable<?>> {
+    private final FastMap<?> baseMap;
+    private final int indexInBaseMap;
+
+    public FastMapEntry(FastMap<?> baseMap, int indexInBaseMap) {
+        this.baseMap = baseMap;
+        this.indexInBaseMap = indexInBaseMap;
+    }
+
+    @Nonnull
+    @Override
+    public Set<Entry<Property<?>, Comparable<?>>> entrySet() {
+        return new EntrySet();
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<Property<?>, Comparable<?>>> {
+
+        @Nonnull
+        @Override
+        public Iterator<Entry<Property<?>, Comparable<?>>> iterator() {
+            Iterator<Property<?>> baseIterator = baseMap.getProperties().iterator();
+            return new Iterator<Entry<Property<?>, Comparable<?>>>() {
+                @Override
+                public boolean hasNext() {
+                    return baseIterator.hasNext();
+                }
+
+                @Override
+                public Entry<Property<?>, Comparable<?>> next() {
+                    Property<?> nextProp = baseIterator.next();
+                    return Pair.of(nextProp, baseMap.getValue(indexInBaseMap, nextProp));
+                }
+            };
+        }
+
+        @Override
+        public int size() {
+            return baseMap.getProperties().size();
+        }
+    }
+}

+ 17 - 22
src/main/java/malte0811/ferritecore/mixin/config/FerriteMixinConfig.java

@@ -10,39 +10,34 @@ import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
 import java.util.List;
 import java.util.Set;
 
-public class FerriteMixinConfig implements IMixinConfigPlugin {
-    private static final String MIXIN_PREFIX = "malte0811.ferritecore.mixin.";
+public abstract class FerriteMixinConfig implements IMixinConfigPlugin {
     private static final Logger LOGGER = LogManager.getLogger("ferritecore-mixin");
+    private String prefix = null;
+    private List<String> providedMixins;
 
     @Override
     public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
-        Preconditions.checkState(mixinClassName.startsWith(MIXIN_PREFIX), "Unexpected prefix on " + mixinClassName);
-        final String name = mixinClassName.substring(MIXIN_PREFIX.length());
-        boolean result;
-        switch (name) {
-            case "OrConditionMixin":
-            case "AndConditionMixin":
-            case "PropertyValueConditionMixin":
-                result = FerriteConfig.cachePredicates();
-                break;
-            case "FastMapStateHolderMixin":
-                result = FerriteConfig.replaceNeighborTable();
-                break;
-            case "NoPropertyStateHolderMixin":
-                result = FerriteConfig.noPropertyState();
-                break;
-            default:
-                throw new RuntimeException("Unknown mixin: " + name);
-        }
+        Preconditions.checkState(mixinClassName.startsWith(prefix), "Unexpected prefix on " + mixinClassName);
+        final String name = mixinClassName.substring(prefix.length());
+        Preconditions.checkState(
+                providedMixins.contains(name),
+                "Unexpected Mixin: " + name + " (" + mixinClassName + ")"
+        );
+        final boolean result = isEnabled(name);
         if (!result) {
-            LOGGER.info("Mixin {} is disabled due to config settings", mixinClassName);
+            LOGGER.debug("Mixin " + mixinClassName + " is disabled by config");
         }
         return result;
     }
 
+    protected abstract List<String> getAllMixins();
+
+    protected abstract boolean isEnabled(String mixin);
+
     @Override
     public void onLoad(String mixinPackage) {
-        Preconditions.checkState(MIXIN_PREFIX.equals(mixinPackage + "."));
+        prefix = mixinPackage + ".";
+        providedMixins = getAllMixins();
     }
 
     @Override

+ 19 - 0
src/main/java/malte0811/ferritecore/mixin/fastmap/Config.java

@@ -0,0 +1,19 @@
+package malte0811.ferritecore.mixin.fastmap;
+
+import com.google.common.collect.ImmutableList;
+import malte0811.ferritecore.mixin.config.FerriteConfig;
+import malte0811.ferritecore.mixin.config.FerriteMixinConfig;
+
+import java.util.List;
+
+public class Config extends FerriteMixinConfig {
+    @Override
+    protected List<String> getAllMixins() {
+        return ImmutableList.of("FastMapStateHolderMixin");
+    }
+
+    @Override
+    protected boolean isEnabled(String mixin) {
+        return FerriteConfig.replaceNeighborTable();
+    }
+}

+ 1 - 1
src/main/java/malte0811/ferritecore/mixin/FastMapStateHolderMixin.java → src/main/java/malte0811/ferritecore/mixin/fastmap/FastMapStateHolderMixin.java

@@ -1,4 +1,4 @@
-package malte0811.ferritecore.mixin;
+package malte0811.ferritecore.mixin.fastmap;
 
 import com.google.common.collect.ImmutableMap;
 import malte0811.ferritecore.FastMap;

+ 28 - 0
src/main/java/malte0811/ferritecore/mixin/nopropertymap/Config.java

@@ -0,0 +1,28 @@
+package malte0811.ferritecore.mixin.nopropertymap;
+
+import com.google.common.collect.ImmutableList;
+import malte0811.ferritecore.mixin.config.FerriteConfig;
+import malte0811.ferritecore.mixin.config.FerriteMixinConfig;
+import org.objectweb.asm.tree.ClassNode;
+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);
+    }
+
+    @Override
+    protected boolean isEnabled(String mixin) {
+        return FerriteConfig.noPropertyState() != DUMMY_MIXIN.equals(mixin);
+    }
+
+    @Override
+    public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
+        //TODO replace JS coremod with this?
+    }
+}

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

@@ -0,0 +1,24 @@
+package malte0811.ferritecore.mixin.nopropertymap;
+
+import com.google.common.collect.ImmutableMap;
+import net.minecraft.state.Property;
+import net.minecraft.state.StateHolder;
+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();
+    }
+}

+ 20 - 6
src/main/java/malte0811/ferritecore/mixin/NoPropertyStateHolderMixin.java → src/main/java/malte0811/ferritecore/mixin/nopropertymap/NoPropertyStateHolderMixin.java

@@ -1,7 +1,8 @@
-package malte0811.ferritecore.mixin;
+package malte0811.ferritecore.mixin.nopropertymap;
 
 import com.google.common.collect.ImmutableMap;
 import malte0811.ferritecore.FastMap;
+import malte0811.ferritecore.FastMapEntry;
 import malte0811.ferritecore.ducks.FastMapStateHolder;
 import malte0811.ferritecore.ducks.NoPropertyStateHolder;
 import net.minecraft.state.Property;
@@ -15,6 +16,7 @@ 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 {
@@ -24,11 +26,12 @@ public abstract class NoPropertyStateHolderMixin implements NoPropertyStateHolde
     // All other Mixins: If the new data structures are initialized, use those. Otherwise (if populateNeighbors didn't
     // run yet) use the vanilla code using `properties`
     @Redirect(
-            method = {"get", "func_235903_d_"}, at = @At(
-            value = "INVOKE",
-            target = "Lcom/google/common/collect/ImmutableMap;get(Ljava/lang/Object;)Ljava/lang/Object;",
-            remap = false
-    )
+            method = {"get", "func_235903_d_"},
+            at = @At(
+                    value = "INVOKE",
+                    target = "Lcom/google/common/collect/ImmutableMap;get(Ljava/lang/Object;)Ljava/lang/Object;",
+                    remap = false
+            )
     )
     @Coerce
     public Object getValueOfProperty(ImmutableMap<?, ?> vanillaMap, Object key) {
@@ -72,4 +75,15 @@ 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 FastMapEntry(globalTable, globalIndex);
+        } else {
+            return getValues();
+        }
+    }
 }

+ 1 - 1
src/main/java/malte0811/ferritecore/mixin/AndConditionMixin.java → src/main/java/malte0811/ferritecore/mixin/predicates/AndConditionMixin.java

@@ -1,4 +1,4 @@
-package malte0811.ferritecore.mixin;
+package malte0811.ferritecore.mixin.predicates;
 
 import malte0811.ferritecore.util.PredicateHelper;
 import net.minecraft.block.Block;

+ 19 - 0
src/main/java/malte0811/ferritecore/mixin/predicates/Config.java

@@ -0,0 +1,19 @@
+package malte0811.ferritecore.mixin.predicates;
+
+import com.google.common.collect.ImmutableList;
+import malte0811.ferritecore.mixin.config.FerriteConfig;
+import malte0811.ferritecore.mixin.config.FerriteMixinConfig;
+
+import java.util.List;
+
+public class Config extends FerriteMixinConfig {
+    @Override
+    protected List<String> getAllMixins() {
+        return ImmutableList.of("AndConditionMixin", "OrConditionMixin", "PropertyValueConditionMixin");
+    }
+
+    @Override
+    protected boolean isEnabled(String mixin) {
+        return FerriteConfig.cachePredicates();
+    }
+}

+ 1 - 9
src/main/java/malte0811/ferritecore/mixin/OrConditionMixin.java → src/main/java/malte0811/ferritecore/mixin/predicates/OrConditionMixin.java

@@ -1,10 +1,9 @@
-package malte0811.ferritecore.mixin;
+package malte0811.ferritecore.mixin.predicates;
 
 import malte0811.ferritecore.CachedOrPredicates;
 import malte0811.ferritecore.util.PredicateHelper;
 import net.minecraft.block.Block;
 import net.minecraft.block.BlockState;
-import net.minecraft.client.renderer.model.multipart.AndCondition;
 import net.minecraft.client.renderer.model.multipart.ICondition;
 import net.minecraft.client.renderer.model.multipart.OrCondition;
 import net.minecraft.state.StateContainer;
@@ -13,15 +12,8 @@ import org.spongepowered.asm.mixin.Mixin;
 import org.spongepowered.asm.mixin.Overwrite;
 import org.spongepowered.asm.mixin.Shadow;
 
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Predicate;
 
-import malte0811.ferritecore.HackyGlobalState;
-
 @Mixin(OrCondition.class)
 public class OrConditionMixin {
     @Shadow @Final private Iterable<? extends ICondition> conditions;

+ 1 - 1
src/main/java/malte0811/ferritecore/mixin/PropertyValueConditionMixin.java → src/main/java/malte0811/ferritecore/mixin/predicates/PropertyValueConditionMixin.java

@@ -1,4 +1,4 @@
-package malte0811.ferritecore.mixin;
+package malte0811.ferritecore.mixin.predicates;
 
 import com.google.common.base.Splitter;
 import malte0811.ferritecore.CachedOrPredicates;

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

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

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

@@ -0,0 +1,88 @@
+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;
+}

+ 14 - 0
src/main/resources/ferritecore.fastmap.mixin.json

@@ -0,0 +1,14 @@
+{
+  "required": true,
+  "package": "malte0811.ferritecore.mixin.fastmap",
+  "compatibilityLevel": "JAVA_8",
+  "refmap": "ferritecore.refmap.json",
+  "mixins": [
+    "FastMapStateHolderMixin"
+  ],
+  "injectors": {
+    "defaultRequire": 1
+  },
+  "minVersion": "0.8",
+  "plugin": "malte0811.ferritecore.mixin.fastmap.Config"
+}

+ 15 - 0
src/main/resources/ferritecore.nopropertymap.mixin.json

@@ -0,0 +1,15 @@
+{
+  "required": true,
+  "package": "malte0811.ferritecore.mixin.nopropertymap",
+  "compatibilityLevel": "JAVA_8",
+  "refmap": "ferritecore.refmap.json",
+  "mixins": [
+    "DummyFerriteValuesMixin",
+    "NoPropertyStateHolderMixin"
+  ],
+  "injectors": {
+    "defaultRequire": 1
+  },
+  "minVersion": "0.8",
+  "plugin": "malte0811.ferritecore.mixin.nopropertymap.Config"
+}

+ 2 - 6
src/main/resources/ferritecore.mixins.json → src/main/resources/ferritecore.predicates.mixin.json

@@ -1,12 +1,8 @@
 {
   "required": true,
-  "package": "malte0811.ferritecore.mixin",
+  "package": "malte0811.ferritecore.mixin.predicates",
   "compatibilityLevel": "JAVA_8",
   "refmap": "ferritecore.refmap.json",
-  "mixins": [
-    "FastMapStateHolderMixin",
-    "NoPropertyStateHolderMixin"
-  ],
   "client": [
     "AndConditionMixin",
     "OrConditionMixin",
@@ -16,5 +12,5 @@
     "defaultRequire": 1
   },
   "minVersion": "0.8",
-  "plugin": "malte0811.ferritecore.mixin.config.FerriteMixinConfig"
+  "plugin": "malte0811.ferritecore.mixin.predicates.Config"
 }