Attempt to correct mappings around SpecialSource2's synthetic mangling

This commit is contained in:
Kyle Wood 2020-12-04 17:11:31 -08:00
parent 141567c6c4
commit db45b1803b
29 changed files with 1339 additions and 781 deletions

View file

@ -16,25 +16,32 @@ repositories {
mavenCentral()
maven("https://oss.sonatype.org/content/repositories/snapshots/")
maven("https://files.minecraftforge.net/maven/")
maven("https://maven.fabricmc.net/")
mavenLocal()
}
dependencies {
implementation("org.apache.httpcomponents:httpclient:4.5.12")
implementation("org.apache.httpcomponents:httpclient:4.5.13")
// Utils
implementation("net.sf.opencsv:opencsv:2.3")
implementation("com.opencsv:opencsv:5.3")
implementation("com.github.salomonbrys.kotson:kotson:2.5.0")
// ASM for inspection
implementation("org.ow2.asm:asm:8.0.1")
val asmVersion = "9.0"
implementation("org.ow2.asm:asm:$asmVersion")
implementation("org.ow2.asm:asm-tree:$asmVersion")
// Cadix
implementation("org.cadixdev:lorenz:0.5.5")
implementation("org.cadixdev:lorenz-asm:0.5.5")
val lorenzVersion = "0.5.6"
implementation("org.cadixdev:lorenz:$lorenzVersion")
implementation("org.cadixdev:lorenz-asm:$lorenzVersion")
implementation("org.cadixdev:lorenz-io-proguard:$lorenzVersion")
implementation("org.cadixdev:atlas:0.2.0")
implementation("org.cadixdev:at:0.1.0-SNAPSHOT")
implementation("org.cadixdev:at:0.1.0-rc1")
implementation("org.cadixdev:mercury:0.1.0-PW0-SNAPSHOT")
implementation("org.cadixdev:mercury:0.1.0-SNAPSHOT")
implementation("net.fabricmc:lorenz-tiny:3.0.0")
}
tasks.withType<KotlinCompile> {

View file

@ -30,12 +30,10 @@ import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.string
import com.google.gson.JsonObject
import io.papermc.paperweight.ext.PaperweightExtension
import io.papermc.paperweight.tasks.AddMissingSpigotClassMappings
import io.papermc.paperweight.tasks.AddAdditionalSpigotMappings
import io.papermc.paperweight.tasks.ApplyDiffPatches
import io.papermc.paperweight.tasks.ApplyGitPatches
import io.papermc.paperweight.tasks.ApplyMcpPatches
import io.papermc.paperweight.tasks.ApplyPaperPatches
import io.papermc.paperweight.tasks.ApplySourceAt
import io.papermc.paperweight.tasks.DecompileVanillaJar
import io.papermc.paperweight.tasks.DownloadMcLibraries
import io.papermc.paperweight.tasks.DownloadMcpFiles
@ -47,18 +45,17 @@ import io.papermc.paperweight.tasks.ExtractMappings
import io.papermc.paperweight.tasks.ExtractMcp
import io.papermc.paperweight.tasks.Filter
import io.papermc.paperweight.tasks.FilterExcludes
import io.papermc.paperweight.tasks.GenerateSpigotSrgs
import io.papermc.paperweight.tasks.GenerateSrgs
import io.papermc.paperweight.tasks.FixJar
import io.papermc.paperweight.tasks.GenerateSpigotMappings
import io.papermc.paperweight.tasks.GenerateMappings
import io.papermc.paperweight.tasks.InspectVanillaJar
import io.papermc.paperweight.tasks.Merge
import io.papermc.paperweight.tasks.MergeAccessTransforms
import io.papermc.paperweight.tasks.PatchMcpCsv
import io.papermc.paperweight.tasks.PatchMappings
import io.papermc.paperweight.tasks.RemapAccessTransform
import io.papermc.paperweight.tasks.RemapJar
import io.papermc.paperweight.tasks.RemapSpigotAt
import io.papermc.paperweight.tasks.RemapVanillaJarSpigot
import io.papermc.paperweight.tasks.RunForgeFlower
import io.papermc.paperweight.tasks.RunMcInjector
import io.papermc.paperweight.tasks.RunSpecialSource
import io.papermc.paperweight.tasks.SetupMcLibraries
import io.papermc.paperweight.tasks.WriteLibrariesFile
import io.papermc.paperweight.tasks.patchremap.ApplyAccessTransform
@ -100,11 +97,20 @@ class Paperweight : Plugin<Project> {
// Make sure the submodules are initialized
Git(target.projectDir)("submodule", "update", "--init").execute()
target.configurations.create(Constants.YARN_CONFIG)
target.configurations.create(Constants.REMAPPER_CONFIG)
target.repositories.apply {
mavenCentral()
// Both of these are needed for Spigot
maven("https://oss.sonatype.org/content/repositories/snapshots/")
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
maven("https://maven.fabricmc.net/") {
content {
onlyForConfigurations(Constants.YARN_CONFIG, Constants.REMAPPER_CONFIG)
}
}
}
target.createTasks(downloadService)
@ -120,18 +126,28 @@ class Paperweight : Plugin<Project> {
createPatchRemapTasks(initialTasks, generalTasks, mcpTasks, spigotTasks)
val applySourceAt by tasks.registering<ApplySourceAt> {
inputZip.set(mcpTasks.applyMcpPatches.flatMap { it.outputZip })
vanillaJar.set(generalTasks.downloadServerJar.flatMap { it.outputJar })
vanillaRemappedSrgJar.set(mcpTasks.remapVanillaJarSrg.flatMap { it.outputJar })
val applyMergedAt by tasks.registering<ApplyAccessTransform> {
inputJar.set(mcpTasks.fixJar.flatMap { it.outputJar })
atFile.set(spigotTasks.mergeGeneratedAts.flatMap { it.outputFile })
}
val mergeRemappedSources by tasks.registering<Merge> {
inputJars.add(spigotTasks.remapSpigotSources.flatMap { it.outputZip })
inputJars.add(applySourceAt.flatMap { it.outputZip })
val writeLibrariesFile by tasks.registering<WriteLibrariesFile> {
libraries.set(mcpTasks.downloadMcLibraries.flatMap { it.outputDir })
}
val decompileVanillaJarYarn by tasks.registering<RunForgeFlower> {
executable.set(initialTasks.downloadMcpTools.flatMap { it.forgeFlowerFile })
configFile.set(initialTasks.extractMcp.flatMap { it.configFile })
inputJar.set(applyMergedAt.flatMap { it.outputJar })
libraries.set(writeLibrariesFile.flatMap { it.outputFile })
}
// val mergeRemappedSources by tasks.registering<Merge> {
// inputJars.add(spigotTasks.remapSpigotSources.flatMap { it.outputZip })
// inputJars.add(applySourceAt.flatMap { it.outputZip })
// }
val patchPaperApi by tasks.registering<ApplyGitPatches> {
branch.set("HEAD")
upstreamBranch.set("upstream")
@ -144,8 +160,11 @@ class Paperweight : Plugin<Project> {
val patchPaperServer by tasks.registering<ApplyPaperPatches> {
patchDir.set(extension.paper.spigotServerPatchDir)
remappedSource.set(mergeRemappedSources.flatMap { it.outputJar })
remappedSource.set(spigotTasks.remapSpigotSources.flatMap { it.outputZip })
templateGitIgnore.set(layout.projectDirectory.file(".gitignore"))
sourceMcDevJar.set(decompileVanillaJarYarn.flatMap { it.outputJar })
mcLibrariesDir.set(mcpTasks.downloadMcLibraries.flatMap { it.outputDir }.get())
libraryImports.set(extension.paper.libraryClassImports)
outputDir.set(extension.paper.paperServerDir)
}
@ -171,6 +190,7 @@ class Paperweight : Plugin<Project> {
// Shared task containers
data class InitialTasks(
val setupMcLibraries: TaskProvider<SetupMcLibraries>,
val downloadMappings: TaskProvider<DownloadTask>,
val extractMcp: Provider<ExtractMcp>,
val mcpMappings: Provider<ExtractMappings>,
val downloadMcpTools: TaskProvider<DownloadMcpTools>
@ -183,14 +203,13 @@ class Paperweight : Plugin<Project> {
)
data class McpTasks(
val generateSrgs: TaskProvider<GenerateSrgs>,
val remapVanillaJarSrg: TaskProvider<RunSpecialSource>,
val downloadMcLibraries: TaskProvider<DownloadMcLibraries>,
val applyMcpPatches: TaskProvider<ApplyMcpPatches>
val generateMappings: TaskProvider<GenerateMappings>,
val fixJar: TaskProvider<FixJar>,
val downloadMcLibraries: TaskProvider<DownloadMcLibraries>
)
data class SpigotTasks(
val generateSpigotSrgs: TaskProvider<GenerateSpigotSrgs>,
val patchMappings: TaskProvider<PatchMappings>,
val decompileVanillaJarSpigot: TaskProvider<DecompileVanillaJar>,
val patchSpigotApi: TaskProvider<ApplyGitPatches>,
val patchSpigotServer: TaskProvider<ApplyGitPatches>,
@ -231,6 +250,15 @@ class Paperweight : Plugin<Project> {
outputFile.set(cache.resolve(Constants.MC_LIBRARIES))
}
val downloadMappings by tasks.registering<DownloadTask> {
url.set(versionManifest.map { version ->
version["downloads"]["server_mappings"]["url"].string
})
outputFile.set(cache.resolve(Constants.SERVER_MAPPINGS))
downloader.set(downloadService)
}
val downloadMcpFiles by tasks.registering<DownloadMcpFiles> {
mcpMinecraftVersion.set(extension.mcpMinecraftVersion)
mcpConfigVersion.set(extension.mcpConfigVersion)
@ -265,6 +293,7 @@ class Paperweight : Plugin<Project> {
return InitialTasks(
setupMcLibraries,
downloadMappings,
extractMcpConfig,
extractMcpMappings,
downloadMcpTools
@ -298,55 +327,57 @@ class Paperweight : Plugin<Project> {
): McpTasks {
val filterVanillaJar: TaskProvider<Filter> = generalTasks.filterVanillaJar
val cache: File = layout.cache
val extension: PaperweightExtension = ext
val mcpRewrites by tasks.registering<PatchMcpCsv> {
fieldsCsv.set(initialTasks.mcpMappings.flatMap { it.fieldsCsv })
methodsCsv.set(initialTasks.mcpMappings.flatMap { it.methodsCsv })
paramsCsv.set(initialTasks.mcpMappings.flatMap { it.paramsCsv })
changesFile.set(extension.paper.mcpRewritesFile)
paperFieldCsv.set(cache.resolve(Constants.PAPER_FIELDS_CSV))
paperMethodCsv.set(cache.resolve(Constants.PAPER_METHODS_CSV))
paperParamCsv.set(cache.resolve(Constants.PAPER_PARAMS_CSV))
}
val generateSrgs by tasks.registering<GenerateSrgs> {
inSrg.set(initialTasks.extractMcp.flatMap { it.mappings })
methodsCsv.set(mcpRewrites.flatMap { it.paperMethodCsv })
fieldsCsv.set(mcpRewrites.flatMap { it.paperFieldCsv })
extraNotchSrgMappings.set(extension.paper.extraNotchSrgMappings)
// val mcpRewrites by tasks.registering<PatchMcpCsv> {
// fieldsCsv.set(initialTasks.mcpMappings.flatMap { it.fieldsCsv })
// methodsCsv.set(initialTasks.mcpMappings.flatMap { it.methodsCsv })
// paramsCsv.set(initialTasks.mcpMappings.flatMap { it.paramsCsv })
// changesFile.set(extension.paper.mcpRewritesFile)
//
// paperFieldCsv.set(cache.resolve(Constants.PAPER_FIELDS_CSV))
// paperMethodCsv.set(cache.resolve(Constants.PAPER_METHODS_CSV))
// paperParamCsv.set(cache.resolve(Constants.PAPER_PARAMS_CSV))
// }
val generateMappings by tasks.registering<GenerateMappings> {
vanillaJar.set(generalTasks.filterVanillaJar.flatMap { it.outputJar })
notchToSrg.set(cache.resolve(Constants.NOTCH_TO_SRG))
notchToMcp.set(cache.resolve(Constants.NOTCH_TO_MCP))
srgToNotch.set(cache.resolve(Constants.SRG_TO_NOTCH))
srgToMcp.set(cache.resolve(Constants.SRG_TO_MCP))
mcpToNotch.set(cache.resolve(Constants.MCP_TO_NOTCH))
mcpToSrg.set(cache.resolve(Constants.MCP_TO_SRG))
vanillaMappings.set(initialTasks.downloadMappings.flatMap { it.outputFile })
yarnMappings.fileProvider(configurations.named(Constants.YARN_CONFIG).map { it.singleFile })
outputMappings.set(cache.resolve(Constants.SRG_DIR).resolve("merged.tiny"))
}
val remapVanillaJarSrg by tasks.registering<RunSpecialSource> {
val remapJar by tasks.registering<RemapJar> {
inputJar.set(filterVanillaJar.flatMap { it.outputJar })
mappings.set(generateSrgs.flatMap { it.notchToSrg })
executable.set(initialTasks.downloadMcpTools.flatMap { it.specialSourceFile })
configFile.set(initialTasks.extractMcp.flatMap { it.configFile })
mappingsFile.set(generateMappings.flatMap { it.outputMappings })
remapper.fileProvider(configurations.named(Constants.REMAPPER_CONFIG).map { it.singleFile })
}
val injectVanillaJarSrg by tasks.registering<RunMcInjector> {
executable.set(initialTasks.downloadMcpTools.flatMap { it.mcInjectorFile })
configFile.set(initialTasks.extractMcp.flatMap { it.configFile })
exceptions.set(initialTasks.extractMcp.flatMap { it.exceptions })
access.set(initialTasks.extractMcp.flatMap { it.access })
constructors.set(initialTasks.extractMcp.flatMap { it.constructors })
inputJar.set(remapVanillaJarSrg.flatMap { it.outputJar })
val fixJar by tasks.registering<FixJar> {
// executable.set(initialTasks.downloadMcpTools.flatMap { it.mcInjectorFile })
inputJar.set(remapJar.flatMap { it.outputJar })
}
// val remapVanillaJarSrg by tasks.registering<RunSpecialSource> {
// inputJar.set(filterVanillaJar.flatMap { it.outputJar })
// mappings.set(generateSrgs.flatMap { it.notchToSrg })
//
// executable.set(initialTasks.downloadMcpTools.flatMap { it.specialSourceFile })
// configFile.set(initialTasks.extractMcp.flatMap { it.configFile })
// }
//
// val injectVanillaJarSrg by tasks.registering<RunMcInjector> {
// executable.set(initialTasks.downloadMcpTools.flatMap { it.mcInjectorFile })
// configFile.set(initialTasks.extractMcp.flatMap { it.configFile })
//
// exceptions.set(initialTasks.extractMcp.flatMap { it.exceptions })
// access.set(initialTasks.extractMcp.flatMap { it.access })
// constructors.set(initialTasks.extractMcp.flatMap { it.constructors })
//
// inputJar.set(remapVanillaJarSrg.flatMap { it.outputJar })
// }
val downloadMcLibraries by tasks.registering<DownloadMcLibraries> {
mcLibrariesFile.set(initialTasks.setupMcLibraries.flatMap { it.outputFile })
mcRepo.set(Constants.MC_LIBRARY_URL)
@ -354,26 +385,14 @@ class Paperweight : Plugin<Project> {
downloader.set(downloadService)
}
//
// val applyMcpPatches by tasks.registering<ApplyMcpPatches> {
// inputZip.set(decompileVanillaJarSrg.flatMap { it.outputJar })
// serverPatchDir.set(initialTasks.extractMcp.flatMap { it.patchDir })
// configFile.set(cache.resolve(Constants.MCP_CONFIG_JSON))
// }
val writeLibrariesFile by tasks.registering<WriteLibrariesFile> {
libraries.set(downloadMcLibraries.flatMap { it.outputDir })
}
val decompileVanillaJarSrg by tasks.registering<RunForgeFlower> {
executable.set(initialTasks.downloadMcpTools.flatMap { it.forgeFlowerFile })
configFile.set(initialTasks.extractMcp.flatMap { it.configFile })
inputJar.set(injectVanillaJarSrg.flatMap { it.outputJar })
libraries.set(writeLibrariesFile.flatMap { it.outputFile })
}
val applyMcpPatches by tasks.registering<ApplyMcpPatches> {
inputZip.set(decompileVanillaJarSrg.flatMap { it.outputJar })
serverPatchDir.set(initialTasks.extractMcp.flatMap { it.patchDir })
configFile.set(cache.resolve(Constants.MCP_CONFIG_JSON))
}
return McpTasks(generateSrgs, remapVanillaJarSrg, downloadMcLibraries, applyMcpPatches)
return McpTasks(generateMappings, fixJar, downloadMcLibraries)
}
private fun Project.createSpigotTasks(
@ -386,35 +405,38 @@ class Paperweight : Plugin<Project> {
val extension: PaperweightExtension = ext
val (buildDataInfo, downloadServerJar, filterVanillaJar) = generalTasks
val (generateSrgs, _, _) = mcpTasks
val (generateMappings, _, _) = mcpTasks
val addMissingSpigotClassMappings by tasks.registering<AddMissingSpigotClassMappings> {
val addAdditionalSpigotMappings by tasks.registering<AddAdditionalSpigotMappings> {
classSrg.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.classMappings }))
memberSrg.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.memberMappings }))
missingClassEntriesSrg.set(extension.paper.missingClassEntriesSrgFile)
missingMemberEntriesSrg.set(extension.paper.missingMemberEntriesSrgFile)
additionalClassEntriesSrg.set(extension.paper.additionalSpigotClassMappings)
additionalMemberEntriesSrg.set(extension.paper.additionalSpigotMemberMappings)
}
val inspectVanillaJar by tasks.registering<InspectVanillaJar> {
inputJar.set(downloadServerJar.flatMap { it.outputJar })
}
val generateSpigotSrgs by tasks.registering<GenerateSpigotSrgs> {
notchToSrg.set(generateSrgs.flatMap { it.notchToSrg })
srgToMcp.set(generateSrgs.flatMap { it.srgToMcp })
classMappings.set(addMissingSpigotClassMappings.flatMap { it.outputClassSrg })
memberMappings.set(addMissingSpigotClassMappings.flatMap { it.outputMemberSrg })
val generateSpigotMappings by tasks.registering<GenerateSpigotMappings> {
classMappings.set(addAdditionalSpigotMappings.flatMap { it.outputClassSrg })
memberMappings.set(addAdditionalSpigotMappings.flatMap { it.outputMemberSrg })
packageMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.packageMappings }))
extraSpigotSrgMappings.set(extension.paper.extraSpigotSrgMappings)
loggerFields.set(inspectVanillaJar.flatMap { it.outputFile })
vanillaJar.set(filterVanillaJar.flatMap { it.outputJar })
spigotToSrg.set(cache.resolve(Constants.SPIGOT_TO_SRG))
spigotToMcp.set(cache.resolve(Constants.SPIGOT_TO_MCP))
spigotToNotch.set(cache.resolve(Constants.SPIGOT_TO_NOTCH))
srgToSpigot.set(cache.resolve(Constants.SRG_TO_SPIGOT))
mcpToSpigot.set(cache.resolve(Constants.MCP_TO_SPIGOT))
notchToSpigot.set(cache.resolve(Constants.NOTCH_TO_SPIGOT))
loggerFields.set(inspectVanillaJar.flatMap { it.loggerFile })
paramIndexes.set(inspectVanillaJar.flatMap { it.paramIndexes })
syntheticMethods.set(inspectVanillaJar.flatMap { it.syntheticMethods })
sourceMappings.set(generateMappings.flatMap { it.outputMappings })
outputMappings.set(cache.resolve(Constants.SRG_DIR).resolve("spigot-named.tiny"))
}
val patchMappings by tasks.registering<PatchMappings> {
inputMappings.set(generateSpigotMappings.flatMap { it.outputMappings })
patchMappings.set(extension.paper.mappingsPatch)
outputMappings.set(cache.resolve(Constants.SRG_DIR).resolve("spigot-named-patched.tiny"))
}
val remapVanillaJarSpigot by tasks.registering<RemapVanillaJarSpigot> {
@ -487,14 +509,14 @@ class Paperweight : Plugin<Project> {
val remapSpigotAt by tasks.registering<RemapSpigotAt> {
inputJar.set(remapVanillaJarSpigot.flatMap { it.outputJar })
mapping.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
mapping.set(patchMappings.flatMap { it.outputMappings })
spigotAt.set(extension.craftBukkit.atFile)
}
val remapSpigotSources by tasks.registering<RemapSources> {
spigotServerDir.set(patchSpigotServer.flatMap { it.outputDir })
spigotApiDir.set(patchSpigotApi.flatMap { it.outputDir })
mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
mappings.set(patchMappings.flatMap { it.outputMappings })
vanillaJar.set(downloadServerJar.flatMap { it.outputJar })
vanillaRemappedSpigotJar.set(removeSpigotExcludes.flatMap { it.outputZip })
spigotDeps.set(downloadSpigotDependencies.flatMap { it.outputDir })
@ -503,7 +525,7 @@ class Paperweight : Plugin<Project> {
val remapGeneratedAt by tasks.registering<RemapAccessTransform> {
inputFile.set(remapSpigotSources.flatMap { it.generatedAt })
mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
mappings.set(patchMappings.flatMap { it.outputMappings })
}
val mergeGeneratedAts by tasks.registering<MergeAccessTransforms> {
@ -512,7 +534,7 @@ class Paperweight : Plugin<Project> {
}
return SpigotTasks(
generateSpigotSrgs,
patchMappings,
decompileVanillaJarSpigot,
patchSpigotApi,
patchSpigotServer,
@ -540,7 +562,7 @@ class Paperweight : Plugin<Project> {
*/
val applyVanillaSrgAt by tasks.registering<ApplyAccessTransform> {
inputJar.set(mcpTasks.remapVanillaJarSrg.flatMap { it.outputJar })
inputJar.set(mcpTasks.fixJar.flatMap { it.outputJar })
atFile.set(spigotTasks.mergeGeneratedAts.flatMap { it.outputFile })
}
@ -564,7 +586,7 @@ class Paperweight : Plugin<Project> {
// sourceJar.set(spigotTasks.remapSpigotSources.flatMap { it.outputZip }.get())
apiPatchDir.set(extension.paper.spigotApiPatchDir)
mappingsFile.set(spigotTasks.generateSpigotSrgs.flatMap { it.spigotToSrg }.get())
mappingsFile.set(spigotTasks.patchMappings.flatMap { it.outputMappings }.get())
// Pull in as many jars as possible to reduce the possibility of type bindings not resolving
classpathJars.add(generalTasks.downloadServerJar.flatMap { it.outputJar }.get())

View file

@ -39,19 +39,15 @@ open class PaperExtension(objects: ObjectFactory, layout: ProjectLayout) {
@Suppress("MemberVisibilityCanBePrivate")
val mcpDir: DirectoryProperty = objects.dirWithDefault(layout, "mcp")
val mcpRewritesFile: RegularFileProperty = objects.fileFrom(mcpDir, "mcp-rewrites.txt")
val missingClassEntriesSrgFile: RegularFileProperty = objects.fileFrom(mcpDir, "missing-spigot-class-mappings.csrg")
val missingMemberEntriesSrgFile: RegularFileProperty = objects.fileFrom(mcpDir, "missing-spigot-member-mappings.csrg")
val extraNotchSrgMappings: RegularFileProperty = objects.fileFrom(mcpDir, "extra-notch-srg.tsrg")
val extraSpigotSrgMappings: RegularFileProperty = objects.fileFrom(mcpDir, "extra-spigot-srg.tsrg")
val additionalSpigotClassMappings: RegularFileProperty = objects.fileProperty()
val additionalSpigotMemberMappings: RegularFileProperty = objects.fileProperty()
val libraryClassImports: RegularFileProperty = objects.fileFrom(mcpDir, "library-imports.txt")
val mappingsPatch: RegularFileProperty = objects.fileProperty()
init {
spigotApiPatchDir.disallowUnsafeRead()
spigotServerPatchDir.disallowUnsafeRead()
paperApiDir.disallowUnsafeRead()
paperServerDir.disallowUnsafeRead()
mcpRewritesFile.disallowUnsafeRead()
}
}

View file

@ -32,7 +32,7 @@ import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class AddMissingSpigotClassMappings : BaseTask() {
abstract class AddAdditionalSpigotMappings : BaseTask() {
@get:InputFile
abstract val classSrg: RegularFileProperty
@ -40,10 +40,10 @@ abstract class AddMissingSpigotClassMappings : BaseTask() {
abstract val memberSrg: RegularFileProperty
@get:Optional
@get:InputFile
abstract val missingClassEntriesSrg: RegularFileProperty
abstract val additionalClassEntriesSrg: RegularFileProperty
@get:Optional
@get:InputFile
abstract val missingMemberEntriesSrg: RegularFileProperty
abstract val additionalMemberEntriesSrg: RegularFileProperty
@get:OutputFile
abstract val outputClassSrg: RegularFileProperty
@ -57,8 +57,8 @@ abstract class AddMissingSpigotClassMappings : BaseTask() {
@TaskAction
fun run() {
addLines(classSrg.file, missingClassEntriesSrg.fileOrNull, outputClassSrg.file)
addLines(memberSrg.file, missingMemberEntriesSrg.fileOrNull, outputMemberSrg.file)
addLines(classSrg.file, additionalClassEntriesSrg.fileOrNull, outputClassSrg.file)
addLines(memberSrg.file, additionalMemberEntriesSrg.fileOrNull, outputMemberSrg.file)
}
private fun addLines(inFile: File, appendFile: File?, outputFile: File) {

View file

@ -1,49 +0,0 @@
/*
* paperweight is a Gradle plugin for the PaperMC project. It uses
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Git
import java.io.File
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
abstract class ApplyMcpPatches : ZippedTask() {
@get:InputDirectory
abstract val serverPatchDir: DirectoryProperty
@get:InputFile
abstract val configFile: RegularFileProperty
override fun run(rootDir: File) {
val git = Git(rootDir)
val extension = ".java.patch"
objects.fileTree().from(serverPatchDir).matching {
include("**/*$extension")
}.forEach { patch ->
git("apply", "--ignore-whitespace", patch.absolutePath).executeSilently()
}
}
}

View file

@ -23,6 +23,7 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.McDev
import io.papermc.paperweight.util.file
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
@ -39,6 +40,12 @@ abstract class ApplyPaperPatches : ControllableOutputTask() {
abstract val remappedSource: RegularFileProperty
@get:InputFile
abstract val templateGitIgnore: RegularFileProperty
@get:InputFile
abstract val sourceMcDevJar: RegularFileProperty
@get:InputDirectory
abstract val mcLibrariesDir: DirectoryProperty
@get:InputFile
abstract val libraryImports: RegularFileProperty
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@ -78,6 +85,9 @@ abstract class ApplyPaperPatches : ControllableOutputTask() {
into(sourceDir)
}
val patches = patchDir.file.listFiles { _, name -> name.endsWith(".patch") } ?: emptyArray()
McDev.importMcDev(patches, sourceMcDevJar.file, libraryImports.file, mcLibrariesDir.file, sourceDir)
templateGitIgnore.file.copyTo(outputFile.resolve(".gitignore"))
git("add", ".gitignore", ".").executeSilently()

View file

@ -0,0 +1,154 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.AsmUtil
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import java.io.ByteArrayInputStream
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.tree.AnnotationNode
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.MethodNode
abstract class FixJar : BaseTask(), AsmUtil {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
JarOutputStream(outputJar.file.outputStream()).use { out ->
JarFile(inputJar.file).use { jarFile ->
for (entry in jarFile.entries()) {
if (!entry.name.endsWith(".class")) {
out.putNextEntry(entry)
try {
jarFile.getInputStream(entry).copyTo(out)
} finally {
out.closeEntry()
}
continue
}
val classData = if (entry.size != -1L) {
ByteArray(entry.size.toInt()).also { data ->
jarFile.getInputStream(entry).readNBytes(data, 0, data.size)
}
} else {
jarFile.getInputStream(entry).readAllBytes()
}
try {
val node = ClassNode(Opcodes.ASM9)
var visitor: ClassVisitor = node
visitor = ParameterAnnotationFixer(node, visitor)
val reader = ClassReader(classData)
reader.accept(visitor, 0)
val writer = ClassWriter(0)
node.accept(writer)
out.putNextEntry(ZipEntry(entry.name))
out.write(writer.toByteArray())
out.flush()
} finally {
out.closeEntry()
}
}
}
}
}
}
class ParameterAnnotationFixer(
private val node: ClassNode,
classVisitor: ClassVisitor?
) : ClassVisitor(Opcodes.ASM9, classVisitor), AsmUtil {
override fun visitEnd() {
super.visitEnd()
val expected = expectedSyntheticParams() ?: return
for (method in node.methods) {
if (method.name == "<init>") {
processConstructor(method, expected)
}
}
}
private fun expectedSyntheticParams(): List<Type>? {
if (Opcodes.ACC_ENUM in node.access) {
return listOf(Type.getObjectType("java/lang/String"), Type.INT_TYPE)
}
val innerNode = node.innerClasses.firstOrNull { it.name == node.name } ?: return null
if (innerNode.innerName == null || (Opcodes.ACC_STATIC or Opcodes.ACC_INTERFACE) in innerNode.access) {
return null
}
return listOf(Type.getObjectType(innerNode.outerName))
}
private fun processConstructor(method: MethodNode, synthParams: List<Type>) {
val params = Type.getArgumentTypes(method.desc).asList()
if (!params.beginsWith(synthParams)) {
return
}
method.visibleParameterAnnotations = process(params.size, synthParams.size, method.visibleParameterAnnotations)
method.invisibleParameterAnnotations = process(params.size, synthParams.size, method.invisibleParameterAnnotations)
method.visibleParameterAnnotations?.let {
method.visibleAnnotableParameterCount = it.size
}
method.invisibleParameterAnnotations?.let {
method.invisibleAnnotableParameterCount = it.size
}
}
private fun process(
paramCount: Int,
synthCount: Int,
annotations: Array<List<AnnotationNode>>?
): Array<List<AnnotationNode>>? {
if (annotations == null) {
return null
}
if (paramCount == annotations.size) {
return annotations.copyOfRange(synthCount, paramCount)
}
return annotations
}
private fun <T> List<T>.beginsWith(other: List<T>): Boolean {
if (this.size < other.size) {
return false
}
for (i in other.indices) {
if (this[i] != other[i]) {
return false
}
}
return true
}
}

View file

@ -0,0 +1,240 @@
/*
* paperweight is a Gradle plugin for the PaperMC project. It uses
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.path
import java.nio.file.FileSystems
import java.nio.file.Files
import net.fabricmc.lorenztiny.TinyMappingFormat
import org.cadixdev.atlas.Atlas
import org.cadixdev.bombe.asm.jar.JarEntryRemappingTransformer
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.asm.LorenzRemapper
import org.cadixdev.lorenz.io.MappingFormats
import org.cadixdev.lorenz.merge.FieldMergeStrategy
import org.cadixdev.lorenz.merge.MappingSetMerger
import org.cadixdev.lorenz.merge.MappingSetMergerHandler
import org.cadixdev.lorenz.merge.MergeConfig
import org.cadixdev.lorenz.merge.MergeContext
import org.cadixdev.lorenz.merge.MergeResult
import org.cadixdev.lorenz.model.ClassMapping
import org.cadixdev.lorenz.model.FieldMapping
import org.cadixdev.lorenz.model.InnerClassMapping
import org.cadixdev.lorenz.model.MethodMapping
import org.cadixdev.lorenz.model.MethodParameterMapping
import org.cadixdev.lorenz.model.TopLevelClassMapping
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class GenerateMappings : DefaultTask() {
@get:InputFile
abstract val vanillaJar: RegularFileProperty
@get:InputFile
abstract val vanillaMappings: RegularFileProperty
@get:InputFile
abstract val yarnMappings: RegularFileProperty
@get:OutputFile
abstract val outputMappings: RegularFileProperty
@TaskAction
fun run() {
val vanillaMappings = MappingFormats.byId("proguard").createReader(vanillaMappings.path).use { it.read() }.reverse()
val yarnMappings = FileSystems.newFileSystem(yarnMappings.path, null).use { fs ->
val path = fs.getPath("mappings", "mappings.tiny")
TinyMappingFormat.STANDARD.read(path, "official", "named")
}
val merged = MappingSetMerger.create(
vanillaMappings,
yarnMappings,
MergeConfig.builder()
.withFieldMergeStrategy(FieldMergeStrategy.STRICT)
.withMergeHandler(MergeHandler())
.build()
).merge()
// Fill out any missing inheritance info in the mappings
val atlasOut = Files.createTempFile("paperweight", "jar")
try {
Atlas().use { atlas ->
atlas.install { ctx -> JarEntryRemappingTransformer(LorenzRemapper(merged, ctx.inheritanceProvider())) }
atlas.run(vanillaJar.path, atlasOut)
}
} finally {
Files.deleteIfExists(atlasOut)
}
ensureParentExists(outputMappings)
TinyMappingFormat.STANDARD.write(merged, outputMappings.path, Constants.OBF_NAMESPACE, Constants.DEOBF_NAMESPACE)
}
/*
private fun remapAnonymousClasses(mapping: InnerClassMapping, target: ClassMapping<*, *>) {
val newMapping = target.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
remapMembers(mapping, newMapping)
}
private fun <T : ClassMapping<*, *>> remapMembers(mapping: T, newMapping: T) {
for (fieldMapping in mapping.fieldMappings) {
newMapping.createFieldMapping(fieldMapping.obfuscatedName, fieldMapping.deobfuscatedName)
}
for (methodMapping in mapping.methodMappings) {
newMapping.createMethodMapping(methodMapping.signature, methodMapping.deobfuscatedName)
}
for (innerClassMapping in mapping.innerClassMappings) {
remapAnonymousClasses(innerClassMapping, newMapping)
}
}
*/
/*
private fun mergeClass(vanillaMapping: ClassMapping<*, *>, yarnMapping: ClassMapping<*, *>) {
for (vanillaMethod in vanillaMapping.methodMappings) {
val yarnMethod = yarnMapping.getMethodMapping(vanillaMethod.signature).orNull ?: continue
for (yarnParam in yarnMethod.parameterMappings) {
vanillaMethod.getOrCreateParameterMapping(yarnParam.index).deobfuscatedName = yarnParam.deobfuscatedName
}
}
for (vanillaClass in vanillaMapping.innerClassMappings) {
val yarnClass = yarnMapping.getInnerClassMapping(vanillaClass.obfuscatedName).orNull ?: continue
mergeClass(vanillaClass, yarnClass)
}
}
*/
}
class MergeHandler : MappingSetMergerHandler {
override fun mergeTopLevelClassMappings(
left: TopLevelClassMapping,
right: TopLevelClassMapping,
target: MappingSet,
context: MergeContext
): MergeResult<TopLevelClassMapping?> {
throw IllegalStateException("Unexpectedly merged class: ${left.fullObfuscatedName}")
}
override fun mergeDuplicateTopLevelClassMappings(
left: TopLevelClassMapping,
right: TopLevelClassMapping,
rightContinuation: TopLevelClassMapping?,
target: MappingSet,
context: MergeContext
): MergeResult<TopLevelClassMapping?> {
return MergeResult(
target.createTopLevelClassMapping(left.obfuscatedName, left.deobfuscatedName),
right
)
}
override fun mergeInnerClassMappings(
left: InnerClassMapping,
right: InnerClassMapping,
target: ClassMapping<*, *>,
context: MergeContext
): MergeResult<InnerClassMapping?> {
throw IllegalStateException("Unexpectedly merged class: ${left.fullObfuscatedName}")
}
override fun mergeDuplicateInnerClassMappings(
left: InnerClassMapping,
right: InnerClassMapping,
rightContinuation: InnerClassMapping?,
target: ClassMapping<*, *>,
context: MergeContext
): MergeResult<InnerClassMapping?> {
return MergeResult(
target.createInnerClassMapping(left.obfuscatedName, left.deobfuscatedName),
right
)
}
override fun mergeFieldMappings(
left: FieldMapping,
strictRight: FieldMapping?,
looseRight: FieldMapping?,
target: ClassMapping<*, *>,
context: MergeContext
): FieldMapping? {
throw IllegalStateException("Unexpectedly merged field: ${left.fullObfuscatedName}")
}
override fun mergeDuplicateFieldMappings(
left: FieldMapping,
strictRightDuplicate: FieldMapping?,
looseRightDuplicate: FieldMapping?,
strictRightContinuation: FieldMapping?,
looseRightContinuation: FieldMapping?,
target: ClassMapping<*, *>,
context: MergeContext
): FieldMapping? {
return target.createFieldMapping(left.signature, left.deobfuscatedName)
}
override fun addLeftFieldMapping(
left: FieldMapping,
target: ClassMapping<*, *>,
context: MergeContext
): FieldMapping? {
return target.createFieldMapping(left.signature, left.deobfuscatedName)
}
override fun mergeMethodMappings(
left: MethodMapping,
standardRight: MethodMapping?,
wiggledRight: MethodMapping?,
target: ClassMapping<*, *>,
context: MergeContext
): MergeResult<MethodMapping?> {
throw IllegalStateException("Unexpectedly merged method: ${left.fullObfuscatedName}")
}
override fun mergeDuplicateMethodMappings(
left: MethodMapping,
standardRightDuplicate: MethodMapping?,
wiggledRightDuplicate: MethodMapping?,
standardRightContinuation: MethodMapping?,
wiggledRightContinuation: MethodMapping?,
target: ClassMapping<*, *>,
context: MergeContext
): MergeResult<MethodMapping?> {
return MergeResult(
target.createMethodMapping(left.signature, left.deobfuscatedName),
listOfNotNull(standardRightDuplicate, wiggledRightDuplicate)
)
}
override fun mergeParameterMappings(
left: MethodParameterMapping,
right: MethodParameterMapping,
target: MethodMapping,
context: MergeContext
): MethodParameterMapping? {
throw IllegalStateException("Unexpectedly merged method: ${left.fullObfuscatedName}")
}
}

View file

@ -22,15 +22,14 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fileOrNull
import io.papermc.paperweight.util.orNull
import io.papermc.paperweight.util.path
import io.papermc.paperweight.util.writeMappings
import java.nio.file.Files
import org.cadixdev.atlas.Atlas
import org.cadixdev.bombe.asm.jar.JarEntryRemappingTransformer
import java.util.Optional
import net.fabricmc.lorenztiny.TinyMappingFormat
import org.cadixdev.bombe.type.signature.MethodSignature
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.asm.LorenzRemapper
import org.cadixdev.lorenz.io.MappingFormats
import org.cadixdev.lorenz.merge.MappingSetMerger
import org.cadixdev.lorenz.merge.MappingSetMergerHandler
@ -45,110 +44,184 @@ import org.cadixdev.lorenz.model.TopLevelClassMapping
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class GenerateSpigotSrgs : DefaultTask() {
abstract class GenerateSpigotMappings : DefaultTask() {
@get:InputFile
abstract val notchToSrg: RegularFileProperty
@get:InputFile
abstract val srgToMcp: RegularFileProperty
@get:InputFile
abstract val classMappings: RegularFileProperty
@get:InputFile
abstract val memberMappings: RegularFileProperty
@get:InputFile
abstract val packageMappings: RegularFileProperty
@get:Optional
@get:InputFile
abstract val extraSpigotSrgMappings: RegularFileProperty
@get:InputFile
abstract val loggerFields: RegularFileProperty
@get:InputFile
abstract val paramIndexes: RegularFileProperty
@get:InputFile
abstract val syntheticMethods: RegularFileProperty
@get:InputFile
abstract val vanillaJar: RegularFileProperty
abstract val sourceMappings: RegularFileProperty
@get:OutputFile
abstract val spigotToSrg: RegularFileProperty
@get:OutputFile
abstract val spigotToMcp: RegularFileProperty
@get:OutputFile
abstract val spigotToNotch: RegularFileProperty
@get:OutputFile
abstract val srgToSpigot: RegularFileProperty
@get:OutputFile
abstract val mcpToSpigot: RegularFileProperty
@get:OutputFile
abstract val notchToSpigot: RegularFileProperty
abstract val outputMappings: RegularFileProperty
@TaskAction
fun run() {
val classMappingSet = MappingFormats.CSRG.createReader(classMappings.file.toPath()).use { it.read() }
val memberMappingSet = MappingFormats.CSRG.createReader(memberMappings.file.toPath()).use { it.read() }
val classMappingSet = MappingFormats.CSRG.createReader(classMappings.path).use { it.read() }
val memberMappingSet = MappingFormats.CSRG.createReader(memberMappings.path).use { it.read() }
val mergedMappingSet = MappingSetMerger.create(classMappingSet, memberMappingSet).merge()
for (line in loggerFields.file.readLines(Charsets.UTF_8)) {
val (className, fieldName) = line.split(' ')
val classMapping = mergedMappingSet.getClassMapping(className).orElse(null) ?: continue
classMapping.getOrCreateFieldMapping(fieldName).deobfuscatedName = "LOGGER"
classMapping.getOrCreateFieldMapping(fieldName, "Lorg/apache/logging/log4j/Logger;").deobfuscatedName = "LOGGER"
}
// Get the new package name
val newPackage = packageMappings.asFile.get().readLines()[0].split(Regex("\\s+"))[1]
// We'll use notch->srg to pick up any classes spigot doesn't map for the package mapping
val notchToSrgSet = MappingFormats.TSRG.createReader(notchToSrg.file.toPath()).use { it.read() }
val sourceMappings = TinyMappingFormat.STANDARD.read(sourceMappings.path, Constants.OBF_NAMESPACE, Constants.DEOBF_NAMESPACE)
val synths = hashMapOf<String, MutableMap<String, MutableMap<String, String>>>()
syntheticMethods.file.useLines { lines ->
for (line in lines) {
val (className, desc, synthName, baseName) = line.split(" ")
synths.computeIfAbsent(className) { hashMapOf() }
.computeIfAbsent(desc) { hashMapOf() }[baseName] = synthName
}
}
val notchToSpigotSet = MappingSetMerger.create(
mergedMappingSet,
notchToSrgSet,
sourceMappings,
MergeConfig.builder()
.withMergeHandler(SpigotPackageMergerHandler(newPackage))
.withMergeHandler(SpigotPackageMergerHandler(newPackage, synths))
.build()
).merge()
// TODO Not sure if this is still needed here since it's already ran in GenerateSrgs too now
// notch <-> spigot is incomplete here, it would result in inheritance issues to work with this incomplete set.
// so we use it once to remap some jar, which fills out the inheritance data
// val atlasOut = Files.createTempFile("paperweight", "jar")
// try {
// Atlas().use { atlas ->
// atlas.install { ctx -> JarEntryRemappingTransformer(LorenzRemapper(notchToSpigotSet, ctx.inheritanceProvider())) }
// atlas.run(vanillaJar.path, atlasOut)
// }
// } finally {
// Files.deleteIfExists(atlasOut)
// }
val adjustedSourceMappings = adjustParamIndexes(sourceMappings)
val srgToMcpSet = MappingFormats.TSRG.createReader(srgToMcp.file.toPath()).use { it.read() }
val spigotToNamedSet = MappingSetMerger.create(
notchToSpigotSet.reverse(),
adjustedSourceMappings
).merge()
val spigotToSrgSet = MappingSetMerger.create(notchToSpigotSet.reverse(), notchToSrgSet).merge()
extraSpigotSrgMappings.fileOrNull?.toPath()?.let { path ->
MappingFormats.TSRG.createReader(path).use { it.read(spigotToSrgSet) }
TinyMappingFormat.STANDARD.write(spigotToNamedSet, outputMappings.path, Constants.SPIGOT_NAMESPACE, Constants.DEOBF_NAMESPACE)
}
private fun adjustParamIndexes(mappings: MappingSet): MappingSet {
val indexes = hashMapOf<String, HashMap<String, HashMap<Int, Int>>>()
paramIndexes.file.useLines { lines ->
lines.forEach { line ->
val parts = line.split(" ")
val (className, methodName, descriptor) = parts
val paramMap = indexes.computeIfAbsent(className) { hashMapOf() }
.computeIfAbsent(methodName + descriptor) { hashMapOf() }
for (i in 3 until parts.size step 2) {
paramMap[parts[i].toInt()] = parts[i + 1].toInt()
}
}
}
val mcpToNotchSet = MappingSetMerger.create(notchToSrgSet, srgToMcpSet).merge().reverse()
val mcpToSpigotSet = MappingSetMerger.create(mcpToNotchSet, notchToSpigotSet).merge()
val result = MappingSet.create()
for (old in mappings.topLevelClassMappings) {
val new = result.createTopLevelClassMapping(old.obfuscatedName, old.deobfuscatedName)
copyClassParam(old, new, indexes)
}
val srgToSpigotSet = spigotToSrgSet.reverse()
val spigotToMcpSet = mcpToSpigotSet.reverse()
val spigotToNotchSet = notchToSpigotSet.reverse()
writeMappings(
MappingFormats.TSRG,
spigotToSrgSet to spigotToSrg.file,
spigotToMcpSet to spigotToMcp.file,
spigotToNotchSet to spigotToNotch.file,
srgToSpigotSet to srgToSpigot.file,
mcpToSpigotSet to mcpToSpigot.file,
notchToSpigotSet to notchToSpigot.file
)
return result
}
private fun copyClassParam(
from: ClassMapping<*, *>,
to: ClassMapping<*, *>,
params: Map<String, Map<String, Map<Int, Int>>>
) {
for (mapping in from.fieldMappings) {
to.createFieldMapping(mapping.signature, mapping.deobfuscatedName)
}
for (mapping in from.innerClassMappings) {
val newMapping = to.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
copyClassParam(mapping, newMapping, params)
}
val classMap = params[from.fullObfuscatedName]
for (mapping in from.methodMappings) {
val newMapping = to.createMethodMapping(mapping.signature, mapping.deobfuscatedName)
val paramMappings = mapping.parameterMappings
if (paramMappings.isEmpty() || classMap == null) {
continue
}
val methodMap = classMap[mapping.signature.toJvmsIdentifier()] ?: continue
for (paramMapping in paramMappings) {
val i = methodMap[paramMapping.index] ?: paramMapping.index
newMapping.createParameterMapping(i, paramMapping.deobfuscatedName)
}
}
}
/*
private fun addSyntheticMethodMappings(mappings: MappingSet): MappingSet {
val synths = hashMapOf<String, MutableMap<String, MutableMap<String, String>>>()
syntheticMethods.file.useLines { lines ->
for (line in lines) {
val (className, desc, synthName, baseName) = line.split(" ")
synths.computeIfAbsent(className) { hashMapOf() }
.computeIfAbsent(desc) { hashMapOf() }[baseName] = synthName
}
}
val result = MappingSet.create()
for (old in mappings.topLevelClassMappings) {
val new = result.createTopLevelClassMapping(old.obfuscatedName, old.deobfuscatedName)
copyClassSynth(old, new, synths)
}
return result
}
private fun copyClassSynth(
from: ClassMapping<*, *>,
to: ClassMapping<*, *>,
synths: Map<String, MutableMap<String, MutableMap<String, String>>>
) {
for (mapping in from.fieldMappings) {
to.createFieldMapping(mapping.signature, mapping.deobfuscatedName)
}
for (mapping in from.innerClassMappings) {
val newMapping = to.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
copyClassSynth(mapping, newMapping, synths)
}
val classMap = synths[from.fullObfuscatedName]
for (mapping in from.methodMappings) {
val names = classMap?.get(mapping.descriptor.toString())
val newName = names?.get(mapping.obfuscatedName) ?: mapping.obfuscatedName
val newMapping = to.createMethodMapping(MethodSignature.of(newName, mapping.descriptor.toString()), mapping.deobfuscatedName)
for (paramMapping in mapping.parameterMappings) {
newMapping.createParameterMapping(paramMapping.index, paramMapping.deobfuscatedName)
}
}
}
*/
}
class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMergerHandler {
typealias Synths = Map<String, Map<String, Map<String, String>>>
class SpigotPackageMergerHandler(
private val newPackage: String,
private val synths: Synths
) : MappingSetMergerHandler {
override fun mergeTopLevelClassMappings(
left: TopLevelClassMapping,
@ -158,6 +231,7 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
): MergeResult<TopLevelClassMapping?> {
throw IllegalStateException("Unexpectedly merged class: ${left.fullObfuscatedName}")
}
override fun mergeDuplicateTopLevelClassMappings(
left: TopLevelClassMapping,
right: TopLevelClassMapping,
@ -171,13 +245,15 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
right
)
}
override fun addLeftTopLevelClassMapping(
left: TopLevelClassMapping,
target: MappingSet,
context: MergeContext
): MergeResult<TopLevelClassMapping?> {
throw IllegalStateException("Unexpected added class from Spigot: ${left.fullDeobfuscatedName}")
throw IllegalStateException("Unexpected added class from Spigot: ${left.fullObfuscatedName} - ${left.fullDeobfuscatedName}")
}
override fun addRightTopLevelClassMapping(
right: TopLevelClassMapping,
target: MappingSet,
@ -198,7 +274,6 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
context: MergeContext
): MergeResult<InnerClassMapping?> {
throw IllegalStateException("Unexpectedly merged class: ${left.fullObfuscatedName}")
// return MergeResult(target.createInnerClassMapping(left.obfuscatedName, left.deobfuscatedName), right)
}
override fun mergeDuplicateInnerClassMappings(
left: InnerClassMapping,
@ -212,12 +287,13 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
right
)
}
override fun addLeftInnerClassMapping(
left: InnerClassMapping,
target: ClassMapping<*, *>,
context: MergeContext
): MergeResult<InnerClassMapping> {
throw IllegalStateException("Unexpected added class from Spigot: ${left.fullDeobfuscatedName}")
throw IllegalStateException("Unexpected added class from Spigot: ${left.fullObfuscatedName} - ${left.fullDeobfuscatedName}")
}
override fun addRightInnerClassMapping(
right: InnerClassMapping,
@ -246,7 +322,8 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
target: ClassMapping<*, *>,
context: MergeContext
): FieldMapping {
return target.createFieldMapping(left.obfuscatedName, left.deobfuscatedName)
val right = strictRightDuplicate ?: looseRightDuplicate ?: strictRightContinuation ?: looseRightContinuation ?: left
return target.createFieldMapping(right.signature, left.deobfuscatedName)
}
override fun mergeMethodMappings(
@ -268,10 +345,23 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
target: ClassMapping<*, *>,
context: MergeContext
): MergeResult<MethodMapping?> {
return MergeResult(target.createMethodMapping(left.signature, left.deobfuscatedName))
// Check if Spigot calls this mapping something else
val synthMethods = synths[left.parent.fullObfuscatedName]?.get(left.obfuscatedDescriptor)
val newName = synthMethods?.get(left.obfuscatedName)
return if (newName != null) {
val newLeftMapping: MethodMapping? = (left.parent.getMethodMapping(MethodSignature.of(newName, left.obfuscatedDescriptor)) as Optional<MethodMapping>).orNull
val newMapping = if (newLeftMapping != null) {
target.createMethodMapping(newLeftMapping.signature, left.deobfuscatedName)
} else {
target.createMethodMapping(left.signature, newName)
}
MergeResult(newMapping)
} else {
MergeResult(target.createMethodMapping(left.signature, left.deobfuscatedName))
}
}
// Disable srg member mappings
// Disable non-spigot mappings
override fun addRightFieldMapping(
right: FieldMapping,
target: ClassMapping<*, *>,
@ -279,12 +369,16 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
): FieldMapping? {
return null
}
override fun addRightMethodMapping(
right: MethodMapping,
target: ClassMapping<*, *>,
context: MergeContext
): MergeResult<MethodMapping?> {
return MergeResult(null)
// Check if spigot changes this method automatically
val synthMethods = synths[right.parent.fullObfuscatedName]?.get(right.obfuscatedDescriptor)
val newName = synthMethods?.get(right.obfuscatedName) ?: return MergeResult(null)
return MergeResult(target.createMethodMapping(MethodSignature.of(right.obfuscatedName, right.obfuscatedDescriptor), newName))
}
private fun prependPackage(name: String): String {

View file

@ -1,281 +0,0 @@
/*
* paperweight is a Gradle plugin for the PaperMC project. It uses
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fileOrNull
import io.papermc.paperweight.util.getCsvReader
import io.papermc.paperweight.util.path
import io.papermc.paperweight.util.writeMappings
import java.nio.file.Files
import org.cadixdev.atlas.Atlas
import org.cadixdev.bombe.asm.jar.JarEntryRemappingTransformer
import org.cadixdev.bombe.type.signature.MethodSignature
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.asm.LorenzRemapper
import org.cadixdev.lorenz.io.MappingFormats
import org.cadixdev.lorenz.merge.MappingSetMerger
import org.cadixdev.lorenz.model.ClassMapping
import org.cadixdev.lorenz.model.InnerClassMapping
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class GenerateSrgs : DefaultTask() {
@get:InputFile
abstract val methodsCsv: RegularFileProperty
@get:InputFile
abstract val fieldsCsv: RegularFileProperty
@get:Optional
@get:InputFile
abstract val extraNotchSrgMappings: RegularFileProperty
@get:InputFile
abstract val inSrg: RegularFileProperty
@get:InputFile
abstract val vanillaJar: RegularFileProperty
@get:OutputFile
abstract val notchToSrg: RegularFileProperty
@get:OutputFile
abstract val notchToMcp: RegularFileProperty
@get:OutputFile
abstract val mcpToNotch: RegularFileProperty
@get:OutputFile
abstract val mcpToSrg: RegularFileProperty
@get:OutputFile
abstract val srgToNotch: RegularFileProperty
@get:OutputFile
abstract val srgToMcp: RegularFileProperty
@TaskAction
fun run() {
val methods = HashMap<String, String>()
val fields = HashMap<String, String>()
readCsvs(methods, fields)
val inSet = MappingFormats.TSRG.createReader(inSrg.file.toPath()).use { it.read() }
extraNotchSrgMappings.fileOrNull?.toPath()?.let { path ->
MappingFormats.TSRG.createReader(path).use { it.read(inSet) }
}
// Fill out any missing inheritance info in the mappings
val atlasOut = Files.createTempFile("paperweight", "jar")
try {
Atlas().use { atlas ->
atlas.install { ctx -> JarEntryRemappingTransformer(LorenzRemapper(inSet, ctx.inheritanceProvider())) }
atlas.run(vanillaJar.path, atlasOut)
}
} finally {
Files.deleteIfExists(atlasOut)
}
ensureParentExists(notchToSrg, notchToMcp, mcpToNotch, mcpToSrg, srgToNotch, srgToMcp)
createMappings(inSet, methods, fields)
}
private fun readCsvs(methods: MutableMap<String, String>, fields: MutableMap<String, String>) {
getCsvReader(methodsCsv.asFile.get()).use { reader ->
for (line in reader.readAll()) {
methods[line[0]] = line[1]
}
}
getCsvReader(fieldsCsv.asFile.get()).use { reader ->
for (line in reader.readAll()) {
fields[line[0]] = line[1]
}
}
}
private fun createMappings(inSet: MappingSet, methods: Map<String, String>, fields: Map<String, String>) {
val notchToSrgSet = MappingSet.create()
for (mapping in inSet.topLevelClassMappings) {
val newMapping = notchToSrgSet.createTopLevelClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
remapMembers(mapping, newMapping)
}
handleKeywordMappings(notchToSrgSet)
// We have Notch -> SRG
val srgToNotchSet = notchToSrgSet.reverse()
val notchToMcpSet: MappingSet
val mcpToNotchSet: MappingSet
val mcpToSrgSet: MappingSet
val srgToMcpSet = MappingSet.create()
// Create SRG -> MCP from Notch -> SRG and the CSVs
for (topLevelClassMapping in inSet.topLevelClassMappings) {
// MCP and SRG have the same class names
val srgToMcpClass = srgToMcpSet.createTopLevelClassMapping(
topLevelClassMapping.deobfuscatedName,
topLevelClassMapping.deobfuscatedName
)
mapClass(topLevelClassMapping, srgToMcpClass, methods, fields)
}
// We have Notch->SRG and SRG->MCP mapping sets now
// All other sets can be generated from these two
notchToMcpSet = MappingSetMerger.create(notchToSrgSet, srgToMcpSet).merge()
mcpToNotchSet = notchToMcpSet.reverse()
mcpToSrgSet = srgToMcpSet.reverse()
writeMappings(
MappingFormats.TSRG,
notchToSrgSet to notchToSrg.asFile.get(),
notchToMcpSet to notchToMcp.asFile.get(),
mcpToNotchSet to mcpToNotch.asFile.get(),
mcpToSrgSet to mcpToSrg.asFile.get(),
srgToNotchSet to srgToNotch.asFile.get(),
srgToMcpSet to srgToMcp.asFile.get()
)
}
private fun handleKeywordMappings(mappings: MappingSet) {
for (classMapping in mappings.topLevelClassMappings) {
handleKeywordMappingClass(classMapping)
}
}
private fun handleKeywordMappingClass(classMapping: ClassMapping<*, *>) {
for (innerClassMapping in classMapping.innerClassMappings) {
handleKeywordMappingClass(innerClassMapping)
}
for (fieldMapping in classMapping.fieldMappings) {
if (fieldMapping.obfuscatedName in javaKeywords) {
val sourceName = fieldMapping.obfuscatedName + '_'
if (classMapping.hasFieldMapping(sourceName)) {
// If the "source name" of the mapping already exists, just skip it. I don't even know what would
// happen in this case at decompile time to be honest
continue
}
classMapping.createFieldMapping(sourceName, fieldMapping.deobfuscatedName)
}
}
for (methodMapping in classMapping.methodMappings) {
if (methodMapping.obfuscatedName in javaKeywords) {
val sourceName = methodMapping.obfuscatedName + "_"
val sourceSignature = MethodSignature(sourceName, methodMapping.signature.descriptor)
if (classMapping.hasMethodMapping(sourceSignature)) {
continue
}
classMapping.createMethodMapping(sourceSignature, methodMapping.deobfuscatedName)
}
}
}
private fun mapClass(inClass: ClassMapping<*, *>, outClass: ClassMapping<*, *>, methods: Map<String, String>, fields: Map<String, String>) {
for (fieldMapping in inClass.fieldMappings) {
val mcpName = fields[fieldMapping.deobfuscatedName] ?: fieldMapping.deobfuscatedName
val mapping = outClass.createFieldMapping(fieldMapping.deobfuscatedSignature, mcpName)
mapping.obfuscatedName
}
for (methodMapping in inClass.methodMappings) {
val mcpName = methods[methodMapping.deobfuscatedName] ?: methodMapping.deobfuscatedName
outClass.createMethodMapping(methodMapping.deobfuscatedSignature, mcpName)
}
for (innerClassMapping in inClass.innerClassMappings) {
val innerOutClass = outClass.createInnerClassMapping(innerClassMapping.deobfuscatedName)
mapClass(innerClassMapping, innerOutClass, methods, fields)
}
}
private fun remapAnonymousClasses(mapping: InnerClassMapping, target: ClassMapping<*, *>) {
val newMapping = target.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
remapMembers(mapping, newMapping)
}
private fun <T : ClassMapping<*, *>> remapMembers(mapping: T, newMapping: T) {
for (fieldMapping in mapping.fieldMappings) {
newMapping.createFieldMapping(fieldMapping.obfuscatedName, fieldMapping.deobfuscatedName)
}
for (methodMapping in mapping.methodMappings) {
newMapping.createMethodMapping(methodMapping.signature, methodMapping.deobfuscatedName)
}
for (innerClassMapping in mapping.innerClassMappings) {
remapAnonymousClasses(innerClassMapping, newMapping)
}
}
}
private val javaKeywords: HashSet<String> = hashSetOf(
"abstract",
"continue",
"for",
"new",
"switch",
"assert",
"default",
"goto",
"package",
"synchronized",
"boolean",
"do",
"if",
"private",
"this",
"break",
"double",
"implements",
"protected",
"throw",
"byte",
"else",
"import",
"public",
"throws",
"case",
"enum",
"instanceof",
"return",
"transient",
"catch",
"extends",
"int",
"short",
"try",
"char",
"final",
"interface",
"static",
"void",
"class",
"finally",
"long",
"strictfp",
"volatile",
"const",
"float",
"native",
"super",
"while"
)

View file

@ -22,6 +22,7 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.AsmUtil
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import org.gradle.api.file.RegularFileProperty
@ -31,7 +32,15 @@ import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.FieldVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.tree.LabelNode
import org.objectweb.asm.tree.LineNumberNode
import org.objectweb.asm.tree.MethodInsnNode
import org.objectweb.asm.tree.MethodNode
import org.objectweb.asm.tree.TypeInsnNode
import org.objectweb.asm.tree.VarInsnNode
abstract class InspectVanillaJar : BaseTask() {
@ -39,18 +48,32 @@ abstract class InspectVanillaJar : BaseTask() {
abstract val inputJar: RegularFileProperty
@get:OutputFile
abstract val outputFile: RegularFileProperty
abstract val loggerFile: RegularFileProperty
@get:OutputFile
abstract val paramIndexes: RegularFileProperty
@get:OutputFile
abstract val syntheticMethods: RegularFileProperty
override fun init() {
outputFile.convention(defaultOutput("txt"))
loggerFile.convention(defaultOutput("$name-loggerFields", "txt"))
paramIndexes.convention(defaultOutput("$name-paramIndexes", "txt"))
syntheticMethods.convention(defaultOutput("$name-syntheticMethods", "txt"))
}
@TaskAction
fun run() {
val outputList = mutableListOf<LoggerField>()
val loggers = mutableListOf<LoggerFields.Data>()
val params = mutableListOf<ParamIndexes.Data>()
val synthMethods = mutableListOf<SyntheticMethods.Data>()
val jarFile = inputJar.file
archives.zipTree(jarFile).matching {
var visitor: ClassVisitor
visitor = LoggerFields.Visitor(null, loggers)
visitor = ParamIndexes.Visitor(visitor, params)
visitor = SyntheticMethods.Visitor(visitor, synthMethods)
archives.zipTree(inputJar.file).matching {
include("/*.class")
include("/net/minecraft/**/*.class")
}.forEach { file ->
@ -59,25 +82,52 @@ abstract class InspectVanillaJar : BaseTask() {
}
val classData = file.readBytes()
val reader = ClassReader(classData)
reader.accept(LoggerFinder(outputList), 0)
ClassReader(classData).accept(visitor, 0)
}
outputFile.file.bufferedWriter(Charsets.UTF_8).use { writer ->
for (loggerField in outputList) {
loggerFile.file.bufferedWriter(Charsets.UTF_8).use { writer ->
for (loggerField in loggers) {
writer.append(loggerField.className)
writer.append(' ')
writer.append(loggerField.fieldName)
writer.newLine()
}
}
paramIndexes.file.bufferedWriter(Charsets.UTF_8).use { writer ->
for (methodData in params) {
writer.append(methodData.className)
writer.append(' ')
writer.append(methodData.methodName)
writer.append(' ')
writer.append(methodData.methodDescriptor)
for (target in methodData.params) {
writer.append(' ')
writer.append(target.binaryIndex.toString())
writer.append(' ')
writer.append(target.sourceIndex.toString())
}
writer.newLine()
}
}
syntheticMethods.file.bufferedWriter(Charsets.UTF_8).use { writer ->
for ((className, desc, synthName, baseName) in synthMethods) {
writer.append(className)
writer.append(' ')
writer.append(desc)
writer.append(' ')
writer.append(synthName)
writer.append(' ')
writer.append(baseName)
writer.newLine()
}
}
}
}
class LoggerFinder(private val fields: MutableList<LoggerField>) : ClassVisitor(Opcodes.ASM8) {
private var currentClass: String? = null
abstract class BaseClassVisitor(classVisitor: ClassVisitor?) : ClassVisitor(Opcodes.ASM8, classVisitor), AsmUtil {
protected var currentClass: String? = null
override fun visit(
version: Int,
@ -88,22 +138,190 @@ class LoggerFinder(private val fields: MutableList<LoggerField>) : ClassVisitor(
interfaces: Array<out String>?
) {
this.currentClass = name
super.visit(version, access, name, signature, superName, interfaces)
}
}
/*
* SpecialSource2 automatically maps all Logger fields to the name LOGGER, without needing mappings defined, so we need
* to make a note of all of those fields
*/
class LoggerFields {
class Visitor(
classVisitor: ClassVisitor?,
private val fields: MutableList<Data>
) : BaseClassVisitor(classVisitor) {
override fun visitField(
access: Int,
name: String,
descriptor: String,
signature: String?,
value: Any?
): FieldVisitor? {
val ret = super.visitField(access, name, descriptor, signature, value)
val className = currentClass ?: return ret
if (Opcodes.ACC_STATIC !in access || Opcodes.ACC_FINAL !in access) {
return ret
}
if (descriptor != "Lorg/apache/logging/log4j/Logger;") {
return ret
}
fields += Data(className, name)
return ret
}
}
override fun visitField(
data class Data(val className: String, val fieldName: String)
}
/*
* Source-remapping uses 0-based param indexes, but the param indexes we have are LVT-based. We have to look at the
* actual bytecode to translate the LVT-based indexes back to 0-based param indexes.
*/
class ParamIndexes {
class Visitor(
classVisitor: ClassVisitor?,
private val methods: MutableList<Data>
) : BaseClassVisitor(classVisitor) {
override fun visitMethod(
access: Int,
name: String,
descriptor: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
val ret = super.visitMethod(access, name, descriptor, signature, exceptions)
val className = currentClass ?: return ret
val isStatic = access and Opcodes.ACC_STATIC != 0
var currentIndex = if (isStatic) 0 else 1
val types = Type.getArgumentTypes(descriptor)
if (types.isEmpty()) {
return ret
}
val params = ArrayList<ParamTarget>(types.size)
val data = Data(className, name, descriptor, params)
methods += data
for (i in types.indices) {
params += ParamTarget(currentIndex, i)
currentIndex++
// Figure out if we should skip the next index
val type = types[i]
if (type === Type.LONG_TYPE || type === Type.DOUBLE_TYPE) {
currentIndex++
}
}
return ret
}
}
data class Data(
val className: String,
val methodName: String,
val methodDescriptor: String,
val params: List<ParamTarget>
)
data class ParamTarget(val binaryIndex: Int, val sourceIndex: Int)
}
/*
* SpecialSource2 automatically handles certain synthetic method renames, which leads to methods which don't match any
* existing mapping. We need to make a note of all of the synthetic methods which match SpecialSource2's checks so we
* can handle it in our generated mappings.
*/
class SyntheticMethods {
class Visitor(
classVisitor: ClassVisitor?,
private val methods: MutableList<Data>
) : BaseClassVisitor(classVisitor) {
override fun visitMethod(
access: Int,
name: String,
descriptor: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
val ret = super.visitMethod(access, name, descriptor, signature, exceptions)
val className = currentClass ?: return ret
if (Opcodes.ACC_SYNTHETIC !in access || Opcodes.ACC_BRIDGE in access || name.contains('$')) {
return ret
}
return SynthMethodVisitor(access, name, descriptor, signature, exceptions, className, methods)
}
}
private class SynthMethodVisitor(
access: Int,
name: String,
descriptor: String,
signature: String?,
value: Any?
): FieldVisitor? {
val className = currentClass ?: return null
if (descriptor != "Lorg/apache/logging/log4j/Logger;") {
return null
}
fields += LoggerField(className, name)
return null
}
}
exceptions: Array<out String>?,
private val className: String,
private val methods: MutableList<Data>
) : MethodNode(Opcodes.ASM9, access, name, descriptor, signature, exceptions) {
data class LoggerField(val className: String, val fieldName: String)
// This emulates the behavior of SpecialSource2's SyntheticFinder.addSynthetics() method
override fun visitEnd() {
var nextLvt = 0
val insns = instructions.iterator().asSequence()
.filter { it !is LabelNode && it !is LineNumberNode && it !is TypeInsnNode }
.dropWhile {
if (it !is VarInsnNode || it.`var` != nextLvt) {
return@dropWhile false
}
nextLvt++
if (it.opcode == Opcodes.LLOAD || it.opcode == Opcodes.DLOAD) {
nextLvt++
}
return@dropWhile true
}
.take(3)
.toList()
// Must only have 2 instructions left
if (insns.size != 2) {
return
}
val insn = insns.first()
// Must be a virtual or interface invoke instruction
if ((insn.opcode != Opcodes.INVOKEVIRTUAL && insn.opcode != Opcodes.INVOKEINTERFACE) || insn !is MethodInsnNode) {
return
}
// The next instruction must be a return
val next = insns[1]
if (next.opcode !in Opcodes.IRETURN..Opcodes.RETURN) {
return
}
// Must be a method in the same class with a different signature
if (className != insn.owner || name == insn.name || desc == insn.desc) {
return
}
// The descriptors need to be the same size
if (Type.getArgumentTypes(desc).size != Type.getArgumentTypes(insn.desc).size) {
return
}
// Add this method as a synthetic accessor for insn.name
methods += Data(className, insn.desc, name, insn.name)
}
}
data class Data(val className: String, val desc: String, val synthName: String, val baseName: String)
}

View file

@ -24,6 +24,7 @@ package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.path
import org.cadixdev.at.AccessTransformSet
import org.cadixdev.at.io.AccessTransformFormats
import org.gradle.api.file.RegularFile
@ -55,6 +56,6 @@ abstract class MergeAccessTransforms : BaseTask() {
outputAt.merge(at)
}
AccessTransformFormats.FML.write(outputFile.file.toPath(), outputAt)
AccessTransformFormats.FML.write(outputFile.path, outputAt)
}
}

View file

@ -0,0 +1,53 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.path
import io.papermc.paperweight.util.pathOrNull
import java.nio.file.Files
import net.fabricmc.lorenztiny.TinyMappingFormat
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class PatchMappings : DefaultTask() {
@get:InputFile
abstract val inputMappings: RegularFileProperty
@get:InputFile
@get:Optional
abstract val patchMappings: RegularFileProperty
@get:OutputFile
abstract val outputMappings: RegularFileProperty
@TaskAction
fun run() {
val mappings = TinyMappingFormat.STANDARD.read(inputMappings.path, Constants.SPIGOT_NAMESPACE, Constants.DEOBF_NAMESPACE)
patchMappings.pathOrNull?.let { patchFile ->
val temp = Files.createTempFile("patch", "tiny")
try {
val comment = Regex("\\s*#.*")
// tiny format doesn't allow comments, so we manually remove them
// The tiny mappings reader also doesn't have a InputStream or Reader input...
Files.newBufferedReader(patchFile).useLines { lines ->
Files.newBufferedWriter(temp).use { writer ->
for (line in lines) {
val newLine = comment.replace(line, "")
if (newLine.isNotBlank()) {
writer.appendln(newLine)
}
}
}
}
TinyMappingFormat.STANDARD.read(mappings, temp, Constants.SPIGOT_NAMESPACE, Constants.DEOBF_NAMESPACE)
} finally {
Files.deleteIfExists(temp)
}
}
TinyMappingFormat.STANDARD.write(mappings, outputMappings.path, Constants.SPIGOT_NAMESPACE, Constants.DEOBF_NAMESPACE)
}
}

View file

@ -1,96 +0,0 @@
/*
* paperweight is a Gradle plugin for the PaperMC project. It uses
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package io.papermc.paperweight.tasks
import java.io.PrintWriter
import java.util.regex.Pattern
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class PatchMcpCsv : DefaultTask() {
@get:InputFile
abstract val fieldsCsv: RegularFileProperty
@get:InputFile
abstract val methodsCsv: RegularFileProperty
@get:InputFile
abstract val paramsCsv: RegularFileProperty
@get:InputFile
abstract val changesFile: RegularFileProperty
@get:OutputFile
abstract val paperFieldCsv: RegularFileProperty
@get:OutputFile
abstract val paperMethodCsv: RegularFileProperty
@get:OutputFile
abstract val paperParamCsv: RegularFileProperty
@TaskAction
fun run() {
val changes = changesFile.asFile.get().readLines()
val changeMap = changes.asSequence()
.filterNot { l -> l.trim().run { startsWith('#') || isEmpty() } }
.map { l -> commentPattern.matcher(l).replaceAll("") }
.map { l -> l.split(',').run { get(0) to get(1) } }
.toMap()
val fields = fieldsCsv.asFile.get().readLines().toMutableList()
val methods = methodsCsv.asFile.get().readLines().toMutableList()
val params = paramsCsv.asFile.get().readLines().toMutableList()
replaceChanges(changeMap, fields, fieldPattern)
replaceChanges(changeMap, methods, methodPattern)
replaceChanges(changeMap, params, paramPattern)
paperFieldCsv.asFile.get().printWriter().use { writeFile(fields, it) }
paperMethodCsv.asFile.get().printWriter().use { writeFile(methods, it) }
paperParamCsv.asFile.get().printWriter().use { writeFile(params, it) }
}
private fun replaceChanges(changes: Map<String, String>, lines: MutableList<String>, pattern: Pattern) {
// Start at 1 to skip csv header row
for (i in 1 until lines.size) {
val matcher = pattern.matcher(lines[i])
matcher.find()
val srgName = matcher.group(1) ?: continue
val changedName = changes[srgName] ?: continue
lines[i] = matcher.replaceFirst("$1,$changedName,$3")
}
}
private fun writeFile(lines: List<String>, writer: PrintWriter) {
for (line in lines) {
writer.println(line)
}
}
private companion object {
private val fieldPattern = Pattern.compile("(field_\\d+_[a-zA-Z_]+),(\\w+),(\\d,.*)")
private val methodPattern = Pattern.compile("(func_\\d+_[a-zA-Z_]+),(\\w+),(\\d,.*)")
private val paramPattern = Pattern.compile("(p_i?\\d+_\\d+_),(\\w+),(\\d)")
private val commentPattern = Pattern.compile("\\s*#.*")
}
}

View file

@ -22,8 +22,11 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.path
import net.fabricmc.lorenztiny.TinyMappingFormat
import org.cadixdev.at.io.AccessTransformFormats
import org.cadixdev.lorenz.io.MappingFormats
import org.gradle.api.file.RegularFileProperty
@ -47,10 +50,10 @@ abstract class RemapAccessTransform : BaseTask() {
@TaskAction
fun run() {
val at = AccessTransformFormats.FML.read(inputFile.file.toPath())
val mappingSet = MappingFormats.TSRG.createReader(mappings.file.toPath()).use { it.read() }
val at = AccessTransformFormats.FML.read(inputFile.path)
val mappingSet = TinyMappingFormat.STANDARD.read(mappings.path, Constants.SPIGOT_NAMESPACE, Constants.DEOBF_NAMESPACE)
val resultAt = at.remap(mappingSet)
AccessTransformFormats.FML.write(outputFile.file.toPath(), resultAt)
AccessTransformFormats.FML.write(outputFile.path, resultAt)
}
}

View file

@ -0,0 +1,79 @@
/*
* paperweight is a Gradle plugin for the PaperMC project. It uses
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.Constants.paperTaskOutput
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.path
import io.papermc.paperweight.util.runJar
import javax.inject.Inject
import net.fabricmc.lorenztiny.TinyMappingFormat
import org.cadixdev.atlas.Atlas
import org.cadixdev.bombe.asm.jar.JarEntryRemappingTransformer
import org.cadixdev.lorenz.asm.LorenzRemapper
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.submit
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
abstract class RemapJar : BaseTask() {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:InputFile
abstract val mappingsFile: RegularFileProperty
@get:Classpath
abstract val remapper: RegularFileProperty
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
val logFile = layout.cache.resolve(paperTaskOutput("log"))
logFile.delete()
val args = arrayOf(
inputJar.file.absolutePath,
outputJar.file.absolutePath,
mappingsFile.file.absolutePath,
Constants.OBF_NAMESPACE, Constants.DEOBF_NAMESPACE,
"--fixpackageaccess", "--renameinvalidlocals", "--rebuildsourcefilenames"
)
runJar(remapper, layout.cache, logFile, jvmArgs = listOf("-Xmx512m"), args = *args);
}
}

View file

@ -22,9 +22,12 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.path
import java.util.jar.JarFile
import net.fabricmc.lorenztiny.TinyMappingFormat
import org.cadixdev.at.AccessChange
import org.cadixdev.at.AccessTransform
import org.cadixdev.at.AccessTransformSet
@ -32,7 +35,6 @@ import org.cadixdev.at.ModifierChange
import org.cadixdev.at.io.AccessTransformFormats
import org.cadixdev.bombe.type.MethodDescriptor
import org.cadixdev.bombe.type.signature.MethodSignature
import org.cadixdev.lorenz.io.MappingFormats
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
@ -97,10 +99,10 @@ abstract class RemapSpigotAt : BaseTask() {
}
}
val mappings = MappingFormats.TSRG.createReader(mapping.file.toPath()).use { it.read() }
val mappings = TinyMappingFormat.STANDARD.read(mapping.path, Constants.SPIGOT_NAMESPACE, Constants.DEOBF_NAMESPACE)
val remappedAt = outputAt.remap(mappings)
AccessTransformFormats.FML.write(outputFile.file.toPath(), remappedAt)
AccessTransformFormats.FML.write(outputFile.path, remappedAt)
}
private fun parseAccess(text: String): AccessTransform {

View file

@ -27,6 +27,7 @@ import io.papermc.paperweight.util.Constants.paperTaskOutput
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.runJar
import java.nio.file.Paths
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
@ -91,8 +92,10 @@ abstract class RemapVanillaJarSpigot : BaseTask() {
logFile.delete()
runJar(
specialSource2Jar,
// Paths.get("/home/demonwav/IdeaProjects/SpecialSource2/build/libs/SpecialSource2-2.0.0-PW-SNAPSHOT-all.jar"),
workingDir = work,
logFile = logFile,
// jvmArgs = listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005"),
args = *doReplacements(classMapCommand.get(), inputJarPath, classMappingPath, classJarPath) {
// ignore excludes, we actually want to map every class
it != "-e"
@ -106,9 +109,11 @@ abstract class RemapVanillaJarSpigot : BaseTask() {
val logFile = layout.cache.resolve(paperTaskOutput("member.log"))
logFile.delete()
runJar(
// Paths.get("/home/demonwav/IdeaProjects/SpecialSource2/build/libs/SpecialSource2-2.0.0-PW-SNAPSHOT-all.jar"),
specialSource2Jar,
workingDir = work,
logFile = logFile,
// jvmArgs = listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005"),
args = *doReplacements(memberMapCommand.get(), classJarPath, memberMappingsPath, membersJarPath)
)
} catch (e: Exception) {

View file

@ -66,14 +66,23 @@ abstract class RunForgeFlower : BaseTask() {
val config = gson.fromJson<McpConfig>(configFile)
val argList = config.functions.decompile.args.map {
when (it) {
"{libraries}" -> libraries.file.absolutePath
"{input}" -> inputJar.file.absolutePath
"{output}" -> target.absolutePath
else -> it
}
}
val argList = listOf(
"-ind= ",
"-din=1",
"-rbr=1",
"-dgs=1",
"-asc=1",
"-rsy=1",
"-iec=1",
"-jvn=0",
"-isl=0",
"-iib=1",
"-log=TRACE",
"-cfg",
libraries.file.absolutePath,
inputJar.file.absolutePath,
target.absolutePath
)
val logFile = layout.cache.resolve(paperTaskOutput("log"))
logFile.delete()

View file

@ -22,65 +22,120 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.McpConfig
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fromJson
import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.mcinject
import io.papermc.paperweight.util.runJar
import java.io.ByteArrayInputStream
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
import javax.inject.Inject
import org.gradle.api.file.FileVisitDetails
import org.gradle.api.file.FileVisitor
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.logging.LogLevel
import org.gradle.api.logging.LoggingManager
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.ClassNode
abstract class RunMcInjector : BaseTask() {
@get:InputFile
abstract val configFile: RegularFileProperty
@get:InputFile
abstract val executable: RegularFileProperty
// @get:InputFile
// abstract val configFile: RegularFileProperty
// @get:InputFile
// abstract val executable: RegularFileProperty
@get:InputFile
abstract val exceptions: RegularFileProperty
@get:InputFile
abstract val access: RegularFileProperty
@get:InputFile
abstract val constructors: RegularFileProperty
// @get:InputFile
// abstract val exceptions: RegularFileProperty
// @get:InputFile
// abstract val access: RegularFileProperty
// @get:InputFile
// abstract val constructors: RegularFileProperty
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:OutputFile
abstract val outputJar: RegularFileProperty
@get:Internal
abstract val logFile: RegularFileProperty
// @get:Internal
// abstract val logFile: RegularFileProperty
@get:Inject
abstract val loggingManger: LoggingManager
override fun init() {
outputJar.convention(defaultOutput())
logFile.convention(defaultOutput("log"))
// logFile.convention(defaultOutput("log"))
}
@TaskAction
fun run() {
val config = gson.fromJson<McpConfig>(configFile)
loggingManger.captureStandardOutput(LogLevel.QUIET)
loggingManger.captureStandardError(LogLevel.QUIET)
val argList = config.functions.mcinject.args.map {
when (it) {
"{input}" -> inputJar.file.absolutePath
"{output}" -> outputJar.file.absolutePath
"{log}" -> logFile.file.absolutePath
"{exceptions}" -> exceptions.file.absolutePath
"{access}" -> access.file.absolutePath
"{constructors}" -> constructors.file.absolutePath
else -> it
}
val classNode = ClassNode(Opcodes.ASM6)
var visitor: ClassVisitor
visitor = ParameterAnnotationFixer(classNode, null)
// visitor = InnerClassInitAdder(visitor)
// visitor = ClassInitAdder(visitor)
JarOutputStream(outputJar.file.outputStream()).use { out ->
archives.zipTree(inputJar.file).matching {
include("/*.class")
include("/net/minecraft/**/*.class")
}.visit(object : FileVisitor {
override fun visitDir(dirDetails: FileVisitDetails) {}
override fun visitFile(fileDetails: FileVisitDetails) {
val classData = fileDetails.file.readBytes()
out.putNextEntry(ZipEntry(fileDetails.path))
try {
val reader = ClassReader(classData)
reader.accept(visitor, 0)
val writer = ClassWriter(ClassWriter.COMPUTE_MAXS)
classNode.accept(writer)
ByteArrayInputStream(writer.toByteArray()).copyTo(out)
} finally {
out.closeEntry()
}
}
})
}
val jvmArgs = config.functions.mcinject.jvmargs ?: listOf()
runJar(executable, layout.cache, logFile = null, jvmArgs = jvmArgs, args = *argList.toTypedArray())
// val config = gson.fromJson<McpConfig>(configFile)
//
// val argList = config.functions.mcinject.args.map {
// when (it) {
// "{input}" -> inputJar.file.absolutePath
// "{output}" -> outputJar.file.absolutePath
// "{log}" -> logFile.file.absolutePath
// "{exceptions}" -> exceptions.file.absolutePath
// "{access}" -> access.file.absolutePath
// "{constructors}" -> constructors.file.absolutePath
// else -> it
// }
// }
//
// val jvmArgs = config.functions.mcinject.jvmargs ?: listOf()
// runJar(
// executable,
// layout.cache,
// logFile = null,
// args = *arrayOf(
// "--in", inputJar.file.absolutePath,
// "--out", outputJar.file.absolutePath,
// "--log", logFile.file.absolutePath,
// "--level=INFO",
// "--lvt=STRIP"
// )
// )
}
}

View file

@ -69,6 +69,7 @@ abstract class Filter : BaseTask() {
}
}
/*
abstract class Merge : BaseTask() {
@get:InputFiles
abstract val inputJars: ListProperty<RegularFile>
@ -98,3 +99,4 @@ abstract class Merge : BaseTask() {
target.deleteRecursively()
}
}
*/

View file

@ -28,6 +28,7 @@ import io.papermc.paperweight.util.ensureDeleted
import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.orNull
import io.papermc.paperweight.util.path
import org.cadixdev.at.AccessChange
import org.cadixdev.at.AccessTransform
import org.cadixdev.at.AccessTransformSet
@ -68,13 +69,13 @@ abstract class ApplyAccessTransform : BaseTask() {
ensureParentExists(outputJar.file)
ensureDeleted(outputJar.file)
val at = AccessTransformFormats.FML.read(atFile.file.toPath())
val at = AccessTransformFormats.FML.read(atFile.path)
Atlas().apply {
install {
AtJarEntryTransformer(at)
}
run(inputJar.file.toPath(), outputJar.file.toPath())
run(inputJar.path, outputJar.path)
}
}
}

View file

@ -27,8 +27,10 @@ import io.papermc.paperweight.tasks.BaseTask
import io.papermc.paperweight.tasks.sourceremap.parseConstructors
import io.papermc.paperweight.tasks.sourceremap.parseParamNames
import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.McDev
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.path
import java.io.File
import java.util.zip.ZipFile
import org.cadixdev.lorenz.io.MappingFormats
@ -103,7 +105,7 @@ abstract class RemapPatches : BaseTask() {
val constructorsData = parseConstructors(constructors.file)
val paramMap = parseParamNames(parameterNames.file)
val mappings = MappingFormats.TSRG.createReader(mappingsFile.file.toPath()).use { it.read() }
val mappings = MappingFormats.TSRG.createReader(mappingsFile.path).use { it.read() }
// This should pull in any libraries needed for type bindings
val configFiles = project.project(":Paper-Server").configurations["runtimeClasspath"].resolve()
@ -140,7 +142,7 @@ abstract class RemapPatches : BaseTask() {
if (skip == 0) {
// We need to include any missing classes for the patches later on
importMcDev(patches, tempInputDir.resolve("src/main/java"))
McDev.importMcDev(patches, spigotDecompJar.file, libraryImports.file, mcLibrariesDir.file, tempInputDir.resolve("src/main/java"))
patchApplier.commitInitialSource() // Initial commit of Spigot sources
patchApplier.checkoutRemapped() // Switch to remapped branch without checking out files
@ -169,71 +171,6 @@ abstract class RemapPatches : BaseTask() {
}
}
private fun importMcDev(patches: Array<File>, inputDir: File) {
val importMcDev = readMcDevNames(patches).asSequence()
.map { inputDir.resolve("net/minecraft/server/$it.java") }
.filter { !it.exists() }
.toSet()
ZipFile(spigotDecompJar.file).use { zipFile ->
for (file in importMcDev) {
val zipEntry = zipFile.getEntry(file.relativeTo(inputDir).path) ?: continue
zipFile.getInputStream(zipEntry).use { input ->
file.outputStream().buffered().use { output ->
input.copyTo(output)
}
}
}
}
// Import library classes
val libraryLines = libraryImports.file.readLines()
if (libraryLines.isEmpty()) {
return
}
val libDir = mcLibrariesDir.file
val libFiles = (libDir.listFiles() ?: emptyArray()).filter { it.name.endsWith("-sources.jar" )}
if (libFiles.isEmpty()) {
throw PaperweightException("No library files found")
}
for (line in libraryLines) {
val (libraryName, filePath) = line.split(" ")
val libFile = libFiles.firstOrNull { it.name.startsWith(libraryName) }
?: throw PaperweightException("Failed to find library: $libraryName for class $filePath")
val outputFile = inputDir.resolve(filePath)
if (outputFile.exists()) {
continue
}
outputFile.parentFile.mkdirs()
ZipFile(libFile).use { zipFile ->
val zipEntry = zipFile.getEntry(filePath)
zipFile.getInputStream(zipEntry).use { input ->
outputFile.outputStream().buffered().use { output ->
input.copyTo(output)
}
}
}
}
}
private fun readMcDevNames(patches: Array<File>): Set<String> {
val result = hashSetOf<String>()
val prefix = "+++ b/src/main/java/net/minecraft/server/"
val suffix = ".java"
for (patch in patches) {
patch.useLines { lines ->
lines.filter { it.startsWith(prefix) }
.mapTo(result) { it.substring(prefix.length, it.length - suffix.length) }
}
}
return result
}
private fun createWorkDir(name: String, source: File? = null, recreate: Boolean = true): File {
return layout.cache.resolve("paperweight").resolve(name).apply {
if (recreate) {

View file

@ -23,11 +23,13 @@
package io.papermc.paperweight.tasks.sourceremap
import io.papermc.paperweight.tasks.ZippedTask
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.path
import java.io.File
import javax.inject.Inject
import net.fabricmc.lorenztiny.TinyMappingFormat
import org.cadixdev.at.AccessTransformSet
import org.cadixdev.at.io.AccessTransformFormats
import org.cadixdev.lorenz.io.MappingFormats
@ -107,7 +109,7 @@ abstract class RemapSources : ZippedTask() {
abstract class RemapAction : WorkAction<RemapParams> {
override fun execute() {
val mappingSet = MappingFormats.TSRG.read(parameters.mappings.path)
val mappingSet = TinyMappingFormat.STANDARD.read(parameters.mappings.path, Constants.SPIGOT_NAMESPACE, Constants.DEOBF_NAMESPACE)
val processAt = AccessTransformSet.create()
val constructorsData = parseConstructors(parameters.constructors.file)

View file

@ -0,0 +1,7 @@
package io.papermc.paperweight.util
interface AsmUtil {
operator fun Int.contains(value: Int): Boolean {
return value and this == value
}
}

View file

@ -31,6 +31,9 @@ object Constants {
const val MC_LIBRARY_URL = "https://libraries.minecraft.net/"
const val MC_MANIFEST_URL = "https://launchermeta.mojang.com/mc/game/version_manifest.json"
const val YARN_CONFIG = "yarn"
const val REMAPPER_CONFIG = "remapper"
const val CACHE_PATH = "caches"
private const val PAPER_PATH = "paperweight"
@ -42,7 +45,12 @@ object Constants {
const val MCP_DATA_DIR = "mcp/data"
const val MCP_MAPPINGS_DIR = "mcp/mappings"
private const val SRG_DIR = "$MCP_MAPPINGS_DIR/srgs"
const val SERVER_MAPPINGS = "mcp/server_mappings.txt"
const val SRG_DIR = "$MCP_MAPPINGS_DIR/srgs"
const val OBF_NAMESPACE = "official"
const val SPIGOT_NAMESPACE = "spigot"
const val DEOBF_NAMESPACE = "mojang+yarn"
const val MCP_CONFIG_JSON = "$MCP_DATA_DIR/config.json"

View file

@ -0,0 +1,73 @@
package io.papermc.paperweight.util
import io.papermc.paperweight.PaperweightException
import java.io.File
import java.util.zip.ZipFile
object McDev {
fun importMcDev(patches: Array<File>, decompJar: File, libraryImports: File, libraryDir: File, targetDir: File) {
val importMcDev = readMcDevNames(patches).asSequence()
.map { targetDir.resolve("net/minecraft/server/$it.java") }
.filter { !it.exists() }
.toSet()
ZipFile(decompJar).use { zipFile ->
for (file in importMcDev) {
val zipEntry = zipFile.getEntry(file.relativeTo(targetDir).path) ?: continue
zipFile.getInputStream(zipEntry).use { input ->
file.outputStream().buffered().use { output ->
input.copyTo(output)
}
}
}
}
// Import library classes
val libraryLines = libraryImports.readLines()
if (libraryLines.isEmpty()) {
return
}
val libFiles = (libraryDir.listFiles() ?: emptyArray()).filter { it.name.endsWith("-sources.jar" )}
if (libFiles.isEmpty()) {
throw PaperweightException("No library files found")
}
for (line in libraryLines) {
val (libraryName, filePath) = line.split(" ")
val libFile = libFiles.firstOrNull { it.name.startsWith(libraryName) }
?: throw PaperweightException("Failed to find library: $libraryName for class $filePath")
val outputFile = targetDir.resolve(filePath)
if (outputFile.exists()) {
continue
}
outputFile.parentFile.mkdirs()
ZipFile(libFile).use { zipFile ->
val zipEntry = zipFile.getEntry(filePath)
zipFile.getInputStream(zipEntry).use { input ->
outputFile.outputStream().buffered().use { output ->
input.copyTo(output)
}
}
}
}
}
private fun readMcDevNames(patches: Array<File>): Set<String> {
val result = hashSetOf<String>()
val prefix = "+++ b/src/main/java/net/minecraft/server/"
val suffix = ".java"
for (patch in patches) {
patch.useLines { lines ->
lines.filter { it.startsWith(prefix) }
.mapTo(result) { it.substring(prefix.length, it.length - suffix.length) }
}
}
return result
}
}

View file

@ -25,17 +25,12 @@ package io.papermc.paperweight.util
import io.papermc.paperweight.PaperweightException
import java.io.OutputStream
import org.gradle.internal.jvm.Jvm
import org.gradle.process.ExecOperations
fun runJar(jar: Any, workingDir: Any, logFile: Any?, jvmArgs: List<String> = listOf(), vararg args: String) {
val jarFile = jar.convertToFile()
val dir = workingDir.convertToFile()
val process = ProcessBuilder(
Jvm.current().javaExecutable.canonicalPath, *jvmArgs.toTypedArray(),
"-jar", jarFile.canonicalPath,
*args
).directory(dir).start()
val output = when {
logFile is OutputStream -> logFile
logFile != null -> {
@ -45,6 +40,19 @@ fun runJar(jar: Any, workingDir: Any, logFile: Any?, jvmArgs: List<String> = lis
else -> UselessOutputStream
}
val processBuilder = ProcessBuilder(
Jvm.current().javaExecutable.canonicalPath, *jvmArgs.toTypedArray(),
"-jar", jarFile.canonicalPath,
*args
).directory(dir)
output.writer().let {
it.appendln("Command: ${processBuilder.command().joinToString(" ")}")
it.flush()
}
val process = processBuilder.start()
output.use {
redirect(process.inputStream, it)
redirect(process.errorStream, it)

View file

@ -22,10 +22,11 @@
package io.papermc.paperweight.util
import au.com.bytecode.opencsv.CSVParser
import au.com.bytecode.opencsv.CSVReader
import com.github.salomonbrys.kotson.fromJson
import com.google.gson.Gson
import com.opencsv.CSVParserBuilder
import com.opencsv.CSVReader
import com.opencsv.CSVReaderBuilder
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.ext.PaperweightExtension
import io.papermc.paperweight.tasks.BaseTask
@ -85,14 +86,9 @@ object UselessOutputStream : OutputStream() {
}
}
fun getCsvReader(file: File) = CSVReader(
file.reader(),
CSVParser.DEFAULT_SEPARATOR,
CSVParser.DEFAULT_QUOTE_CHARACTER,
CSVParser.NULL_CHARACTER,
1,
false
)
fun getCsvReader(file: File): CSVReader = CSVReaderBuilder(file.bufferedReader())
.withCSVParser(CSVParserBuilder().withStrictQuotes(false).build())
.build()
fun Any.convertToFile(): File {
return when (this) {
@ -153,6 +149,8 @@ val RegularFileProperty.fileOrNull: File?
get() = orNull?.asFile
val RegularFileProperty.path: Path
get() = file.toPath()
val RegularFileProperty.pathOrNull: Path?
get() = fileOrNull?.toPath()
val DirectoryProperty.file: File
get() = get().asFile
val DirectoryProperty.path: Path