Run paperclip patch process in separate process
This commit is contained in:
parent
c4eb91fe8f
commit
2c4b1e1409
4 changed files with 123 additions and 79 deletions
|
@ -92,10 +92,12 @@ class Paperweight : Plugin<Project> {
|
|||
|
||||
val tasks = target.createTasks()
|
||||
|
||||
val generatePaperclipPatch by target.tasks.registering<GeneratePaperclipPatch>()
|
||||
|
||||
// Setup the server jar
|
||||
target.afterEvaluate {
|
||||
target.ext.serverProject.forUseAtConfigurationTime().orNull?.setupServerProject(target, tasks.spigotTasks)?.let { reobfJar ->
|
||||
val generatePaperclipPatch by target.tasks.registering<GeneratePaperclipPatch> {
|
||||
generatePaperclipPatch.configure {
|
||||
originalJar.set(tasks.generalTasks.downloadServerJar.flatMap { it.outputJar })
|
||||
patchedJar.set(reobfJar.flatMap { it.outputJar })
|
||||
mcVersion.set(target.ext.minecraftVersion)
|
||||
|
@ -103,13 +105,13 @@ class Paperweight : Plugin<Project> {
|
|||
|
||||
target.tasks.named("jar", Jar::class) {
|
||||
val paperclipConfig = target.configurations.named(Constants.PAPERCLIP_CONFIG)
|
||||
dependsOn(paperclipConfig)
|
||||
dependsOn(paperclipConfig, generatePaperclipPatch)
|
||||
|
||||
val paperclipZip = target.zipTree(paperclipConfig.map { it.singleFile })
|
||||
from(paperclipZip) {
|
||||
exclude("META-INF/MANIFEST.MF")
|
||||
}
|
||||
from(target.zipTree(generatePaperclipPatch.flatMap { it.outputZip }.get()))
|
||||
from(target.zipTree(generatePaperclipPatch.flatMap { it.outputZip }))
|
||||
|
||||
manifest.from(paperclipZip.matching { include("META-INF/MANIFEST.MF") }.singleFile)
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ abstract class GenerateMappings : DefaultTask() {
|
|||
@get:OutputFile
|
||||
abstract val outputMappings: RegularFileProperty
|
||||
|
||||
// @get:Inject
|
||||
// abstract val workerExecutor: WorkerExecutor
|
||||
@get:Inject
|
||||
abstract val workerExecutor: WorkerExecutor
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
|
@ -94,7 +94,6 @@ abstract class GenerateMappings : DefaultTask() {
|
|||
).merge()
|
||||
|
||||
// Fill out any missing inheritance info in the mappings
|
||||
/*
|
||||
val tempMappingsFile = Files.createTempFile("mappings", "tiny")
|
||||
val tempMappingsOutputFile = Files.createTempFile("mappings-out", "tiny")
|
||||
|
||||
|
@ -118,10 +117,9 @@ abstract class GenerateMappings : DefaultTask() {
|
|||
Files.deleteIfExists(tempMappingsFile)
|
||||
Files.deleteIfExists(tempMappingsOutputFile)
|
||||
}
|
||||
*/
|
||||
|
||||
ensureParentExists(outputMappings)
|
||||
MappingFormats.TINY.write(merged, outputMappings.path, Constants.OBF_NAMESPACE, Constants.DEOBF_NAMESPACE)
|
||||
MappingFormats.TINY.write(filledMerged, outputMappings.path, Constants.OBF_NAMESPACE, Constants.DEOBF_NAMESPACE)
|
||||
}
|
||||
|
||||
abstract class AtlasAction : WorkAction<AtlasParameters> {
|
||||
|
|
|
@ -36,11 +36,16 @@ import java.nio.file.StandardCopyOption
|
|||
import java.security.MessageDigest
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.util.Properties
|
||||
import javax.inject.Inject
|
||||
import kotlin.experimental.and
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.kotlin.dsl.submit
|
||||
import org.gradle.workers.WorkAction
|
||||
import org.gradle.workers.WorkParameters
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
|
||||
abstract class GeneratePaperclipPatch : ZippedTask() {
|
||||
|
||||
|
@ -51,88 +56,122 @@ abstract class GeneratePaperclipPatch : ZippedTask() {
|
|||
@get:Input
|
||||
abstract val mcVersion: Property<String>
|
||||
|
||||
@get:Inject
|
||||
abstract val workerExecutor: WorkerExecutor
|
||||
|
||||
override fun run(rootDir: File) {
|
||||
val patchFile = rootDir.resolve("paperMC.patch").toPath()
|
||||
val propFile = rootDir.resolve("patch.properties").toPath()
|
||||
val protocol = rootDir.resolve("META-INF/$PROTOCOL_FILE").toPath()
|
||||
|
||||
val zipUri = try {
|
||||
val jarUri = patchedJar.file.toURI()
|
||||
URI("jar:${jarUri.scheme}", jarUri.path, null)
|
||||
} catch (e: URISyntaxException) {
|
||||
throw PaperweightException("Failed to create jar URI for $patchedJar", e)
|
||||
val queue = workerExecutor.processIsolation {
|
||||
forkOptions.jvmArgs("-Xmx2G")
|
||||
}
|
||||
|
||||
try {
|
||||
FileSystems.newFileSystem(zipUri, mapOf<String, Any>()).use { zipFs ->
|
||||
val protocolPath = zipFs.getPath("META-INF", PROTOCOL_FILE)
|
||||
if (Files.notExists(protocolPath)) {
|
||||
Files.deleteIfExists(protocol)
|
||||
return@use
|
||||
queue.submit(PaperclipAction::class) {
|
||||
zipRootDir.set(rootDir)
|
||||
originalJar.set(this@GeneratePaperclipPatch.originalJar.file)
|
||||
patchedJar.set(this@GeneratePaperclipPatch.patchedJar.file)
|
||||
mcVersion.set(this@GeneratePaperclipPatch.mcVersion.get())
|
||||
}
|
||||
|
||||
queue.await()
|
||||
}
|
||||
|
||||
abstract class PaperclipAction : WorkAction<PaperclipParameters> {
|
||||
override fun execute() {
|
||||
val rootDir = parameters.zipRootDir.path
|
||||
val originalJarPath = parameters.originalJar.path
|
||||
val patchedJarPath = parameters.patchedJar.path
|
||||
|
||||
val patchFile = rootDir.resolve("paperMC.patch")
|
||||
val propFile = rootDir.resolve("patch.properties")
|
||||
val protocol = rootDir.resolve("META-INF/$PROTOCOL_FILE")
|
||||
|
||||
val zipUri = try {
|
||||
val jarUri = patchedJarPath.toUri()
|
||||
URI("jar:${jarUri.scheme}", jarUri.path, null)
|
||||
} catch (e: URISyntaxException) {
|
||||
throw PaperweightException("Failed to create jar URI for $patchedJarPath", e)
|
||||
}
|
||||
|
||||
try {
|
||||
FileSystems.newFileSystem(zipUri, mapOf<String, Any>()).use { zipFs ->
|
||||
val protocolPath = zipFs.getPath("META-INF", PROTOCOL_FILE)
|
||||
if (Files.notExists(protocolPath)) {
|
||||
Files.deleteIfExists(protocol)
|
||||
return@use
|
||||
}
|
||||
|
||||
Files.createDirectories(protocol.parent)
|
||||
Files.copy(protocolPath, protocol, StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
|
||||
Files.createDirectories(protocol.parent)
|
||||
Files.copy(protocolPath, protocol, StandardCopyOption.REPLACE_EXISTING)
|
||||
} catch (e: IOException) {
|
||||
throw PaperweightException("Failed to read $patchedJarPath contents", e)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
throw PaperweightException("Failed to read $patchedJar contents", e)
|
||||
}
|
||||
|
||||
// Read the files into memory
|
||||
println("Reading jars into memory")
|
||||
val originalBytes = Files.readAllBytes(originalJar.path)
|
||||
val patchedBytes = Files.readAllBytes(patchedJar.path)
|
||||
// Read the files into memory
|
||||
println("Reading jars into memory")
|
||||
val originalBytes = Files.readAllBytes(originalJarPath)
|
||||
val patchedBytes = Files.readAllBytes(patchedJarPath)
|
||||
|
||||
println("Creating Paperclip patch")
|
||||
try {
|
||||
Files.newOutputStream(patchFile).use { patchOutput ->
|
||||
Diff.diff(originalBytes, patchedBytes, patchOutput)
|
||||
println("Creating Paperclip patch")
|
||||
try {
|
||||
Files.newOutputStream(patchFile).use { patchOutput ->
|
||||
Diff.diff(originalBytes, patchedBytes, patchOutput)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw PaperweightException("Error creating patch between $originalJarPath and $patchedJarPath", e)
|
||||
}
|
||||
|
||||
// Add the SHA-256 hashes for the files
|
||||
val digestSha256 = try {
|
||||
MessageDigest.getInstance("SHA-256")
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
throw PaperweightException("Could not create SHA-256 hasher", e)
|
||||
}
|
||||
|
||||
// Vanilla's URL uses a SHA1 hash of the vanilla server jar
|
||||
val digestSha1 = try {
|
||||
MessageDigest.getInstance("SHA1")
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
throw PaperweightException("Could not create SHA1 hasher", e)
|
||||
}
|
||||
|
||||
println("Hashing files")
|
||||
val originalSha1 = digestSha1.digest(originalBytes)
|
||||
val originalSha256 = digestSha256.digest(originalBytes)
|
||||
val patchedSha256 = digestSha256.digest(patchedBytes)
|
||||
|
||||
val prop = Properties()
|
||||
prop["originalHash"] = toHex(originalSha256)
|
||||
prop["patchedHash"] = toHex(patchedSha256)
|
||||
prop["patch"] = "paperMC.patch"
|
||||
prop["sourceUrl"] = "https://launcher.mojang.com/v1/objects/" + toHex(originalSha1).toLowerCase() + "/server.jar"
|
||||
prop["version"] = parameters.mcVersion.get()
|
||||
|
||||
println("Writing properties file")
|
||||
Files.newBufferedWriter(propFile).use { writer ->
|
||||
prop.store(
|
||||
writer,
|
||||
"Default Paperclip launch values. Can be overridden by placing a paperclip.properties file in the server directory."
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw PaperweightException("Error creating patch between ${originalJar.path} and ${patchedJar.path}", e)
|
||||
}
|
||||
|
||||
// Add the SHA-256 hashes for the files
|
||||
val digestSha256 = try {
|
||||
MessageDigest.getInstance("SHA-256")
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
throw PaperweightException("Could not create SHA-256 hasher", e)
|
||||
private fun toHex(hash: ByteArray): String {
|
||||
val sb: StringBuilder = StringBuilder(hash.size * 2)
|
||||
for (aHash in hash) {
|
||||
sb.append("%02X".format(aHash and 0xFF.toByte()))
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
// Vanilla's URL uses a SHA1 hash of the vanilla server jar
|
||||
val digestSha1 = try {
|
||||
MessageDigest.getInstance("SHA1")
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
throw PaperweightException("Could not create SHA1 hasher", e)
|
||||
}
|
||||
|
||||
println("Hashing files")
|
||||
val originalSha1 = digestSha1.digest(originalBytes)
|
||||
val originalSha256 = digestSha256.digest(originalBytes)
|
||||
val patchedSha256 = digestSha256.digest(patchedBytes)
|
||||
|
||||
val prop = Properties()
|
||||
prop["originalHash"] = toHex(originalSha256)
|
||||
prop["patchedHash"] = toHex(patchedSha256)
|
||||
prop["patch"] = "paperMC.patch"
|
||||
prop["sourceUrl"] = "https://launcher.mojang.com/v1/objects/" + toHex(originalSha1).toLowerCase() + "/server.jar"
|
||||
prop["version"] = mcVersion.get()
|
||||
|
||||
println("Writing properties file")
|
||||
Files.newBufferedWriter(propFile).use { writer ->
|
||||
prop.store(writer, "Default Paperclip launch values. Can be overridden by placing a paperclip.properties file in the server directory.")
|
||||
companion object {
|
||||
private const val PROTOCOL_FILE = "io.papermc.paper.daemon.protocol"
|
||||
}
|
||||
}
|
||||
|
||||
private fun toHex(hash: ByteArray): String {
|
||||
val sb: StringBuilder = StringBuilder(hash.size * 2)
|
||||
for (aHash in hash) {
|
||||
sb.append("%02X".format(aHash and 0xFF.toByte()))
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PROTOCOL_FILE = "io.papermc.paper.daemon.protocol"
|
||||
interface PaperclipParameters : WorkParameters {
|
||||
val zipRootDir: RegularFileProperty
|
||||
val originalJar: RegularFileProperty
|
||||
val patchedJar: RegularFileProperty
|
||||
val mcVersion: Property<String>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,16 +168,21 @@ fun <T> emptyMergeResult(): MergeResult<T?> {
|
|||
}
|
||||
|
||||
// We have to create our own task delegate because the ones Gradle provides don't work in plugin dev environments
|
||||
inline fun <reified T : Task> TaskContainer.registering(noinline configure: T.() -> Unit): TaskDelegateProvider<T> {
|
||||
inline fun <reified T : Task> TaskContainer.registering(noinline configure: (T.() -> Unit)? = null): TaskDelegateProvider<T> {
|
||||
return TaskDelegateProvider(this, T::class, configure)
|
||||
}
|
||||
class TaskDelegateProvider<T : Task>(
|
||||
private val container: TaskContainer,
|
||||
private val type: KClass<T>,
|
||||
private val configure: T.() -> Unit
|
||||
private val configure: (T.() -> Unit)?
|
||||
) {
|
||||
operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): TaskDelegate<T> {
|
||||
val provider = container.register(property.name, type.java, configure)
|
||||
val provider = if (configure != null) {
|
||||
container.register(property.name, type.java, configure)
|
||||
} else {
|
||||
container.register(property.name, type.java) {
|
||||
}
|
||||
}
|
||||
return TaskDelegate(provider)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue