teddyxlandlee
本帖最后由 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. package com.foo.bar;

  2. import com.google.common.base.Suppliers;
  3. import org.apache.logging.log4j.LogManager;
  4. import org.apache.logging.log4j.Logger;
  5. import org.jetbrains.annotations.Nullable;

  6. import java.lang.invoke.MethodHandle;
  7. import java.lang.invoke.MethodHandles;
  8. import java.lang.invoke.MethodType;
  9. import java.nio.file.Path;
  10. import java.util.function.IntSupplier;
  11. import java.util.function.Supplier;

  12. public class PlatformUtil {
  13.     static final Logger LOGGER = LogManager.getLogger();

  14.     private static final IntSupplier LAZY_FORGE_VERSION = Suppliers.memoize(PlatformUtil::getForgeVersion1)::get;

  15.     private static final Supplier<Path> CONFIG_PATH = Suppliers.memoize(() -> {
  16.         Class<?> c;
  17.         MethodHandles.Lookup lookup = MethodHandles.lookup();
  18.         try {
  19.             if (getForgeVersion() < 0) {
  20.                 c = Class.forName("net.fabricmc.loader.api.FabricLoader");
  21.                 MethodHandle mh = lookup.findStatic(c, "getInstance", MethodType.methodType(c));
  22.                 MethodHandle mh2 = lookup.findVirtual(c, "getConfigDir", MethodType.methodType(Path.class));

  23.                 return (Path) mh2.invoke(mh.invoke());
  24.             } else {
  25.                 c = Class.forName("net.minecraftforge.fml.loading.FMLPaths");
  26.                 MethodHandle mh = lookup.findStaticGetter(c, "CONFIGDIR", c);
  27.                 MethodHandle mh2 = lookup.findVirtual(c, "get", MethodType.methodType(Path.class));

  28.                 return (Path) mh2.invoke(mh.invoke());
  29.             }
  30.         } catch (Throwable t) {
  31.             throw new RuntimeException("Can't fetch config path", t);
  32.         }
  33.     });

  34.     public static Path getConfigDir() {
  35.         return CONFIG_PATH.get();
  36.     }

  37.     public static int getForgeVersion() {
  38.         return LAZY_FORGE_VERSION.getAsInt();
  39.     }

  40.     private static int getForgeVersion1() {
  41.         String s = getForgeVersion0();
  42.         if (s != null) {
  43.             s = s.split("\\.")[0];
  44.             // 36 means 1.16.5, 37 means 1.17.1
  45.             return Integer.parseUnsignedInt(s);
  46.         } else {    // Still checking if Fabric, otherwise throw
  47.             try {
  48.                 Class.forName("net.fabricmc.api.Environment");
  49.             } catch (ClassNotFoundException e) {
  50.                 throw new RuntimeException("Detected environment is neither FML nor Fabric/Quilt.", e);
  51.             }
  52.             return -1;
  53.         }
  54.     }

  55.     private static @Nullable String getForgeVersion0() {
  56.         try {
  57.             Class<?> clazz = Class.forName("net.minecraftforge.fml.loading.StringSubstitutor");
  58.             MethodHandle mh = MethodHandles.lookup().findStatic(clazz, "replace",
  59.                     MethodType.fromMethodDescriptorString("(Ljava/lang/String;Lnet/minecraftforge/fml/loading/moddiscovery/ModFile;)Ljava/lang/String;",
  60.                             PlatformUtil.class.getClassLoader()));
  61.             return (String) mh.invoke("${global.forgeVersion}", null);
  62.         } catch (ClassNotFoundException e) {
  63.             return null;
  64.         } catch (NoSuchMethodException | IllegalAccessException e) {
  65.             LOGGER.warn(() ->
  66.                     "Can't get forge version: " + e);
  67.             return null;
  68.         } catch (Throwable e) {
  69.             throw new RuntimeException(e);
  70.         }
  71.     }
  72. }
复制代码