本帖最后由 teddyxlandlee 于 2023-2-9 16:02 编辑 
本文只针对 1.16+ 的情况,低版本暂不考虑,因为楼主没涉猎过。
当你想要做一个 非常小型的跨平台Mod,不想调用MC相关代码,只使用Mixin时,
你就需要写一个 MixinConfigPlugin,用来在不同平台下加载不同的 refmap。
为了保证模组跨版本,我们必须使用较为稳定的中间名。
Fabric的中间名与Forge的完全不同;Forge使用的MCP自1.17也彻底投奔了MojMaps。所以我们通常需要3份mapping。(如果MC相关代码在中间有修改,则可能需要更多)
我称之为:FORGE_116, FORGE_117, FABRIC_INT。
下面的PlatformUtil类,包含了 获取 config 文件夹、Forge版本(若为 Fabric/Quilt 则返回 -1)
复制代码
本文只针对 1.16+ 的情况,低版本暂不考虑,因为楼主没涉猎过。
当你想要做一个 非常小型的跨平台Mod,不想调用MC相关代码,只使用Mixin时,
你就需要写一个 MixinConfigPlugin,用来在不同平台下加载不同的 refmap。
为了保证模组跨版本,我们必须使用较为稳定的中间名。
Fabric的中间名与Forge的完全不同;Forge使用的MCP自1.17也彻底投奔了MojMaps。所以我们通常需要3份mapping。(如果MC相关代码在中间有修改,则可能需要更多)
我称之为:FORGE_116, FORGE_117, FABRIC_INT。
下面的PlatformUtil类,包含了 获取 config 文件夹、Forge版本(若为 Fabric/Quilt 则返回 -1)
- package com.foo.bar;
 
 
- import com.google.common.base.Suppliers;
 
- import org.apache.logging.log4j.LogManager;
 
- import org.apache.logging.log4j.Logger;
 
- import org.jetbrains.annotations.Nullable;
 
 
- import java.lang.invoke.MethodHandle;
 
- import java.lang.invoke.MethodHandles;
 
- import java.lang.invoke.MethodType;
 
- import java.nio.file.Path;
 
- import java.util.function.IntSupplier;
 
- import java.util.function.Supplier;
 
 
- public class PlatformUtil {
 
-     static final Logger LOGGER = LogManager.getLogger();
 
 
-     private static final IntSupplier LAZY_FORGE_VERSION = Suppliers.memoize(PlatformUtil::getForgeVersion1)::get;
 
 
-     private static final Supplier<Path> CONFIG_PATH = Suppliers.memoize(() -> {
 
-         Class<?> c;
 
-         MethodHandles.Lookup lookup = MethodHandles.lookup();
 
-         try {
 
-             if (getForgeVersion() < 0) {
 
-                 c = Class.forName("net.fabricmc.loader.api.FabricLoader");
 
-                 MethodHandle mh = lookup.findStatic(c, "getInstance", MethodType.methodType(c));
 
-                 MethodHandle mh2 = lookup.findVirtual(c, "getConfigDir", MethodType.methodType(Path.class));
 
 
-                 return (Path) mh2.invoke(mh.invoke());
 
-             } else {
 
-                 c = Class.forName("net.minecraftforge.fml.loading.FMLPaths");
 
-                 MethodHandle mh = lookup.findStaticGetter(c, "CONFIGDIR", c);
 
-                 MethodHandle mh2 = lookup.findVirtual(c, "get", MethodType.methodType(Path.class));
 
 
-                 return (Path) mh2.invoke(mh.invoke());
 
-             }
 
-         } catch (Throwable t) {
 
-             throw new RuntimeException("Can't fetch config path", t);
 
-         }
 
-     });
 
 
-     public static Path getConfigDir() {
 
-         return CONFIG_PATH.get();
 
-     }
 
 
-     public static int getForgeVersion() {
 
-         return LAZY_FORGE_VERSION.getAsInt();
 
-     }
 
 
-     private static int getForgeVersion1() {
 
-         String s = getForgeVersion0();
 
-         if (s != null) {
 
-             s = s.split("\\.")[0];
 
-             // 36 means 1.16.5, 37 means 1.17.1
 
-             return Integer.parseUnsignedInt(s);
 
-         } else {    // Still checking if Fabric, otherwise throw
 
-             try {
 
-                 Class.forName("net.fabricmc.api.Environment");
 
-             } catch (ClassNotFoundException e) {
 
-                 throw new RuntimeException("Detected environment is neither FML nor Fabric/Quilt.", e);
 
-             }
 
-             return -1;
 
-         }
 
-     }
 
 
-     private static @Nullable String getForgeVersion0() {
 
-         try {
 
-             Class<?> clazz = Class.forName("net.minecraftforge.fml.loading.StringSubstitutor");
 
-             MethodHandle mh = MethodHandles.lookup().findStatic(clazz, "replace",
 
-                     MethodType.fromMethodDescriptorString("(Ljava/lang/String;Lnet/minecraftforge/fml/loading/moddiscovery/ModFile;)Ljava/lang/String;",
 
-                             PlatformUtil.class.getClassLoader()));
 
-             return (String) mh.invoke("${global.forgeVersion}", null);
 
-         } catch (ClassNotFoundException e) {
 
-             return null;
 
-         } catch (NoSuchMethodException | IllegalAccessException e) {
 
-             LOGGER.warn(() ->
 
-                     "Can't get forge version: " + e);
 
-             return null;
 
-         } catch (Throwable e) {
 
-             throw new RuntimeException(e);
 
-         }
 
-     }
 
- }