Plugin remapping (#239)

* Work

* Include mappings hash in manifest

* Use manifest instead of marker file

* Create the manifest if it doesn't exist

* Make RemapJar no-op when the namespaces match

* move files

* decorate userdev jar manifests

* fix relocated shadow jar manifest

* feat(core/patcher): Replace use of shadow plugin

We now reobf using the relocated mappings.
The constant pool still needs to be relocated for references to CB classes by name in for example Commodore or class preloading.

* chore(core/patcher): Remove no longer needed relocation logic from GenerateDevBundle

* chore(core/patcher): Do not extract manifest when including mappings

We don't need this after removing shadow usage

* Bump version to 1.6.0-SNAPSHOT
This commit is contained in:
Jason Penilla 2024-04-23 11:40:20 -07:00 committed by GitHub
parent 4a2e036152
commit c8f6e05472
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 502 additions and 167 deletions

View file

@ -1,5 +1,5 @@
group = io.papermc.paperweight
version = 1.5.16-SNAPSHOT
version = 1.6.0-SNAPSHOT
org.gradle.caching = true
org.gradle.parallel = true

View file

@ -37,7 +37,7 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip
import org.gradle.kotlin.dsl.*
class PaperweightCore : Plugin<Project> {
@ -138,21 +138,24 @@ class PaperweightCore : Plugin<Project> {
val cache = target.layout.cache
val serverProj = target.ext.serverProject.orNull ?: return@afterEvaluate
serverProj.apply(plugin = "com.github.johnrengelman.shadow")
val shadowJar = serverProj.tasks.named("shadowJar", Jar::class)
val serverJar = serverProj.tasks.register("serverJar", Zip::class)
tasks.generateReobfMappings {
inputJar.set(shadowJar.flatMap { it.archiveFile })
inputJar.set(serverJar.flatMap { it.archiveFile })
}
tasks.generateRelocatedReobfMappings {
inputJar.set(serverJar.flatMap { it.archiveFile })
}
val (_, reobfJar) = serverProj.setupServerProject(
val (includeMappings, reobfJar) = serverProj.setupServerProject(
target,
tasks.lineMapJar.flatMap { it.outputJar },
tasks.decompileJar.flatMap { it.outputJar },
ext.mcDevSourceDir.path,
cache.resolve(SERVER_LIBRARIES_TXT),
ext.paper.reobfPackagesToFix,
tasks.patchReobfMappings.flatMap { it.outputMappings }
tasks.generateRelocatedReobfMappings,
serverJar
) ?: return@afterEvaluate
devBundleTasks.configure(
@ -168,7 +171,7 @@ class PaperweightCore : Plugin<Project> {
tasks.extractFromBundler.map { it.versionJson.path }.convertToFileProvider(layout, providers)
) {
vanillaJarIncludes.set(ext.vanillaJarIncludes)
reobfMappingsFile.set(tasks.patchReobfMappings.flatMap { it.outputMappings })
reobfMappingsFile.set(tasks.generateRelocatedReobfMappings.flatMap { it.outputMappings })
paramMappingsCoordinates.set(
target.provider {
@ -183,7 +186,7 @@ class PaperweightCore : Plugin<Project> {
tasks.extractFromBundler.flatMap { it.versionJson },
tasks.extractFromBundler.flatMap { it.serverLibrariesList },
tasks.downloadServerJar.flatMap { it.outputJar },
shadowJar,
includeMappings.flatMap { it.outputJar },
reobfJar,
ext.minecraftVersion
)

View file

@ -176,4 +176,9 @@ open class AllTasks(
outputMappings.set(cache.resolve(PATCHED_REOBF_MOJANG_SPIGOT_MAPPINGS))
}
val generateRelocatedReobfMappings by tasks.registering<GenerateRelocatedReobfMappings> {
inputMappings.set(patchReobfMappings.flatMap { it.outputMappings })
outputMappings.set(cache.resolve(RELOCATED_PATCHED_REOBF_MOJANG_SPIGOT_MAPPINGS))
}
}

View file

@ -2,6 +2,10 @@ plugins {
`config-kotlin`
}
repositories {
gradlePluginPortal()
}
dependencies {
implementation(libs.httpclient)
implementation(libs.bundles.kotson)

View file

@ -0,0 +1,31 @@
/*
* paperweight is a Gradle plugin for the PaperMC project.
*
* Copyright (c) 2023 Kyle Wood (DenWav)
* Contributors
*
* 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;
* version 2.1 only, no later versions.
*
* 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.extension
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.property
abstract class PaperweightServerExtension(objects: ObjectFactory) {
val craftBukkitPackageVersion: Property<String> = objects.property()
}

View file

@ -31,7 +31,6 @@ import org.gradle.api.Project
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.kotlin.dsl.*
@Suppress("MemberVisibilityCanBePrivate")
@ -60,7 +59,7 @@ class BundlerJarTasks(
bundlerVersionJson: Provider<RegularFile>,
serverLibrariesList: Provider<RegularFile>,
vanillaJar: Provider<RegularFile>,
shadowJar: TaskProvider<out AbstractArchiveTask>,
mojangJar: Provider<RegularFile>,
reobfJar: TaskProvider<RemapJar>,
mcVersion: Provider<String>
) {
@ -68,7 +67,7 @@ class BundlerJarTasks(
bundlerVersionJson,
serverLibrariesList,
vanillaJar,
shadowJar.flatMap { it.archiveFile },
mojangJar,
)
createReobfBundlerJar.configureWith(
bundlerVersionJson,

View file

@ -22,7 +22,6 @@
package io.papermc.paperweight.taskcontainers
import io.papermc.paperweight.extension.RelocationExtension
import io.papermc.paperweight.taskcontainers.BundlerJarTasks.Companion.registerVersionArtifact
import io.papermc.paperweight.tasks.*
import io.papermc.paperweight.util.*
@ -108,7 +107,6 @@ class DevBundleTasks(
serverProject.set(serverProj)
runtimeConfiguration.set(project.configurations.named(SERVER_RUNTIME_CLASSPATH))
relocations.set(serverProj.extensions.getByType<RelocationExtension>().relocations.map { gson.toJson(it) })
decompiledJar.pathProvider(decompileJar)
atFile.pathProvider(accessTransformFile)

View file

@ -23,8 +23,6 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.extension.Relocation
import io.papermc.paperweight.extension.RelocationWrapper
import io.papermc.paperweight.util.*
import io.papermc.paperweight.util.constants.*
import io.papermc.paperweight.util.data.*
@ -35,10 +33,8 @@ import java.nio.file.Path
import java.util.Locale
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import java.util.stream.Collectors
import javax.inject.Inject
import kotlin.io.path.*
import org.apache.tools.ant.types.selectors.SelectorUtils
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
@ -101,9 +97,6 @@ abstract class GenerateDevBundle : DefaultTask() {
@get:Classpath
abstract val runtimeConfiguration: Property<Configuration>
@get:Input
abstract val relocations: Property<String>
@get:Input
abstract val paramMappingsUrl: Property<String>
@ -180,8 +173,6 @@ abstract class GenerateDevBundle : DefaultTask() {
workingDir.createDirectories()
sourceDir.path.copyRecursivelyTo(workingDir)
relocate(relocations(), workingDir)
Files.walk(workingDir).use { stream ->
decompiledJar.path.openZip().use { decompJar ->
val decompRoot = decompJar.rootDirectories.single()
@ -214,60 +205,6 @@ abstract class GenerateDevBundle : DefaultTask() {
workingDir.deleteRecursive()
}
private fun relocate(relocations: List<Relocation>, workingDir: Path) {
val wrappedRelocations = relocations.map { RelocationWrapper(it) }
Files.walk(workingDir).use { stream ->
stream.filter { it.isRegularFile() && it.name.endsWith(".java") }
.forEach { path -> replaceRelocationsInFile(path, wrappedRelocations) }
}
relocateFiles(wrappedRelocations, workingDir)
}
private fun replaceRelocationsInFile(path: Path, relocations: List<RelocationWrapper>) {
var content = path.readText(Charsets.UTF_8)
// Use hashes as intermediary to avoid double relocating
for (relocation in relocations) {
content = content.replace(relocation.fromDot, '.' + relocation.hashCode().toString())
.replace(relocation.fromSlash, '/' + relocation.hashCode().toString())
}
for (relocation in relocations) {
content = content.replace('.' + relocation.hashCode().toString(), relocation.toDot)
.replace('/' + relocation.hashCode().toString(), relocation.toSlash)
}
path.writeText(content, Charsets.UTF_8)
}
private fun relocateFiles(relocations: List<RelocationWrapper>, workingDir: Path) {
Files.walk(workingDir).use { stream -> stream.collect(Collectors.toList()) }
.asSequence().filter { it.isRegularFile() && it.name.endsWith(".java") }
.forEach { path ->
val potential = path.relativeTo(workingDir).invariantSeparatorsPathString
for (relocation in relocations) {
if (potential.startsWith(relocation.fromSlash)) {
if (excluded(relocation.relocation, potential)) {
break
}
val dest = workingDir.resolve(potential.replace(relocation.fromSlash, relocation.toSlash))
dest.parent.createDirectories()
path.moveTo(dest)
break
}
}
}
}
private fun excluded(relocation: Relocation, potential: String): Boolean = relocation.excludes.map {
it.replace('.', '/')
}.any { exclude ->
SelectorUtils.matchPath(exclude, potential, true)
}
private fun diffFiles(fileName: String, original: Path, patched: Path): String {
val dir = createTempDirectory("diff")
try {
@ -320,7 +257,7 @@ abstract class GenerateDevBundle : DefaultTask() {
}
private fun asString(out: ByteArrayOutputStream) = String(out.toByteArray(), Charset.defaultCharset())
.replace(System.getProperty("line.separator"), "\n")
.replace(System.lineSeparator(), "\n")
@Suppress("SameParameterValue")
private fun createBundleConfig(dataTargetDir: String, patchTargetDir: String): DevBundleConfig {
@ -336,8 +273,6 @@ abstract class GenerateDevBundle : DefaultTask() {
)
}
private fun relocations(): List<Relocation> = gson.fromJson(relocations.get())
private fun createBuildDataConfig(targetDir: String): BuildData {
return BuildData(
paramMappings = MavenDep(paramMappingsUrl.get(), listOf(paramMappingsCoordinates.get())),
@ -348,7 +283,7 @@ abstract class GenerateDevBundle : DefaultTask() {
compileDependencies = determineLibraries(vanillaServerLibraries.get()).sorted(),
runtimeDependencies = collectRuntimeDependencies().map { it.coordinates }.sorted(),
libraryRepositories = libraryRepositories.get(),
relocations = relocations(),
relocations = emptyList(), // Nothing is relocated in the dev bundle as of 1.20.5
minecraftRemapArgs = TinyRemapper.minecraftRemapArgs,
pluginRemapArgs = TinyRemapper.pluginRemapArgs,
)
@ -381,13 +316,7 @@ abstract class GenerateDevBundle : DefaultTask() {
}
}
val result = new.map { it.toString() }.toMutableSet()
// Remove relocated libraries
val libs = relocations().mapNotNull { it.owningLibraryCoordinates }
result.removeIf { coords -> libs.any { coords.startsWith(it) } }
return result
return new.map { it.toString() }.toSet()
}
private val ResolvedArtifactResult.coordinates: String

View file

@ -0,0 +1,156 @@
/*
* paperweight is a Gradle plugin for the PaperMC project.
*
* Copyright (c) 2023 Kyle Wood (DenWav)
* Contributors
*
* 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;
* version 2.1 only, no later versions.
*
* 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 dev.denwav.hypo.asm.AsmClassDataProvider
import dev.denwav.hypo.core.HypoConfig
import dev.denwav.hypo.core.HypoContext
import dev.denwav.hypo.hydrate.HydrationManager
import dev.denwav.hypo.mappings.ChangeChain
import dev.denwav.hypo.mappings.ChangeRegistry
import dev.denwav.hypo.mappings.MappingsCompletionManager
import dev.denwav.hypo.mappings.contributors.ChangeContributor
import dev.denwav.hypo.model.ClassProviderRoot
import dev.denwav.hypo.model.data.ClassData
import io.papermc.paperweight.util.*
import io.papermc.paperweight.util.constants.*
import javax.inject.Inject
import kotlin.io.path.*
import org.cadixdev.lorenz.model.ClassMapping
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.kotlin.dsl.*
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
@CacheableTask
abstract class GenerateRelocatedReobfMappings : JavaLauncherTask() {
@get:InputFile
@get:PathSensitive(PathSensitivity.NONE)
abstract val inputMappings: RegularFileProperty
@get:Classpath
abstract val inputJar: RegularFileProperty
@get:OutputFile
abstract val outputMappings: RegularFileProperty
@get:Internal
abstract val jvmArgs: ListProperty<String>
@get:Inject
abstract val workerExecutor: WorkerExecutor
@get:Input
abstract val craftBukkitPackageVersion: Property<String>
override fun init() {
super.init()
jvmArgs.convention(listOf("-Xmx2G"))
}
@TaskAction
fun run() {
val queue = workerExecutor.processIsolation {
forkOptions.jvmArgs(jvmArgs.get())
forkOptions.executable(launcher.get().executablePath.path.absolutePathString())
}
queue.submit(Action::class) {
inputMappings.set(this@GenerateRelocatedReobfMappings.inputMappings)
inputJar.set(this@GenerateRelocatedReobfMappings.inputJar)
craftBukkitPackageVersion.set(this@GenerateRelocatedReobfMappings.craftBukkitPackageVersion)
outputMappings.set(this@GenerateRelocatedReobfMappings.outputMappings)
}
}
abstract class Action : WorkAction<Action.Parameters> {
interface Parameters : WorkParameters {
val inputMappings: RegularFileProperty
val inputJar: RegularFileProperty
val craftBukkitPackageVersion: Property<String>
val outputMappings: RegularFileProperty
}
override fun execute() {
val mappingsIn = MappingFormats.TINY.read(
parameters.inputMappings.path,
DEOBF_NAMESPACE,
SPIGOT_NAMESPACE
)
val mappingsOut = HypoContext.builder()
.withConfig(HypoConfig.builder().setRequireFullClasspath(false).withParallelism(1).build())
.withProvider(AsmClassDataProvider.of(ClassProviderRoot.fromJar(parameters.inputJar.path)))
.withContextProvider(AsmClassDataProvider.of(ClassProviderRoot.ofJdk()))
.build().use { hypoContext ->
HydrationManager.createDefault().hydrate(hypoContext)
ChangeChain.create()
.addLink(CraftBukkitRelocation(parameters.craftBukkitPackageVersion.get()))
.applyChain(mappingsIn, MappingsCompletionManager.create(hypoContext))
}
MappingFormats.TINY.write(
mappingsOut,
parameters.outputMappings.path,
DEOBF_NAMESPACE,
SPIGOT_NAMESPACE
)
}
}
class CraftBukkitRelocation(packageVersion: String) : ChangeContributor {
companion object {
const val PREFIX = "org/bukkit/craftbukkit/"
const val MAIN = "${PREFIX}Main"
}
private val relocateTo: String = "$PREFIX$packageVersion"
override fun name(): String = "CraftBukkitRelocation"
override fun contribute(
currentClass: ClassData?,
classMapping: ClassMapping<*, *>?,
context: HypoContext,
registry: ChangeRegistry
) {
if (currentClass == null || classMapping != null) {
return
}
if (currentClass.name().startsWith(PREFIX) && !currentClass.name().startsWith(MAIN)) {
registry.submitChange(
GenerateReobfMappings.AddClassMappingChange(
currentClass.name(),
"$relocateTo/${currentClass.name().substring(PREFIX.length)}"
)
)
}
}
}
}

View file

@ -74,7 +74,7 @@ abstract class GenerateReobfMappings : JavaLauncherTask() {
abstract val reobfMappings: RegularFileProperty
@get:Internal
abstract val jvmargs: ListProperty<String>
abstract val jvmArgs: ListProperty<String>
@get:Inject
abstract val workerExecutor: WorkerExecutor
@ -86,13 +86,13 @@ abstract class GenerateReobfMappings : JavaLauncherTask() {
override fun init() {
super.init()
jvmargs.convention(listOf("-Xmx2G"))
jvmArgs.convention(listOf("-Xmx2G"))
}
@TaskAction
fun run() {
val queue = workerExecutor.processIsolation {
forkOptions.jvmArgs(jvmargs.get())
forkOptions.jvmArgs(jvmArgs.get())
forkOptions.executable(launcher.get().executablePath.path.absolutePathString())
}

View file

@ -22,11 +22,8 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.openZip
import io.papermc.paperweight.util.path
import kotlin.io.path.copyTo
import kotlin.io.path.createDirectories
import io.papermc.paperweight.util.*
import kotlin.io.path.*
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
@ -60,6 +57,10 @@ abstract class IncludeMappings : BaseTask() {
val dest = fs.getPath(mappingsDest.get())
dest.parent.createDirectories()
mappings.path.copyTo(dest)
fs.modifyManifest {
mainAttributes.putValue("Included-Mappings-Hash", mappings.path.hashFile(HashingAlgorithm.SHA256).asHexString().uppercase())
}
}
}
}

View file

@ -0,0 +1,145 @@
/*
* paperweight is a Gradle plugin for the PaperMC project.
*
* Copyright (c) 2023 Kyle Wood (DenWav)
* Contributors
*
* 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;
* version 2.1 only, no later versions.
*
* 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.*
import java.nio.file.Path
import kotlin.io.path.*
import org.gradle.api.Action
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.*
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.ClassNode
@Suppress("LeakingThis")
abstract class RelocateClassNameConstants : BaseTask() {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:OutputFile
abstract val outputJar: RegularFileProperty
@get:Nested
@get:Optional
abstract val relocations: ListProperty<RelocationInput>
@get:Input
@get:Optional
abstract val processOnly: ListProperty<String>
fun relocate(fromPackage: String, toPackage: String, op: Action<RelocationInput>) {
relocations.add(
objects.newInstance<RelocationInput>().apply {
this.fromPackage.set(fromPackage)
this.toPackage.set(toPackage)
op.execute(this)
}
)
}
init {
outputJar.convention(defaultOutput())
processOnly.convention(
listOf(
"org/bukkit/craftbukkit/**/*.class",
"org/bukkit/craftbukkit/*.class"
)
)
}
@TaskAction
fun run() {
outputJar.path.deleteForcefully()
outputJar.path.parent.createDirectories()
val relocations = relocations.get().map {
RelocationWrapper(Relocation(null, it.fromPackage.get(), it.toPackage.get(), emptyList()))
}
outputJar.path.writeZip().use { outputFs ->
inputJar.path.openZip().use { inputFs ->
val includes = processOnly.getOrElse(emptyList()).map {
inputFs.getPathMatcher("glob:${if (it.startsWith('/')) it else "/$it"}")
}
JarProcessing.processJar(
inputFs,
outputFs,
object : JarProcessing.ClassProcessor.VisitorBased {
override fun shouldProcess(file: Path): Boolean =
includes.isEmpty() || includes.any { it.matches(file) }
override fun processClass(node: ClassNode, parent: ClassVisitor, classNodeCache: ClassNodeCache): ClassVisitor =
ConstantRelocatingClassVisitor(parent, relocations)
}
)
}
}
}
private class ConstantRelocatingClassVisitor(
parent: ClassVisitor,
private val relocations: List<RelocationWrapper>
) : ClassVisitor(Opcodes.ASM9, parent) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
return object : MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) {
override fun visitLdcInsn(value: Any?) {
if (value is String) {
var v: String = value
for (relocation in relocations) {
if (v.startsWith(relocation.fromDot)) {
v = v.replace(relocation.fromDot, relocation.toDot)
} else if (v.startsWith(relocation.fromSlash)) {
v = v.replace(relocation.fromSlash, relocation.toSlash)
}
}
super.visitLdcInsn(v)
} else {
super.visitLdcInsn(value)
}
}
}
}
}
abstract class RelocationInput {
@get:Input
abstract val fromPackage: Property<String>
@get:Input
abstract val toPackage: Property<String>
}
}

View file

@ -76,21 +76,33 @@ abstract class RemapJar : JavaLauncherTask() {
@TaskAction
fun run() {
val logFile = layout.cache.resolve(paperTaskOutput("log"))
TinyRemapper.run(
argsList = remapperArgs.get(),
logFile = logFile,
inputJar = inputJar.path,
mappingsFile = mappingsFile.path,
fromNamespace = fromNamespace.get(),
toNamespace = toNamespace.get(),
remapClasspath = remapClasspath.files.map { it.toPath() },
remapper = remapper,
outputJar = outputJar.path,
launcher = launcher.get(),
workingDir = layout.cache,
jvmArgs = jvmArgs.get()
)
if (toNamespace.get() != fromNamespace.get()) {
val logFile = layout.cache.resolve(paperTaskOutput("log"))
TinyRemapper.run(
argsList = remapperArgs.get(),
logFile = logFile,
inputJar = inputJar.path,
mappingsFile = mappingsFile.path,
fromNamespace = fromNamespace.get(),
toNamespace = toNamespace.get(),
remapClasspath = remapClasspath.files.map { it.toPath() },
remapper = remapper,
outputJar = outputJar.path,
launcher = launcher.get(),
workingDir = layout.cache,
jvmArgs = jvmArgs.get()
)
} else {
outputJar.path.deleteForcefully()
outputJar.path.parent.createDirectories()
inputJar.path.copyTo(outputJar.path)
}
outputJar.path.openZip().use { fs ->
fs.modifyManifest {
mainAttributes.putValue(MAPPINGS_NAMESPACE_MANIFEST_KEY, toNamespace.get())
}
}
}
}

View file

@ -88,10 +88,12 @@ const val PATCHED_SPIGOT_MOJANG_YARN_MAPPINGS = "$MAPPINGS_DIR/spigot-mojang+yar
const val PATCHED_SPIGOT_MOJANG_YARN_SOURCE_MAPPINGS = "$MAPPINGS_DIR/spigot-mojang+yarn-patched-source.tiny"
const val REOBF_MOJANG_SPIGOT_MAPPINGS = "$MAPPINGS_DIR/mojang+yarn-spigot-reobf.tiny"
const val PATCHED_REOBF_MOJANG_SPIGOT_MAPPINGS = "$MAPPINGS_DIR/mojang+yarn-spigot-reobf-patched.tiny"
const val RELOCATED_PATCHED_REOBF_MOJANG_SPIGOT_MAPPINGS = "$MAPPINGS_DIR/mojang+yarn-spigot-reobf-patched-relocated.tiny"
const val OBF_NAMESPACE = "official"
const val SPIGOT_NAMESPACE = "spigot"
const val DEOBF_NAMESPACE = "mojang+yarn"
const val MAPPINGS_NAMESPACE_MANIFEST_KEY = "paperweight-mappings-namespace"
private const val DATA_PATH = "$PAPER_PATH/data"
const val MC_MANIFEST = "$DATA_PATH/McManifest.json"
@ -114,8 +116,6 @@ const val MC_DEV_SOURCES_DIR = "$PAPER_PATH/mc-dev-sources"
const val IVY_REPOSITORY = "$PAPER_PATH/ivyRepository"
const val RELOCATION_EXTENSION = "relocation"
const val DOWNLOAD_SERVICE_NAME = "paperweightDownloadService"
fun paperSetupOutput(name: String, ext: String) = "$SETUP_CACHE/$name.$ext"

View file

@ -22,7 +22,7 @@
package io.papermc.paperweight.util
import io.papermc.paperweight.extension.RelocationExtension
import io.papermc.paperweight.extension.PaperweightServerExtension
import io.papermc.paperweight.tasks.*
import io.papermc.paperweight.util.constants.*
import java.nio.file.Path
@ -31,13 +31,13 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.api.attributes.Usage
import org.gradle.api.file.RegularFile
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip
import org.gradle.kotlin.dsl.*
import org.gradle.plugins.ide.idea.model.IdeaModel
@ -48,7 +48,8 @@ fun Project.setupServerProject(
mcDevSourceDir: Path,
libsFile: Any,
packagesToFix: Provider<List<String>?>,
reobfMappings: Provider<RegularFile>,
relocatedReobfMappings: TaskProvider<GenerateRelocatedReobfMappings>,
serverJar: TaskProvider<Zip>
): ServerTasks? {
if (!projectDir.exists()) {
return null
@ -56,7 +57,10 @@ fun Project.setupServerProject(
plugins.apply("java")
extensions.create<RelocationExtension>(RELOCATION_EXTENSION, objects)
val serverExt = extensions.create<PaperweightServerExtension>(PAPERWEIGHT_EXTENSION, objects)
relocatedReobfMappings {
craftBukkitPackageVersion.set(serverExt.craftBukkitPackageVersion)
}
exportRuntimeClasspathTo(parent)
@ -103,8 +107,7 @@ fun Project.setupServerProject(
addMcDevSourcesRoot(mcDevSourceDir)
plugins.apply("com.github.johnrengelman.shadow")
return createBuildTasks(parent, packagesToFix, reobfMappings)
return createBuildTasks(parent, serverExt, serverJar, vanillaServer, packagesToFix, relocatedReobfMappings)
}
private fun Project.exportRuntimeClasspathTo(parent: Project) {
@ -137,25 +140,55 @@ private fun Project.exportRuntimeClasspathTo(parent: Project) {
private fun Project.createBuildTasks(
parent: Project,
serverExt: PaperweightServerExtension,
serverJar: TaskProvider<Zip>,
vanillaServer: Configuration,
packagesToFix: Provider<List<String>?>,
reobfMappings: Provider<RegularFile>
relocatedReobfMappings: TaskProvider<GenerateRelocatedReobfMappings>
): ServerTasks {
val shadowJar: TaskProvider<Jar> = tasks.named("shadowJar", Jar::class)
serverJar {
destinationDirectory.set(layout.buildDirectory.dir("libs"))
archiveExtension.set("jar")
archiveClassifier.set("mojang-mapped")
from(zipTree(tasks.named<Jar>("jar").flatMap { it.archiveFile }.map { it.asFile }))
from(vanillaServer.elements.map { it.map { f -> zipTree(f.asFile) } }) {
exclude("META-INF/MANIFEST.MF")
}
isReproducibleFileOrder = true
isPreserveFileTimestamps = false
}
val fixJarForReobf by tasks.registering<FixJarForReobf> {
dependsOn(shadowJar)
inputJar.set(shadowJar.flatMap { it.archiveFile })
inputJar.set(serverJar.flatMap { it.archiveFile })
packagesToProcess.set(packagesToFix)
}
val includeMappings by tasks.registering<IncludeMappings> {
inputJar.set(fixJarForReobf.flatMap { it.outputJar })
mappings.set(relocatedReobfMappings.flatMap { it.outputMappings })
mappingsDest.set("META-INF/mappings/reobf.tiny")
}
// We only need to manually relocate references to CB class names in string constants, the actual relocation is handled by the mappings
val relocateConstants by tasks.registering<RelocateClassNameConstants> {
inputJar.set(includeMappings.flatMap { it.outputJar })
}
afterEvaluate {
relocateConstants {
relocate("org.bukkit.craftbukkit", "org.bukkit.craftbukkit.${serverExt.craftBukkitPackageVersion.get()}") {
// This is not actually needed as there are no string constant references to Main
// exclude("org.bukkit.craftbukkit.Main*")
}
}
}
val reobfJar by tasks.registering<RemapJar> {
group = "paperweight"
description = "Re-obfuscate the built jar to obf mappings"
inputJar.set(fixJarForReobf.flatMap { it.outputJar })
inputJar.set(relocateConstants.flatMap { it.outputJar })
mappingsFile.set(reobfMappings)
mappingsFile.set(relocatedReobfMappings.flatMap { it.outputMappings })
fromNamespace.set(DEOBF_NAMESPACE)
toNamespace.set(SPIGOT_NAMESPACE)
@ -166,11 +199,11 @@ private fun Project.createBuildTasks(
outputJar.set(layout.buildDirectory.map { it.dir("libs").file("${project.name}-${project.version}-reobf.jar") })
}
return ServerTasks(fixJarForReobf, reobfJar)
return ServerTasks(includeMappings, reobfJar)
}
data class ServerTasks(
val fixJarForReobf: TaskProvider<FixJarForReobf>,
val includeMappings: TaskProvider<IncludeMappings>,
val reobfJar: TaskProvider<RemapJar>,
)

View file

@ -20,29 +20,7 @@
* USA
*/
package io.papermc.paperweight.extension
import org.gradle.api.model.ObjectFactory
import org.gradle.kotlin.dsl.*
abstract class RelocationExtension(objects: ObjectFactory) {
val relocations = objects.listProperty<Relocation>()
fun relocate(
owningLibraryCoordinates: String,
relocation: Pair<String, String>,
config: Relocation.() -> Unit = {}
) {
relocations.add(Relocation(owningLibraryCoordinates, relocation.first, relocation.second, arrayListOf()).apply(config))
}
fun relocate(
relocation: Pair<String, String>,
config: Relocation.() -> Unit = {}
) {
relocations.add(Relocation(null, relocation.first, relocation.second, arrayListOf()).apply(config))
}
}
package io.papermc.paperweight.util
data class Relocation(
val owningLibraryCoordinates: String?,

View file

@ -36,6 +36,7 @@ import java.lang.management.ManagementFactory
import java.lang.reflect.Type
import java.net.URI
import java.net.URL
import java.nio.file.FileSystem
import java.nio.file.Path
import java.nio.file.Paths
import java.security.MessageDigest
@ -46,6 +47,8 @@ import java.util.Optional
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ThreadLocalRandom
import java.util.concurrent.atomic.AtomicLong
import java.util.jar.Attributes
import java.util.jar.Manifest
import kotlin.io.path.*
import org.cadixdev.lorenz.merge.MergeResult
import org.gradle.api.Project
@ -380,3 +383,23 @@ inline fun <reified P> printId(pluginId: String, gradle: Gradle) {
}
println("$pluginId v${P::class.java.`package`.implementationVersion} (running on '${System.getProperty("os.name")}')")
}
fun FileSystem.modifyManifest(create: Boolean = true, op: Manifest.() -> Unit) {
modifyManifest(getPath("META-INF/MANIFEST.MF"), create, op)
}
fun modifyManifest(path: Path, create: Boolean = true, op: Manifest.() -> Unit) {
val exists = path.exists()
if (exists || create) {
val mf = if (exists) {
path.inputStream().buffered().use { Manifest(it) }
} else {
path.parent.createDirectories()
val manifest = Manifest()
manifest.mainAttributes[Attributes.Name.MANIFEST_VERSION] = "1.0"
manifest
}
op(mf)
path.outputStream().buffered().use { mf.write(it) }
}
}

View file

@ -41,7 +41,7 @@ import org.gradle.api.Task
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip
import org.gradle.kotlin.dsl.*
import org.gradle.kotlin.dsl.registering
@ -90,6 +90,11 @@ class PaperweightPatcher : Plugin<Project> {
toNamespace.set(SPIGOT_NAMESPACE)
}
val generateRelocatedReobfMappings by target.tasks.registering<GenerateRelocatedReobfMappings> {
inputMappings.set(patchReobfMappings.flatMap { it.outputMappings })
outputMappings.set(target.layout.cache.resolve(RELOCATED_PATCHED_REOBF_MOJANG_SPIGOT_MAPPINGS))
}
val prepareForDownstream = target.tasks.register<PaperweightPatcherPrepareForDownstream>(PAPERWEIGHT_PREPARE_DOWNSTREAM) {
dataFile.fileProvider(dataFileProp.map { File(it) })
reobfMappingsPatch.set(mergeReobfMappingsPatches.flatMap { it.outputMappings })
@ -155,27 +160,30 @@ class PaperweightPatcher : Plugin<Project> {
}
val serverProj = patcher.serverProject.orNull ?: return@afterEvaluate
serverProj.apply(plugin = "com.github.johnrengelman.shadow")
val shadowJar = serverProj.tasks.named("shadowJar", Jar::class)
val serverJar = serverProj.tasks.register("serverJar", Zip::class)
generateReobfMappings {
inputMappings.pathProvider(upstreamData.map { it.mappings })
notchToSpigotMappings.pathProvider(upstreamData.map { it.notchToSpigotMappings })
sourceMappings.pathProvider(upstreamData.map { it.sourceMappings })
inputJar.set(shadowJar.flatMap { it.archiveFile })
inputJar.set(serverJar.flatMap { it.archiveFile })
spigotRecompiledClasses.pathProvider(upstreamData.map { it.spigotRecompiledClasses })
reobfMappings.set(target.layout.cache.resolve(REOBF_MOJANG_SPIGOT_MAPPINGS))
}
generateRelocatedReobfMappings {
inputJar.set(serverJar.flatMap { it.archiveFile })
}
val (_, reobfJar) = serverProj.setupServerProject(
val (includeMappings, reobfJar) = serverProj.setupServerProject(
target,
upstreamData.map { it.remappedJar },
upstreamData.map { it.decompiledJar },
patcher.mcDevSourceDir.path,
upstreamData.map { it.libFile },
mergedReobfPackagesToFix,
patchReobfMappings.flatMap { it.outputMappings }
generateRelocatedReobfMappings,
serverJar
) ?: return@afterEvaluate
devBundleTasks.configure(
@ -191,7 +199,7 @@ class PaperweightPatcher : Plugin<Project> {
upstreamData.map { it.bundlerVersionJson }.convertToFileProvider(layout, providers)
) {
vanillaJarIncludes.set(upstreamData.map { it.vanillaIncludes })
reobfMappingsFile.set(patchReobfMappings.flatMap { it.outputMappings })
reobfMappingsFile.set(generateRelocatedReobfMappings.flatMap { it.outputMappings })
paramMappingsCoordinates.set(upstreamData.map { it.paramMappings.coordinates.single() })
paramMappingsUrl.set(upstreamData.map { it.paramMappings.url })
@ -202,7 +210,7 @@ class PaperweightPatcher : Plugin<Project> {
upstreamData.map { it.bundlerVersionJson }.convertToFileProvider(target.layout, target.providers),
upstreamData.map { it.serverLibrariesList }.convertToFileProvider(target.layout, target.providers),
upstreamData.map { it.vanillaJar }.convertToFileProvider(target.layout, target.providers),
shadowJar,
includeMappings.flatMap { it.outputJar },
reobfJar,
upstreamData.map { it.mcVersion }
)

View file

@ -33,6 +33,7 @@ import io.papermc.paperweight.util.*
import io.papermc.paperweight.util.constants.*
import java.nio.file.Path
import javax.inject.Inject
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.ModuleDependency
@ -48,6 +49,7 @@ import org.gradle.api.logging.Logging
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.bundling.Jar
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.kotlin.dsl.*
import org.gradle.util.internal.NameMatcher
@ -156,6 +158,8 @@ abstract class PaperweightUser : Plugin<Project> {
userdev.reobfArtifactConfiguration.get()
.configure(this, reobfJar)
decorateJarManifests()
if (userdev.injectPaperRepository.get()) {
repositories.maven(PAPER_MAVEN_REPO_URL) {
content { onlyForConfigurations(DEV_BUNDLE_CONFIG) }
@ -171,6 +175,18 @@ abstract class PaperweightUser : Plugin<Project> {
}
}
private fun Project.decorateJarManifests() {
val op = Action<Jar> {
manifest {
attributes(MAPPINGS_NAMESPACE_MANIFEST_KEY to DEOBF_NAMESPACE)
}
}
tasks.named("jar", Jar::class, op)
if ("shadowJar" in tasks.names) {
tasks.named("shadowJar", Jar::class, op)
}
}
private fun Project.configureRepositories(userdevSetup: UserdevSetup) = repositories {
maven(userdevSetup.paramMappings.url) {
name = PARAM_MAPPINGS_REPO_NAME

View file

@ -22,15 +22,10 @@
package io.papermc.paperweight.userdev.internal.setup.step
import io.papermc.paperweight.extension.Relocation
import io.papermc.paperweight.extension.RelocationWrapper
import io.papermc.paperweight.userdev.internal.setup.SetupHandler
import io.papermc.paperweight.userdev.internal.setup.util.HashFunctionBuilder
import io.papermc.paperweight.userdev.internal.setup.util.siblingHashesFile
import io.papermc.paperweight.util.filterJar
import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.openZip
import io.papermc.paperweight.util.walk
import io.papermc.paperweight.util.*
import java.nio.file.Path
import kotlin.io.path.isRegularFile
import kotlin.io.path.name

View file

@ -22,7 +22,6 @@
package io.papermc.paperweight.userdev.internal.setup.v2
import io.papermc.paperweight.extension.Relocation
import io.papermc.paperweight.util.*
object DevBundleV2 {