Class GenerateForgePrePatchJarTask
- All Implemented Interfaces:
Comparable<org.gradle.api.Task>,org.gradle.api.internal.DynamicObjectAware,org.gradle.api.internal.TaskInternal,org.gradle.api.Named,org.gradle.api.plugins.ExtensionAware,org.gradle.api.Task,org.gradle.util.Configurable<org.gradle.api.Task>
minecraft-<type>-<ns>.jar).
它取代的是 MinecraftPatchedProvider.provide() 里那段配置期同步执行的
「取跨进程锁 → 判断是否需要重建 → 选分支 → 跑 MCP rename 步(或 NeoForge installer tools)→ 原子落位」。
| 旧路径 | 本任务 | |
|---|---|---|
| 是否需要生产 | 配置期 needsWork() 设的 dirty + 锁内二次确认 |
Gradle up-to-date 检查(输入内容 + 输出快照),叠加「产物已就绪且身份相符就跳过」的前置判据 |
| 并发保护 | 跨进程文件锁 | 任务图 + 跨进程文件锁(产物仍在共享缓存) |
| 执行时机 | 配置期(CompileConfiguration.setupMinecraft) | 执行期 |
生产逻辑不在这里
真正的生产仍由MinecraftPatchedProvider.runMcpExecutor(org.gradle.api.provider.Provider<dev.architectury.loom.mcpconfig.McpExecutor.Options>, java.nio.file.Path, net.fabricmc.loom.util.service.ServiceFactory) 与
ForgeExternalToolService.exec(java.util.Map<java.lang.String, java.lang.String>) 持有:配置期路径与本任务共用同一份实现,
因此两条路径的 MCP 步进集合、命令行与产物逐字节一致。本任务另写一套「等价」的实现就会引入分叉。
两条分支由配置期定死
getBranch() 是配置期算好的纯值(判据见
MinecraftPatchedProvider.shouldUseNeoForgeInstallerToolsToCreatePrePatchJar()),
执行期不再回读项目模型;两条分支各自的工具声明也只挂它自己那一个 @Nested 输入。
MCP 工作目录为什么是任务自己的
配置期路径用TempFiles 造一个随机临时目录,本次调用结束即删;任务路径必须让目录活到执行期,
因此改由 getMcpWorkDir() 给出(build/tmp/<任务名>/mcp),由本任务在执行期创建、
结束即删——对 MCP 执行链而言与配置期的 TempFiles 语义完全一致。
目录路径不参与产物内容(旧路径每次都是随机路径而产物不变),故它是 @Internal。
产物就绪就跳过整条链(前置判据)
产物落在跨项目共享的 forge 缓存目录,属于「执行前就已存在、又不是本任务创建的」输出。 Gradle 对这种输出的口径是Gradle does not know how file … was created:
构建缓存被直接关掉(见 GenerateForgePatchedSourcesTask 类注释第 4 条),up-to-date 在跨工作树 / 跨
loom 版本时也不可靠;而整条 MCP 链是十余个外部进程、分钟到十分钟级。
于是 generate() 的第一件事是判「产物已就绪且身份与本次输入逐项相符」,命中即直接返回,
不启动任何外部进程;判据与身份的完整说明见 ForgePrePatchJarReuse。要点:
- 判据是纯读的(stat + 小文件内容摘要),不解压 jar、不改写产物;
- 身份记在产物**旁边**的旁车文件里,而不是产物自己的 manifest——往产物里写清单会改变它的字节, 而那正是本仓库逐字节等价性用例所钉住的东西;
- 旁车只在生产成功后写(
ForgePrePatchJarReuse.record(java.nio.file.Path, java.lang.String, org.gradle.api.logging.Logger)),因此旁车永远描述一份真实存在的产物; - 不命中时行为与改造前完全一致:照常跑链、原子落位。
它不影响 Gradle 的缓存口径:输入输出声明一个未改,getReuseInputs() 是 @Internal。
-
Nested Class Summary
Nested classes/interfaces inherited from interface org.gradle.api.Named
org.gradle.api.Named.Namer -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final String分支:跑 MCP 的rename步(现代 Forge / NeoForge 的常规形态).static final String分支:跑 MCP 的merge/preProcessJar步(disableObfuscation / unobfuscated 形态).static final String分支:NeoForge installer tools 的PROCESS_MINECRAFT_JAR(见 NeoForge#2848 的绕行).static final String任务名:消费侧(本仓库的测试与诊断)按它引用产出任务.Fields inherited from interface org.gradle.api.Task
TASK_ACTION, TASK_CONSTRUCTOR_ARGS, TASK_DEPENDS_ON, TASK_DESCRIPTION, TASK_GROUP, TASK_NAME, TASK_OVERWRITE, TASK_TYPE -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidgenerate()abstract org.gradle.api.provider.Property<String> 本次走哪条分支(配置期算好的纯值).abstract org.gradle.api.provider.Property<String> installer tools 分支要下载的 client 映射地址;另一条分支下不设置.abstract org.gradle.api.provider.Property<ForgeExternalToolService.Options> NeoForge installer tools 的声明式选项(BRANCH_NEOFORGE_INSTALLER_TOOLS);另一条分支下不设置.abstract org.gradle.api.provider.Property<Boolean> 是否显式要求刷新依赖(与配置期extension.download同判据).abstract org.gradle.api.provider.Property<McpExecutor.Options> MCP 执行器选项(BRANCH_MCP_RENAME/BRANCH_MCP_UNOBFUSCATED);其余分支下不设置.abstract org.gradle.api.file.DirectoryPropertyMCP 执行链的工作目录.abstract org.gradle.api.provider.Property<Boolean> 是否处于 Gradle 的离线模式(与配置期extension.download同判据).abstract org.gradle.api.file.RegularFileProperty产物:pre-patch jar(与配置期同一条路径).abstract org.gradle.api.provider.Property<String> 本次执行的身份前缀:决定「该产出什么」的那些纯值(分支、平台、MC/Forge 版本、side、命名空间).abstract org.gradle.api.file.ConfigurableFileCollection本次执行的输入文件:它们的内容决定产物内容,因而参与复用判据的键.Methods inherited from class org.gradle.api.DefaultTask
compareTo, configure, dependsOn, doFirst, doFirst, doFirst, doLast, doLast, doLast, finalizedBy, getActions, getAnt, getDependsOn, getDescription, getDestroyables, getDidWork, getEnabled, getExtensions, getFinalizedBy, getGroup, getInputs, getLocalState, getLogger, getLogging, getMustRunAfter, getName, getOutputs, getPath, getProject, getShouldRunAfter, getState, getTaskDependencies, getTemporaryDir, getTimeout, hasProperty, mustRunAfter, onlyIf, onlyIf, onlyIf, property, setActions, setDependsOn, setDescription, setDidWork, setEnabled, setFinalizedBy, setGroup, setMustRunAfter, setOnlyIf, setOnlyIf, setOnlyIf, setProperty, setShouldRunAfter, shouldRunAfter, usesServiceMethods inherited from class org.gradle.api.internal.AbstractTask
acceptServiceReferences, appendParallelSafeAction, doNotTrackState, doNotTrackStateIf, getAsDynamicObject, getIdentityPath, getImpliesSubProjects, getLifecycleDependencies, getOnlyIf, getReasonNotToTrackState, getReasonsNotToTrackState, getReasonTaskIsIncompatibleWithConfigurationCache, getRequiredServices, getServices, getSharedResources, getStandardOutputCapture, getTaskActions, getTaskIdentity, getTemporaryDirFactory, hasTaskActions, injectIntoNewInstance, isCompatibleWithConfigurationCache, isEnabled, isHasCustomActions, notCompatibleWithConfigurationCache, prependParallelSafeAction, restoreOnlyIf, restoreTaskActions, setImpliesSubProjectsMethods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface org.gradle.api.Task
doNotTrackState, notCompatibleWithConfigurationCache
-
Field Details
-
NAME
任务名:消费侧(本仓库的测试与诊断)按它引用产出任务.- See Also:
-
BRANCH_MCP_RENAME
分支:跑 MCP 的rename步(现代 Forge / NeoForge 的常规形态).- See Also:
-
BRANCH_MCP_UNOBFUSCATED
分支:跑 MCP 的merge/preProcessJar步(disableObfuscation / unobfuscated 形态).与
BRANCH_MCP_RENAME共用同一个McpExecutor实现与同一条落位路径, 唯一区别是排队哪一步:配置期的createUnobfuscatedPrePatchJar排的是isNeoForge() ? "preProcessJar" : "merge"(1.7-1.16 的 FG2 形态另有实现,不走这里)。 步进集合因此仍只有一处定义,两条路径不会分叉。- See Also:
-
BRANCH_NEOFORGE_INSTALLER_TOOLS
分支:NeoForge installer tools 的PROCESS_MINECRAFT_JAR(见 NeoForge#2848 的绕行).- See Also:
-
-
Constructor Details
-
GenerateForgePrePatchJarTask
public GenerateForgePrePatchJarTask()
-
-
Method Details
-
getBranch
本次走哪条分支(配置期算好的纯值). -
getMcpOptions
MCP 执行器选项(BRANCH_MCP_RENAME/BRANCH_MCP_UNOBFUSCATED);其余分支下不设置. -
getInstallerTools
@Optional public abstract org.gradle.api.provider.Property<ForgeExternalToolService.Options> getInstallerTools()NeoForge installer tools 的声明式选项(BRANCH_NEOFORGE_INSTALLER_TOOLS);另一条分支下不设置. -
getClientMappingsUrl
installer tools 分支要下载的 client 映射地址;另一条分支下不设置. -
getOffline
是否处于 Gradle 的离线模式(与配置期extension.download同判据). -
getManualRefreshDeps
是否显式要求刷新依赖(与配置期extension.download同判据). -
getMcpWorkDir
@Internal public abstract org.gradle.api.file.DirectoryProperty getMcpWorkDir()MCP 执行链的工作目录.@Internal:它只决定中间文件放在哪里,不决定产物内容——配置期路径每次都用新的随机临时目录, 产物却逐字节相同(见类注释)。 -
getOutputJar
@OutputFile public abstract org.gradle.api.file.RegularFileProperty getOutputJar()产物:pre-patch jar(与配置期同一条路径). -
getReuseIdentity
本次执行的身份前缀:决定「该产出什么」的那些纯值(分支、平台、MC/Forge 版本、side、命名空间).@Input而不只是「日志用」:它参与 Gradle 的 up-to-date 判定,也参与下面那条复用判据的键 (见ForgePrePatchJarReuse)。配置期拼好,执行期不再回读项目模型。 -
getReuseInputs
@Internal public abstract org.gradle.api.file.ConfigurableFileCollection getReuseInputs()本次执行的输入文件:它们的内容决定产物内容,因而参与复用判据的键.这些路径**不**作为
@InputFile声明(除了下面已经声明过的输入):它们在任务里本以「路径」形式 出现(McpExecutor.Options的初始配置、installer tools 的参数模板),并不等价于「本任务的输入」—— 两条分支读的集合不同,误声明会让任务在 1.17 及更早的非 bundle 版本上以「输入文件不存在」失败。 故它们只用于复用判据:@Internal,不影响 Gradle 的输入快照与缓存键。 -
generate
- Throws:
Exception
-