Class AbstractMappedMinecraftProvider<M extends MinecraftProvider>

java.lang.Object
net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider<M>
All Implemented Interfaces:
MappedMinecraftProvider, MappedMinecraftProvider.ProviderImpl
Direct Known Subclasses:
IntermediaryMinecraftProvider, MojangMappedMinecraftProvider, NamedMinecraftProvider, SrgMinecraftProvider

public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvider> extends Object implements MappedMinecraftProvider.ProviderImpl
  • Field Details

  • Constructor Details

    • AbstractMappedMinecraftProvider

      public AbstractMappedMinecraftProvider(org.gradle.api.Project project, M minecraftProvider)
  • Method Details

    • getTargetNamespace

      public abstract MappingsNamespace getTargetNamespace()
    • getRemappedJars

      public abstract List<AbstractMappedMinecraftProvider.RemappedJars> getRemappedJars()
      Returns:
      A list of jars that should be remapped
    • getOutputJars

      public List<? extends AbstractMappedMinecraftProvider.OutputJar> getOutputJars()
      Returns:
      A list of output jars that this provider generates
    • getDependencyTypes

      public List<MinecraftJar.Type> getDependencyTypes()
    • provide

      供给本 provider 的产物:**生产已改由任务承担**,本方法不再在配置期写任何产物.

      本次改造把「判断是否重建 → 取跨进程锁 → 重映射 → 落位」整段交给 RemapMinecraftTask:产物有效性交给 Gradle 的 up-to-date 判定与构建缓存,并发保护交给 任务图,残骸恢复交给构建缓存。本方法只做三件事——逐 jar 注册任务(失败则整批回退,见下)、 把任务产出登记进 getMinecraftJarsTaskOutputs、以及把带任务依赖的文件集合注入消费配置。

      不可投影时整批回退到配置期生产,且必留痕

      verifyProjectable(RemappedJars) 判为「无法安全投影」的形态(例如 disableObfuscation 的直通形态)不进入任务路径,改由 produceInConfiguration(net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider.ProvideContext, java.util.List<net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider.RemappedJars>, java.util.List<net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar>) 走改造前的配置期路径。回退是**按 provider 整批**而不是按 jar 的:半批投影会留下 「一部分产物由任务生产、一部分由配置期生产」的混合状态,同一份缓存里出现两种就绪判据。 回退必定打日志(含被拒的具体原因),不是静默吞掉——静默吞掉会得到「以为切了任务、其实还在配置期写」。
      Throws:
      Exception
    • disableTaskProduction

      protected void disableTaskProduction()
      关闭本 provider 的任务生产(见 taskProduction).

      只在创建 legacy merged 的委托 provider 时调用,且必须早于 provide。

    • getRemapTask

      protected @Nullable RemapMinecraftTaskRegistry.Producer getRemapTask(MinecraftJar.Type type)
      Returns 本 provider 为指定 jar 类型登记到的生产位置;未登记(不可投影或未启用任务生产)时为 null..

      子 provider 用它建立「本任务以该产物为输入」的任务依赖,而不是只按路径声明输入。

      Returns:
      本 provider 为指定 jar 类型登记到的生产位置;未登记(不可投影或未启用任务生产)时为 null
    • cacheKey

      protected String cacheKey()
    • getBackupJarPath

      public static Path getBackupJarPath(MinecraftJar minecraftJar)
    • requiresBackupJars

      protected boolean requiresBackupJars()
    • createBackupJars

      protected void createBackupJars(List<MinecraftJar> minecraftJars) throws IOException
      Throws:
      IOException
    • getJar

      public Path getJar(MinecraftJar.Type type)
      Specified by:
      getJar in interface MappedMinecraftProvider.ProviderImpl
    • getMavenScope

      public abstract AbstractMappedMinecraftProvider.MavenScope getMavenScope()
    • getMavenHelper

      public LocalMavenHelper getMavenHelper(MinecraftJar.Type type)
    • getName

      protected String getName(MinecraftJar.Type type)
    • getVersion

      protected String getVersion()
    • getDependencyNotation

      protected String getDependencyNotation(MinecraftJar.Type type)
    • isUpToDate

      public boolean isUpToDate(AbstractMappedMinecraftProvider.ProvideContext context)
      Returns 产物是否已就绪(无需重建)..

      供外部(如 minecraft-provision 事务锁的无锁快路径)在锁外做只读判定; 实现即 shouldRefreshOutputs(net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider.ProvideContext) 的取反,判定产物存在且内容可复用(见下)。

      Returns:
      产物是否已就绪(无需重建)
    • shouldRefreshOutputs

      protected boolean shouldRefreshOutputs(AbstractMappedMinecraftProvider.ProvideContext context)
    • remapJar

      protected void remapJar(AbstractMappedMinecraftProvider.RemappedJars remappedJars, ConfigContext configContext) throws IOException
      Throws:
      IOException
    • configureRemapper

      protected void configureRemapper(AbstractMappedMinecraftProvider.RemappedJars remappedJars, net.fabricmc.tinyremapper.TinyRemapper.Builder tinyRemapperBuilder)
    • configureSplitRemapper

      public static void configureSplitRemapper(AbstractMappedMinecraftProvider.RemappedJars remappedJars, net.fabricmc.tinyremapper.TinyRemapper.Builder tinyRemapperBuilder)
    • remapperHookKind

      Returns 本 provider 对 configureRemapper(net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider.RemappedJars, net.fabricmc.tinyremapper.TinyRemapper.Builder) 的覆写在投影视角下的形态..

      这是一个显式声明,不是探测:钩子是实例方法,它的效果(往 TinyRemapper.Builder 上挂什么) 无法被序列化成任务输入,而反射只能确认「覆写了」、不能确认「覆写成什么」。因此默认值刻意保守: AbstractMappedMinecraftProvider.RemapperHookKind.UNKNOWN,即「不可假定」。不认识的覆写一律拒绝投影,而不是把它当作空实现—— 后者会得到「任务成功、产物却比配置期少了钩子改动」的静默损坏。

      三种形态各自意味着什么

      Returns:
      本 provider 对 configureRemapper(net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider.RemappedJars, net.fabricmc.tinyremapper.TinyRemapper.Builder) 的覆写在投影视角下的形态
    • registerRemapTask

      把一个 AbstractMappedMinecraftProvider.RemappedJars 投影成 L3 重映射任务,返回的任务引用可承载消费侧的文件依赖.

      本方法是 provide(net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider.ProvideContext) 里「remapInputs + createBackupJars」那段的替代路径的**注册侧**: 产物有效性、并发保护、损坏恢复分别改由 Gradle 的 up-to-date 判定、任务图与构建缓存承担, 取代 shouldRefreshOutputs + 跨进程锁 + JarReusability 这套手写协议。

      本方法只做「配置期已知量 → 任务输入」的映射,不写任何产物文件。它现在是 provide(net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider.ProvideContext) 的生产路径:provide 对每个 jar 调用它,并把返回的任务登记进 setMinecraftJarsTaskOutputs 与消费配置。与 jar processor 链同批接线——后者是 ProcessedNamedMinecraftProvider 的输入(Named 的产出),只切一环会断链。

      输入映射

      • inputJar / outputJar / remapClasspath ← AbstractMappedMinecraftProvider.RemappedJars 的同名字段,fromNamespace ← sourceNamespace
      • toNamespace ← getTargetNamespace()(取 toString(), 与 remapJar 交给 L4 的字符串一致)
      • fixRecords / validateTargetNamespace / objectHolder* ← 与 remapJar 逐项同判据
      • innerClassNames ← 判据同 remapJar(Forge 系才算,否则空集):它是输入 jar 的纯函数, 由任务在执行期从 (inputJar, forgeLike) 现算,**不经任何任务属性** (理由见 RemapMinecraftTask.resolveInnerClassNames 的说明)
      • mappingsServiceOptions ← MappingConfiguration.getMappingsServiceOptions(project, MappingOption.forPlatform(extension)), 与配置期 getMappingsService 取的是同一份映射来源(换来源会产出不等价的 jar)

      为什么 annotations / signatureFixes 只能在配置期算

      AnnotationsData.getRemappedAnnotations 与 SignatureFixerApplyVisitor.getRemappedSignatures 都要一个 ServiceFactory,而 configContext 携带的那个是配置期 作用域(由调用方 try-with-resources 持有,配置结束后关闭),执行期已不可用。要让任务自己算, 必须把这两个 service 的 Options 也收进任务输入——那是协议扩展,本次不做,因此这里如实提前计算。 代价也如实记下:原路径只在「需要重建」时才算这两个量,投影后变成注册即计算(无注解数据 / 无签名修复时是 O(1) 早退,只有映射带 extras 时才有真实开销)。

      产物落位:三个具体文件,目录一律不声明

      产物取自 remappedJars.outputJarPath(),即 getJar(net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar.Type) 给出的 maven 仓库位置 (getMavenScope() 决定落在全局仓库还是项目级仓库,布局由 LocalMavenHelper 决定)。 该构件目录里属于本任务的产物有三个,本方法逐个声明为 @OutputFile、由任务写出:
      1. jar —— 重映射产物本身;
      2. <name>-<version>.pom —— 内容与落位都由 LocalMavenHelper.savePom() 决定 (任务按坐标调用它,不另写一份模板)。缺它会让按坐标解析该构件的依赖直接失败;
      3. <jar>.backup —— jar 的逐字节副本,由任务用 AtomicFiles 原子复制得到, 位置与 getBackupJarPath(net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar) 一致(消费者 genSources 按后者找它)。requiresBackupJars() 为假的 provider 不声明该输出。
      三者都是文件,本方法绝不声明 @OutputDirectory:仓库根与版本目录里还有别的 provider、 别的 MC 版本的产物,把它们纳入本任务的快照与清理范围会让并发构建互相破坏。

      共享路径:同一条路径只有一个生产者

      AbstractMappedMinecraftProvider.MavenScope.GLOBAL 下产物路径跨项目、跨工作树共享(全局仓库位于 Gradle 用户目录,同一台机器上的 所有工作树共用),同一构建内两个配置相同的子项目会算出同一条路径。这件事交给 RemapMinecraftTaskRegistry:同一路径的第一次登记创建任务,后续登记只取回生产者的任务路径, 因此不存在两个任务声明同一个 @OutputFile——实测 Gradle 9.5 对这种重叠既不报错也不排序, 两个任务都会写、后完成的覆盖先完成的,而一旦有消费方按该路径取产物,隐式依赖校验会直接让构建失败。 输入指纹不同的登记会被拒绝而不是共享:共享一份输入不同的产物,等于把别的配置的 jar 静默交给本项目。 指纹必须覆盖注解与签名修复(它们是产物内容的一部分),所以去重判定发生在这些量算完之后—— 代价与非共享路径相同(见上面「注册即计算」的说明),共享的那一方会白算一次,但换来的是判定精确。

      本方法覆盖不到的 provider 形态

      这两种形态在 verifyProjectable(RemappedJars) 之后、更早的地方就拒绝被投影,属于本次未解决项:
      • LegacyMergedImpl(MC 1.3 之前的合并 jar):getRemappedJars() 直接抛 UnsupportedOperationException,它的生产过程是「分别重映射 client/server 再合并 jar」, 并不是一次重映射,本任务无从承载;需要为「合并」单列一个任务。
      • ProcessedNamedMinecraftProvider:落位是 AbstractMappedMinecraftProvider.MavenScope.LOCAL(同名目录由 jar processor 哈希区分),且它的 getRemappedJars() 与 getJar() 都抛异常——它的产物由 jar processor 链产生,不经本任务;因此 LOCAL 范围下的跨子项目共享不在本方法职责内。
      Parameters:
      remappedJars - 待重映射的一对输入/输出 jar
      configContext - 配置上下文;只用其 service factory(配置期作用域)
      Returns:
      该产物的生产位置;同一构建内同一产物路径只对应一个生产者
      Throws:
      IllegalStateException - 产物路径与 maven 助手的构件路径不一致,或同一路径被以不同输入登记时
    • getProject

      public org.gradle.api.Project getProject()
    • getMinecraftProvider

      public M getMinecraftProvider()