From e3944d7879b4314fc6031def100358d71a562ffe Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 26 Jun 2023 19:43:53 -0400 Subject: [PATCH] Add option to aggressively clear Fabric mapping tables --- .../core/config/ModernFixEarlyConfig.java | 22 +++++++-- .../modernfix/util/CommonModUtil.java | 7 ++- .../modernfix/ModernFixPreLaunchFabric.java | 4 ++ .../fabric/mappings/MappingsClearer.java | 46 +++++++++++++++++++ 4 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 fabric/src/main/java/org/embeddedt/modernfix/fabric/mappings/MappingsClearer.java diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index dd260480..14d1ac3b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -17,6 +17,7 @@ import org.objectweb.asm.tree.ClassNode; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.function.BooleanSupplier; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -141,7 +142,21 @@ public class ModernFixEarlyConfig { shouldReplaceSearchTrees = modPresent("jei"); } - private static final ImmutableMap DEFAULT_SETTING_OVERRIDES = ImmutableMap.builder() + private static class DefaultSettingMapBuilder extends ImmutableMap.Builder { + public DefaultSettingMapBuilder putConditionally(BooleanSupplier condition, String k, Boolean v) { + if(condition.getAsBoolean()) + put(k, v); + return this; + } + + @Override + public DefaultSettingMapBuilder put(String key, Boolean value) { + super.put(key, value); + return this; + } + } + + private static final ImmutableMap DEFAULT_SETTING_OVERRIDES = new DefaultSettingMapBuilder() .put("mixin.perf.dynamic_resources", false) .put("mixin.feature.direct_stack_trace", false) .put("mixin.perf.rewrite_registry", false) @@ -157,6 +172,8 @@ public class ModernFixEarlyConfig { .put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees) .put("mixin.devenv", isDevEnv) .put("mixin.perf.remove_spawn_chunks", isDevEnv) + .putConditionally(() -> !isFabric, "mixin.bugfix.fix_config_crashes", true) + .putConditionally(() -> isFabric, "mixin.perf.clear_fabric_mapping_tables", false) .build(); private ModernFixEarlyConfig(File file) { @@ -164,9 +181,6 @@ public class ModernFixEarlyConfig { this.scanForAndBuildMixinOptions(); mixinOptions.addAll(DEFAULT_SETTING_OVERRIDES.keySet()); - if(!isFabric) { - mixinOptions.add("mixin.bugfix.fix_config_crashes"); - } for(String optionName : mixinOptions) { boolean defaultEnabled = DEFAULT_SETTING_OVERRIDES.getOrDefault(optionName, true); this.options.putIfAbsent(optionName, new Option(optionName, defaultEnabled, false)); diff --git a/common/src/main/java/org/embeddedt/modernfix/util/CommonModUtil.java b/common/src/main/java/org/embeddedt/modernfix/util/CommonModUtil.java index 003d638d..83d4148e 100644 --- a/common/src/main/java/org/embeddedt/modernfix/util/CommonModUtil.java +++ b/common/src/main/java/org/embeddedt/modernfix/util/CommonModUtil.java @@ -3,11 +3,16 @@ package org.embeddedt.modernfix.util; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; public class CommonModUtil { + @FunctionalInterface + public interface SafeRunnable { + void run() throws Throwable; + } + /** * Avoid using this, it's bad practice but cleanest way of suppressing errors for nonessential mod-dependent * functionality. */ - public static void runWithoutCrash(Runnable r, String errorMsg) { + public static void runWithoutCrash(SafeRunnable r, String errorMsg) { try { r.run(); } catch(Throwable e) { diff --git a/fabric/src/main/java/org/embeddedt/modernfix/ModernFixPreLaunchFabric.java b/fabric/src/main/java/org/embeddedt/modernfix/ModernFixPreLaunchFabric.java index 6d1137b4..8251d6d7 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/ModernFixPreLaunchFabric.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/ModernFixPreLaunchFabric.java @@ -2,6 +2,7 @@ package org.embeddedt.modernfix; import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; +import org.embeddedt.modernfix.fabric.mappings.MappingsClearer; import org.embeddedt.modernfix.fabric.spark.SparkLaunchProfiler; import org.embeddedt.modernfix.util.CommonModUtil; @@ -11,5 +12,8 @@ public class ModernFixPreLaunchFabric implements PreLaunchEntrypoint { if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spark_profile_launch.OnFabric")) { CommonModUtil.runWithoutCrash(() -> SparkLaunchProfiler.start("launch"), "Failed to start profiler"); } + if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_fabric_mapping_tables.MappingsClearer")) { + MappingsClearer.clear(); + } } } diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mappings/MappingsClearer.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mappings/MappingsClearer.java new file mode 100644 index 00000000..1e392e57 --- /dev/null +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mappings/MappingsClearer.java @@ -0,0 +1,46 @@ +package org.embeddedt.modernfix.fabric.mappings; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.MappingResolver; +import net.fabricmc.loader.impl.launch.FabricLauncherBase; +import net.fabricmc.loader.impl.launch.MappingConfiguration; +import net.fabricmc.mapping.tree.TinyMappingFactory; +import org.embeddedt.modernfix.util.CommonModUtil; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Map; + +/** + * Designed for Fabric Loader 0.14.x, probably has issues on other versions. The entire thing is wrapped in a try-catch + * so it should never cause crashes, just fail to work. + */ +public class MappingsClearer { + @SuppressWarnings("unchecked") + public static void clear() { + if(FabricLoader.getInstance().isDevelopmentEnvironment()) + return; // never do this in dev + CommonModUtil.runWithoutCrash(() -> { + // clear notch->intermediary mappings + MappingConfiguration config = FabricLauncherBase.getLauncher().getMappingConfiguration(); + Field mappingsField = MappingConfiguration.class.getDeclaredField("mappings"); + mappingsField.setAccessible(true); + mappingsField.set(config, TinyMappingFactory.EMPTY_TREE); + + // clear useless intermediary->intermediary mappings + MappingResolver resolver = FabricLoader.getInstance().getMappingResolver(); + Class targetResolverClz = Class.forName("net.fabricmc.loader.impl.MappingResolverImpl"); + if(targetResolverClz.isAssignableFrom(resolver.getClass())) { + // hopefully still Loader 0.14.x, proceed + Class namespaceDataClz = Class.forName("net.fabricmc.loader.impl.MappingResolverImpl$NamespaceData"); + Constructor constructor = namespaceDataClz.getDeclaredConstructor(); + constructor.setAccessible(true); + Object theData = constructor.newInstance(); + Field mapField = resolver.getClass().getDeclaredField("namespaceDataMap"); + mapField.setAccessible(true); + Map theMap = (Map)mapField.get(resolver); + theMap.replace("intermediary", theData); + } + }, "Failed to clear mappings"); + } +}