Gradle 6.7, initial patch remap (not working)

This commit is contained in:
Kyle Wood 2020-08-11 23:01:37 -07:00
parent 1a94055556
commit a25958b31e
68 changed files with 3498 additions and 1658 deletions

1
.gitattributes vendored
View file

@ -5,4 +5,3 @@ gradlew text eol=lf
*.bat text eol=crlf
*.jar binary

143
.gitignore vendored
View file

@ -1,25 +1,14 @@
### Intellij ###
# IntelliJ
.idea/
out/
# File-based project format
*.ipr
*.iws
*.iml
# IntelliJ
out/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Eclipse ###
# Eclipse
.metadata
.project
bin/
tmp/
*.tmp
@ -30,143 +19,27 @@ local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
### Eclipse Patch ###
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Annotation Processing
.apt_generated
.sts4-cache/
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
# macOS
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Windows ###
# Windows
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
### Gradle ###
# Gradle
.gradle
/build/
# Ignore Gradle GUI config
gradle-app.setting
# Cache of project
.gradletasknamecache
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.ja

View file

@ -4,7 +4,6 @@ plugins {
idea
eclipse
maven
kotlin("jvm") version "1.3.70"
`kotlin-dsl`
id("net.minecrell.licenser") version "0.4.1"
id("com.github.johnrengelman.shadow") version "6.0.0"
@ -16,43 +15,36 @@ version = "1.0.0-SNAPSHOT"
repositories {
mavenLocal()
mavenCentral()
jcenter()
maven("https://oss.sonatype.org/content/repositories/snapshots/")
maven("https://files.minecraftforge.net/maven/")
}
val mcInjector: Configuration by configurations.creating
dependencies {
implementation(kotlin("stdlib-jdk8"))
compileOnly(gradleApi())
compileOnly(gradleKotlinDsl())
implementation("org.apache.httpcomponents:httpclient:4.5.12")
// Utils
implementation("net.sf.opencsv:opencsv:2.3")
implementation("com.github.salomonbrys.kotson:kotson:2.5.0")
// ASM for inspection
implementation("org.ow2.asm:asm:8.0.1")
// Cadix
implementation("org.cadixdev:lorenz:0.5.4-SNAPSHOT")
implementation("org.cadixdev:lorenz-asm:0.5.3")
implementation("org.cadixdev:mercury:0.1.0-SNAPSHOT")
implementation("org.cadixdev:atlas:0.2.0")
implementation("org.cadixdev:at:0.1.0-SNAPSHOT")
implementation("org.cadixdev:mercury:0.1.0-SNAPSHOT")
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
val mcinjectorJar by tasks.registering(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) {
configurations = listOf(mcInjector)
archiveBaseName.set("mcinjector-shadowed")
archiveVersion.set("")
archiveClassifier.set("")
manifest {
attributes(mapOf("Main-Class" to "de.oceanlabs.mcp.mcinjector.MCInjector"))
}
kotlinOptions.freeCompilerArgs = listOf("-Xjvm-default=enable")
}
tasks.jar {
from(mcinjectorJar)
archiveBaseName.set("io.papermc.paperweight.gradle.plugin")
}

Binary file not shown.

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

53
gradlew vendored
View file

@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

43
gradlew.bat vendored
View file

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

View file

@ -2,7 +2,6 @@ paperweight is a Gradle plugin for the PaperMC project. It uses
some code and systems originally from ForgeGradle.
Copyright (C) 2020 Kyle Wood
Copyright (C) 2018 Forge Development LLC
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -25,149 +24,264 @@
package io.papermc.paperweight
import com.github.salomonbrys.kotson.array
import com.github.salomonbrys.kotson.fromJson
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.ApplyAccessTransform
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
import io.papermc.paperweight.tasks.DownloadMcpTools
import io.papermc.paperweight.tasks.DownloadServerJar
import io.papermc.paperweight.tasks.ExtractMcpData
import io.papermc.paperweight.tasks.ExtractMcpMappings
import io.papermc.paperweight.tasks.DownloadSpigotDependencies
import io.papermc.paperweight.tasks.DownloadTask
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.GatherBuildData
import io.papermc.paperweight.tasks.GenerateSpigotSrgs
import io.papermc.paperweight.tasks.GenerateSrgs
import io.papermc.paperweight.tasks.GetRemoteJsons
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.RemapSources
import io.papermc.paperweight.tasks.RemapVanillaJarSrg
import io.papermc.paperweight.tasks.RemapAccessTransform
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.SetupMcpDependencies
import io.papermc.paperweight.tasks.SetupSpigotDependencies
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
import io.papermc.paperweight.tasks.patchremap.RemapPatches
import io.papermc.paperweight.tasks.sourceremap.RemapSources
import io.papermc.paperweight.util.BuildDataInfo
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.Git
import io.papermc.paperweight.tasks.RemapSrgSources
import io.papermc.paperweight.tasks.RemapVanillaJarSpigot
import io.papermc.paperweight.util.MinecraftManifest
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.contents
import io.papermc.paperweight.util.ext
import io.papermc.paperweight.util.fromJson
import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.registering
import org.gradle.api.Plugin
import org.gradle.api.Project
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.Zip
import org.gradle.kotlin.dsl.maven
import org.gradle.kotlin.dsl.register
import util.BuildDataInfo
import java.io.File
class Paperweight : Plugin<Project> {
override fun apply(target: Project) {
target.extensions.create(Constants.EXTENSION, PaperweightExtension::class.java, target)
target.extensions.create(Constants.EXTENSION, PaperweightExtension::class.java, target.objects, target.layout)
createConfigurations(target)
setupMcpDeps(target)
createTasks(target)
target.tasks.register("cleanCache").configure {
destroyables.register(target.cache)
doLast {
target.delete(target.cache)
}
target.tasks.register<Delete>("cleanCache") {
delete(target.layout.cache)
}
}
private fun createConfigurations(project: Project) {
project.repositories.apply {
// Make sure the submodules are initialized
Git(target.projectDir)("submodule", "update", "--init").execute()
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 {
name = "forge"
url = project.uri(Constants.FORGE_MAVEN_URL)
metadataSources {
artifact()
}
}
mavenCentral()
maven {
name = "minecraft"
url = project.uri(Constants.MC_LIBRARY_URL)
}
}
project.configurations.register(Constants.MCP_MAPPINGS_CONFIG)
project.configurations.register(Constants.MCP_DATA_CONFIG)
project.configurations.register(Constants.SPIGOT_DEP_CONFIG)
project.configurations.create(Constants.MINECRAFT_DEP_CONFIG)
project.configurations.register(Constants.FORGE_FLOWER_CONFIG)
project.configurations.create(Constants.MCINJECT_CONFIG)
target.createTasks()
}
private fun setupMcpDeps(project: Project) {
project.dependencies.add(Constants.MCP_DATA_CONFIG, project.provider {
mapOf(
"group" to "de.oceanlabs.mcp",
"name" to "mcp_config",
"version" to "${project.ext.mcpMinecraftVersion.get()}-${project.ext.mcpVersion.get()}",
"ext" to "zip"
)
})
private fun Project.createTasks() {
val extension = ext
project.dependencies.add(Constants.MCP_MAPPINGS_CONFIG, project.provider {
mapOf(
"group" to "de.oceanlabs.mcp",
"name" to "mcp_${project.ext.mcpMappingsChannel.get()}",
"version" to project.ext.mcpMappingsVersion.get(),
"ext" to "zip"
)
})
val initialTasks = createInitialTasks()
val generalTasks = createGeneralTasks()
val mcpTasks = createMcpTasks(initialTasks, generalTasks)
val spigotTasks = createSpigotTasks(initialTasks, generalTasks, mcpTasks)
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 })
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 patchPaperApi by tasks.registering<ApplyGitPatches> {
branch.set("HEAD")
upstreamBranch.set("upstream")
upstream.set(spigotTasks.patchSpigotApi.flatMap { it.outputDir })
patchDir.set(extension.paper.spigotApiPatchDir)
printOutput.set(true)
outputDir.set(extension.paper.paperApiDir)
}
val patchPaperServer by tasks.registering<ApplyPaperPatches> {
patchDir.set(extension.paper.spigotServerPatchDir)
remappedSource.set(mergeRemappedSources.flatMap { it.outputJar })
templateGitIgnore.set(layout.projectDirectory.file(".gitignore"))
outputDir.set(extension.paper.paperServerDir)
}
val patchPaper by tasks.registering<Task> {
dependsOn(patchPaperApi, patchPaperServer)
}
/*
* Not bothering mapping away from SRG until everything is stable under SRG
* Moving off of SRG will make things a lot more fragile
val remapSrgSourcesSpigotVanilla by tasks.registering<RemapSrgSources> {
inputZips.add(ZipTarget.base(applyMcpPatches.flatMap { outputZip }))
methodsCsv.set(mcpRewrites.flatMap { methodsCsv })
fieldsCsv.set(mcpRewrites.flatMap { fieldsCsv })
paramsCsv.set(mcpRewrites.flatMap { paramsCsv })
}
*/
}
// Types are specified in this method to hopefully improve editor performance a little, though I don't think it helps
private fun createTasks(project: Project) {
val cache: File = project.cache
val extension: PaperweightExtension = project.ext
// Shared task containers
data class InitialTasks(
val setupMcLibraries: TaskProvider<SetupMcLibraries>,
val extractMcp: Provider<ExtractMcp>,
val mcpMappings: Provider<ExtractMappings>,
val downloadMcpTools: TaskProvider<DownloadMcpTools>
)
val initGitSubmodules: TaskProvider<Task> = project.tasks.register("initGitSubmodules") {
outputs.upToDateWhen { false }
doLast {
Git(project.projectDir)("submodule", "update", "--init").execute()
}
}
val gatherBuildData: TaskProvider<GatherBuildData> = project.tasks.register<GatherBuildData>("gatherBuildData") {
dependsOn(initGitSubmodules)
buildDataInfoFile.set(extension.craftBukkit.buildDataInfo)
}
val buildDataInfo: Provider<BuildDataInfo> = gatherBuildData.flatMap { it.buildDataInfo }
data class GeneralTasks(
val buildDataInfo: Provider<BuildDataInfo>,
val downloadServerJar: TaskProvider<DownloadServerJar>,
val filterVanillaJar: TaskProvider<Filter>
)
val extractMcpData: TaskProvider<ExtractMcpData> = project.tasks.register<ExtractMcpData>("extractMcpData") {
config.set(Constants.MCP_DATA_CONFIG)
data class McpTasks(
val generateSrgs: TaskProvider<GenerateSrgs>,
val remapVanillaJarSrg: TaskProvider<RunSpecialSource>,
val applyMcpPatches: TaskProvider<ApplyMcpPatches>
)
data class SpigotTasks(
val generateSpigotSrgs: TaskProvider<GenerateSpigotSrgs>,
val decompileVanillaJarSpigot: TaskProvider<DecompileVanillaJar>,
val patchSpigotApi: TaskProvider<ApplyGitPatches>,
val patchSpigotServer: TaskProvider<ApplyGitPatches>,
val remapSpigotSources: TaskProvider<RemapSources>,
val mergeGeneratedAts: TaskProvider<MergeAccessTransforms>
)
private fun Project.createInitialTasks(): InitialTasks {
val cache: File = layout.cache
val extension: PaperweightExtension = ext
val downloadMcManifest by tasks.registering<DownloadTask> {
url.set(Constants.MC_MANIFEST_URL)
outputFile.set(cache.resolve(Constants.MC_MANIFEST))
}
val mcManifest = downloadMcManifest.flatMap { it.outputFile }.map { gson.fromJson<MinecraftManifest>(it) }
val downloadMcVersionManifest by tasks.registering<DownloadTask> {
url.set(mcManifest.zip(extension.minecraftVersion) { manifest, version ->
manifest.versions.first { it.id == version }.url
})
outputFile.set(cache.resolve(Constants.VERSION_JSON))
}
val versionManifest = downloadMcVersionManifest.flatMap { it.outputFile }.map { gson.fromJson<JsonObject>(it) }
val setupMcLibraries by tasks.registering<SetupMcLibraries> {
dependencies.set(versionManifest.map { version ->
version["libraries"].array.map { library ->
library["name"].string
}.filter { !it.contains("lwjgl") } // we don't need these on the server
})
outputFile.set(cache.resolve(Constants.MC_LIBRARIES))
}
val downloadMcpFiles by tasks.registering<DownloadMcpFiles> {
mcpMinecraftVersion.set(extension.mcpMinecraftVersion)
mcpConfigVersion.set(extension.mcpConfigVersion)
mcpMappingsChannel.set(extension.mcpMappingsChannel)
mcpMappingsVersion.set(extension.mcpMappingsVersion)
configZip.set(cache.resolve(Constants.MCP_ZIPS_PATH).resolve("McpConfig.zip"))
mappingsZip.set(cache.resolve(Constants.MCP_ZIPS_PATH).resolve("McpMappings.zip"))
}
val extractMcpConfig by tasks.registering<ExtractMcp> {
inputFile.set(downloadMcpFiles.flatMap { it.configZip })
outputDir.set(cache.resolve(Constants.MCP_DATA_DIR))
}
val setupMcpDependencies: TaskProvider<SetupMcpDependencies> = project.tasks.register<SetupMcpDependencies>("setupMcpDependencies") {
configFile.set(extractMcpData.flatMap { it.configJson })
forgeFlowerConfig.set(Constants.FORGE_FLOWER_CONFIG)
mcInjectorConfig.set(Constants.MCINJECT_CONFIG)
}
val extractMcpMappings: TaskProvider<ExtractMcpMappings> = project.tasks.register<ExtractMcpMappings>("extractMcpMappings") {
config.set(Constants.MCP_MAPPINGS_CONFIG)
val extractMcpMappings by tasks.registering<ExtractMappings> {
inputFile.set(downloadMcpFiles.flatMap { it.mappingsZip })
outputDir.set(cache.resolve(Constants.MCP_MAPPINGS_DIR))
}
val getRemoteJsons: TaskProvider<GetRemoteJsons> = project.tasks.register<GetRemoteJsons>("getRemoteJsons") {
config.set(Constants.MINECRAFT_DEP_CONFIG)
val downloadMcpTools by tasks.registering<DownloadMcpTools> {
configFile.set(extractMcpConfig.flatMap { it.configFile })
val toolsPath = cache.resolve(Constants.MCP_TOOLS_PATH)
forgeFlowerFile.set(toolsPath.resolve("ForgeFlower.jar"))
mcInjectorFile.set(toolsPath.resolve("McInjector.jar"))
specialSourceFile.set(toolsPath.resolve("SpecialSource.jar"))
}
val mcpRewrites: TaskProvider<PatchMcpCsv> = project.tasks.register<PatchMcpCsv>("mcpRewrites") {
fieldsCsv.set(extractMcpMappings.flatMap { it.fieldsCsv })
methodsCsv.set(extractMcpMappings.flatMap { it.methodsCsv })
paramsCsv.set(extractMcpMappings.flatMap { it.paramsCsv })
return InitialTasks(
setupMcLibraries,
extractMcpConfig,
extractMcpMappings,
downloadMcpTools
)
}
private fun Project.createGeneralTasks(): GeneralTasks {
val buildDataInfo: Provider<BuildDataInfo> = contents(ext.craftBukkit.buildDataInfo) {
gson.fromJson(it)
}
val downloadServerJar by tasks.registering<DownloadServerJar> {
downloadUrl.set(buildDataInfo.map { it.serverUrl })
hash.set(buildDataInfo.map { it.minecraftHash })
}
val filterVanillaJar by tasks.registering<Filter> {
inputJar.set(downloadServerJar.flatMap { it.outputJar })
includes.set(listOf("/*.class", "/net/minecraft/**"))
}
return GeneralTasks(buildDataInfo, downloadServerJar, filterVanillaJar)
}
private fun Project.createMcpTasks(initialTasks: InitialTasks, generalTasks: GeneralTasks): 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))
@ -175,8 +289,9 @@ class Paperweight : Plugin<Project> {
paperParamCsv.set(cache.resolve(Constants.PAPER_PARAMS_CSV))
}
val generateSrgs: TaskProvider<GenerateSrgs> = project.tasks.register<GenerateSrgs>("generateSrgs") {
configFile.set(extractMcpData.flatMap { it.configJson })
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)
@ -189,20 +304,78 @@ class Paperweight : Plugin<Project> {
mcpToSrg.set(cache.resolve(Constants.MCP_TO_SRG))
}
val addMissingSpigotClassMappings: TaskProvider<AddMissingSpigotClassMappings> = project.tasks.register<AddMissingSpigotClassMappings>("addMissingSpigotClassMappings") {
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)
outputDir.set(cache.resolve(Constants.MINECRAFT_JARS_PATH))
}
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, applyMcpPatches)
}
private fun Project.createSpigotTasks(initialTasks: InitialTasks, generalTasks: GeneralTasks, mcpTasks: McpTasks): SpigotTasks {
val cache: File = layout.cache
val extension: PaperweightExtension = ext
val (buildDataInfo, downloadServerJar, filterVanillaJar) = generalTasks
val (generateSrgs, _, _) = mcpTasks
val addMissingSpigotClassMappings by tasks.registering<AddMissingSpigotClassMappings> {
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)
}
val generateSpigotSrgs: TaskProvider<GenerateSpigotSrgs> = project.tasks.register<GenerateSpigotSrgs>("generateSpigotSrgs") {
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 })
packageMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.packageMappings }))
extraSpigotSrgMappings.set(extension.paper.extraSpigotSrgMappings)
loggerFields.set(inspectVanillaJar.flatMap { it.outputFile })
spigotToSrg.set(cache.resolve(Constants.SPIGOT_TO_SRG))
spigotToMcp.set(cache.resolve(Constants.SPIGOT_TO_MCP))
@ -212,25 +385,8 @@ class Paperweight : Plugin<Project> {
notchToSpigot.set(cache.resolve(Constants.NOTCH_TO_SPIGOT))
}
val downloadServerJar: TaskProvider<DownloadServerJar> = project.tasks.register<DownloadServerJar>("downloadServerJar") {
dependsOn(gatherBuildData)
downloadUrl.set(buildDataInfo.map { it.serverUrl })
hash.set(buildDataInfo.map { it.minecraftHash })
}
val filterVanillaJar: TaskProvider<Zip> = project.tasks.register<Zip>("filterVanillaJar") {
dependsOn(downloadServerJar) // the from() block below doesn't set up this dependency
archiveFileName.set("filterVanillaJar.jar")
destinationDirectory.set(cache.resolve(Constants.TASK_CACHE))
from(project.zipTree(downloadServerJar.flatMap { it.outputJar })) {
include("/*.class")
include("/net/minecraft/**")
}
}
val remapVanillaJar: TaskProvider<RemapVanillaJarSpigot> = project.tasks.register<RemapVanillaJarSpigot>("remapVanillaJar") {
inputJar.set(project.layout.file(filterVanillaJar.map { it.outputs.files.singleFile }))
val remapVanillaJarSpigot by tasks.registering<RemapVanillaJarSpigot> {
inputJar.set(filterVanillaJar.flatMap { it.outputJar })
classMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.classMappings }))
memberMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.memberMappings }))
packageMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.packageMappings }))
@ -246,18 +402,18 @@ class Paperweight : Plugin<Project> {
finalMapCommand.set(buildDataInfo.map { it.finalMapCommand })
}
val removeSpigotExcludes: TaskProvider<FilterExcludes> = project.tasks.register<FilterExcludes>("removeSpigotExcludes") {
inputZip.set(remapVanillaJar.flatMap { it.outputJar })
val removeSpigotExcludes by tasks.registering<FilterExcludes> {
inputZip.set(remapVanillaJarSpigot.flatMap { it.outputJar })
excludesFile.set(extension.craftBukkit.excludesFile)
}
val decompileVanillaJarSpigot: TaskProvider<DecompileVanillaJar> = project.tasks.register<DecompileVanillaJar>("decompileVanillaJarSpigot") {
val decompileVanillaJarSpigot by tasks.registering<DecompileVanillaJar> {
inputJar.set(removeSpigotExcludes.flatMap { it.outputZip })
fernFlowerJar.set(extension.craftBukkit.fernFlowerJar)
decompileCommand.set(buildDataInfo.map { it.decompileCommand })
}
val patchCraftBukkit: TaskProvider<ApplyDiffPatches> = project.tasks.register<ApplyDiffPatches>("patchCraftBukkit") {
val patchCraftBukkit by tasks.registering<ApplyDiffPatches> {
sourceJar.set(decompileVanillaJarSpigot.flatMap { it.outputJar })
sourceBasePath.set("net/minecraft/server")
branch.set("patched")
@ -266,7 +422,7 @@ class Paperweight : Plugin<Project> {
outputDir.set(extension.craftBukkit.craftBukkitDir)
}
val patchSpigotApi: TaskProvider<ApplyGitPatches> = project.tasks.register<ApplyGitPatches>("patchSpigotApi") {
val patchSpigotApi by tasks.registering<ApplyGitPatches> {
branch.set("HEAD")
upstreamBranch.set("upstream")
upstream.set(extension.craftBukkit.bukkitDir)
@ -275,7 +431,7 @@ class Paperweight : Plugin<Project> {
outputDir.set(extension.spigot.spigotApiDir)
}
val patchSpigotServer: TaskProvider<ApplyGitPatches> = project.tasks.register<ApplyGitPatches>("patchSpigotServer") {
val patchSpigotServer by tasks.registering<ApplyGitPatches> {
branch.set(patchCraftBukkit.flatMap { it.branch })
upstreamBranch.set("upstream")
upstream.set(patchCraftBukkit.flatMap { it.outputDir })
@ -284,78 +440,98 @@ class Paperweight : Plugin<Project> {
outputDir.set(extension.spigot.spigotServerDir)
}
val patchSpigot: TaskProvider<Task> = project.tasks.register("patchSpigot") {
val patchSpigot by tasks.registering<Task> {
dependsOn(patchSpigotApi, patchSpigotServer)
}
val setupSpigotDependencies: TaskProvider<SetupSpigotDependencies> = project.tasks.register<SetupSpigotDependencies>("setupSpigotDependencies") {
val downloadSpigotDependencies by tasks.registering<DownloadSpigotDependencies> {
dependsOn(patchSpigot)
spigotApi.set(patchSpigotApi.flatMap { it.outputDir })
spigotServer.set(patchSpigotServer.flatMap { it.outputDir })
configurationName.set(Constants.SPIGOT_DEP_CONFIG)
apiPom.set(patchSpigotApi.flatMap { it.outputDir.file("pom.xml") })
serverPom.set(patchSpigotServer.flatMap { it.outputDir.file("pom.xml") })
apiOutputDir.set(cache.resolve(Constants.SPIGOT_API_JARS_PATH))
serverOutputDir.set(cache.resolve(Constants.SPIGOT_SERVER_JARS_PATH))
}
val remapSpigotJarSrg: TaskProvider<RemapVanillaJarSrg> = project.tasks.register<RemapVanillaJarSrg>("remapSpigotJarSrg") {
// Basing off of the Spigot jar lets us inherit the AT modifications Spigot does before decompile
inputJar.set(remapVanillaJar.flatMap { it.outputJar })
mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
val remapSpigotAt by tasks.registering<RemapSpigotAt> {
inputJar.set(remapVanillaJarSpigot.flatMap { it.outputJar })
mapping.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
spigotAt.set(extension.craftBukkit.atFile)
}
val remapSpigotSources: TaskProvider<RemapSources> = project.tasks.register<RemapSources>("remapSpigotSources") {
dependsOn(setupSpigotDependencies)
val remapSpigotSources by tasks.registering<RemapSources> {
spigotServerDir.set(patchSpigotServer.flatMap { it.outputDir })
spigotApiDir.set(patchSpigotApi.flatMap { it.outputDir })
mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
vanillaJar.set(downloadServerJar.flatMap { it.outputJar })
vanillaRemappedSpigotJar.set(removeSpigotExcludes.flatMap { it.outputZip })
vanillaRemappedSrgJar.set(remapSpigotJarSrg.flatMap { it.outputJar })
configuration.set(setupSpigotDependencies.flatMap { it.configurationName })
configFile.set(extractMcpData.flatMap { it.configJson })
spigotApiDeps.set(downloadSpigotDependencies.flatMap { it.apiOutputDir })
spigotServerDeps.set(downloadSpigotDependencies.flatMap { it.serverOutputDir })
constructors.set(initialTasks.extractMcp.flatMap { it.constructors })
}
val fixVanillaJarAccess: TaskProvider<ApplyAccessTransform> = project.tasks.register<ApplyAccessTransform>("fixVanillaJarAccess") {
inputJar.set(remapSpigotJarSrg.flatMap { it.outputJar })
atFile.set(remapSpigotSources.flatMap { it.generatedAt })
mapping.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
val remapGeneratedAt by tasks.registering<RemapAccessTransform> {
inputFile.set(remapSpigotSources.flatMap { it.generatedAt })
mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
}
val remapSrgSourcesSpigot: TaskProvider<RemapSrgSources> = project.tasks.register<RemapSrgSources>("remapSrgSourcesSpigot") {
inputZip.set(remapSpigotSources.flatMap { it.outputZip })
methodsCsv.set(mcpRewrites.flatMap { it.methodsCsv })
fieldsCsv.set(mcpRewrites.flatMap { it.fieldsCsv })
paramsCsv.set(mcpRewrites.flatMap { it.paramsCsv })
val mergeGeneratedAts by tasks.registering<MergeAccessTransforms> {
inputFiles.add(remapGeneratedAt.flatMap { it.outputFile })
inputFiles.add(remapSpigotAt.flatMap { it.outputFile })
}
val injectVanillaJarForge: TaskProvider<RunMcInjector> = project.tasks.register<RunMcInjector>("injectVanillaJarForge") {
dependsOn(setupMcpDependencies)
configuration.set(setupMcpDependencies.flatMap { it.mcInjectorConfig })
inputJar.set(remapSpigotJarSrg.flatMap { it.outputJar })
configFile.set(extractMcpData.flatMap { it.configJson })
return SpigotTasks(
generateSpigotSrgs,
decompileVanillaJarSpigot,
patchSpigotApi,
patchSpigotServer,
remapSpigotSources,
mergeGeneratedAts
)
}
private fun Project.createPatchRemapTasks(
initialTasks: InitialTasks,
generalTasks: GeneralTasks,
mcpTasks: McpTasks,
spigotTasks: SpigotTasks
) {
val extension: PaperweightExtension = ext
/*
* I don't remember what this is supposed to be for tbh
val patchPaperServerForPatchRemap by tasks.registering<ApplyPaperPatches> {
patchDir.set(extension.paper.spigotServerPatchDir)
remappedSource.set(spigotTasks.remapSpigotSources.flatMap { it.outputZip })
outputDir.set(cache.resolve("patch-paper-server-for-remap"))
}
*/
val applyVanillaSrgAt by tasks.registering<ApplyAccessTransform> {
inputJar.set(mcpTasks.remapVanillaJarSrg.flatMap { it.outputJar })
atFile.set(spigotTasks.mergeGeneratedAts.flatMap { it.outputFile })
}
val writeLibrariesFile: TaskProvider<WriteLibrariesFile> = project.tasks.register<WriteLibrariesFile>("writeLibrariesFile") {
dependsOn(getRemoteJsons)
config.set(getRemoteJsons.flatMap { it.config })
}
val remapPatches by tasks.registering<RemapPatches> {
inputPatchDir.set(extension.paper.unmappedSpigotServerPatchDir)
sourceJar.set(spigotTasks.remapSpigotSources.flatMap { it.outputZip })
apiPatchDir.set(extension.paper.spigotApiPatchDir)
val decompileVanillaJarForge: TaskProvider<RunForgeFlower> = project.tasks.register<RunForgeFlower>("decompileVanillaJarForge") {
dependsOn(setupMcpDependencies)
configuration.set(setupMcpDependencies.flatMap { it.forgeFlowerConfig })
inputJar.set(injectVanillaJarForge.flatMap { it.outputJar })
libraries.set(writeLibrariesFile.flatMap { it.outputFile })
configFile.set(extractMcpData.flatMap { it.configJson })
}
mappingsFile.set(spigotTasks.generateSpigotSrgs.flatMap { it.spigotToSrg })
// val applyMcpPatches: TaskProvider<ApplyMcpPatches> = project.tasks.register<ApplyMcpPatches>("applyMcpPatches") {
// inputZips.add(ZipTarget.base(decompileVanillaJarForge.flatMap { it.outputJar }))
// serverPatchDir.set(extractMcpData.flatMap { it.patches })
// }
//
// val remapSrgSourcesSpigotVanilla: TaskProvider<RemapSrgSources> = project.tasks.register<RemapSrgSources>("remapSrgSourcesSpigotVanilla") {
// inputZips.add(ZipTarget.base(applyMcpPatches.flatMap { outputZip }))
// methodsCsv.set(mcpRewrites.flatMap { methodsCsv })
// fieldsCsv.set(mcpRewrites.flatMap { fieldsCsv })
// paramsCsv.set(mcpRewrites.flatMap { paramsCsv })
// }
// Pull in as many jars as possible to reduce the possibility of type bindings not resolving
classpathJars.add(generalTasks.downloadServerJar.flatMap { it.outputJar })
classpathJars.add(spigotTasks.remapSpigotSources.flatMap { it.vanillaRemappedSpigotJar })
classpathJars.add(applyVanillaSrgAt.flatMap { it.outputJar })
spigotApiDir.set(spigotTasks.patchSpigotApi.flatMap { it.outputDir })
spigotServerDir.set(spigotTasks.patchSpigotServer.flatMap { it.outputDir })
spigotDecompJar.set(spigotTasks.decompileVanillaJarSpigot.flatMap { it.outputJar })
constructors.set(initialTasks.extractMcp.flatMap { it.constructors })
parameterNames.set(spigotTasks.remapSpigotSources.flatMap { it.parameterNames })
outputPatchDir.set(extension.paper.remappedSpigotServerPatchDir)
}
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,18 +22,35 @@
package io.papermc.paperweight.ext
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
open class CraftBukkitExtension(project: Project) {
val bukkitDir: DirectoryProperty = project.dirWithDefault("work/Bukkit")
var craftBukkitDir: DirectoryProperty = project.dirWithDefault("work/CraftBukkit")
var patchDir: DirectoryProperty = project.dirWithDefault("work/CraftBukkit/nms-patches")
var mappingsDir: DirectoryProperty = project.dirWithDefault("work/BuildData/mappings")
val excludesFile: RegularFileProperty = project.fileWithDefault("work/BuildData/mappings/bukkit-1.16.1.exclude")
var buildDataInfo: RegularFileProperty = project.fileWithDefault("work/BuildData/info.json")
var fernFlowerJar: RegularFileProperty = project.fileWithDefault("work/BuildData/bin/fernflower.jar")
var specialSourceJar: RegularFileProperty = project.fileWithDefault("work/BuildData/bin/SpecialSource.jar")
var specialSource2Jar: RegularFileProperty = project.fileWithDefault("work/BuildData/bin/SpecialSource-2.jar")
open class CraftBukkitExtension(objects: ObjectFactory, workDir: DirectoryProperty) {
val bukkitDir: DirectoryProperty = objects.dirFrom(workDir, "Bukkit")
val craftBukkitDir: DirectoryProperty = objects.dirFrom(workDir, "CraftBukkit")
val patchDir: DirectoryProperty = objects.dirFrom(craftBukkitDir, "nms-patches")
@Suppress("MemberVisibilityCanBePrivate")
val buildDataDir: DirectoryProperty = objects.dirFrom(workDir, "BuildData")
val mappingsDir: DirectoryProperty = objects.dirFrom(buildDataDir, "mappings")
val excludesFile: RegularFileProperty = objects.bukkitFileFrom(mappingsDir, "exclude")
val atFile: RegularFileProperty = objects.bukkitFileFrom(mappingsDir, "at")
val buildDataInfo: RegularFileProperty = objects.fileFrom(buildDataDir, "info.json")
@Suppress("MemberVisibilityCanBePrivate")
val buildDataBinDir: DirectoryProperty = objects.dirFrom(buildDataDir, "bin")
val fernFlowerJar: RegularFileProperty = objects.fileFrom(buildDataBinDir, "fernflower.jar")
val specialSourceJar: RegularFileProperty = objects.fileFrom(buildDataBinDir, "SpecialSource.jar")
val specialSource2Jar: RegularFileProperty = objects.fileFrom(buildDataBinDir, "SpecialSource-2.jar")
private fun ObjectFactory.bukkitFileFrom(base: DirectoryProperty, extension: String): RegularFileProperty =
fileProperty().convention(base.flatMap { dir ->
val file = dir.asFile.listFiles()?.firstOrNull { it.name.endsWith(extension) }
if (file != null) {
mappingsDir.file(file.name)
} else {
// empty
fileProperty()
}
})
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,25 +22,28 @@
package io.papermc.paperweight.ext
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.property
import org.gradle.api.model.ObjectFactory
open class PaperExtension(project: Project) {
val spigotApiPatchDir: Property<String> = project.objects.property<String>().convention("Spigot-API-Patches")
val spigotServerPatchDir: Property<String> = project.objects.property<String>().convention("Spigot-Server-Patches")
val paperApiDir: Property<String> = project.objects.property<String>().convention("Paper-API")
val paperServerDir: Property<String> = project.objects.property<String>().convention("Paper-Server")
open class PaperExtension(objects: ObjectFactory, layout: ProjectLayout) {
@Suppress("MemberVisibilityCanBePrivate")
val baseTargetDir: DirectoryProperty = objects.dirWithDefault(layout, ".")
val spigotApiPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Spigot-API-Patches")
val spigotServerPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Spigot-Server-Patches")
val remappedSpigotServerPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Spigot-Server-Patches-Remapped")
val unmappedSpigotServerPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Spigot-Server-Patches-Unmapped")
val paperApiDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Paper-API")
val paperServerDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Paper-Server")
val mcpRewritesFile: RegularFileProperty = project.fileWithDefault("mcp/mcp-rewrites.txt")
val missingClassEntriesSrgFile: RegularFileProperty = project.fileWithDefault("mcp/missing-spigot-class-mappings.csrg")
val missingMemberEntriesSrgFile: RegularFileProperty = project.fileWithDefault("mcp/missing-spigot-member-mappings.csrg")
val extraNotchSrgMappings: RegularFileProperty = project.fileWithDefault("mcp/extra-notch-srg.tsrg")
val extraSpigotSrgMappings: RegularFileProperty = project.fileWithDefault("mcp/extra-spigot-srg.tsrg")
val preMapSrgFile: RegularFileProperty = project.fileWithDefault("mcp/paper.srg")
val removeListFile: RegularFileProperty = project.fileWithDefault("mcp/remove-list.txt")
val memberMoveListFile: RegularFileProperty = project.fileWithDefault("mcp/member-moves.txt")
@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")
init {
spigotApiPatchDir.disallowUnsafeRead()
@ -50,8 +52,5 @@ open class PaperExtension(project: Project) {
paperServerDir.disallowUnsafeRead()
mcpRewritesFile.disallowUnsafeRead()
preMapSrgFile.disallowUnsafeRead()
removeListFile.disallowUnsafeRead()
memberMoveListFile.disallowUnsafeRead()
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,26 +23,33 @@
package io.papermc.paperweight.ext
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.property
open class PaperweightExtension(project: Project) {
open class PaperweightExtension(objects: ObjectFactory, layout: ProjectLayout) {
val minecraftVersion: Property<String> = project.objects.property()
val mcpMinecraftVersion: Property<String> = project.objects.property<String>().convention(minecraftVersion)
val mcpVersion: Property<String> = project.objects.property()
val mcpMappingsChannel: Property<String> = project.objects.property()
val mcpMappingsVersion: Property<String> = project.objects.property()
@Suppress("MemberVisibilityCanBePrivate")
val workDir: DirectoryProperty = objects.dirWithDefault(layout, "work")
val craftBukkit = CraftBukkitExtension(project)
val spigot = SpigotExtension(project)
val paper = PaperExtension(project)
val minecraftVersion: Property<String> = objects.property()
val mcpMinecraftVersion: Property<String> = objects.property<String>().convention(minecraftVersion)
val mcpConfigVersion: Property<String> = objects.property()
val mcpMappingsChannel: Property<String> = objects.property()
val mcpMappingsVersion: Property<String> = objects.property()
val mcpConfigFile: RegularFileProperty = objects.fileProperty().convention(null)
val craftBukkit = CraftBukkitExtension(objects, workDir)
val spigot = SpigotExtension(objects, workDir)
val paper = PaperExtension(objects, layout)
init {
minecraftVersion.disallowUnsafeRead()
mcpMinecraftVersion.disallowUnsafeRead()
mcpVersion.disallowUnsafeRead()
mcpMappingsChannel.disallowUnsafeRead()
mcpMappingsVersion.disallowUnsafeRead()
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,15 +22,15 @@
package io.papermc.paperweight.ext
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.model.ObjectFactory
open class SpigotExtension(project: Project) {
var spigotDir: DirectoryProperty = project.dirWithDefault("work/Spigot")
var spigotApiDir: DirectoryProperty = project.dirWithDefault("work/Spigot/Spigot-API")
var spigotServerDir: DirectoryProperty = project.dirWithDefault("work/Spigot/Spigot-Server")
var bukkitPatchDir: DirectoryProperty = project.dirWithDefault("work/Spigot/Bukkit-Patches")
var craftBukkitPatchDir: DirectoryProperty = project.dirWithDefault("work/Spigot/CraftBukkit-Patches")
open class SpigotExtension(objects: ObjectFactory, workDir: DirectoryProperty) {
var spigotDir: DirectoryProperty = objects.dirFrom(workDir, "Spigot")
var spigotApiDir: DirectoryProperty = objects.dirFrom(spigotDir, "Spigot-API")
var spigotServerDir: DirectoryProperty = objects.dirFrom(spigotDir, "Spigot-Server")
var bukkitPatchDir: DirectoryProperty = objects.dirFrom(spigotDir, "Bukkit-Patches")
var craftBukkitPatchDir: DirectoryProperty = objects.dirFrom(spigotDir, "CraftBukkit-Patches")
init {
spigotDir.disallowUnsafeRead()

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,12 +22,16 @@
package io.papermc.paperweight.ext
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
fun Project.dirWithDefault(path: String): DirectoryProperty =
project.objects.directoryProperty().convention(layout.dir(provider { file(path) }))
fun ObjectFactory.dirWithDefault(layout: ProjectLayout, path: String): DirectoryProperty =
directoryProperty().convention(layout.projectDirectory.dir(path))
fun Project.fileWithDefault(path: String): RegularFileProperty =
project.objects.fileProperty().convention(layout.file(provider { file(path) }))
fun ObjectFactory.dirFrom(base: DirectoryProperty, name: String): DirectoryProperty =
directoryProperty().convention(base.dir(name))
fun ObjectFactory.fileFrom(base: DirectoryProperty, name: String): RegularFileProperty =
fileProperty().convention(base.file(name))

View file

@ -1,48 +1,73 @@
/*
* 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.defaultOutput
import io.papermc.paperweight.util.file
import org.gradle.api.DefaultTask
import io.papermc.paperweight.util.fileOrNull
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
import java.io.File
open class AddMissingSpigotClassMappings : DefaultTask() {
abstract class AddMissingSpigotClassMappings : BaseTask() {
@InputFile
val classSrg: RegularFileProperty = project.objects.fileProperty()
@InputFile
val memberSrg: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val classSrg: RegularFileProperty
@get:InputFile
abstract val memberSrg: RegularFileProperty
@get:Optional
@get:InputFile
abstract val missingClassEntriesSrg: RegularFileProperty
@get:Optional
@get:InputFile
abstract val missingMemberEntriesSrg: RegularFileProperty
@InputFile
val missingClassEntriesSrg: RegularFileProperty = project.objects.fileProperty()
@InputFile
val missingMemberEntriesSrg: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile
abstract val outputClassSrg: RegularFileProperty
@get:OutputFile
abstract val outputMemberSrg: RegularFileProperty
@OutputFile
val outputClassSrg: RegularFileProperty = defaultOutput("class.csrg")
@OutputFile
val outputMemberSrg: RegularFileProperty = defaultOutput("member.csrg")
override fun init() {
outputClassSrg.convention(defaultOutput("class.csrg"))
outputMemberSrg.convention(defaultOutput("member.csrg"))
}
@TaskAction
fun run() {
addLines(classSrg.file, missingClassEntriesSrg.file, outputClassSrg.file)
addLines(memberSrg.file, missingMemberEntriesSrg.file, outputMemberSrg.file)
addLines(classSrg.file, missingClassEntriesSrg.fileOrNull, outputClassSrg.file)
addLines(memberSrg.file, missingMemberEntriesSrg.fileOrNull, outputMemberSrg.file)
}
private fun addLines(inFile: File, appendFile: File, outputFile: File) {
private fun addLines(inFile: File, appendFile: File?, outputFile: File) {
val lines = mutableListOf<String>()
inFile.bufferedReader().use { reader ->
lines.addAll(reader.readLines())
}
appendFile.bufferedReader().use { reader ->
lines.addAll(reader.readLines())
}
inFile.useLines { seq -> seq.forEach { lines.add(it) } }
appendFile?.useLines { seq -> seq.forEach { lines.add(it) } }
lines.sort()
outputFile.bufferedWriter().use { writer ->
lines.forEach(writer::appendln)
lines.forEach { writer.appendln(it) }
}
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,10 +23,11 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.util.Command
import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.UselessOutputStream
import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.file
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
@ -36,33 +36,34 @@ import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import java.net.URI
import java.nio.file.FileSystems
import java.nio.file.Files
import java.util.Date
open class ApplyDiffPatches : DefaultTask() {
abstract class ApplyDiffPatches : ControllableOutputTask() {
@InputFile
val sourceJar: RegularFileProperty = project.objects.fileProperty()
@Input
val sourceBasePath: Property<String> = project.objects.property()
@InputDirectory
val patchDir: DirectoryProperty = project.objects.directoryProperty()
@Input
val branch: Property<String> = project.objects.property()
@get:InputFile
abstract val sourceJar: RegularFileProperty
@get:Input
abstract val sourceBasePath: Property<String>
@get:InputDirectory
abstract val patchDir: DirectoryProperty
@get:Input
abstract val branch: Property<String>
@OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty()
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
override fun init() {
printOutput.convention(false)
}
@TaskAction
fun run() {
val git = Git(outputDir.file)
git("checkout", "-B", branch.get(), "HEAD").executeSilently(silenceErr = true)
val uri = URI.create("jar:${sourceJar.file.toURI()}")
val basePatchDirFile = outputDir.file.resolve("src/main/java")
val outputDirFile = basePatchDirFile.resolve(sourceBasePath.get())
outputDirFile.deleteRecursively()
@ -73,6 +74,7 @@ open class ApplyDiffPatches : DefaultTask() {
}
// Copy in patch targets
val uri = URI.create("jar:" + sourceJar.file.toURI())
FileSystems.newFileSystem(uri, mapOf<String, Any>()).use { fs ->
for (file in patchList) {
val javaName = file.name.replaceAfterLast('.', "java")
@ -88,19 +90,29 @@ open class ApplyDiffPatches : DefaultTask() {
}
}
git("add", "src").executeOut()
git("commit", "-m", "Vanilla $ ${Date()}", "--author=Vanilla <auto@mated.null>").executeOut()
git("add", "src").setupOut().execute()
git("commit", "-m", "Vanilla $ ${Date()}", "--author=Vanilla <auto@mated.null>").setupOut().execute()
// Apply patches
for (file in patchList) {
val javaName = file.name.replaceAfterLast('.', "java")
println("Patching ${javaName.removeSuffix(".java")}")
git("apply", "--directory=${basePatchDirFile.relativeTo(outputDir.file).path}", file.absolutePath).executeOut()
if (printOutput.get()) {
println("Patching ${javaName.removeSuffix(".java")}")
}
git("apply", "--directory=${basePatchDirFile.relativeTo(outputDir.file).path}", file.absolutePath).setupOut().execute()
}
git("add", "src").executeOut()
git("commit", "-m", "CraftBukkit $ ${Date()}", "--author=CraftBukkit <auto@mated.null>").executeOut()
git("checkout", "-f", "HEAD~2").executeSilently()
git("add", "src").setupOut().execute()
git("commit", "-m", "CraftBukkit $ ${Date()}", "--author=CraftBukkit <auto@mated.null>").setupOut().execute()
git("checkout", "-f", "HEAD~2").setupOut().execute()
}
private fun Command.setupOut() = apply {
if (printOutput.get()) {
setup(System.out, System.err)
} else {
setup(UselessOutputStream, UselessOutputStream)
}
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -26,7 +25,6 @@ package io.papermc.paperweight.tasks
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.file
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
@ -34,80 +32,95 @@ import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.os.OperatingSystem
import org.gradle.kotlin.dsl.property
import java.io.File
open class ApplyGitPatches : DefaultTask() {
abstract class ApplyGitPatches : ControllableOutputTask() {
@Input
val branch: Property<String> = project.objects.property()
@Input
val upstreamBranch: Property<String> = project.objects.property()
@InputDirectory
val upstream: DirectoryProperty = project.objects.directoryProperty()
@InputDirectory
val patchDir: DirectoryProperty = project.objects.directoryProperty()
@get:Input
abstract val branch: Property<String>
@get:Input
abstract val upstreamBranch: Property<String>
@get:InputDirectory
abstract val upstream: DirectoryProperty
@get:InputDirectory
abstract val patchDir: DirectoryProperty
@OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty()
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
override fun init() {
printOutput.convention(false)
}
@TaskAction
fun run() {
Git(upstream.file).let { git ->
git("fetch").run()
git("fetch").setupOut().run()
git("branch", "-f", upstreamBranch.get(), branch.get()).runSilently()
}
if (!outputDir.file.exists() || !outputDir.file.resolve(".git").exists()) {
outputDir.file.deleteRecursively()
Git(outputDir.file.parentFile)("clone", upstream.file.absolutePath, outputDir.file.name).runOut()
Git(outputDir.file.parentFile)("clone", upstream.file.absolutePath, outputDir.file.name).setupOut().run()
}
val target = outputDir.file.name
println(" Resetting $target to ${upstream.file.name}...")
if (printOutput.get()) {
println(" Resetting $target to ${upstream.file.name}...")
}
Git(outputDir.file).let { git ->
git("remote", "rm", "upstream").runSilently(silenceErr = true)
git("remote", "add", "upstream", upstream.file.absolutePath).runSilently(silenceErr = true)
if (git("checkout", "master").runSilently(silenceOut = false, silenceErr = true) != 0) {
git("checkout", "-b", "master").runOut()
if (git("checkout", "master").setupOut(showError = false).run() != 0) {
git("checkout", "-b", "master").setupOut().run()
}
git("fetch", "upstream").runSilently(silenceErr = true)
git("reset", "--hard", "upstream/${upstreamBranch.get()}").runOut()
git("reset", "--hard", "upstream/${upstreamBranch.get()}").setupOut().run()
println(" Applying patches to $target...")
val statusFile = outputDir.file.resolve(".git/patch-apply-failed")
if (statusFile.exists()) {
statusFile.delete()
}
git("am", "--abort").runSilently(silenceErr = true)
val patches = patchDir.file.listFiles { _, name -> name.endsWith(".patch") } ?: run {
println("No patches found")
return
}
patches.sort()
if (git("am", "--3way", "--ignore-whitespace", *patches.map { it.absolutePath }.toTypedArray()).runOut() != 0) {
Thread.sleep(100) // Wait for git
statusFile.writeText("1")
logger.error("*** Something did not apply cleanly to $target.")
logger.error("*** Please review above details and finish the apply then")
logger.error("*** save the changes with ./gradlew `rebuildPatches`")
if (OperatingSystem.current().isWindows) {
logger.error("")
logger.error("*** Because you're on Windows you'll need to finish the AM,")
logger.error("*** rebuild all patches, and then re-run the patch apply again.")
logger.error("*** Consider using the scripts with Windows Subsystem for Linux.")
}
throw PaperweightException("Failed to apply patches")
} else {
statusFile.delete()
println(" Patches applied cleanly to $target")
}
applyGitPatches(git, target, outputDir.file, patchDir.file, printOutput.get())
}
}
}
fun ControllableOutputTask.applyGitPatches(git: Git, target: String, outputDir: File, patchDir: File, printOutput: Boolean) {
if (printOutput) {
println(" Applying patches to $target...")
}
val statusFile = outputDir.resolve(".git/patch-apply-failed")
if (statusFile.exists()) {
statusFile.delete()
}
git("am", "--abort").runSilently(silenceErr = true)
val patches = patchDir.listFiles { _, name -> name.endsWith(".patch") } ?: run {
if (printOutput) {
println("No patches found")
}
return
}
patches.sort()
if (git("am", "--3way", "--ignore-whitespace", *patches.map { it.absolutePath }.toTypedArray()).showErrors().run() != 0) {
statusFile.writeText("1")
logger.error("*** Please review above details and finish the apply then")
logger.error("*** save the changes with ./gradlew `rebuildPatches`")
if (OperatingSystem.current().isWindows) {
logger.error("")
logger.error("*** Because you're on Windows you'll need to finish the AM,")
logger.error("*** rebuild all patches, and then re-run the patch apply again.")
logger.error("*** Consider using the scripts with Windows Subsystem for Linux.")
}
throw PaperweightException("Failed to apply patches")
} else {
statusFile.delete()
if (printOutput) {
println(" Patches applied cleanly to $target")
}
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,39 +23,27 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.mcpConfig
import io.papermc.paperweight.util.mcpFile
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import java.io.File
open class ApplyMcpPatches : ZippedTask() {
abstract class ApplyMcpPatches : ZippedTask() {
@InputFile
val configFile: RegularFileProperty = project.objects.fileProperty()
init {
inputs.dir(configFile.map { mcpConfig(configFile) }.map { mcpFile(configFile, it.data.patches.server) })
}
@get:InputDirectory
abstract val serverPatchDir: DirectoryProperty
@get:InputFile
abstract val configFile: RegularFileProperty
override fun run(rootDir: File) {
val config = mcpConfig(configFile)
val serverPatchDir = mcpFile(configFile, config.data.patches.server)
val git = Git(rootDir)
val extension = ".java.patch"
project.fileTree(serverPatchDir).matching {
include("*$extension")
objects.fileTree().from(serverPatchDir).matching {
include("**/*$extension")
}.forEach { patch ->
val patchName = patch.name
print("Patching ${patchName.substring(0, extension.length)}")
val exit = git("apply", "--ignore-whitespace", patch.absolutePath).setup(System.out, null).run()
if (exit != 0) {
println("...Failed")
} else {
println()
}
git("apply", "--ignore-whitespace", patch.absolutePath).executeSilently()
}
}
}

View file

@ -0,0 +1,89 @@
/*
* 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 io.papermc.paperweight.util.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
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
abstract class ApplyPaperPatches : ControllableOutputTask() {
@get:InputDirectory
abstract val patchDir: DirectoryProperty
@get:InputFile
abstract val remappedSource: RegularFileProperty
@get:InputFile
abstract val templateGitIgnore: RegularFileProperty
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@get:OutputDirectory
abstract val remapTargetDir: DirectoryProperty
override fun init() {
printOutput.convention(true)
remapTargetDir.convention(outputDir.dir("src/main/java"))
}
@TaskAction
fun run() {
val outputFile = outputDir.file
if (outputFile.exists()) {
outputFile.deleteRecursively()
}
outputFile.mkdirs()
val target = outputFile.name
if (printOutput.get()) {
println(" Creating $target from remapped source...")
}
Git(outputFile).let { git ->
git("init").runSilently(silenceErr = true)
val sourceDir = remapTargetDir.file
if (sourceDir.exists()) {
sourceDir.deleteRecursively()
}
sourceDir.mkdirs()
fs.copy {
from(archives.zipTree(remappedSource.file))
into(sourceDir)
}
templateGitIgnore.file.copyTo(outputFile.resolve(".gitignore"))
git("add", ".gitignore", ".").executeSilently()
git("commit", "-m", "Initial", "--author=Initial <auto@mated.null>").executeSilently()
applyGitPatches(git, target, outputFile, patchDir.file, printOutput.get())
}
}
}

View file

@ -0,0 +1,81 @@
/*
* 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.path
import org.cadixdev.at.io.AccessTransformFormats
import org.cadixdev.mercury.Mercury
import org.cadixdev.mercury.at.AccessTransformerRewriter
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import java.io.File
abstract class ApplySourceAt : ZippedTask() {
@get:InputFile
abstract val vanillaJar: RegularFileProperty
@get:InputFile
abstract val vanillaRemappedSrgJar: RegularFileProperty
@get:InputFile
abstract val atFile: RegularFileProperty
override fun run(rootDir: File) {
val inputDir = rootDir.resolve("input")
val outputDir = rootDir.resolve("output")
// Move everything into `input/` so we can put output into `output/`
inputDir.mkdirs()
rootDir.listFiles()?.forEach { file ->
if (file != inputDir) {
file.renameTo(inputDir.resolve(file.name))
}
}
outputDir.mkdirs()
val at = AccessTransformFormats.FML.read(atFile.path)
Mercury().apply {
classPath.addAll(listOf(
vanillaJar.path,
vanillaRemappedSrgJar.path
))
processors.add(AccessTransformerRewriter.create(at))
rewrite(inputDir.toPath(), outputDir.toPath())
}
// Remove input files
rootDir.listFiles()?.forEach { file ->
if (file != outputDir) {
file.deleteRecursively()
}
}
// Move output into root
outputDir.listFiles()?.forEach { file ->
file.renameTo(rootDir.resolve(file.name))
}
outputDir.delete()
}
}

View file

@ -0,0 +1,48 @@
/*
* 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 org.gradle.api.DefaultTask
import org.gradle.api.file.ArchiveOperations
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.ProjectLayout
import org.gradle.api.model.ObjectFactory
import javax.inject.Inject
abstract class BaseTask : DefaultTask() {
@get:Inject
abstract val objects: ObjectFactory
@get:Inject
abstract val layout: ProjectLayout
@get:Inject
abstract val fs: FileSystemOperations
@get:Inject
abstract val archives: ArchiveOperations
open fun init() {}
init {
this.init()
}
}

View file

@ -0,0 +1,51 @@
/*
* 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.Command
import io.papermc.paperweight.util.UselessOutputStream
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Console
abstract class ControllableOutputTask : BaseTask() {
@get:Console
abstract val printOutput: Property<Boolean>
fun Command.setupOut(showError: Boolean = true) = apply {
if (printOutput.get()) {
val err = if (showError) System.out else UselessOutputStream
setup(System.out, err)
} else {
setup(UselessOutputStream, UselessOutputStream)
}
}
fun Command.showErrors() = apply {
if (printOutput.get()) {
setup(System.out, System.out)
} else {
setup(UselessOutputStream, System.out)
}
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -29,27 +28,29 @@ import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.ensureDeleted
import io.papermc.paperweight.util.runJar
import org.gradle.api.DefaultTask
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.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import java.util.concurrent.ThreadLocalRandom
open class DecompileVanillaJar : DefaultTask() {
abstract class DecompileVanillaJar : BaseTask() {
@InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty()
@InputFile
val fernFlowerJar: RegularFileProperty = project.objects.fileProperty()
@Input
val decompileCommand: Property<String> = project.objects.property()
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:InputFile
abstract val fernFlowerJar: RegularFileProperty
@get:Input
abstract val decompileCommand: Property<String>
@OutputFile
val outputJar: RegularFileProperty = defaultOutput()
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
@ -68,10 +69,10 @@ open class DecompileVanillaJar : DefaultTask() {
cmd += inputJarPath
cmd += decomp.canonicalPath
val logFile = project.cache.resolve(paperTaskOutput("log"))
val logFile = layout.cache.resolve(paperTaskOutput("log"))
logFile.delete()
runJar(fernFlowerJar, workingDir = project.cache, logFile = logFile, args = *cmd.toTypedArray())
runJar(fernFlowerJar, workingDir = layout.cache, logFile = logFile, args = *cmd.toTypedArray())
ensureDeleted(outputJarFile)
decomp.resolve(inputJarFile.name).renameTo(outputJarFile)

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -25,38 +24,34 @@ package io.papermc.paperweight.tasks
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.ensureDeleted
import io.papermc.paperweight.util.ensureParentExists
import org.gradle.api.DefaultTask
import io.papermc.paperweight.util.download
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import java.math.BigInteger
import java.net.URL
import java.security.MessageDigest
open class DownloadServerJar : DefaultTask() {
abstract class DownloadServerJar : BaseTask() {
@Input
val downloadUrl: Property<String> = project.objects.property()
@Input
val hash: Property<String> = project.objects.property()
@get:Input
abstract val downloadUrl: Property<String>
@get:Input
abstract val hash: Property<String>
@OutputFile
val outputJar: RegularFileProperty = defaultOutput()
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
val file = outputJar.asFile.get()
ensureParentExists(file)
ensureDeleted(file)
file.outputStream().buffered().use { out ->
URL(downloadUrl.get()).openStream().copyTo(out)
}
download(downloadUrl, outputJar)
val digest = MessageDigest.getInstance("MD5")

View file

@ -1,72 +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
* Copyright (C) 2018 Forge Development LLC
*
* 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 org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.property
open class Extract : DefaultTask() {
@Input
val config: Property<String> = project.objects.property()
@OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty()
@TaskAction
fun run() {
project.copy {
from(project.zipTree(project.configurations[config.get()].resolve().single()))
into(outputDir)
}
}
}
open class ExtractMcpMappings : Extract() {
@OutputFile
val fieldsCsv: RegularFileProperty = project.objects.fileProperty()
.convention(outputDir.map { it.file("fields.csv") })
@OutputFile
val methodsCsv: RegularFileProperty = project.objects.fileProperty()
.convention(outputDir.map { it.file("methods.csv") })
@OutputFile
val paramsCsv: RegularFileProperty = project.objects.fileProperty()
.convention(outputDir.map { it.file("params.csv") })
}
open class ExtractMcpData : Extract() {
@OutputFile
val configJson: RegularFileProperty = project.objects.fileProperty()
.convention(outputDir.map { it.file("config.json") })
}

View file

@ -1,3 +1,25 @@
/*
* 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.file
@ -9,10 +31,10 @@ import java.io.File
* Because Spigot doesn't remap all classes, there are class and package name clashes if we don't do this in the source
* remap step. Other than that, we don't need this jar
*/
open class FilterExcludes : ZippedTask() {
abstract class FilterExcludes : ZippedTask() {
@InputFile
val excludesFile: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val excludesFile: RegularFileProperty
override fun run(rootDir: File) {
excludesFile.file.useLines { lines ->

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,6 +23,7 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fileOrNull
import io.papermc.paperweight.util.writeMappings
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.io.MappingFormats
@ -40,37 +40,40 @@ 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
import java.lang.IllegalStateException
open class GenerateSpigotSrgs : DefaultTask() {
abstract class GenerateSpigotSrgs : DefaultTask() {
@InputFile
val notchToSrg: RegularFileProperty = project.objects.fileProperty()
@InputFile
val srgToMcp: RegularFileProperty = project.objects.fileProperty()
@InputFile
val classMappings: RegularFileProperty = project.objects.fileProperty()
@InputFile
val memberMappings: RegularFileProperty = project.objects.fileProperty()
@InputFile
val packageMappings: RegularFileProperty = project.objects.fileProperty()
@InputFile
val extraSpigotSrgMappings: RegularFileProperty = project.objects.fileProperty()
@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
@OutputFile
val spigotToSrg: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val spigotToMcp: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val spigotToNotch: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val srgToSpigot: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val mcpToSpigot: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val notchToSpigot: RegularFileProperty = project.objects.fileProperty()
@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
@TaskAction
fun run() {
@ -78,6 +81,12 @@ open class GenerateSpigotSrgs : DefaultTask() {
val memberMappingSet = MappingFormats.CSRG.createReader(memberMappings.file.toPath()).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"
}
// Get the new package name
val newPackage = packageMappings.asFile.get().readLines()[0].split(Regex("\\s+"))[1]
@ -88,14 +97,16 @@ open class GenerateSpigotSrgs : DefaultTask() {
mergedMappingSet,
notchToSrgSet,
MergeConfig.builder()
.withHandler(SpigotPackageMergerHandler(newPackage))
.withMergeHandler(SpigotPackageMergerHandler(newPackage))
.build()
).merge()
val srgToMcpSet = MappingFormats.TSRG.createReader(srgToMcp.file.toPath()).use { it.read() }
val spigotToSrgSet = MappingSetMerger.create(notchToSpigotSet.reverse(), notchToSrgSet).merge()
MappingFormats.TSRG.createReader(extraSpigotSrgMappings.file.toPath()).use { it.read(spigotToSrgSet) }
extraSpigotSrgMappings.fileOrNull?.toPath()?.let { path ->
MappingFormats.TSRG.createReader(path).use { it.read(spigotToSrgSet) }
}
val mcpToNotchSet = MappingSetMerger.create(notchToSrgSet, srgToMcpSet).merge().reverse()
val mcpToSpigotSet = MappingSetMerger.create(mcpToNotchSet, notchToSpigotSet).merge()
@ -135,7 +146,7 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
): MergeResult<TopLevelClassMapping?> {
// If both are provided, keep spigot
return MergeResult(
target.createTopLevelClassMapping(left.obfuscatedName, prependPackage(left.deobfuscatedName)),
target.createTopLevelClassMapping(prependPackage(left.obfuscatedName), prependPackage(left.deobfuscatedName)),
right
)
}
@ -145,7 +156,7 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
context: MergeContext
): MergeResult<TopLevelClassMapping?> {
return MergeResult(
target.createTopLevelClassMapping(left.obfuscatedName, prependPackage(left.deobfuscatedName))
target.createTopLevelClassMapping(prependPackage(left.obfuscatedName), prependPackage(left.deobfuscatedName))
)
}
override fun addRightTopLevelClassMapping(
@ -157,8 +168,10 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
return if (right.deobfuscatedName.contains("/client/")) {
MergeResult(null)
} else {
// This is a mapping Spigot is totally missing, but Spigot maps all classes without a package to
// /net/minecraft regardless if there are mappings for the classes or not
MergeResult(
target.createTopLevelClassMapping(right.obfuscatedName, prependPackage(right.obfuscatedName)),
target.createTopLevelClassMapping(prependPackage(right.obfuscatedName), right.obfuscatedName),
right
)
}
@ -195,19 +208,23 @@ class SpigotPackageMergerHandler(private val newPackage: String) : MappingSetMer
override fun mergeFieldMappings(
left: FieldMapping,
right: FieldMapping,
strictRight: FieldMapping?,
looseRight: FieldMapping?,
target: ClassMapping<*, *>,
context: MergeContext
): FieldMapping? {
): FieldMapping {
throw IllegalStateException("Unexpectedly merged field: $left")
}
override fun mergeDuplicateFieldMappings(
left: FieldMapping,
right: FieldMapping,
rightContinuation: FieldMapping?,
strictRightDuplicate: FieldMapping?,
looseRightDuplicate: FieldMapping?,
strictRightContinuation: FieldMapping?,
looseRightContinuation: FieldMapping?,
target: ClassMapping<*, *>,
context: MergeContext
): FieldMapping? {
): FieldMapping {
return target.createFieldMapping(left.obfuscatedName, left.deobfuscatedName)
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -25,10 +24,10 @@ 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.mcpConfig
import io.papermc.paperweight.util.mcpFile
import io.papermc.paperweight.util.writeMappings
import org.cadixdev.bombe.type.signature.MethodSignature
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.io.MappingFormats
import org.cadixdev.lorenz.merge.MappingSetMerger
@ -37,44 +36,46 @@ 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
open class GenerateSrgs : DefaultTask() {
abstract class GenerateSrgs : DefaultTask() {
@InputFile
val configFile: RegularFileProperty = project.objects.fileProperty()
@InputFile
val methodsCsv: RegularFileProperty = project.objects.fileProperty()
@InputFile
val fieldsCsv: RegularFileProperty = project.objects.fileProperty()
@InputFile
val extraNotchSrgMappings: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val methodsCsv: RegularFileProperty
@get:InputFile
abstract val fieldsCsv: RegularFileProperty
@get:Optional
@get:InputFile
abstract val extraNotchSrgMappings: RegularFileProperty
@OutputFile
val notchToSrg: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val notchToMcp: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val mcpToNotch: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val mcpToSrg: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val srgToNotch: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val srgToMcp: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val inSrg: 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 config = mcpConfig(configFile)
val inSrg = mcpFile(configFile, config.data.mappings)
val methods = HashMap<String, String>()
val fields = HashMap<String, String>()
readCsvs(methods, fields)
val inSet = MappingFormats.TSRG.createReader(inSrg.toPath()).use { it.read() }
MappingFormats.TSRG.createReader(extraNotchSrgMappings.file.toPath()).use { it.read(inSet) }
val inSet = MappingFormats.TSRG.createReader(inSrg.file.toPath()).use { it.read() }
extraNotchSrgMappings.fileOrNull?.toPath()?.let { path ->
MappingFormats.TSRG.createReader(path).use { it.read(inSet) }
}
ensureParentExists(notchToSrg, notchToMcp, mcpToNotch, mcpToSrg, srgToNotch, srgToMcp)
createMappings(inSet, methods, fields)
@ -96,10 +97,12 @@ open class GenerateSrgs : DefaultTask() {
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()
@ -138,6 +141,39 @@ open class GenerateSrgs : DefaultTask() {
)
}
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
@ -155,13 +191,7 @@ open class GenerateSrgs : DefaultTask() {
}
private fun remapAnonymousClasses(mapping: InnerClassMapping, target: ClassMapping<*, *>) {
val newMapping = if (mapping.obfuscatedName.toIntOrNull() != null) {
// This is an anonymous class, keep the index
target.createInnerClassMapping(mapping.deobfuscatedName, mapping.deobfuscatedName)
} else {
target.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
}
val newMapping = target.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
remapMembers(mapping, newMapping)
}
@ -177,3 +207,56 @@ open class GenerateSrgs : DefaultTask() {
}
}
}
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

@ -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
* Copyright (C) 2018 Forge Development LLC
*
* 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 com.github.salomonbrys.kotson.array
import com.github.salomonbrys.kotson.fromJson
import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.string
import com.google.gson.JsonObject
import io.papermc.paperweight.util.Constants
import io.papermc.paperweight.util.Constants.paperTaskOutput
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.ext
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.getWithEtag
import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.toProvider
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import util.MinecraftManifest
open class GetRemoteJsons : DefaultTask() {
@Input
val config: Property<String> = project.objects.property()
@OutputFile
val artifactOutputFile: RegularFileProperty = project.objects.run {
fileProperty().convention(project.toProvider {
project.cache.resolve(paperTaskOutput("mc-libraries", "txt"))
})
}
init {
outputs.upToDateWhen { false }
}
@TaskAction
fun run() {
val cache = project.cache
val extension = project.ext
val mcManifestJson = cache.resolve(Constants.MC_MANIFEST)
val mcVersionJson = cache.resolve(Constants.VERSION_JSON)
ensureParentExists(mcManifestJson, mcVersionJson)
// McManifest.json
val mcManifestEtag = cache.resolve("${Constants.MC_MANIFEST}.etag")
getWithEtag(Constants.MC_MANIFEST_URL, mcManifestJson, mcManifestEtag)
val mcManifestText = gson.fromJson<MinecraftManifest>(mcManifestJson.readText())
val mcVersionEtag = mcVersionJson.resolveSibling("${mcVersionJson.name}.etag")
getWithEtag(mcManifestText.versions.first { it.id == extension.minecraftVersion.get() }.url, mcVersionJson, mcVersionEtag)
val jsonObject = mcVersionJson.bufferedReader().use { reader ->
gson.fromJson<JsonObject>(reader)
}
val conf = config.get()
artifactOutputFile.file.delete()
artifactOutputFile.file.bufferedWriter().use { writer ->
for (library in jsonObject["libraries"].array) {
val artifact = library["name"].string
project.dependencies.add(conf, artifact)
writer.appendln(artifact)
}
}
}
}

View file

@ -0,0 +1,109 @@
/*
* 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.defaultOutput
import io.papermc.paperweight.util.file
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.FieldVisitor
import org.objectweb.asm.Opcodes
abstract class InspectVanillaJar : BaseTask() {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:OutputFile
abstract val outputFile: RegularFileProperty
override fun init() {
outputFile.convention(defaultOutput("txt"))
}
@TaskAction
fun run() {
val outputList = mutableListOf<LoggerField>()
val jarFile = inputJar.file
archives.zipTree(jarFile).matching {
include("/*.class")
include("/net/minecraft/**/*.class")
}.forEach { file ->
if (file.isDirectory) {
return@forEach
}
val classData = file.readBytes()
val reader = ClassReader(classData)
reader.accept(LoggerFinder(outputList), 0)
}
outputFile.file.bufferedWriter(Charsets.UTF_8).use { writer ->
for (loggerField in outputList) {
writer.append(loggerField.className)
writer.append(' ')
writer.append(loggerField.fieldName)
writer.newLine()
}
}
}
}
class LoggerFinder(private val fields: MutableList<LoggerField>) : ClassVisitor(Opcodes.ASM8) {
private var currentClass: String? = null
override fun visit(
version: Int,
access: Int,
name: String,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
this.currentClass = name
}
override fun visitField(
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
}
}
data class LoggerField(val className: String, val fieldName: String)

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,42 +23,38 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.ensureDeleted
import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.file
import org.cadixdev.atlas.Atlas
import org.cadixdev.bombe.asm.jar.JarEntryRemappingTransformer
import org.cadixdev.lorenz.asm.LorenzRemapper
import org.cadixdev.lorenz.io.MappingFormats
import org.gradle.api.DefaultTask
import org.cadixdev.at.AccessTransformSet
import org.cadixdev.at.io.AccessTransformFormats
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
open class RemapVanillaJarSrg : DefaultTask() {
abstract class MergeAccessTransforms : BaseTask() {
@InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty()
@get:InputFiles
abstract val inputFiles: ListProperty<RegularFile>
@InputFile
val mappings: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile
abstract val outputFile: RegularFileProperty
@OutputFile
val outputJar: RegularFileProperty = defaultOutput()
override fun init() {
outputFile.convention(defaultOutput("at"))
}
@TaskAction
fun run() {
ensureParentExists(outputJar.file)
ensureDeleted(outputJar.file)
val ats = inputFiles.get()
.map { AccessTransformFormats.FML.read(it.asFile.toPath()) }
val mappings = MappingFormats.TSRG.createReader(mappings.file.toPath()).use { it.read() }
Atlas().apply {
install { ctx ->
JarEntryRemappingTransformer(LorenzRemapper(mappings, ctx.inheritanceProvider()))
}
run(inputJar.file.toPath(), outputJar.file.toPath())
val outputAt = AccessTransformSet.create()
for (at in ats) {
outputAt.merge(at)
}
AccessTransformFormats.FML.write(outputFile.file.toPath(), outputAt)
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -31,23 +30,23 @@ import org.gradle.api.tasks.TaskAction
import java.io.PrintWriter
import java.util.regex.Pattern
open class PatchMcpCsv : DefaultTask() {
abstract class PatchMcpCsv : DefaultTask() {
@InputFile
val fieldsCsv: RegularFileProperty = project.objects.fileProperty()
@InputFile
val methodsCsv: RegularFileProperty = project.objects.fileProperty()
@InputFile
val paramsCsv: RegularFileProperty = project.objects.fileProperty()
@InputFile
val changesFile: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val fieldsCsv: RegularFileProperty
@get:InputFile
abstract val methodsCsv: RegularFileProperty
@get:InputFile
abstract val paramsCsv: RegularFileProperty
@get:InputFile
abstract val changesFile: RegularFileProperty
@OutputFile
val paperFieldCsv: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val paperMethodCsv: RegularFileProperty = project.objects.fileProperty()
@OutputFile
val paperParamCsv: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile
abstract val paperFieldCsv: RegularFileProperty
@get:OutputFile
abstract val paperMethodCsv: RegularFileProperty
@get:OutputFile
abstract val paperParamCsv: RegularFileProperty
@TaskAction
fun run() {

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,33 +22,35 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.mcpConfig
import org.gradle.api.DefaultTask
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import org.cadixdev.at.io.AccessTransformFormats
import org.cadixdev.lorenz.io.MappingFormats
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.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
open class SetupMcpDependencies : DefaultTask() {
abstract class RemapAccessTransform : BaseTask() {
@InputFile
val configFile: RegularFileProperty = project.objects.fileProperty()
@Input
val forgeFlowerConfig: Property<String> = project.objects.property()
@Input
val mcInjectorConfig: Property<String> = project.objects.property()
@get:InputFile
abstract val inputFile: RegularFileProperty
@get:InputFile
abstract val mappings: RegularFileProperty
init {
outputs.upToDateWhen { false }
@get:OutputFile
abstract val outputFile: RegularFileProperty
override fun init() {
outputFile.convention(defaultOutput("at"))
}
@TaskAction
fun run() {
val config = mcpConfig(configFile)
val at = AccessTransformFormats.FML.read(inputFile.file.toPath())
val mappingSet = MappingFormats.TSRG.createReader(mappings.file.toPath()).use { it.read() }
project.dependencies.add(forgeFlowerConfig.get(), config.functions.getValue("decompile").version)
project.dependencies.add(mcInjectorConfig.get(), config.functions.getValue("mcinject").version)
val resultAt = at.remap(mappingSet)
AccessTransformFormats.FML.write(outputFile.file.toPath(), resultAt)
}
}

View file

@ -1,267 +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
* Copyright (C) 2018 Forge Development LLC
*
* 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.PaperweightException
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.mcpConfig
import io.papermc.paperweight.util.mcpFile
import org.cadixdev.at.AccessTransformSet
import org.cadixdev.at.io.AccessTransformFormats
import org.cadixdev.lorenz.io.MappingFormats
import org.cadixdev.mercury.Mercury
import org.cadixdev.mercury.RewriteContext
import org.cadixdev.mercury.SourceProcessor
import org.cadixdev.mercury.SourceRewriter
import org.cadixdev.mercury.at.AccessTransformerRewriter
import org.cadixdev.mercury.extra.AccessAnalyzerProcessor
import org.cadixdev.mercury.extra.BridgeMethodRewriter
import org.cadixdev.mercury.remapper.MercuryRemapper
import org.cadixdev.mercury.util.BombeBindings
import org.eclipse.jdt.core.dom.ASTVisitor
import org.eclipse.jdt.core.dom.IMethodBinding
import org.eclipse.jdt.core.dom.IVariableBinding
import org.eclipse.jdt.core.dom.MethodDeclaration
import org.eclipse.jdt.core.dom.Modifier
import org.eclipse.jdt.core.dom.SimpleName
import org.eclipse.jdt.core.dom.VariableDeclaration
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.property
import java.io.File
open class RemapSources : ZippedTask() {
@InputFile
val vanillaJar: RegularFileProperty = project.objects.fileProperty()
@InputFile
val vanillaRemappedSpigotJar: RegularFileProperty = project.objects.fileProperty() // Required for pre-remap pass
@InputFile
val vanillaRemappedSrgJar: RegularFileProperty = project.objects.fileProperty() // Required for post-remap pass
@InputFile
val mappings: RegularFileProperty = project.objects.fileProperty()
@Input
val configuration: Property<String> = project.objects.property()
@InputFile
val configFile: RegularFileProperty = project.objects.fileProperty()
@InputDirectory
val spigotServerDir: DirectoryProperty = project.objects.directoryProperty()
@InputDirectory
val spigotApiDir: DirectoryProperty = project.objects.directoryProperty()
@OutputFile
val generatedAt: RegularFileProperty = defaultOutput("at")
override fun run(rootDir: File) {
val config = mcpConfig(configFile)
val constructors = mcpFile(configFile, config.data.constructors)
val mappings = MappingFormats.TSRG.createReader(mappings.file.toPath()).use { it.read() }
val srcDir = spigotServerDir.file.resolve("src/main/java")
val pass1Dir = rootDir.resolve("pass1")
val outDir = rootDir.resolve("out")
val configuration = project.configurations[configuration.get()]
val ats = AccessTransformSet.create()
// Remap any references Spigot maps to SRG
Mercury().apply {
classPath.addAll(listOf(
vanillaJar.asFile.get().toPath(),
vanillaRemappedSpigotJar.asFile.get().toPath(),
spigotApiDir.file.resolve("src/main/java").toPath()
))
for (file in configuration.resolvedConfiguration.files) {
classPath.add(file.toPath())
}
// Generate AT
processors.add(AccessAnalyzerProcessor.create(ats, mappings))
process(srcDir.toPath())
// Remap
processors.clear()
processors.addAll(listOf(
MercuryRemapper.create(mappings),
BridgeMethodRewriter.create(),
AccessTransformerRewriter.create(ats)
))
rewrite(srcDir.toPath(), pass1Dir.toPath())
}
Mercury().apply {
// Remap SRG parameters
classPath.addAll(listOf(
vanillaJar.asFile.get().toPath(),
vanillaRemappedSrgJar.asFile.get().toPath(),
spigotApiDir.file.resolve("src/main/java").toPath()
))
processors.add(SrgParameterRemapper(constructors))
rewrite(pass1Dir.toPath(), outDir.toPath())
}
// Only leave remapped source
val fileList = rootDir.listFiles() ?: throw PaperweightException("Could not list files in $rootDir")
for (file in fileList) {
if (file != outDir) {
file.deleteRecursively()
}
}
// Move out/* to base dir
val files = outDir.listFiles() ?: throw PaperweightException("No files found in $outDir")
for (file in files) {
file.renameTo(rootDir.resolve(file.name))
}
outDir.delete()
// And write generated AT file
AccessTransformFormats.FML.write(generatedAt.asFile.get().toPath(), ats)
}
}
class SrgParameterRemapper(constructors: File) : SourceRewriter {
private val constructorMap = hashMapOf<String, MutableList<ConstructorNode>>()
init {
constructors.useLines { lines ->
lines.forEach { line ->
val parts = line.split(' ')
constructorMap.compute(parts[1].replace('/', '.')) { _, v ->
val node = ConstructorNode(parts[0].toInt(), parts[2])
if (v == null) {
return@compute mutableListOf(node)
} else {
v += node
return@compute v
}
}
}
}
for (list in constructorMap.values) {
// Put bigger numbers first
// Old constructor entries are still present, just with smaller numbers. So we don't want to grab an older
// entry
list.reverse()
}
}
override fun getFlags(): Int = SourceProcessor.FLAG_RESOLVE_BINDINGS
override fun rewrite(context: RewriteContext) {
context.compilationUnit.accept(SrgParameterVisitor(context, constructorMap))
}
}
data class ConstructorNode(
val id: Int,
val signature: String
)
class SrgParameterVisitor(
private val context: RewriteContext,
private val constructors: Map<String, List<ConstructorNode>>
) : ASTVisitor() {
companion object {
private val MATCHER = Regex("func_(\\d+)_.*")
}
override fun visit(node: SimpleName): Boolean {
val binding = node.resolveBinding() as? IVariableBinding ?: return false
if (!binding.isParameter) {
return false
}
val variableDecl = context.compilationUnit.findDeclaringNode(binding.variableDeclaration) as VariableDeclaration
val method = binding.declaringMethod
val methodDecl = context.compilationUnit.findDeclaringNode(method) as? MethodDeclaration ?: return false
handleMethod(node, methodDecl, method, variableDecl)
return false
}
private fun handleMethod(node: SimpleName, methodDecl: MethodDeclaration, method: IMethodBinding, variableDecl: VariableDeclaration) {
if (method.isConstructor) {
handleConstructor(node, methodDecl, method, variableDecl)
return
}
val match = MATCHER.matchEntire(method.name) ?: return
val isStatic = method.modifiers and Modifier.STATIC != 0
var index = getParameterIndex(methodDecl, variableDecl)
if (index == -1) {
return
}
if (!isStatic) {
index++
}
val paramName = "p_${match.groupValues[1]}_${index}_"
context.createASTRewrite().set(node, SimpleName.IDENTIFIER_PROPERTY, paramName, null)
}
private fun handleConstructor(node: SimpleName, methodDecl: MethodDeclaration, method: IMethodBinding, variableDecl: VariableDeclaration) {
val constructorNodes = constructors[method.declaringClass.binaryName] ?: return
val constructorNode = constructorNodes.firstOrNull { constructorNode ->
constructorNode.signature == BombeBindings.convertSignature(method).descriptor.toString()
} ?: return
val id = constructorNode.id
var index = getParameterIndex(methodDecl, variableDecl)
if (index == -1) {
return
}
// Constructors are never static
index++
val paramName = "p_i${id}_${index}_"
context.createASTRewrite().set(node, SimpleName.IDENTIFIER_PROPERTY, paramName, null)
}
private fun getParameterIndex(methodDecl: MethodDeclaration, decl: VariableDeclaration): Int {
@Suppress("UNCHECKED_CAST")
val params = methodDecl.parameters() as List<VariableDeclaration>
return params.indexOfFirst { it === decl }
}
}

View file

@ -0,0 +1,135 @@
/*
* 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.defaultOutput
import io.papermc.paperweight.util.file
import org.cadixdev.at.AccessChange
import org.cadixdev.at.AccessTransform
import org.cadixdev.at.AccessTransformSet
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
import org.gradle.api.tasks.TaskAction
import java.util.jar.JarFile
abstract class RemapSpigotAt : BaseTask() {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:InputFile
abstract val spigotAt: RegularFileProperty
@get:InputFile
abstract val mapping: RegularFileProperty
@get:OutputFile
abstract val outputFile: RegularFileProperty
override fun init() {
outputFile.convention(defaultOutput("at"))
}
@TaskAction
fun run() {
val outputAt = AccessTransformSet.create()
spigotAt.file.useLines { lines ->
JarFile(inputJar.file).use { jarFile ->
for (line in lines) {
if (line.isBlank() || line.startsWith('#')) {
continue
}
val (access, desc) = line.split(' ')
if (desc.contains('(')) {
// method
val index = desc.indexOf('(')
val methodDesc = desc.substring(index)
val classAndMethodName = desc.substring(0, index)
val slashIndex = classAndMethodName.lastIndexOf('/')
val className = classAndMethodName.substring(0, slashIndex)
val methodName = classAndMethodName.substring(slashIndex + 1)
outputAt.getOrCreateClass(className).replaceMethod(
MethodSignature(methodName, MethodDescriptor.of(methodDesc)),
parseAccess(access)
)
} else {
// either field or class
if (jarFile.getJarEntry("$desc.class") == null) {
// field
val index = desc.lastIndexOf('/')
val className = desc.substring(0, index)
val fieldName = desc.substring(index + 1)
outputAt.getOrCreateClass(className).replaceField(fieldName, parseAccess(access))
} else {
// class
outputAt.getOrCreateClass(desc).replace(parseAccess(access))
}
}
}
}
}
val mappings = MappingFormats.TSRG.createReader(mapping.file.toPath()).use { it.read() }
val remappedAt = outputAt.remap(mappings)
AccessTransformFormats.FML.write(outputFile.file.toPath(), remappedAt)
}
private fun parseAccess(text: String): AccessTransform {
val index = text.indexOfAny(charArrayOf('+', '-'))
return if (index == -1) {
// only access
AccessTransform.of(parseAccessChange(text))
} else {
val accessChange = parseAccessChange(text.substring(0, index))
val modifierChange = parseModifierChange(text[index])
AccessTransform.of(accessChange, modifierChange)
}
}
private fun parseAccessChange(text: String): AccessChange {
return when (text) {
"public" -> AccessChange.PUBLIC
"private" -> AccessChange.PRIVATE
"protected" -> AccessChange.PROTECTED
"default" -> AccessChange.PACKAGE_PRIVATE
else -> AccessChange.NONE
}
}
private fun parseModifierChange(c: Char): ModifierChange {
return when (c) {
'+' -> ModifierChange.ADD
'-' -> ModifierChange.REMOVE
else -> ModifierChange.NONE
}
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -32,14 +31,14 @@ import java.io.BufferedWriter
import java.io.File
import java.util.regex.Pattern
open class RemapSrgSources : ZippedTask() {
abstract class RemapSrgSources : ZippedTask() {
@InputFile
val methodsCsv: RegularFileProperty = project.objects.fileProperty()
@InputFile
val fieldsCsv: RegularFileProperty = project.objects.fileProperty()
@InputFile
val paramsCsv: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val methodsCsv: RegularFileProperty
@get:InputFile
abstract val fieldsCsv: RegularFileProperty
@get:InputFile
abstract val paramsCsv: RegularFileProperty
private val methods = hashMapOf<String, String>()
private val methodDocs = hashMapOf<String, String>()

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -28,52 +27,44 @@ import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.runJar
import io.papermc.paperweight.util.wrapException
import org.gradle.api.DefaultTask
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.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
open class RemapVanillaJarSpigot : DefaultTask() {
abstract class RemapVanillaJarSpigot : BaseTask() {
@InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:InputFile
abstract val classMappings: RegularFileProperty
@get:InputFile
abstract val memberMappings: RegularFileProperty
@get:InputFile
abstract val packageMappings: RegularFileProperty
@get:InputFile
abstract val accessTransformers: RegularFileProperty
@get:Input
abstract val workDirName: Property<String>
@get:InputFile
abstract val specialSourceJar: RegularFileProperty
@get:InputFile
abstract val specialSource2Jar: RegularFileProperty
@get:Input
abstract val classMapCommand: Property<String>
@get:Input
abstract val memberMapCommand: Property<String>
@get:Input
abstract val finalMapCommand: Property<String>
@InputFile
val classMappings: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile
abstract val outputJar: RegularFileProperty
@InputFile
val memberMappings: RegularFileProperty = project.objects.fileProperty()
@InputFile
val packageMappings: RegularFileProperty = project.objects.fileProperty()
@InputFile
val accessTransformers: RegularFileProperty = project.objects.fileProperty()
@Input
val workDirName: Property<String> = project.objects.property()
@InputFile
val specialSourceJar: RegularFileProperty = project.objects.fileProperty()
@InputFile
val specialSource2Jar: RegularFileProperty = project.objects.fileProperty()
@Input
val classMapCommand: Property<String> = project.objects.property()
@Input
val memberMapCommand: Property<String> = project.objects.property()
@Input
val finalMapCommand: Property<String> = project.objects.property()
@OutputFile
val outputJar: RegularFileProperty = defaultOutput()
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
@ -92,14 +83,15 @@ open class RemapVanillaJarSpigot : DefaultTask() {
val packageMappingsPath = packageMappings.asFile.get().canonicalPath
val accessTransformersPath = accessTransformers.asFile.get().canonicalPath
val work = layout.projectDirectory.file(workDirName.get())
try {
println("Applying class mappings...")
wrapException("Failed to apply class mappings") {
val logFile = project.cache.resolve(paperTaskOutput("class.log"))
val logFile = layout.cache.resolve(paperTaskOutput("class.log"))
logFile.delete()
runJar(
specialSource2Jar,
workingDir = workDirName.get(),
workingDir = work,
logFile = logFile,
args = *doReplacements(classMapCommand.get(), inputJarPath, classMappingPath, classJarPath) {
// ignore excludes, we actually want to map every class
@ -107,24 +99,22 @@ open class RemapVanillaJarSpigot : DefaultTask() {
}
)
}
println("Applying member mappings...")
wrapException("Failed to apply member mappings") {
val logFile = project.cache.resolve(paperTaskOutput("member.log"))
val logFile = layout.cache.resolve(paperTaskOutput("member.log"))
logFile.delete()
runJar(
specialSource2Jar,
workingDir = workDirName.get(),
workingDir = work,
logFile = logFile,
args = *doReplacements(memberMapCommand.get(), classJarPath, memberMappingsPath, membersJarPath)
)
}
println("Creating remapped jar...")
wrapException("Failed to create remapped jar") {
val logFile = project.cache.resolve(paperTaskOutput("final.log"))
val logFile = layout.cache.resolve(paperTaskOutput("final.log"))
logFile.delete()
runJar(
specialSourceJar,
workingDir = workDirName.get(),
workingDir = work,
logFile = logFile,
args = *doReplacements(finalMapCommand.get(), membersJarPath, accessTransformersPath, packageMappingsPath, outputJarPath)
)

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,57 +23,67 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants.paperTaskOutput
import io.papermc.paperweight.util.McpConfig
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.decompile
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.mcpConfig
import io.papermc.paperweight.util.fromJson
import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.runJar
import org.gradle.api.DefaultTask
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.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.property
open class RunForgeFlower : DefaultTask() {
abstract class RunForgeFlower : BaseTask() {
@Input
val configuration: Property<String> = project.objects.property()
@get:InputFile
abstract val configFile: RegularFileProperty
@get:InputFile
abstract val executable: RegularFileProperty
@InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty()
@InputFile
val libraries: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:InputFile
abstract val libraries: RegularFileProperty
@InputFile
val configFile: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile
abstract val outputJar: RegularFileProperty
@OutputFile
val outputJar: RegularFileProperty = defaultOutput()
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
val config = mcpConfig(configFile)
val out = outputJar.file
val target = out.resolveSibling("${out.name}.dir")
if (target.exists()) {
target.deleteRecursively()
}
target.mkdirs()
val forgeFlowerArgs = config.functions.getValue("decompile").args
val jvmArgs = config.functions.getValue("decompile").jvmargs ?: listOf()
val config = gson.fromJson<McpConfig>(configFile)
val argList = forgeFlowerArgs.map {
val argList = config.functions.decompile.args.map {
when (it) {
"{libraries}" -> libraries.file.absolutePath
"{input}" -> inputJar.file.absolutePath
"{output}" -> outputJar.file.absolutePath
"{output}" -> target.absolutePath
else -> it
}
}
val logFile = project.cache.resolve(paperTaskOutput("log"))
val logFile = layout.cache.resolve(paperTaskOutput("log"))
logFile.delete()
val forgeFlowerJar = project.configurations[configuration.get()].resolve().single()
runJar(forgeFlowerJar, project.cache, logFile, jvmArgs = jvmArgs, args = *argList.toTypedArray())
val jvmArgs = config.functions.decompile.jvmargs ?: listOf()
runJar(executable.file, layout.cache, logFile, jvmArgs = jvmArgs, args = *argList.toTypedArray())
// FernFlower is weird with how it does directory output
target.resolve(inputJar.file.name).renameTo(out)
target.deleteRecursively()
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,60 +22,65 @@
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.mcpConfig
import io.papermc.paperweight.util.mcpFile
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 org.gradle.api.DefaultTask
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.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.property
open class RunMcInjector : DefaultTask() {
abstract class RunMcInjector : BaseTask() {
@Input
val configuration: Property<String> = project.objects.property()
@InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty()
@InputFile
val configFile: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val configFile: RegularFileProperty
@get:InputFile
abstract val executable: RegularFileProperty
@OutputFile
val outputJar: RegularFileProperty = defaultOutput()
@OutputFile
val logFile: RegularFileProperty = defaultOutput("log")
@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
override fun init() {
outputJar.convention(defaultOutput())
logFile.convention(defaultOutput("log"))
}
@TaskAction
fun run() {
val config = mcpConfig(configFile)
val exceptions = mcpFile(configFile, config.data.exceptions)
val access = mcpFile(configFile, config.data.access)
val constructors = mcpFile(configFile, config.data.constructors)
val config = gson.fromJson<McpConfig>(configFile)
val mcInjectorArgs = config.functions.getValue("mcinject").args
val jvmArgs = config.functions.getValue("mcinject").jvmargs ?: listOf()
val argList = mcInjectorArgs.map {
val argList = config.functions.mcinject.args.map {
when (it) {
"{input}" -> inputJar.file.absolutePath
"{output}" -> outputJar.file.absolutePath
"{log}" -> logFile.file.absolutePath
"{exceptions}" -> exceptions.absolutePath
"{access}" -> access.absolutePath
"{constructors}" -> constructors.absolutePath
"{exceptions}" -> exceptions.file.absolutePath
"{access}" -> access.file.absolutePath
"{constructors}" -> constructors.file.absolutePath
else -> it
}
}
val mcInjectorJar = project.configurations[configuration.get()].resolve().single()
val jvmArgs = config.functions.mcinject.jvmargs ?: listOf()
runJar(mcInjectorJar, project.cache, logFile = null, jvmArgs = jvmArgs, args = *argList.toTypedArray())
runJar(executable, layout.cache, logFile = null, jvmArgs = jvmArgs, args = *argList.toTypedArray())
}
}

View file

@ -0,0 +1,84 @@
/*
* 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.paperTaskOutput
import io.papermc.paperweight.util.McpConfig
import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.ensureDeleted
import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fromJson
import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.rename
import io.papermc.paperweight.util.runJar
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 RunSpecialSource : BaseTask() {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:InputFile
abstract val mappings: RegularFileProperty
@get:InputFile
abstract val configFile: RegularFileProperty
@get:InputFile
abstract val executable: RegularFileProperty
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
val out = outputJar.file
ensureParentExists(out)
ensureDeleted(out)
val config = gson.fromJson<McpConfig>(configFile)
val argList = config.functions.rename.args.map {
when (it) {
"{input}" -> inputJar.file.absolutePath
"{output}" -> outputJar.file.absolutePath
"{mappings}" -> mappings.file.absolutePath
else -> it
}
}
val jvmArgs = config.functions.rename.jvmargs ?: listOf()
val logFile = layout.cache.resolve(paperTaskOutput("log"))
logFile.delete()
runJar(executable.file, layout.cache, logFile, jvmArgs = jvmArgs, args = *argList.toTypedArray())
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,22 +22,30 @@
package io.papermc.paperweight.tasks
import com.github.salomonbrys.kotson.fromJson
import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.file
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import util.BuildDataInfo
import org.gradle.api.tasks.TaskAction
open class GatherBuildData : DefaultTask() {
abstract class SetupMcLibraries : DefaultTask() {
@OutputFile
val buildDataInfoFile: RegularFileProperty = project.objects.fileProperty()
@get:Input
abstract val dependencies: ListProperty<String>
val buildDataInfo: Provider<BuildDataInfo> = buildDataInfoFile.map {
it.asFile.bufferedReader().use { reader ->
gson.fromJson(reader)
@get:OutputFile
abstract val outputFile: RegularFileProperty
@TaskAction
fun run() {
val list = dependencies.get().sorted()
outputFile.file.bufferedWriter().use { writer ->
for (line in list) {
writer.appendln(line)
}
}
}
}

View file

@ -1,117 +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
* Copyright (C) 2018 Forge Development LLC
*
* 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.file
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import org.w3c.dom.Element
import java.io.File
import javax.xml.parsers.DocumentBuilderFactory
open class SetupSpigotDependencies : DefaultTask() {
@InputDirectory
val spigotApi: DirectoryProperty = project.objects.directoryProperty()
@InputDirectory
val spigotServer: DirectoryProperty = project.objects.directoryProperty()
@Input
val configurationName: Property<String> = project.objects.property()
init {
// we set dependencies here, can't cache this
outputs.upToDateWhen { false }
}
@TaskAction
fun run() {
val apiDeps = parsePom(spigotApi.file.resolve("pom.xml"))
val serverDeps = parsePom(spigotServer.file.resolve("pom.xml"))
for (dep in apiDeps) {
project.dependencies.add(configurationName.get(), dep)
}
for (dep in serverDeps) {
project.dependencies.add(configurationName.get(), dep)
}
}
private fun parsePom(pomFile: File): List<String> {
val depList = arrayListOf<String>()
val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
val doc = pomFile.inputStream().buffered().use { stream ->
stream.buffered().use { buffered ->
builder.parse(buffered)
}
}
doc.documentElement.normalize()
val list = doc.getElementsByTagName("dependencies")
for (i in 0 until list.length) {
val node = list.item(i) as? Element ?: continue
val depNode = node.getElementsByTagName("dependency")
for (j in 0 until depNode.length) {
val dependency = depNode.item(j) as? Element ?: continue
val text = getDependency(dependency) ?: continue
depList += text
}
}
return depList
}
private fun getDependency(node: Element): String? {
val scopeNode = node.getElementsByTagName("scope")
val scope = if (scopeNode.length == 0) {
"compile"
} else {
scopeNode.item(0).textContent
}
if (scope != "compile") {
return null
}
val group = node.getElementsByTagName("groupId").item(0).textContent
val artifact = node.getElementsByTagName("artifactId").item(0).textContent
val version = node.getElementsByTagName("version").item(0).textContent
if (version.contains("\${")) {
// Don't handle complicated things
// We don't need to (for now anyways)
return null
}
return "$group:$artifact:$version"
}
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,32 +22,31 @@
package io.papermc.paperweight.tasks
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.property
open class WriteLibrariesFile : DefaultTask() {
abstract class WriteLibrariesFile : BaseTask() {
@Input
val config: Property<String> = project.objects.property()
@get:Classpath
abstract val libraries: DirectoryProperty
@OutputFile
val outputFile: RegularFileProperty = defaultOutput("txt")
@get:OutputFile
abstract val outputFile: RegularFileProperty
init {
outputs.upToDateWhen { false }
override fun init() {
outputFile.convention(defaultOutput("txt"))
}
@TaskAction
fun run() {
val files = project.configurations[config.get()].resolve().sorted()
val files = libraries.file.listFiles()?.sorted()
?: throw PaperweightException("Libraries directory does not exist")
outputFile.file.delete()
outputFile.file.bufferedWriter().use { writer ->

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -29,7 +28,6 @@ import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fileOrNull
import io.papermc.paperweight.util.unzip
import io.papermc.paperweight.util.zip
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
@ -38,17 +36,21 @@ import org.gradle.api.tasks.TaskAction
import java.io.File
import java.util.concurrent.ThreadLocalRandom
abstract class ZippedTask : DefaultTask() {
abstract class ZippedTask : BaseTask() {
@InputFile
@Optional
val inputZip: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
@get:Optional
abstract val inputZip: RegularFileProperty
@OutputFile
val outputZip: RegularFileProperty = defaultOutput("zip")
@get:OutputFile
abstract val outputZip: RegularFileProperty
abstract fun run(rootDir: File)
override fun init() {
outputZip.convention(defaultOutput("zip"))
}
@TaskAction
fun exec() {
val outputZipFile = outputZip.file

View file

@ -0,0 +1,317 @@
/*
* 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.MavenArtifact
import io.papermc.paperweight.util.McpConfig
import io.papermc.paperweight.util.decompile
import io.papermc.paperweight.util.download
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.rename
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
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.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
import org.w3c.dom.Element
import java.io.File
import javax.inject.Inject
import javax.xml.parsers.DocumentBuilderFactory
abstract class DownloadTask : DefaultTask() {
@get:Input
abstract val url: Property<String>
@get:OutputFile
abstract val outputFile: RegularFileProperty
@TaskAction
fun run() = download(url, outputFile)
}
abstract class DownloadMcpFiles : DefaultTask() {
@get:Input
abstract val mcpMinecraftVersion: Property<String>
@get:Input
abstract val mcpConfigVersion: Property<String>
@get:Input
abstract val mcpMappingsChannel: Property<String>
@get:Input
abstract val mcpMappingsVersion: Property<String>
@get:OutputFile
abstract val configZip: RegularFileProperty
@get:OutputFile
abstract val mappingsZip: RegularFileProperty
@TaskAction
fun run() {
val repo = listOf(Constants.FORGE_MAVEN_URL)
MavenArtifact(
group = "de.oceanlabs.mcp",
artifact = "mcp_config",
version = mcpMinecraftVersion.get() + "-" + mcpConfigVersion.get(),
extension = "zip"
).downloadToFile(configZip.file, repo)
MavenArtifact(
group = "de.oceanlabs.mcp",
artifact = "mcp_${mcpMappingsChannel.get()}",
version = mcpMappingsVersion.get(),
extension = "zip"
).downloadToFile(mappingsZip.file, repo)
}
}
abstract class DownloadMcpTools : DefaultTask() {
@get:InputFile
abstract val configFile: RegularFileProperty
@get:OutputFile
abstract val forgeFlowerFile: RegularFileProperty
@get:OutputFile
abstract val mcInjectorFile: RegularFileProperty
@get:OutputFile
abstract val specialSourceFile: RegularFileProperty
@get:Inject
abstract val workerExecutor: WorkerExecutor
@TaskAction
fun run() {
val config = gson.fromJson<McpConfig>(configFile)
val queue = workerExecutor.noIsolation()
queue.submit(DownloadWorker::class.java) {
repos.add(config.functions.decompile.repo)
artifact.set(config.functions.decompile.version)
target.set(forgeFlowerFile.file)
downloadToDir.set(false)
}
queue.submit(DownloadWorker::class.java) {
repos.add(config.functions.mcinject.repo)
artifact.set(config.functions.mcinject.version)
target.set(mcInjectorFile.file)
downloadToDir.set(false)
}
queue.submit(DownloadWorker::class.java) {
repos.add(config.functions.rename.repo)
artifact.set(config.functions.rename.version)
target.set(specialSourceFile.file)
downloadToDir.set(false)
}
}
}
abstract class DownloadMcLibraries : DefaultTask() {
@get:InputFile
abstract val mcLibrariesFile: RegularFileProperty
@get:Input
abstract val mcRepo: Property<String>
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@get:Inject
abstract val workerExecutor: WorkerExecutor
@TaskAction
fun run() {
val out = outputDir.file
out.deleteRecursively()
val mcRepos = listOf(mcRepo.get())
val queue = workerExecutor.noIsolation()
mcLibrariesFile.file.useLines { lines ->
lines.forEach { line ->
queue.submit(DownloadWorker::class.java) {
repos.set(mcRepos)
artifact.set(line)
target.set(out)
downloadToDir.set(true)
}
}
}
}
}
abstract class DownloadSpigotDependencies : BaseTask() {
@get:InputFile
abstract val apiPom: RegularFileProperty
@get:InputFile
abstract val serverPom: RegularFileProperty
@get:OutputDirectory
abstract val apiOutputDir: DirectoryProperty
@get:OutputDirectory
abstract val serverOutputDir: DirectoryProperty
@get:Inject
abstract val workerExecutor: WorkerExecutor
@TaskAction
fun run() {
val apiSetup = parsePom(apiPom.file)
val serverSetup = parsePom(serverPom.file)
val apiOut = apiOutputDir.file
apiOut.deleteRecursively()
val serverOut = serverOutputDir.file
serverOut.deleteRecursively()
val queue = workerExecutor.noIsolation()
for (art in apiSetup.artifacts) {
queue.submit(DownloadWorker::class.java) {
repos.set(apiSetup.repos)
artifact.set(art.toString())
target.set(apiOut)
downloadToDir.set(true)
}
}
for (art in serverSetup.artifacts) {
queue.submit(DownloadWorker::class.java) {
repos.set(serverSetup.repos)
artifact.set(art.toString())
target.set(serverOut)
downloadToDir.set(true)
}
}
}
private fun parsePom(pomFile: File): MavenSetup {
val depList = arrayListOf<MavenArtifact>()
val repoList = arrayListOf<String>()
// Maven Central is implicit
repoList += "https://repo.maven.apache.org/maven2/"
val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
val doc = pomFile.inputStream().buffered().use { stream ->
stream.buffered().use { buffered ->
builder.parse(buffered)
}
}
doc.documentElement.normalize()
val list = doc.getElementsByTagName("dependencies")
for (i in 0 until list.length) {
val node = list.item(i) as? Element ?: continue
val depNode = node.getElementsByTagName("dependency")
for (j in 0 until depNode.length) {
val dependency = depNode.item(j) as? Element ?: continue
val artifact = getDependency(dependency) ?: continue
depList += artifact
}
}
val repos = doc.getElementsByTagName("repositories")
for (i in 0 until repos.length) {
val node = repos.item(i) as? Element ?: continue
val depNode = node.getElementsByTagName("repository")
for (j in 0 until depNode.length) {
val repo = depNode.item(j) as? Element ?: continue
val repoUrl = repo.getElementsByTagName("url").item(0).textContent
repoList += repoUrl
}
}
return MavenSetup(repos = repoList, artifacts = depList)
}
private fun getDependency(node: Element): MavenArtifact? {
val scopeNode = node.getElementsByTagName("scope")
val scope = if (scopeNode.length == 0) {
"compile"
} else {
scopeNode.item(0).textContent
}
if (scope != "compile") {
return null
}
val group = node.getElementsByTagName("groupId").item(0).textContent
val artifact = node.getElementsByTagName("artifactId").item(0).textContent
val version = node.getElementsByTagName("version").item(0).textContent
if (version.contains("\${")) {
// Don't handle complicated things
// We don't need to (for now anyways)
return null
}
return MavenArtifact(
group = group,
artifact = artifact,
version = version
)
}
}
data class MavenSetup(
val repos: List<String>,
val artifacts: List<MavenArtifact>
)
interface DownloadParams : WorkParameters {
val repos: ListProperty<String>
val artifact: Property<String>
val target: RegularFileProperty
val downloadToDir: Property<Boolean>
}
abstract class DownloadWorker : WorkAction<DownloadParams> {
@get:Inject
abstract val layout: ProjectLayout
override fun execute() {
val artifact = MavenArtifact.parse(parameters.artifact.get())
if (parameters.downloadToDir.get()) {
artifact.downloadToDir(parameters.target.file, parameters.repos.get())
} else {
artifact.downloadToFile(parameters.target.file, parameters.repos.get())
}
}
}

View file

@ -0,0 +1,127 @@
/*
* 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.McpConfig
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fromJson
import io.papermc.paperweight.util.gson
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.io.File
abstract class Extract : BaseTask() {
@get:InputFile
abstract val inputFile: RegularFileProperty
@get:OutputDirectory
abstract val outputDir: DirectoryProperty
@TaskAction
open fun run() {
val input = inputFile.file
val output = outputDir.file
if (output.exists()) {
output.deleteRecursively()
}
output.mkdirs()
fs.copy {
from(archives.zipTree(input))
into(output)
}
}
}
abstract class ExtractMcp : Extract() {
@get:OutputFile
abstract val configFile: RegularFileProperty
@get:OutputFile
abstract val access: RegularFileProperty
@get:OutputFile
abstract val constructors: RegularFileProperty
@get:OutputFile
abstract val exceptions: RegularFileProperty
@get:OutputFile
abstract val mappings: RegularFileProperty
@get:OutputDirectory
abstract val patchDir: DirectoryProperty
override fun init() {
configFile.convention(outputDir.file("config.json"))
access.convention(outputDir.file("config/access.txt"))
constructors.convention(outputDir.file("config/constructors.txt"))
exceptions.convention(outputDir.file("config/exceptions.txt"))
mappings.convention(outputDir.file("config/joined.tsrg"))
patchDir.convention(outputDir.dir("config/patches/server"))
}
@TaskAction
override fun run() {
super.run()
val output = outputDir.file
val config = gson.fromJson<McpConfig>(output.resolve("config.json"))
// We have to know what our output file paths are at configuration time, but these could change based on the
// config.json file.
// So as a workaround we just rename the files the config.json file points to to our expected paths. Likely
// is a no-op.
output.resolve(config.data.access).renameTo(access.file.createParent())
output.resolve(config.data.constructors).renameTo(constructors.file.createParent())
output.resolve(config.data.exceptions).renameTo(exceptions.file.createParent())
output.resolve(config.data.mappings).renameTo(mappings.file.createParent())
output.resolve(config.data.patches.server).renameTo(patchDir.file.createParent())
}
private fun File.createParent(): File {
val par = this.parentFile
if (!par.exists()) {
par.mkdirs()
}
return this
}
}
abstract class ExtractMappings : Extract() {
@get:OutputFile
abstract val fieldsCsv: RegularFileProperty
@get:OutputFile
abstract val methodsCsv: RegularFileProperty
@get:OutputFile
abstract val paramsCsv: RegularFileProperty
override fun init() {
fieldsCsv.convention(outputDir.file("fields.csv"))
methodsCsv.convention(outputDir.file("methods.csv"))
paramsCsv.convention(outputDir.file("params.csv"))
}
}

View file

@ -0,0 +1,100 @@
/*
* 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.defaultOutput
import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.zip
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class Filter : BaseTask() {
@get:InputFile
abstract val inputJar: RegularFileProperty
@get:Input
abstract val includes: ListProperty<String>
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
val out = outputJar.file
val target = out.resolveSibling("${out.name}.dir")
target.mkdirs()
fs.copy {
from(archives.zipTree(inputJar)) {
for (inc in this@Filter.includes.get()) {
include(inc)
}
}
into(target)
}
zip(target, outputJar)
target.deleteRecursively()
}
}
abstract class Merge : BaseTask() {
@get:InputFiles
abstract val inputJars: ListProperty<RegularFile>
@get:OutputFile
abstract val outputJar: RegularFileProperty
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
val out = outputJar.file
val target = out.resolveSibling("${out.name}.dir")
target.mkdirs()
fs.copy {
for (file in inputJars.get()) {
from(archives.zipTree(file))
}
into(target)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
zip(target, outputJar)
target.deleteRecursively()
}
}

View file

@ -1,5 +1,28 @@
package io.papermc.paperweight.tasks
/*
* 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.patchremap
import io.papermc.paperweight.tasks.BaseTask
import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.ensureDeleted
import io.papermc.paperweight.util.ensureParentExists
@ -14,11 +37,8 @@ import org.cadixdev.atlas.Atlas
import org.cadixdev.bombe.jar.JarClassEntry
import org.cadixdev.bombe.jar.JarEntryTransformer
import org.cadixdev.bombe.type.signature.MethodSignature
import org.cadixdev.lorenz.io.MappingFormats
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
import org.objectweb.asm.ClassReader
@ -28,19 +48,20 @@ import org.objectweb.asm.FieldVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
open class ApplyAccessTransform : DefaultTask() {
abstract class ApplyAccessTransform : BaseTask() {
@InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val inputJar: RegularFileProperty
@InputFile
val atFile: RegularFileProperty = project.objects.fileProperty()
@get:InputFile
abstract val atFile: RegularFileProperty
@InputFile
val mapping: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile
abstract val outputJar: RegularFileProperty
@OutputFile
val outputJar: RegularFileProperty = defaultOutput()
override fun init() {
outputJar.convention(defaultOutput())
}
@TaskAction
fun run() {
@ -48,12 +69,10 @@ open class ApplyAccessTransform : DefaultTask() {
ensureDeleted(outputJar.file)
val at = AccessTransformFormats.FML.read(atFile.file.toPath())
val mappings = MappingFormats.TSRG.createReader(mapping.file.toPath()).use { it.read() }
val remappedAt = at.remap(mappings)
Atlas().apply {
install {
AtJarEntryTransformer(remappedAt)
AtJarEntryTransformer(at)
}
run(inputJar.file.toPath(), outputJar.file.toPath())
}

View file

@ -0,0 +1,91 @@
/*
* 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.patchremap
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.util.Git
import java.io.File
class PatchApplier(
private val remappedBranch: String,
private val unmappedBranch: String,
targetDir: File
) {
private val git = Git(targetDir)
private var commitMessage: String? = null
private var commitAuthor: String? = null
private var commitTime: String? = null
fun initRepo() {
println("Initializing patch remap repo")
git("init").executeSilently()
git("commit", "-m", "Initial", "--author=Initial <auto@mated.null>", "--allow-empty").executeSilently()
git("branch", remappedBranch).executeSilently()
git("branch", unmappedBranch).executeSilently()
git("checkout", unmappedBranch).executeSilently()
}
fun checkoutRemapped() {
println("Switching to $remappedBranch without losing changes")
git("symbolic-ref", "HEAD", "refs/heads/$remappedBranch").executeSilently()
}
fun checkoutOld() {
println("Resetting back to $unmappedBranch branch")
git("checkout", unmappedBranch).executeSilently()
}
fun commitInitialSource() {
git("add", ".").executeSilently()
git("commit", "-m", "Initial Source", "--author=Initial <auto@mated.null>").executeSilently()
}
fun recordCommit() {
commitMessage = git("git", "log", "--format=%B", "-n", "1", "HEAD").getText()
commitAuthor = git("git", "log", "--format=%an <%ae>", "-n", "1", "HEAD").getText()
commitTime = git("git", "log", "--format=%aD", "-n", "1", "HEAD").getText()
}
fun commitChanges() {
println("Committing remapped changes to $remappedBranch")
val message = commitMessage ?: throw PaperweightException("commitMessage not set")
val author = commitAuthor ?: throw PaperweightException("commitAuthor not set")
val time = commitTime ?: throw PaperweightException("commitTime not set")
commitMessage = null
commitAuthor = null
commitTime = null
git("add", ".").executeSilently()
git("commit", "-m", message, "--author=$author", "--date=$time").execute()
}
fun applyPatch(patch: File) {
println("Applying patch ${patch.name}")
val result = git("am", "--3way", "--ignore-whitespace", patch.absolutePath).runOut()
if (result != 0) {
System.err.println("Patch failed to apply: $patch")
}
}
}

View file

@ -0,0 +1,96 @@
/*
* 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.patchremap
import io.papermc.paperweight.tasks.sourceremap.ConstructorsData
import io.papermc.paperweight.tasks.sourceremap.ParamNames
import io.papermc.paperweight.tasks.sourceremap.PatchParameterRemapper
import io.papermc.paperweight.tasks.sourceremap.SrgParameterRemapper
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.mercury.Mercury
import org.cadixdev.mercury.remapper.MercuryRemapper
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
class PatchSourceRemapWorker(
private val mappings: MappingSet,
private val classpath: Collection<Path>,
private val paramNames: ParamNames,
private val constructorsData: ConstructorsData,
private val inputDir: Path,
private val outputDir: Path
) {
private val reverseMappings: MappingSet = mappings.reverse()
fun remap() {
setup()
Mercury().apply {
classPath.addAll(classpath)
processors.addAll(listOf(
MercuryRemapper.create(reverseMappings),
PatchParameterRemapper(paramNames, constructorsData)
))
rewrite(inputDir, outputDir)
}
cleanup()
}
fun remapBack() {
setup()
Mercury().apply {
classPath.addAll(classpath)
processors.addAll(listOf(
MercuryRemapper.create(mappings),
SrgParameterRemapper(mappings, constructorsData, paramNames)
))
rewrite(inputDir, outputDir)
}
cleanup()
}
private fun setup() {
Files.walk(outputDir).use { it.forEach(Files::delete) }
Files.createDirectories(outputDir)
}
private fun cleanup() {
Files.walk(inputDir).use { it.forEach(Files::delete) }
Files.walk(outputDir).use {
it.forEach { src ->
val dest = inputDir.resolve(outputDir.relativize(src))
Files.createDirectories(dest.parent)
Files.copy(src, dest, REPLACE_EXISTING)
}
}
}
}

View file

@ -0,0 +1,187 @@
/*
* 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.patchremap
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.cache
import io.papermc.paperweight.util.file
import org.cadixdev.lorenz.io.MappingFormats
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.get
import java.io.File
import java.util.zip.ZipFile
abstract class RemapPatches : BaseTask() {
@get:InputDirectory
abstract val inputPatchDir: DirectoryProperty
@get:InputFile
abstract val sourceJar: RegularFileProperty
@get:InputDirectory
abstract val apiPatchDir: DirectoryProperty
@get:InputFile
abstract val mappingsFile: RegularFileProperty
@get:Classpath
abstract val classpathJars: ListProperty<RegularFile>
@get:InputDirectory
abstract val spigotApiDir: DirectoryProperty
@get:InputDirectory
abstract val spigotServerDir: DirectoryProperty
@get:InputFile
abstract val spigotDecompJar: RegularFileProperty
// For parameter name remapping
@get:InputFile
abstract val parameterNames: RegularFileProperty
@get:InputFile
abstract val constructors: RegularFileProperty
@get:OutputDirectory
abstract val outputPatchDir: DirectoryProperty
@TaskAction
fun run() {
// Check patches
val patches = inputPatchDir.file.listFiles() ?: return run {
println("No input patches found")
}
patches.sort()
// Setup param remapping
val constructorsData = parseConstructors(constructors.file)
val paramMap = parseParamNames(parameterNames.file)
val mappings = MappingFormats.TSRG.createReader(mappingsFile.file.toPath()).use { it.read() }
// This should pull in any libraries needed for type bindings
val configFiles = project.project(":Paper-Server").configurations["runtimeClasspath"].resolve()
val classpathFiles = classpathJars.get().map { it.asFile } + configFiles
// Remap output directory, after each output this directory will be re-named to the input directory below for
// the next remap operation
val tempApiDir = createWorkDir("patch-remap-api", source = spigotApiDir.file)
val tempInputDir = createWorkDir("patch-remap-input", source = spigotServerDir.file)
val tempOutputDir = createWorkDir("patch-remap-output")
val sourceInputDir = tempInputDir.resolve("src/main/java")
sourceInputDir.deleteRecursively()
sourceInputDir.mkdirs()
project.copy {
from(project.zipTree(sourceJar.file))
into(sourceInputDir)
}
tempInputDir.resolve(".git").deleteRecursively()
PatchSourceRemapWorker(
mappings,
listOf(*classpathFiles.toTypedArray(), tempApiDir.resolve("src/main/java")).map { it.toPath() },
paramMap,
constructorsData,
sourceInputDir.toPath(),
tempOutputDir.toPath()
).let { remapper ->
val patchApplier = PatchApplier("remapped", "old", tempInputDir)
// Setup patch remapping repo
patchApplier.initRepo() // Create empty initial commit
remapper.remap() // Remap to Spigot mappings
// We need to include any missing classes for the patches later on
importMcDev(patches, tempInputDir.resolve("src/main/java"))
patchApplier.commitInitialSource() // Initial commit of Spigot sources
patchApplier.checkoutRemapped() // Switch to remapped branch without checking out files
remapper.remapBack() // Remap to new mappings
patchApplier.commitInitialSource() // Initial commit of Spigot sources mapped to new mappings
patchApplier.checkoutOld() // Normal checkout back to Spigot mappings branch
// Repo setup is done, we can begin the patch "loop" now
// - not a loop yet cause it doesn't even work for the first patch
remapper.remap() // Remap to to Spigot mappings TODO: verify this step produces correct results
patchApplier.applyPatch(patches.first()) // Apply patch on Spigot mappings
patchApplier.recordCommit() // Keep track of commit author, message, and time
patchApplier.checkoutRemapped() // Switch to remapped branch without checkout out files
remapper.remapBack() // Remap to new mappings
patchApplier.commitChanges() // Commit the changes
patchApplier.checkoutOld() // Normal checkout back to Spigot mappings branch
}
}
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)
}
}
}
}
}
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) }
.map { it.substring(prefix.length, it.length - suffix.length) }
.forEach { result.add(it) }
}
}
return result
}
private fun createWorkDir(name: String, source: File? = null): File {
return layout.cache.resolve("paperweight").resolve(name).apply {
deleteRecursively()
mkdirs()
source?.copyRecursively(this)
}
}
}

View file

@ -0,0 +1,74 @@
/*
* 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.sourceremap
import org.cadixdev.mercury.RewriteContext
import org.eclipse.jdt.core.dom.ASTVisitor
import org.eclipse.jdt.core.dom.IMethodBinding
import org.eclipse.jdt.core.dom.IVariableBinding
import org.eclipse.jdt.core.dom.MethodDeclaration
import org.eclipse.jdt.core.dom.SimpleName
import org.eclipse.jdt.core.dom.VariableDeclaration
abstract class AbstractParameterVisitor(protected val context: RewriteContext) : ASTVisitor() {
override fun visit(node: SimpleName): Boolean {
val binding = node.resolveBinding() as? IVariableBinding ?: return false
if (!binding.isParameter) {
return false
}
val variableDecl = context.compilationUnit.findDeclaringNode(binding.variableDeclaration) as VariableDeclaration
val method = binding.declaringMethod
val methodDecl = context.compilationUnit.findDeclaringNode(method) as? MethodDeclaration ?: return false
if (method.isConstructor) {
handleConstructor(node, methodDecl, method, variableDecl)
} else {
handleMethod(node, methodDecl, method, variableDecl)
}
return false
}
abstract fun handleMethod(
node: SimpleName,
methodDecl: MethodDeclaration,
method: IMethodBinding,
variableDecl: VariableDeclaration
)
abstract fun handleConstructor(
node: SimpleName,
methodDecl: MethodDeclaration,
method: IMethodBinding,
variableDecl: VariableDeclaration
)
fun getParameterIndex(methodDecl: MethodDeclaration, decl: VariableDeclaration): Int {
@Suppress("UNCHECKED_CAST")
val params = methodDecl.parameters() as List<VariableDeclaration>
return params.indexOfFirst { it === decl }
}
}

View file

@ -0,0 +1,95 @@
/*
* 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.sourceremap
import io.papermc.paperweight.PaperweightException
import org.cadixdev.mercury.RewriteContext
import org.cadixdev.mercury.SourceProcessor
import org.cadixdev.mercury.SourceRewriter
import org.cadixdev.mercury.util.BombeBindings
import org.eclipse.jdt.core.dom.IMethodBinding
import org.eclipse.jdt.core.dom.MethodDeclaration
import org.eclipse.jdt.core.dom.SimpleName
import org.eclipse.jdt.core.dom.VariableDeclaration
class PatchParameterRemapper(
private val paramNames: ParamNames,
private val constructorsData: ConstructorsData
) : SourceRewriter {
override fun getFlags(): Int = SourceProcessor.FLAG_RESOLVE_BINDINGS
override fun rewrite(context: RewriteContext) {
context.compilationUnit.accept(PatchParameterVisitor(context, paramNames, constructorsData))
}
}
class PatchParameterVisitor(
context: RewriteContext,
private val paramNames: ParamNames,
private val constructorsData: ConstructorsData
) : AbstractParameterVisitor(context) {
override fun handleMethod(
node: SimpleName,
methodDecl: MethodDeclaration,
method: IMethodBinding,
variableDecl: VariableDeclaration
) {
val paramNames = paramNames[methodDecl.name.identifier] ?: return
val params = methodDecl.parameters()
if (paramNames.size != params.size) {
throw PaperweightException("Invalid parameter length; expected ${paramNames.size}, actual ${params.size} " +
"for method ${methodDecl.name.identifier}")
}
val index = getParameterIndex(methodDecl, variableDecl)
val newName = paramNames[index] ?: return
context.createASTRewrite().set(node, SimpleName.IDENTIFIER_PROPERTY, newName, null)
}
override fun handleConstructor(
node: SimpleName,
methodDecl: MethodDeclaration,
method: IMethodBinding,
variableDecl: VariableDeclaration
) {
val className = method.declaringClass.binaryName.replace('.', '/')
val descriptor = BombeBindings.convertSignature(method).descriptor
val constructorNode = constructorsData.findConstructorNode(className, descriptor) ?: return
val paramNames = paramNames["const_${constructorNode.id}"] ?: return
val params = methodDecl.parameters()
if (paramNames.size != params.size) {
throw PaperweightException("Invalid parameter length; expected ${paramNames.size}, actual ${params.size} " +
"for constructor $className $descriptor")
}
val index = getParameterIndex(methodDecl, variableDecl)
val newName = paramNames[index]
context.createASTRewrite().set(node, SimpleName.IDENTIFIER_PROPERTY, newName, null)
}
}

View file

@ -0,0 +1,114 @@
/*
* 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.sourceremap
import io.papermc.paperweight.tasks.ZippedTask
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.cadixdev.lorenz.io.MappingFormats
import org.cadixdev.mercury.Mercury
import org.cadixdev.mercury.at.AccessTransformerRewriter
import org.cadixdev.mercury.extra.AccessAnalyzerProcessor
import org.cadixdev.mercury.extra.BridgeMethodRewriter
import org.cadixdev.mercury.remapper.MercuryRemapper
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import java.io.File
abstract class RemapSources : ZippedTask() {
@get:InputFile
abstract val vanillaJar: RegularFileProperty
@get:InputFile
abstract val vanillaRemappedSpigotJar: RegularFileProperty // Required for pre-remap pass
@get:InputFile
abstract val mappings: RegularFileProperty
@get:InputDirectory
abstract val spigotApiDeps: DirectoryProperty
@get:InputDirectory
abstract val spigotServerDeps: DirectoryProperty
@get:InputFile
abstract val constructors: RegularFileProperty
@get:InputDirectory
abstract val spigotServerDir: DirectoryProperty
@get:InputDirectory
abstract val spigotApiDir: DirectoryProperty
@get:OutputFile
abstract val generatedAt: RegularFileProperty
@get:OutputFile
abstract val parameterNames: RegularFileProperty
override fun init() {
super.init()
generatedAt.convention(defaultOutput("at"))
parameterNames.convention(defaultOutput("params"))
}
override fun run(rootDir: File) {
val constructorsData = parseConstructors(constructors.file)
val paramNames: ParamNames = newParamNames()
val srcDir = spigotServerDir.file.resolve("src/main/java")
val mappingSet = MappingFormats.TSRG.read(mappings.path)
val processAt = AccessTransformSet.create()
// Remap any references Spigot maps to SRG
Mercury().apply {
classPath.addAll(listOf(
vanillaJar.path,
vanillaRemappedSpigotJar.path,
spigotApiDir.path.resolve("src/main/java"),
*spigotApiDeps.get().asFileTree.files.map { it.toPath() }.toTypedArray(),
*spigotServerDeps.get().asFileTree.files.map { it.toPath() }.toTypedArray()
))
processors += AccessAnalyzerProcessor.create(processAt, mappingSet)
process(srcDir.toPath())
processors.clear()
processors.addAll(listOf(
MercuryRemapper.create(mappingSet),
BridgeMethodRewriter.create(),
AccessTransformerRewriter.create(processAt),
SrgParameterRemapper(mappingSet, constructorsData, paramNames)
))
rewrite(srcDir.toPath(), rootDir.toPath())
}
AccessTransformFormats.FML.write(generatedAt.path, processAt)
writeParamNames(paramNames, parameterNames.file)
}
}

View file

@ -0,0 +1,142 @@
/*
* 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.sourceremap
import org.cadixdev.bombe.type.MethodDescriptor
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.mercury.RewriteContext
import org.cadixdev.mercury.SourceProcessor
import org.cadixdev.mercury.SourceRewriter
import org.cadixdev.mercury.util.BombeBindings
import org.eclipse.jdt.core.dom.IMethodBinding
import org.eclipse.jdt.core.dom.MethodDeclaration
import org.eclipse.jdt.core.dom.Modifier
import org.eclipse.jdt.core.dom.SimpleName
import org.eclipse.jdt.core.dom.VariableDeclaration
class SrgParameterRemapper(
private val mappings: MappingSet,
private val constructorsData: ConstructorsData,
private val parameterNames: ParamNames? = null
) : SourceRewriter {
override fun getFlags(): Int = SourceProcessor.FLAG_RESOLVE_BINDINGS
override fun rewrite(context: RewriteContext) {
context.compilationUnit.accept(SrgParameterVisitor(context, mappings, constructorsData, parameterNames))
}
}
class SrgParameterVisitor(
context: RewriteContext,
private val mappings: MappingSet,
private val constructorsData: ConstructorsData,
private val paramNames: ParamNames?
) : AbstractParameterVisitor(context) {
companion object {
private val MATCHER = Regex("func_(\\d+)_.*")
}
override fun handleMethod(
node: SimpleName,
methodDecl: MethodDeclaration,
method: IMethodBinding,
variableDecl: VariableDeclaration
) {
val methodName = mappings.getClassMapping(method.declaringClass.binaryName)
.flatMap { it.getMethodMapping(BombeBindings.convertSignature(method)) }
.map { it.deobfuscatedName }
.orElse(null) ?: return
val match = MATCHER.matchEntire(methodName) ?: return
val isStatic = method.modifiers and Modifier.STATIC != 0
var index = getParameterIndex(methodDecl, variableDecl)
if (index == -1) {
return
}
recordName(methodName, method, node, index)
if (!isStatic) {
index++
}
val paramName = "p_${match.groupValues[1]}_${index}_"
context.createASTRewrite().set(node, SimpleName.IDENTIFIER_PROPERTY, paramName, null)
}
override fun handleConstructor(
node: SimpleName,
methodDecl: MethodDeclaration,
method: IMethodBinding,
variableDecl: VariableDeclaration
) {
val binaryName = method.declaringClass.binaryName
val classMapping = mappings.getClassMapping(binaryName)
val className = classMapping
.map { it.fullDeobfuscatedName }
.orElse(binaryName)
val descriptor = BombeBindings.convertSignature(method).descriptor
val constructorNode = constructorsData.findConstructorNode(className, descriptor) ?: return
val id = constructorNode.id
var index = getParameterIndex(methodDecl, variableDecl)
if (index == -1) {
return
}
recordName("const_$id", method, node, index)
// Constructors are never static
index++
val paramName = "p_i${id}_${index}_"
context.createASTRewrite().set(node, SimpleName.IDENTIFIER_PROPERTY, paramName, null)
}
private fun recordName(
methodName: String,
method: IMethodBinding,
node: SimpleName,
index: Int
) {
paramNames?.let { map ->
val paramCount = method.parameterTypes.size
map.computeIfAbsent(methodName) { arrayOfNulls(paramCount) }[index] = node.identifier
}
}
}
fun ConstructorsData.findConstructorNode(className: String, desc: MethodDescriptor): ConstructorNode? {
val constructorNodes = constructors[className] ?: return null
val descriptorText = desc.toString()
return constructorNodes.firstOrNull { constructorNode ->
constructorNode.descriptor == descriptorText
}
}

View file

@ -0,0 +1,90 @@
/*
* 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.sourceremap
import java.io.File
data class ConstructorsData(val constructors: Map<String, List<ConstructorNode>>)
data class ConstructorNode(
val id: Int,
val descriptor: String
)
fun parseConstructors(constructors: File): ConstructorsData {
val constructorMap = hashMapOf<String, MutableList<ConstructorNode>>()
constructors.useLines { lines ->
lines.forEach { line ->
val parts = line.split(' ')
constructorMap.compute(parts[1]) { _, v ->
val node = ConstructorNode(parts[0].toInt(), parts[2])
if (v == null) {
return@compute mutableListOf(node)
} else {
v += node
return@compute v
}
}
}
}
for (list in constructorMap.values) {
// Put bigger numbers first
// Old constructor entries are still present, just with smaller numbers. So we don't want to grab an older
// entry
list.reverse()
}
return ConstructorsData(constructorMap)
}
typealias ParamNames = MutableMap<String, Array<String?>>
fun newParamNames(): ParamNames = mutableMapOf()
fun writeParamNames(names: ParamNames, file: File) {
file.bufferedWriter().use { writer ->
for ((desc, params) in names.entries) {
writer.append(desc).append(' ')
for (i in params.indices) {
writer.append(i.toString()).append(' ').append(params[i])
if (i != params.lastIndex) {
writer.append(' ')
}
}
writer.newLine()
}
}
}
fun parseParamNames(file: File): ParamNames {
val paramNames: MutableMap<String, Array<String?>> = mutableMapOf()
file.useLines { lines ->
for (line in lines) {
val parts = line.split(' ')
val params = parts.asSequence().drop(1).chunked(2).associate { it[0].toInt() to it[1] }
paramNames[parts.first()] = Array(params.size) { params.getValue(it) }
}
}
return paramNames
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -21,7 +20,7 @@
* USA
*/
package util
package io.papermc.paperweight.util
data class BuildDataInfo(
val minecraftVersion: String,

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -28,14 +27,6 @@ import org.gradle.api.Task
object Constants {
const val EXTENSION = "paperweight"
const val MCP_MAPPINGS_CONFIG = "mcpConfig"
const val MCP_DATA_CONFIG = "mcpData"
const val SPIGOT_DEP_CONFIG = "spigotDeps"
const val MINECRAFT_DEP_CONFIG = "minecraft"
const val FORGE_FLOWER_CONFIG = "forgeFlower"
const val MCINJECT_CONFIG = "mcinject"
const val FORGE_MAVEN_URL = "https://files.minecraftforge.net/maven"
const val MC_LIBRARY_URL = "https://libraries.minecraft.net/"
const val MC_MANIFEST_URL = "https://launchermeta.mojang.com/mc/game/version_manifest.json"
@ -43,9 +34,19 @@ object Constants {
const val CACHE_PATH = "caches"
private const val PAPER_PATH = "paperweight"
private const val JARS_PATH = "$PAPER_PATH/jars"
const val MINECRAFT_JARS_PATH = "$JARS_PATH/minecraft"
const val MCP_TOOLS_PATH = "$JARS_PATH/tools"
const val MCP_ZIPS_PATH = "$JARS_PATH/mcp"
private const val SPIGOT_JARS_PATH = "$JARS_PATH/spigot"
const val SPIGOT_API_JARS_PATH = "$SPIGOT_JARS_PATH/api"
const val SPIGOT_SERVER_JARS_PATH = "$SPIGOT_JARS_PATH/server"
const val MCP_DATA_DIR = "mcp/data"
const val MCP_MAPPINGS_DIR = "mcp/mappings"
const val SRG_DIR = "$MCP_MAPPINGS_DIR/srgs"
private const val SRG_DIR = "$MCP_MAPPINGS_DIR/srgs"
const val MCP_CONFIG_JSON = "$MCP_DATA_DIR/config.json"
const val PAPER_FIELDS_CSV = "$MCP_MAPPINGS_DIR/paper_fields.csv"
const val PAPER_METHODS_CSV = "$MCP_MAPPINGS_DIR/paper_methods.csv"
@ -69,10 +70,10 @@ object Constants {
const val MC_MANIFEST = "jsons/McManifest.json"
const val VERSION_JSON = "jsons/McVersion.json"
const val MC_LIBRARIES = "jsons/McLibraries.txt"
const val TASK_CACHE = "$PAPER_PATH/taskCache"
private const val TASK_CACHE = "$PAPER_PATH/taskCache"
fun Task.paperTaskOutput() = paperTaskOutput("jar")
fun Task.paperTaskOutput(ext: String) = paperTaskOutput(name, ext)
fun Task.paperTaskOutput(name: String, ext: String) = "$TASK_CACHE/$name.$ext"
fun paperTaskOutput(name: String, ext: String) = "$TASK_CACHE/$name.$ext"
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,23 +23,66 @@
package io.papermc.paperweight.util
import io.papermc.paperweight.PaperweightException
import java.io.File
data class ArtifactDescriptor(
val group: String,
val artifact: String,
val version: String,
val classifier: String?,
val extension: String
class MavenArtifact(
private val group: String,
private val artifact: String,
private val version: String,
private val classifier: String? = null,
private val extension: String? = null
) {
private val classifierText: String
get() = if (classifier != null) "-$classifier" else ""
private val ext: String
get() = extension ?: "jar"
private val path: String
get() = "${group.replace('.', '/')}/$artifact/$version/$file"
val file: String
get() = "$artifact-$version$classifierText.$ext"
fun downloadToFile(targetFile: File, repos: List<String>) {
targetFile.parentFile.mkdirs()
var thrown: Exception? = null
for (repo in repos) {
try {
download(addSlash(repo) + path, targetFile)
return
} catch (e: Exception) {
if (thrown != null) {
thrown.addSuppressed(e)
} else {
thrown = e
}
}
}
thrown?.let { throw PaperweightException("Failed to download artifact: $this. Checked repos: $repos", it) }
}
fun downloadToDir(targetDir: File, repos: List<String>): File {
val out = targetDir.resolve(file)
downloadToFile(targetDir.resolve(file), repos)
return out
}
override fun toString(): String {
val path = group.replace('.', '/')
val classifierText = classifier?.let { "-$it" } ?: ""
val file = "$artifact-$version$classifierText.$extension"
return "$path/$artifact/$version/$file"
return if (classifier == null) {
"$group:$artifact:$version"
} else {
"$group:$artifact:$version:$classifier"
}
}
private fun addSlash(url: String): String {
return if (url.endsWith('/')) url else "$url/"
}
companion object {
fun parse(text: String): ArtifactDescriptor {
fun parse(text: String): MavenArtifact {
val (group, groupIndex) = text.nextSubstring(0, charArrayOf(':'))
val (artifact, artifactIndex) = text.nextSubstring(groupIndex, charArrayOf(':'))
val (version, versionIndex) = text.nextSubstring(artifactIndex, charArrayOf(':', '@'), goToEnd = true)
@ -51,7 +93,7 @@ data class ArtifactDescriptor(
artifact ?: throw PaperweightException("Invalid Maven artifact descriptor (no artifactId found): $text")
version ?: throw PaperweightException("Invalid Maven artifact descriptor (no version found): $text")
return ArtifactDescriptor(group, artifact, version, classifier, extension ?: "jar")
return MavenArtifact(group, artifact, version, classifier, extension)
}
private fun String.nextSubstring(startIndex: Int, stops: CharArray, goToEnd: Boolean = false): Pair<String?, Int> {

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -23,6 +22,14 @@
package io.papermc.paperweight.util
typealias FunctionMap = Map<String, McpJvmCommand>
val FunctionMap.decompile: McpJvmCommand
get() = getValue("decompile")
val FunctionMap.mcinject: McpJvmCommand
get() = getValue("mcinject")
val FunctionMap.rename: McpJvmCommand
get() = getValue("rename")
data class McpConfig(
val spec: Int,
val version: String,

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -21,7 +20,7 @@
* USA
*/
package util
package io.papermc.paperweight.util
data class MinecraftManifest(
internal val latest: Map<String, *>,

View file

@ -0,0 +1,140 @@
/*
* 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.util
import io.papermc.paperweight.PaperweightException
import org.apache.http.HttpHost
import org.apache.http.HttpStatus
import org.apache.http.client.config.CookieSpecs
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.utils.DateUtils
import org.apache.http.impl.client.HttpClientBuilder
import org.gradle.api.provider.Provider
import java.io.File
import java.net.URI
import java.net.URL
import java.util.Date
import java.util.concurrent.TimeUnit
fun download(source: Any, target: Any) {
val url = source.convertToUrl()
val file = target.convertToFile()
download(url, file)
}
private fun download(source: URL, target: File) {
target.parentFile.mkdirs()
val etagFile = target.resolveSibling(target.name + ".etag")
val etag = if (etagFile.exists()) etagFile.readText() else null
val host = HttpHost(source.host, source.port, source.protocol)
val httpClient = HttpClientBuilder.create().run {
setRetryHandler { _, count, _ -> count < 3 }
useSystemProperties()
build()
}
val time = if (target.exists()) target.lastModified() else 0
httpClient.use { client ->
val httpGet = HttpGet(source.file)
// Super high timeout, reduce chances of weird things going wrong
val timeouts = TimeUnit.MINUTES.toMillis(5).toInt()
httpGet.config = RequestConfig.custom()
.setConnectTimeout(timeouts)
.setConnectionRequestTimeout(timeouts)
.setSocketTimeout(timeouts)
.setCookieSpec(CookieSpecs.STANDARD)
.build()
if (time > 0) {
httpGet.setHeader("If-Modified-Since", DateUtils.formatDate(Date(time)))
}
if (etag != null) {
httpGet.setHeader("If-None-Match", etag)
}
client.execute(host, httpGet).use { response ->
val code = response.statusLine.statusCode
if ((code < 200 || code > 299) && code != HttpStatus.SC_NOT_MODIFIED) {
val reason = response.statusLine.reasonPhrase
throw PaperweightException("Download failed, HTTP code: $code; URL: $source; Reason: $reason")
}
val lastModified = handleResponse(response, time, target)
saveEtag(response, lastModified, target, etagFile)
}
}
}
private fun handleResponse(response: CloseableHttpResponse, time: Long, target: File): Long {
val lastModified = with(response.getLastHeader("Last-Modified")) {
if (this == null) {
return@with 0
}
if (value.isNullOrBlank()) {
return@with 0
}
val date = DateUtils.parseDate(value) ?: return@with 0
return@with date.time
}
if (response.statusLine.statusCode == HttpStatus.SC_NOT_MODIFIED) {
if (lastModified != 0L && time >= lastModified) {
return lastModified
}
}
val entity = response.entity ?: return lastModified
entity.content.use { input ->
target.outputStream().buffered().use { output ->
input.copyTo(output)
}
}
return lastModified
}
private fun saveEtag(response: CloseableHttpResponse, lastModified: Long, target: File, etagFile: File) {
if (lastModified > 0) {
target.setLastModified(lastModified)
}
val header = response.getFirstHeader("ETag") ?: return
val etag = header.value
etagFile.writeText(etag)
}
private fun Any.convertToUrl(): URL {
return when (this) {
is URL -> this
is URI -> this.toURL()
is String -> URI.create(this).toURL()
is Provider<*> -> this.get().convertToUrl()
else -> throw PaperweightException("Unknown URL type: ${this.javaClass.name}")
}
}

View file

@ -1,106 +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
* Copyright (C) 2018 Forge Development LLC
*
* 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.util
import io.papermc.paperweight.PaperweightException
import java.io.File
import java.net.HttpURLConnection
import java.net.URL
import java.util.concurrent.TimeUnit
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"
fun getWithEtag(urlText: String, cache: File, etagFile: File) {
if (cache.exists() && cache.lastModified() + TimeUnit.MINUTES.toMillis(1) >= System.currentTimeMillis()) {
return
}
val etag = if (etagFile.exists()) {
etagFile.readText()
} else {
etagFile.parentFile.mkdirs()
""
}
var thrown: Throwable? = null
try {
val url = URL(urlText)
val con = url.openConnection() as HttpURLConnection
con.instanceFollowRedirects = true
con.setRequestProperty("User-Agent", USER_AGENT)
con.ifModifiedSince = cache.lastModified()
if (etag.isNotEmpty()) {
con.setRequestProperty("If-None-Match", etag)
}
try {
con.connect()
when (con.responseCode) {
304 -> {
cache.setLastModified(System.currentTimeMillis())
return
}
200 -> {
val data = con.inputStream.use { stream ->
stream.readBytes()
}
cache.writeBytes(data)
val newEtag = con.getHeaderField("ETag")
if (newEtag.isNullOrEmpty()) {
if (!etagFile.createNewFile()) {
etagFile.setLastModified(System.currentTimeMillis())
}
} else {
etagFile.writeText(newEtag)
}
return
}
else -> throw RuntimeException("Etag download for $urlText failed with code ${con.responseCode}")
}
} finally {
con.disconnect()
}
} catch (e: Exception) {
if (thrown == null) {
thrown = e
} else {
thrown.addSuppressed(e)
}
}
val errorString = "Unable to download from $urlText with etag"
val ex = if (thrown != null) {
PaperweightException(errorString, thrown)
} else {
PaperweightException(errorString)
}
throw ex
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -37,12 +36,6 @@ class Git(private var repo: File) {
}
}
val status
get() = this("status", "-z").getText()
val ref
get() = this("rev-parse", "HEAD").getText().replace('\n', ' ').replace(Regex("\\s+"), "")
operator fun invoke(vararg args: String, disableGpg: Boolean = true): Command {
val cmd = if (disableGpg) {
arrayOf("git", "-c", "commit.gpgsign=false", *args)
@ -57,17 +50,37 @@ class Git(private var repo: File) {
}
}
class Command(internal val process: Process, private val command: String) {
class Command(private val process: Process, private val command: String) {
var outStream: OutputStream? = null
private var outStream: OutputStream = UselessOutputStream
private var errStream: OutputStream = UselessOutputStream
fun run(): Int = try {
outStream?.let { out ->
process.inputStream.copyTo(out)
fun run(): Int {
try {
val input = process.inputStream
val error = process.errorStream
val buffer = ByteArray(1000)
while (process.isAlive) {
// Read both stdout and stderr on the same thread
// This is important for how Gradle outputs the logs
if (input.available() > 0) {
val count = input.read(buffer)
outStream.write(buffer, 0, count)
}
if (error.available() > 0) {
val count = error.read(buffer)
errStream.write(buffer, 0, count)
}
Thread.sleep(1)
}
// Catch any other output we may have missed
outStream.write(input.readBytes())
errStream.write(error.readBytes())
return process.waitFor()
} catch (e: Exception) {
throw PaperweightException("Failed to call git command: $command", e)
}
process.waitFor()
} catch (e: Exception) {
throw PaperweightException("Failed to call git command: $command", e)
}
fun runSilently(silenceOut: Boolean = true, silenceErr: Boolean = false): Int {
@ -76,7 +89,7 @@ class Command(internal val process: Process, private val command: String) {
}
fun runOut(): Int {
setup(System.out, System.out)
setup(System.out, System.err)
return run()
}
@ -93,8 +106,8 @@ class Command(internal val process: Process, private val command: String) {
}
private fun silence(silenceOut: Boolean, silenceErr: Boolean) {
val out = if (silenceOut) UselessOutputStream else System.out
val err = if (silenceErr) UselessOutputStream else System.err
val out = if (silenceOut) null else System.out
val err = if (silenceErr) null else System.err
setup(out, err)
}
@ -104,16 +117,15 @@ class Command(internal val process: Process, private val command: String) {
}
fun setup(out: OutputStream? = null, err: OutputStream? = null): Command {
outStream = out
if (err != null) {
redirect(process.errorStream, err)
}
outStream = out ?: UselessOutputStream
errStream = err ?: UselessOutputStream
return this
}
fun getText(): String {
val out = ByteArrayOutputStream()
setup(out, System.err)
execute()
return String(out.toByteArray(), Charsets.UTF_8)
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,19 +23,12 @@
package io.papermc.paperweight.util
import io.papermc.paperweight.PaperweightException
import org.gradle.api.Task
import org.gradle.internal.jvm.Jvm
import java.io.OutputStream
fun Task.runJar(
jar: Any,
workingDir: Any,
logFile: Any?,
jvmArgs: List<String> = listOf(),
vararg args: String
) {
val jarFile = project.file(jar)
val dir = project.file(workingDir)
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(),
@ -47,20 +39,15 @@ fun Task.runJar(
val output = when {
logFile is OutputStream -> logFile
logFile != null -> {
val log = project.file(logFile)
val log = logFile.convertToFile()
log.outputStream().buffered()
}
else -> null
else -> UselessOutputStream
}
output.use {
output?.let {
redirect(process.inputStream, it)
redirect(process.errorStream, it)
} ?: run {
redirect(process.inputStream, UselessOutputStream)
redirect(process.errorStream, UselessOutputStream)
}
redirect(process.inputStream, it)
redirect(process.errorStream, it)
val e = process.waitFor()
if (e != 0) {

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -29,28 +28,36 @@ import com.github.salomonbrys.kotson.fromJson
import com.google.gson.Gson
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.ext.PaperweightExtension
import io.papermc.paperweight.tasks.BaseTask
import io.papermc.paperweight.util.Constants.paperTaskOutput
import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.io.TextMappingFormat
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskProvider
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.nio.file.Path
import java.util.Optional
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
val gson: Gson = Gson()
inline val Project.ext: PaperweightExtension
inline fun <reified T> Gson.fromJson(file: Any): T =
file.convertToFile().bufferedReader().use { fromJson(it) }
val Project.ext: PaperweightExtension
get() = extensions.getByName(Constants.EXTENSION) as PaperweightExtension
inline val Project.cache: File
get() = file(".gradle").resolve(Constants.CACHE_PATH)
val ProjectLayout.cache: File
get() = projectDirectory.file(".gradle/${Constants.CACHE_PATH}").asFile
fun writeMappings(format: TextMappingFormat, vararg mappings: Pair<MappingSet, File>) {
for ((set, file) in mappings) {
@ -58,8 +65,8 @@ fun writeMappings(format: TextMappingFormat, vararg mappings: Pair<MappingSet, F
}
}
fun redirect(input: InputStream, out: OutputStream) {
Thread {
fun redirect(input: InputStream, out: OutputStream): Thread {
return Thread {
try {
input.copyTo(out)
} catch (e: Exception) {
@ -93,63 +100,81 @@ fun getCsvReader(file: File) = CSVReader(
false
)
fun Task.ensureParentExists(vararg files: Any) {
fun Any.convertToFile(): File {
return when (this) {
is File -> this
is Path -> this.toFile()
is RegularFile -> this.asFile
is Provider<*> -> this.get().convertToFile()
else -> throw PaperweightException("Unknown type representing a file: ${this.javaClass.name}")
}
}
fun ensureParentExists(vararg files: Any) {
for (file in files) {
val parent = project.file(file).parentFile
val parent = file.convertToFile().parentFile
if (!parent.exists() && !parent.mkdirs()) {
throw PaperweightException("Failed to create directory $parent")
}
}
}
fun Task.ensureDeleted(vararg files: Any) {
fun ensureDeleted(vararg files: Any) {
for (file in files) {
val f = project.file(file)
val f = file.convertToFile()
if (f.exists() && !f.deleteRecursively()) {
throw PaperweightException("Failed to delete file $f")
}
}
}
inline fun Project.toProvider(crossinline func: () -> File): Provider<RegularFile> {
return layout.file(provider { func() })
fun BaseTask.defaultOutput(name: String, ext: String): RegularFileProperty {
return objects.fileProperty().convention {
layout.cache.resolve(paperTaskOutput(name, ext))
}
}
fun Task.defaultOutput(name: String, ext: String): RegularFileProperty {
return project.objects.fileProperty().convention(project.toProvider {
project.cache.resolve(paperTaskOutput(name, ext))
})
}
fun Task.defaultOutput(ext: String): RegularFileProperty {
fun BaseTask.defaultOutput(ext: String): RegularFileProperty {
return defaultOutput(name, ext)
}
fun Task.defaultOutput(): RegularFileProperty {
fun BaseTask.defaultOutput(): RegularFileProperty {
return defaultOutput("jar")
}
val <T> Optional<T>.orNull: T?
get() = orElse(null)
val RegularFileProperty.file
val RegularFileProperty.file: File
get() = get().asFile
val RegularFileProperty.fileOrNull
val RegularFileProperty.fileOrNull: File?
get() = orNull?.asFile
val DirectoryProperty.file
val RegularFileProperty.path: Path
get() = file.toPath()
val DirectoryProperty.file: File
get() = get().asFile
val DirectoryProperty.fileOrNull
get() = orNull?.asFile
val DirectoryProperty.path: Path
get() = file.toPath()
inline fun <reified T> Project.contents(contentFile: Any, crossinline convert: (String) -> T): Provider<T> {
return providers.fileContents(layout.projectDirectory.file(contentFile.convertToFile().absolutePath))
.asText
.forUseAtConfigurationTime()
.map { convert(it) }
}
private var parsedConfig: McpConfig? = null
fun mcpConfig(file: Provider<RegularFile>): McpConfig {
if (parsedConfig != null) {
return parsedConfig as McpConfig
}
parsedConfig = file.get().asFile.bufferedReader().use { reader ->
gson.fromJson(reader)
}
return parsedConfig as McpConfig
// We have to create our own 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> {
return TaskDelegateProvider(this, T::class, configure)
}
fun mcpFile(configFile: RegularFileProperty, path: String): File {
return configFile.file.resolveSibling(path)
class TaskDelegateProvider<T : Task>(
private val container: TaskContainer,
private val type: KClass<T>,
private val configure: T.() -> Unit
) {
operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): TaskDelegate<T> {
val provider = container.register(property.name, type.java, configure)
return TaskDelegate(provider)
}
}
class TaskDelegate<T : Task>(private val provider: TaskProvider<T>) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): TaskProvider<T> = provider
}

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle.
*
* Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -24,7 +23,7 @@
package io.papermc.paperweight.util
import io.papermc.paperweight.PaperweightException
import org.gradle.api.Task
import io.papermc.paperweight.tasks.BaseTask
import java.io.File
import java.net.URI
import java.nio.file.FileSystems
@ -35,26 +34,26 @@ import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
import java.util.concurrent.ThreadLocalRandom
fun Task.unzip(zip: Any, target: Any? = null): File {
val input = project.file(zip)
val outputDir = target?.let { project.file(it) }
fun BaseTask.unzip(zip: Any, target: Any? = null): File {
val input = zip.convertToFile()
val outputDir = target?.convertToFile()
?: input.resolveSibling("${input.name}-" + ThreadLocalRandom.current().nextInt())
project.copy {
from(project.zipTree(zip))
fs.copy {
from(archives.zipTree(zip))
into(outputDir)
}
return outputDir
}
fun Task.zip(inputDir: Any, zip: Any) {
val outputZipFile = project.file(zip)
fun zip(inputDir: Any, zip: Any) {
val outputZipFile = zip.convertToFile()
if (outputZipFile.exists() && !outputZipFile.delete()) {
throw PaperweightException("Could not delete $outputZipFile")
}
val dirPath = project.file(inputDir).toPath()
val dirPath = inputDir.convertToFile().toPath()
val outUri = URI.create("jar:${outputZipFile.toURI()}")
FileSystems.newFileSystem(outUri, mapOf("create" to "true")).use { fs ->