Class MinecraftPatchedProvider

java.lang.Object
dev.architectury.loom.forge.minecraft.MinecraftPatchedProvider
Direct Known Subclasses:
MinecraftLegacyPatchedProvider

public class MinecraftPatchedProvider extends Object
  • Field Details

    • project

      protected final org.gradle.api.Project project
    • logger

      protected final org.gradle.api.logging.Logger logger
    • minecraftProvider

      protected final MinecraftProvider minecraftProvider
    • type

      protected final MinecraftPatchedProvider.Type type
    • dirty

      protected boolean dirty
  • Constructor Details

  • Method Details

    • get

      public static MinecraftPatchedProvider get(org.gradle.api.Project project)
    • getGlobalCaches

      protected Path[] getGlobalCaches()
      Returns 本配置下必须可复用的共享产物列表,供 needsWork() 判定..

      列表只包含当前 jar 配置确实会生成的产物:server-only 不提供 client jar, client-extra.jar 既不生成也不进 classpath、不注册进 FORGE_EXTRA(见 providesClientJar()), 把它计入判定会让 needsWork() 恒为真、每次构建都白取一次跨进程锁。

      Returns:
      本配置下必须可复用的共享产物列表,供 needsWork() 判定
    • isReusableJar

      protected static boolean isReusableJar(Path jar)
      Returns 该共享产物是否可作为输入复用..

      口径与理由见 JarReusability.isReusable(Path):能作为 zip 打开且至少含一个条目。 实现只有那一份,其它共享缓存链(mapped minecraft jar、mcp.zip、SrgProvider 产物等)用的是同一判定; 本方法保留,是因为 legacy 子类仍以 isReusableJar 的名字调用它。

      Returns:
      该共享产物是否可作为输入复用
    • checkCache

      protected boolean checkCache() throws IOException
      锁内二次确认:判定现有产物能否复用,并返回本次是否需要整链重建.

      本方法刻意不再删除共享产物。这些 jar 位于跨 daemon 共享的 forge 缓存目录: 删除会让锁外只做存在性判定的读方拿到缺失文件,也会让其它工作树误判「需要重建」而互相触发重建。 取而代之的策略是:

      • 可复用的产物原样保留,缺失或损坏的产物由后续步骤按件补齐(needsWork() 同样基于可复用性判定);
      • 需要整链重建时由返回值表达,各步骤以「临时文件 + 原子落位」重新生成, 读方见到的要么是旧文件、要么是完整的新文件。
      Returns:
      是否需要整链重建
      Throws:
      IOException
    • provide

      public void provide() throws Exception
      Throws:
      Exception
    • getOrProduceMinecraftPatchedIntermediateJar

      public Path getOrProduceMinecraftPatchedIntermediateJar()
      Returns 打补丁后的中间 Minecraft jar;产物不可复用时先按件补齐..

      该 jar 位于跨 daemon 共享的 forge 缓存目录:其它工作树的构建(尤其是仍在删除整组产物的 旧版本 loom)可能让它在被读取前一刻消失,直接读取会以 NoSuchFileException 打断整个构建。

      判定与补齐都基于「可复用」(存在、能作为 zip/jar 打开且至少含一个条目,见 isReusableJar(Path))而非「存在」:共享缓存里可能出现 22 字节空 zip 或截断文件, 只判存在性会把这类半成品原样交给调用方——它能以只读 jar 文件系统打开但读不出任何 class, 下游(FieldMappingsMigrator / MethodInheritanceMappingsMigrator)会把「读不出内容」当成 「没有内容」,从而把空结果写进映射缓存,形成静默错误映射。

      补齐走 produceIntermediateJarIfMissing():产物齐备时它是无锁快路径,不可复用时在 forge-patched 跨进程锁内只重建缺失件,并以原子方式落位。

      Returns:
      打补丁后的中间 Minecraft jar;产物不可复用时先按件补齐
    • produceIntermediateJarIfMissing

      protected void produceIntermediateJarIfMissing() throws Exception
      确保 getMinecraftPatchedIntermediateJar() 指向的产物已存在.

      默认实现调用 provide();legacy 链的产物在 remapJar(ServiceFactory) 阶段生成(provide() 只做判定),由子类覆盖补齐。

      Throws:
      Exception
    • remapJar

      public void remapJar(ServiceFactory serviceFactory) throws Exception
      Throws:
      Exception
    • withPatchedLock

      protected void withPatchedLock(Callable<Void> action)
      在跨进程锁保护下执行 patched jar 生产.

      产物位于跨 daemon 共享的 forge 缓存目录(不按项目隔离),且 client-extra.jar 在 各 Type 实例间共享同一路径;同一 MC+Forge 版本的多个并发构建会互相读写/删除同一批文件, 必须整段生产串行化。锁内判定均为幂等二次确认,等锁期间其它进程完成生产后直接复用。

    • publishAtomically

      protected static void publishAtomically(Path target, MinecraftPatchedProvider.ThrowingProducer producer) throws IOException
      原子发布:在「临时文件 + 原子落位」保护下执行可能抛出任意受检异常的生产动作.

      补丁步骤会调用外部工具(binpatcher / installer tools 等),其受检异常不限于 IOException, 无法直接作为 AtomicFiles.IOConsumer;这里统一折叠为 UncheckedIOException 后向上抛, 以保证共享缓存里永远不会出现半截产物。

      Parameters:
      target - 最终落位路径(位于跨 daemon 共享的缓存目录)
      producer - 内容生产者,接收本次独占的临时文件路径
      Throws:
      IOException
    • isPatchedJarUpToDate

      protected boolean isPatchedJarUpToDate(Path jar) throws IOException
      Throws:
      IOException
    • accessTransformForge

      protected void accessTransformForge() throws IOException
      Throws:
      IOException
    • accessTransform

      protected void accessTransform(Path input, Path target) throws IOException
      对给定 jar 执行 Forge 的 access transform.

      现代 Forge 走 accessTransformForge()(中间产物路径);legacy Forge 的补丁 流程在 FG2 自己的工作目录下产出 jar(client/server/merged-patched.jar),必须显式指定 输入输出,否则会写错产物,令后续的 walkFileSystems / applyLoomPatchVersion 拿到陈旧文件。

      Throws:
      IOException
    • patchJars

      protected void patchJars(Path clean, Path output, Path patches) throws Exception
      Throws:
      Exception
    • walkFileSystems

      protected void walkFileSystems(Path source, Path target, Predicate<Path> filter, FsPathConsumer action) throws IOException
      Throws:
      IOException
    • copyMissingClasses

      protected void copyMissingClasses(Path source, Path target) throws IOException
      Throws:
      IOException
    • copyReplacing

      protected void copyReplacing(FileSystem sourceFs, FileSystem targetFs, Path sourcePath, Path targetPath) throws IOException
      Throws:
      IOException
    • applyLoomPatchVersion

      public void applyLoomPatchVersion(Path target) throws IOException
      Throws:
      IOException
    • createMcpExecutor

      public McpExecutorBuilder createMcpExecutor(Path cache)
    • getMinecraftIntermediateJar

      public Path getMinecraftIntermediateJar()
    • getMinecraftPatchedIntermediateJar

      public Path getMinecraftPatchedIntermediateJar()
    • getMinecraftPatchedJar

      public Path getMinecraftPatchedJar()
    • isDirty

      public boolean isDirty()
      Checks whether the provider's state is dirty (regenerating jars).