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 *.bat text eol=crlf
*.jar binary *.jar binary

143
.gitignore vendored
View file

@ -1,25 +1,14 @@
### Intellij ### # IntelliJ
.idea/ .idea/
out/
# File-based project format *.ipr
*.iws *.iws
*.iml *.iml
# IntelliJ # Eclipse
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 ###
.metadata .metadata
.project
bin/ bin/
tmp/ tmp/
*.tmp *.tmp
@ -30,143 +19,27 @@ local.properties
.settings/ .settings/
.loadpath .loadpath
.recommenders .recommenders
# External tool builders
.externalToolBuilders/ .externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch *.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath .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/ .apt_generated/
# Scala IDE specific (Scala & Java development for Eclipse) # macOS
.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
.DS_Store .DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r # Windows
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 thumbnail cache files # Windows thumbnail cache files
Thumbs.db Thumbs.db
ehthumbs.db ehthumbs.db
ehthumbs_vista.db ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file # Folder config file
[Dd]esktop.ini [Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk *.lnk
### Gradle ### # Gradle
.gradle .gradle
/build/ /build/
# Ignore Gradle GUI config
gradle-app.setting
# Cache of project
.gradletasknamecache .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) # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.ja !gradle-wrapper.ja

View file

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

Binary file not shown.

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

53
gradlew vendored
View file

@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/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 ## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` 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. # 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; 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\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
@ -138,19 +156,19 @@ if $cygwin ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=$((i+1)) i=`expr $i + 1`
done done
case $i in case $i in
(0) set -- ;; 0) set -- ;;
(1) set -- "$args0" ;; 1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;; 2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;; 3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " " echo " "
} }
APP_ARGS=$(save "$@") APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules # 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" 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" "$@" 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 @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% 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. @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 @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 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_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail 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 :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @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 :end
@rem End local scope for the variables with windows NT shell @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. some code and systems originally from ForgeGradle.
Copyright (C) 2020 Kyle Wood Copyright (C) 2020 Kyle Wood
Copyright (C) 2018 Forge Development LLC
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -25,149 +24,264 @@
package io.papermc.paperweight 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.ext.PaperweightExtension
import io.papermc.paperweight.tasks.AddMissingSpigotClassMappings import io.papermc.paperweight.tasks.AddMissingSpigotClassMappings
import io.papermc.paperweight.tasks.ApplyAccessTransform
import io.papermc.paperweight.tasks.ApplyDiffPatches import io.papermc.paperweight.tasks.ApplyDiffPatches
import io.papermc.paperweight.tasks.ApplyGitPatches 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.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.DownloadServerJar
import io.papermc.paperweight.tasks.ExtractMcpData import io.papermc.paperweight.tasks.DownloadSpigotDependencies
import io.papermc.paperweight.tasks.ExtractMcpMappings 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.FilterExcludes
import io.papermc.paperweight.tasks.GatherBuildData
import io.papermc.paperweight.tasks.GenerateSpigotSrgs import io.papermc.paperweight.tasks.GenerateSpigotSrgs
import io.papermc.paperweight.tasks.GenerateSrgs 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.PatchMcpCsv
import io.papermc.paperweight.tasks.RemapSources import io.papermc.paperweight.tasks.RemapAccessTransform
import io.papermc.paperweight.tasks.RemapVanillaJarSrg import io.papermc.paperweight.tasks.RemapSpigotAt
import io.papermc.paperweight.tasks.RemapVanillaJarSpigot
import io.papermc.paperweight.tasks.RunForgeFlower import io.papermc.paperweight.tasks.RunForgeFlower
import io.papermc.paperweight.tasks.RunMcInjector import io.papermc.paperweight.tasks.RunMcInjector
import io.papermc.paperweight.tasks.SetupMcpDependencies import io.papermc.paperweight.tasks.RunSpecialSource
import io.papermc.paperweight.tasks.SetupSpigotDependencies import io.papermc.paperweight.tasks.SetupMcLibraries
import io.papermc.paperweight.tasks.WriteLibrariesFile 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.Constants
import io.papermc.paperweight.util.Git import io.papermc.paperweight.util.Git
import io.papermc.paperweight.tasks.RemapSrgSources import io.papermc.paperweight.util.MinecraftManifest
import io.papermc.paperweight.tasks.RemapVanillaJarSpigot
import io.papermc.paperweight.util.cache import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.contents
import io.papermc.paperweight.util.ext 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.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Zip
import org.gradle.kotlin.dsl.maven import org.gradle.kotlin.dsl.maven
import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.register
import util.BuildDataInfo
import java.io.File import java.io.File
class Paperweight : Plugin<Project> { class Paperweight : Plugin<Project> {
override fun apply(target: 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) target.tasks.register<Delete>("cleanCache") {
setupMcpDeps(target) delete(target.layout.cache)
createTasks(target)
target.tasks.register("cleanCache").configure {
destroyables.register(target.cache)
doLast {
target.delete(target.cache)
}
} }
}
private fun createConfigurations(project: Project) { // Make sure the submodules are initialized
project.repositories.apply { 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://oss.sonatype.org/content/repositories/snapshots/")
maven("https://hub.spigotmc.org/nexus/content/groups/public/") 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) target.createTasks()
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)
} }
private fun setupMcpDeps(project: Project) { private fun Project.createTasks() {
project.dependencies.add(Constants.MCP_DATA_CONFIG, project.provider { val extension = ext
mapOf(
"group" to "de.oceanlabs.mcp",
"name" to "mcp_config",
"version" to "${project.ext.mcpMinecraftVersion.get()}-${project.ext.mcpVersion.get()}",
"ext" to "zip"
)
})
project.dependencies.add(Constants.MCP_MAPPINGS_CONFIG, project.provider { val initialTasks = createInitialTasks()
mapOf( val generalTasks = createGeneralTasks()
"group" to "de.oceanlabs.mcp", val mcpTasks = createMcpTasks(initialTasks, generalTasks)
"name" to "mcp_${project.ext.mcpMappingsChannel.get()}", val spigotTasks = createSpigotTasks(initialTasks, generalTasks, mcpTasks)
"version" to project.ext.mcpMappingsVersion.get(),
"ext" to "zip" 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 // Shared task containers
private fun createTasks(project: Project) { data class InitialTasks(
val cache: File = project.cache val setupMcLibraries: TaskProvider<SetupMcLibraries>,
val extension: PaperweightExtension = project.ext val extractMcp: Provider<ExtractMcp>,
val mcpMappings: Provider<ExtractMappings>,
val downloadMcpTools: TaskProvider<DownloadMcpTools>
)
val initGitSubmodules: TaskProvider<Task> = project.tasks.register("initGitSubmodules") { data class GeneralTasks(
outputs.upToDateWhen { false } val buildDataInfo: Provider<BuildDataInfo>,
doLast { val downloadServerJar: TaskProvider<DownloadServerJar>,
Git(project.projectDir)("submodule", "update", "--init").execute() val filterVanillaJar: TaskProvider<Filter>
} )
}
val gatherBuildData: TaskProvider<GatherBuildData> = project.tasks.register<GatherBuildData>("gatherBuildData") {
dependsOn(initGitSubmodules)
buildDataInfoFile.set(extension.craftBukkit.buildDataInfo)
}
val buildDataInfo: Provider<BuildDataInfo> = gatherBuildData.flatMap { it.buildDataInfo }
val extractMcpData: TaskProvider<ExtractMcpData> = project.tasks.register<ExtractMcpData>("extractMcpData") { data class McpTasks(
config.set(Constants.MCP_DATA_CONFIG) 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)) outputDir.set(cache.resolve(Constants.MCP_DATA_DIR))
} }
val extractMcpMappings by tasks.registering<ExtractMappings> {
val setupMcpDependencies: TaskProvider<SetupMcpDependencies> = project.tasks.register<SetupMcpDependencies>("setupMcpDependencies") { inputFile.set(downloadMcpFiles.flatMap { it.mappingsZip })
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)
outputDir.set(cache.resolve(Constants.MCP_MAPPINGS_DIR)) outputDir.set(cache.resolve(Constants.MCP_MAPPINGS_DIR))
} }
val getRemoteJsons: TaskProvider<GetRemoteJsons> = project.tasks.register<GetRemoteJsons>("getRemoteJsons") { val downloadMcpTools by tasks.registering<DownloadMcpTools> {
config.set(Constants.MINECRAFT_DEP_CONFIG) 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") { return InitialTasks(
fieldsCsv.set(extractMcpMappings.flatMap { it.fieldsCsv }) setupMcLibraries,
methodsCsv.set(extractMcpMappings.flatMap { it.methodsCsv }) extractMcpConfig,
paramsCsv.set(extractMcpMappings.flatMap { it.paramsCsv }) 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) changesFile.set(extension.paper.mcpRewritesFile)
paperFieldCsv.set(cache.resolve(Constants.PAPER_FIELDS_CSV)) paperFieldCsv.set(cache.resolve(Constants.PAPER_FIELDS_CSV))
@ -175,8 +289,9 @@ class Paperweight : Plugin<Project> {
paperParamCsv.set(cache.resolve(Constants.PAPER_PARAMS_CSV)) paperParamCsv.set(cache.resolve(Constants.PAPER_PARAMS_CSV))
} }
val generateSrgs: TaskProvider<GenerateSrgs> = project.tasks.register<GenerateSrgs>("generateSrgs") { val generateSrgs by tasks.registering<GenerateSrgs> {
configFile.set(extractMcpData.flatMap { it.configJson }) inSrg.set(initialTasks.extractMcp.flatMap { it.mappings })
methodsCsv.set(mcpRewrites.flatMap { it.paperMethodCsv }) methodsCsv.set(mcpRewrites.flatMap { it.paperMethodCsv })
fieldsCsv.set(mcpRewrites.flatMap { it.paperFieldCsv }) fieldsCsv.set(mcpRewrites.flatMap { it.paperFieldCsv })
extraNotchSrgMappings.set(extension.paper.extraNotchSrgMappings) extraNotchSrgMappings.set(extension.paper.extraNotchSrgMappings)
@ -189,20 +304,78 @@ class Paperweight : Plugin<Project> {
mcpToSrg.set(cache.resolve(Constants.MCP_TO_SRG)) 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 })) classSrg.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.classMappings }))
memberSrg.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.memberMappings })) memberSrg.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.memberMappings }))
missingClassEntriesSrg.set(extension.paper.missingClassEntriesSrgFile) missingClassEntriesSrg.set(extension.paper.missingClassEntriesSrgFile)
missingMemberEntriesSrg.set(extension.paper.missingMemberEntriesSrgFile) 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 }) notchToSrg.set(generateSrgs.flatMap { it.notchToSrg })
srgToMcp.set(generateSrgs.flatMap { it.srgToMcp }) srgToMcp.set(generateSrgs.flatMap { it.srgToMcp })
classMappings.set(addMissingSpigotClassMappings.flatMap { it.outputClassSrg }) classMappings.set(addMissingSpigotClassMappings.flatMap { it.outputClassSrg })
memberMappings.set(addMissingSpigotClassMappings.flatMap { it.outputMemberSrg }) memberMappings.set(addMissingSpigotClassMappings.flatMap { it.outputMemberSrg })
packageMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.packageMappings })) packageMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.packageMappings }))
extraSpigotSrgMappings.set(extension.paper.extraSpigotSrgMappings) extraSpigotSrgMappings.set(extension.paper.extraSpigotSrgMappings)
loggerFields.set(inspectVanillaJar.flatMap { it.outputFile })
spigotToSrg.set(cache.resolve(Constants.SPIGOT_TO_SRG)) spigotToSrg.set(cache.resolve(Constants.SPIGOT_TO_SRG))
spigotToMcp.set(cache.resolve(Constants.SPIGOT_TO_MCP)) spigotToMcp.set(cache.resolve(Constants.SPIGOT_TO_MCP))
@ -212,25 +385,8 @@ class Paperweight : Plugin<Project> {
notchToSpigot.set(cache.resolve(Constants.NOTCH_TO_SPIGOT)) notchToSpigot.set(cache.resolve(Constants.NOTCH_TO_SPIGOT))
} }
val downloadServerJar: TaskProvider<DownloadServerJar> = project.tasks.register<DownloadServerJar>("downloadServerJar") { val remapVanillaJarSpigot by tasks.registering<RemapVanillaJarSpigot> {
dependsOn(gatherBuildData) inputJar.set(filterVanillaJar.flatMap { it.outputJar })
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 }))
classMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.classMappings })) classMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.classMappings }))
memberMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.memberMappings })) memberMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.memberMappings }))
packageMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.packageMappings })) packageMappings.set(extension.craftBukkit.mappingsDir.file(buildDataInfo.map { it.packageMappings }))
@ -246,18 +402,18 @@ class Paperweight : Plugin<Project> {
finalMapCommand.set(buildDataInfo.map { it.finalMapCommand }) finalMapCommand.set(buildDataInfo.map { it.finalMapCommand })
} }
val removeSpigotExcludes: TaskProvider<FilterExcludes> = project.tasks.register<FilterExcludes>("removeSpigotExcludes") { val removeSpigotExcludes by tasks.registering<FilterExcludes> {
inputZip.set(remapVanillaJar.flatMap { it.outputJar }) inputZip.set(remapVanillaJarSpigot.flatMap { it.outputJar })
excludesFile.set(extension.craftBukkit.excludesFile) 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 }) inputJar.set(removeSpigotExcludes.flatMap { it.outputZip })
fernFlowerJar.set(extension.craftBukkit.fernFlowerJar) fernFlowerJar.set(extension.craftBukkit.fernFlowerJar)
decompileCommand.set(buildDataInfo.map { it.decompileCommand }) 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 }) sourceJar.set(decompileVanillaJarSpigot.flatMap { it.outputJar })
sourceBasePath.set("net/minecraft/server") sourceBasePath.set("net/minecraft/server")
branch.set("patched") branch.set("patched")
@ -266,7 +422,7 @@ class Paperweight : Plugin<Project> {
outputDir.set(extension.craftBukkit.craftBukkitDir) outputDir.set(extension.craftBukkit.craftBukkitDir)
} }
val patchSpigotApi: TaskProvider<ApplyGitPatches> = project.tasks.register<ApplyGitPatches>("patchSpigotApi") { val patchSpigotApi by tasks.registering<ApplyGitPatches> {
branch.set("HEAD") branch.set("HEAD")
upstreamBranch.set("upstream") upstreamBranch.set("upstream")
upstream.set(extension.craftBukkit.bukkitDir) upstream.set(extension.craftBukkit.bukkitDir)
@ -275,7 +431,7 @@ class Paperweight : Plugin<Project> {
outputDir.set(extension.spigot.spigotApiDir) 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 }) branch.set(patchCraftBukkit.flatMap { it.branch })
upstreamBranch.set("upstream") upstreamBranch.set("upstream")
upstream.set(patchCraftBukkit.flatMap { it.outputDir }) upstream.set(patchCraftBukkit.flatMap { it.outputDir })
@ -284,78 +440,98 @@ class Paperweight : Plugin<Project> {
outputDir.set(extension.spigot.spigotServerDir) outputDir.set(extension.spigot.spigotServerDir)
} }
val patchSpigot: TaskProvider<Task> = project.tasks.register("patchSpigot") { val patchSpigot by tasks.registering<Task> {
dependsOn(patchSpigotApi, patchSpigotServer) dependsOn(patchSpigotApi, patchSpigotServer)
} }
val setupSpigotDependencies: TaskProvider<SetupSpigotDependencies> = project.tasks.register<SetupSpigotDependencies>("setupSpigotDependencies") { val downloadSpigotDependencies by tasks.registering<DownloadSpigotDependencies> {
dependsOn(patchSpigot) dependsOn(patchSpigot)
spigotApi.set(patchSpigotApi.flatMap { it.outputDir }) apiPom.set(patchSpigotApi.flatMap { it.outputDir.file("pom.xml") })
spigotServer.set(patchSpigotServer.flatMap { it.outputDir }) serverPom.set(patchSpigotServer.flatMap { it.outputDir.file("pom.xml") })
configurationName.set(Constants.SPIGOT_DEP_CONFIG) 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") { val remapSpigotAt by tasks.registering<RemapSpigotAt> {
// Basing off of the Spigot jar lets us inherit the AT modifications Spigot does before decompile inputJar.set(remapVanillaJarSpigot.flatMap { it.outputJar })
inputJar.set(remapVanillaJar.flatMap { it.outputJar }) mapping.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg }) spigotAt.set(extension.craftBukkit.atFile)
} }
val remapSpigotSources: TaskProvider<RemapSources> = project.tasks.register<RemapSources>("remapSpigotSources") { val remapSpigotSources by tasks.registering<RemapSources> {
dependsOn(setupSpigotDependencies)
spigotServerDir.set(patchSpigotServer.flatMap { it.outputDir }) spigotServerDir.set(patchSpigotServer.flatMap { it.outputDir })
spigotApiDir.set(patchSpigotApi.flatMap { it.outputDir }) spigotApiDir.set(patchSpigotApi.flatMap { it.outputDir })
mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg }) mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
vanillaJar.set(downloadServerJar.flatMap { it.outputJar }) vanillaJar.set(downloadServerJar.flatMap { it.outputJar })
vanillaRemappedSpigotJar.set(removeSpigotExcludes.flatMap { it.outputZip }) vanillaRemappedSpigotJar.set(removeSpigotExcludes.flatMap { it.outputZip })
vanillaRemappedSrgJar.set(remapSpigotJarSrg.flatMap { it.outputJar }) spigotApiDeps.set(downloadSpigotDependencies.flatMap { it.apiOutputDir })
configuration.set(setupSpigotDependencies.flatMap { it.configurationName }) spigotServerDeps.set(downloadSpigotDependencies.flatMap { it.serverOutputDir })
configFile.set(extractMcpData.flatMap { it.configJson }) constructors.set(initialTasks.extractMcp.flatMap { it.constructors })
} }
val fixVanillaJarAccess: TaskProvider<ApplyAccessTransform> = project.tasks.register<ApplyAccessTransform>("fixVanillaJarAccess") { val remapGeneratedAt by tasks.registering<RemapAccessTransform> {
inputJar.set(remapSpigotJarSrg.flatMap { it.outputJar }) inputFile.set(remapSpigotSources.flatMap { it.generatedAt })
atFile.set(remapSpigotSources.flatMap { it.generatedAt }) mappings.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
mapping.set(generateSpigotSrgs.flatMap { it.spigotToSrg })
} }
val remapSrgSourcesSpigot: TaskProvider<RemapSrgSources> = project.tasks.register<RemapSrgSources>("remapSrgSourcesSpigot") { val mergeGeneratedAts by tasks.registering<MergeAccessTransforms> {
inputZip.set(remapSpigotSources.flatMap { it.outputZip }) inputFiles.add(remapGeneratedAt.flatMap { it.outputFile })
methodsCsv.set(mcpRewrites.flatMap { it.methodsCsv }) inputFiles.add(remapSpigotAt.flatMap { it.outputFile })
fieldsCsv.set(mcpRewrites.flatMap { it.fieldsCsv })
paramsCsv.set(mcpRewrites.flatMap { it.paramsCsv })
} }
val injectVanillaJarForge: TaskProvider<RunMcInjector> = project.tasks.register<RunMcInjector>("injectVanillaJarForge") { return SpigotTasks(
dependsOn(setupMcpDependencies) generateSpigotSrgs,
configuration.set(setupMcpDependencies.flatMap { it.mcInjectorConfig }) decompileVanillaJarSpigot,
inputJar.set(remapSpigotJarSrg.flatMap { it.outputJar }) patchSpigotApi,
configFile.set(extractMcpData.flatMap { it.configJson }) 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") { val remapPatches by tasks.registering<RemapPatches> {
dependsOn(getRemoteJsons) inputPatchDir.set(extension.paper.unmappedSpigotServerPatchDir)
config.set(getRemoteJsons.flatMap { it.config }) sourceJar.set(spigotTasks.remapSpigotSources.flatMap { it.outputZip })
} apiPatchDir.set(extension.paper.spigotApiPatchDir)
val decompileVanillaJarForge: TaskProvider<RunForgeFlower> = project.tasks.register<RunForgeFlower>("decompileVanillaJarForge") { mappingsFile.set(spigotTasks.generateSpigotSrgs.flatMap { it.spigotToSrg })
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 })
}
// val applyMcpPatches: TaskProvider<ApplyMcpPatches> = project.tasks.register<ApplyMcpPatches>("applyMcpPatches") { // Pull in as many jars as possible to reduce the possibility of type bindings not resolving
// inputZips.add(ZipTarget.base(decompileVanillaJarForge.flatMap { it.outputJar })) classpathJars.add(generalTasks.downloadServerJar.flatMap { it.outputJar })
// serverPatchDir.set(extractMcpData.flatMap { it.patches }) classpathJars.add(spigotTasks.remapSpigotSources.flatMap { it.vanillaRemappedSpigotJar })
// } classpathJars.add(applyVanillaSrgAt.flatMap { it.outputJar })
//
// val remapSrgSourcesSpigotVanilla: TaskProvider<RemapSrgSources> = project.tasks.register<RemapSrgSources>("remapSrgSourcesSpigotVanilla") { spigotApiDir.set(spigotTasks.patchSpigotApi.flatMap { it.outputDir })
// inputZips.add(ZipTarget.base(applyMcpPatches.flatMap { outputZip })) spigotServerDir.set(spigotTasks.patchSpigotServer.flatMap { it.outputDir })
// methodsCsv.set(mcpRewrites.flatMap { methodsCsv }) spigotDecompJar.set(spigotTasks.decompileVanillaJarSpigot.flatMap { it.outputJar })
// fieldsCsv.set(mcpRewrites.flatMap { fieldsCsv }) constructors.set(initialTasks.extractMcp.flatMap { it.constructors })
// paramsCsv.set(mcpRewrites.flatMap { paramsCsv })
// } 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -23,18 +22,35 @@
package io.papermc.paperweight.ext package io.papermc.paperweight.ext
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
open class CraftBukkitExtension(project: Project) { open class CraftBukkitExtension(objects: ObjectFactory, workDir: DirectoryProperty) {
val bukkitDir: DirectoryProperty = project.dirWithDefault("work/Bukkit")
var craftBukkitDir: DirectoryProperty = project.dirWithDefault("work/CraftBukkit") val bukkitDir: DirectoryProperty = objects.dirFrom(workDir, "Bukkit")
var patchDir: DirectoryProperty = project.dirWithDefault("work/CraftBukkit/nms-patches") val craftBukkitDir: DirectoryProperty = objects.dirFrom(workDir, "CraftBukkit")
var mappingsDir: DirectoryProperty = project.dirWithDefault("work/BuildData/mappings") val patchDir: DirectoryProperty = objects.dirFrom(craftBukkitDir, "nms-patches")
val excludesFile: RegularFileProperty = project.fileWithDefault("work/BuildData/mappings/bukkit-1.16.1.exclude") @Suppress("MemberVisibilityCanBePrivate")
var buildDataInfo: RegularFileProperty = project.fileWithDefault("work/BuildData/info.json") val buildDataDir: DirectoryProperty = objects.dirFrom(workDir, "BuildData")
var fernFlowerJar: RegularFileProperty = project.fileWithDefault("work/BuildData/bin/fernflower.jar") val mappingsDir: DirectoryProperty = objects.dirFrom(buildDataDir, "mappings")
var specialSourceJar: RegularFileProperty = project.fileWithDefault("work/BuildData/bin/SpecialSource.jar") val excludesFile: RegularFileProperty = objects.bukkitFileFrom(mappingsDir, "exclude")
var specialSource2Jar: RegularFileProperty = project.fileWithDefault("work/BuildData/bin/SpecialSource-2.jar") 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -23,25 +22,28 @@
package io.papermc.paperweight.ext 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.file.RegularFileProperty
import org.gradle.api.provider.Property import org.gradle.api.model.ObjectFactory
import org.gradle.kotlin.dsl.property
open class PaperExtension(project: Project) { open class PaperExtension(objects: ObjectFactory, layout: ProjectLayout) {
val spigotApiPatchDir: Property<String> = project.objects.property<String>().convention("Spigot-API-Patches") @Suppress("MemberVisibilityCanBePrivate")
val spigotServerPatchDir: Property<String> = project.objects.property<String>().convention("Spigot-Server-Patches") val baseTargetDir: DirectoryProperty = objects.dirWithDefault(layout, ".")
val paperApiDir: Property<String> = project.objects.property<String>().convention("Paper-API") val spigotApiPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Spigot-API-Patches")
val paperServerDir: Property<String> = project.objects.property<String>().convention("Paper-Server") 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") @Suppress("MemberVisibilityCanBePrivate")
val missingClassEntriesSrgFile: RegularFileProperty = project.fileWithDefault("mcp/missing-spigot-class-mappings.csrg") val mcpDir: DirectoryProperty = objects.dirWithDefault(layout, "mcp")
val missingMemberEntriesSrgFile: RegularFileProperty = project.fileWithDefault("mcp/missing-spigot-member-mappings.csrg") val mcpRewritesFile: RegularFileProperty = objects.fileFrom(mcpDir, "mcp-rewrites.txt")
val extraNotchSrgMappings: RegularFileProperty = project.fileWithDefault("mcp/extra-notch-srg.tsrg") val missingClassEntriesSrgFile: RegularFileProperty = objects.fileFrom(mcpDir, "missing-spigot-class-mappings.csrg")
val extraSpigotSrgMappings: RegularFileProperty = project.fileWithDefault("mcp/extra-spigot-srg.tsrg") val missingMemberEntriesSrgFile: RegularFileProperty = objects.fileFrom(mcpDir, "missing-spigot-member-mappings.csrg")
val preMapSrgFile: RegularFileProperty = project.fileWithDefault("mcp/paper.srg") val extraNotchSrgMappings: RegularFileProperty = objects.fileFrom(mcpDir, "extra-notch-srg.tsrg")
val removeListFile: RegularFileProperty = project.fileWithDefault("mcp/remove-list.txt") val extraSpigotSrgMappings: RegularFileProperty = objects.fileFrom(mcpDir, "extra-spigot-srg.tsrg")
val memberMoveListFile: RegularFileProperty = project.fileWithDefault("mcp/member-moves.txt")
init { init {
spigotApiPatchDir.disallowUnsafeRead() spigotApiPatchDir.disallowUnsafeRead()
@ -50,8 +52,5 @@ open class PaperExtension(project: Project) {
paperServerDir.disallowUnsafeRead() paperServerDir.disallowUnsafeRead()
mcpRewritesFile.disallowUnsafeRead() mcpRewritesFile.disallowUnsafeRead()
preMapSrgFile.disallowUnsafeRead()
removeListFile.disallowUnsafeRead()
memberMoveListFile.disallowUnsafeRead()
} }
} }

View file

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

View file

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

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -23,12 +22,16 @@
package io.papermc.paperweight.ext package io.papermc.paperweight.ext
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
fun Project.dirWithDefault(path: String): DirectoryProperty = fun ObjectFactory.dirWithDefault(layout: ProjectLayout, path: String): DirectoryProperty =
project.objects.directoryProperty().convention(layout.dir(provider { file(path) })) directoryProperty().convention(layout.projectDirectory.dir(path))
fun Project.fileWithDefault(path: String): RegularFileProperty = fun ObjectFactory.dirFrom(base: DirectoryProperty, name: String): DirectoryProperty =
project.objects.fileProperty().convention(layout.file(provider { file(path) })) 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 package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.defaultOutput import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file 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.file.RegularFileProperty
import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import java.io.File import java.io.File
open class AddMissingSpigotClassMappings : DefaultTask() { abstract class AddMissingSpigotClassMappings : BaseTask() {
@InputFile @get:InputFile
val classSrg: RegularFileProperty = project.objects.fileProperty() abstract val classSrg: RegularFileProperty
@InputFile @get:InputFile
val memberSrg: RegularFileProperty = project.objects.fileProperty() abstract val memberSrg: RegularFileProperty
@get:Optional
@get:InputFile
abstract val missingClassEntriesSrg: RegularFileProperty
@get:Optional
@get:InputFile
abstract val missingMemberEntriesSrg: RegularFileProperty
@InputFile @get:OutputFile
val missingClassEntriesSrg: RegularFileProperty = project.objects.fileProperty() abstract val outputClassSrg: RegularFileProperty
@InputFile @get:OutputFile
val missingMemberEntriesSrg: RegularFileProperty = project.objects.fileProperty() abstract val outputMemberSrg: RegularFileProperty
@OutputFile override fun init() {
val outputClassSrg: RegularFileProperty = defaultOutput("class.csrg") outputClassSrg.convention(defaultOutput("class.csrg"))
@OutputFile outputMemberSrg.convention(defaultOutput("member.csrg"))
val outputMemberSrg: RegularFileProperty = defaultOutput("member.csrg") }
@TaskAction @TaskAction
fun run() { fun run() {
addLines(classSrg.file, missingClassEntriesSrg.file, outputClassSrg.file) addLines(classSrg.file, missingClassEntriesSrg.fileOrNull, outputClassSrg.file)
addLines(memberSrg.file, missingMemberEntriesSrg.file, outputMemberSrg.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>() val lines = mutableListOf<String>()
inFile.bufferedReader().use { reader -> inFile.useLines { seq -> seq.forEach { lines.add(it) } }
lines.addAll(reader.readLines()) appendFile?.useLines { seq -> seq.forEach { lines.add(it) } }
}
appendFile.bufferedReader().use { reader ->
lines.addAll(reader.readLines())
}
lines.sort() lines.sort()
outputFile.bufferedWriter().use { writer -> 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,10 +23,11 @@
package io.papermc.paperweight.tasks package io.papermc.paperweight.tasks
import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.util.Command
import io.papermc.paperweight.util.Git import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.UselessOutputStream
import io.papermc.paperweight.util.ensureParentExists import io.papermc.paperweight.util.ensureParentExists
import io.papermc.paperweight.util.file import io.papermc.paperweight.util.file
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property 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.InputFile
import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import java.net.URI import java.net.URI
import java.nio.file.FileSystems import java.nio.file.FileSystems
import java.nio.file.Files import java.nio.file.Files
import java.util.Date import java.util.Date
open class ApplyDiffPatches : DefaultTask() { abstract class ApplyDiffPatches : ControllableOutputTask() {
@InputFile @get:InputFile
val sourceJar: RegularFileProperty = project.objects.fileProperty() abstract val sourceJar: RegularFileProperty
@Input @get:Input
val sourceBasePath: Property<String> = project.objects.property() abstract val sourceBasePath: Property<String>
@InputDirectory @get:InputDirectory
val patchDir: DirectoryProperty = project.objects.directoryProperty() abstract val patchDir: DirectoryProperty
@Input @get:Input
val branch: Property<String> = project.objects.property() abstract val branch: Property<String>
@OutputDirectory @get:OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty() abstract val outputDir: DirectoryProperty
override fun init() {
printOutput.convention(false)
}
@TaskAction @TaskAction
fun run() { fun run() {
val git = Git(outputDir.file) val git = Git(outputDir.file)
git("checkout", "-B", branch.get(), "HEAD").executeSilently(silenceErr = true) 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 basePatchDirFile = outputDir.file.resolve("src/main/java")
val outputDirFile = basePatchDirFile.resolve(sourceBasePath.get()) val outputDirFile = basePatchDirFile.resolve(sourceBasePath.get())
outputDirFile.deleteRecursively() outputDirFile.deleteRecursively()
@ -73,6 +74,7 @@ open class ApplyDiffPatches : DefaultTask() {
} }
// Copy in patch targets // Copy in patch targets
val uri = URI.create("jar:" + sourceJar.file.toURI())
FileSystems.newFileSystem(uri, mapOf<String, Any>()).use { fs -> FileSystems.newFileSystem(uri, mapOf<String, Any>()).use { fs ->
for (file in patchList) { for (file in patchList) {
val javaName = file.name.replaceAfterLast('.', "java") val javaName = file.name.replaceAfterLast('.', "java")
@ -88,19 +90,29 @@ open class ApplyDiffPatches : DefaultTask() {
} }
} }
git("add", "src").executeOut() git("add", "src").setupOut().execute()
git("commit", "-m", "Vanilla $ ${Date()}", "--author=Vanilla <auto@mated.null>").executeOut() git("commit", "-m", "Vanilla $ ${Date()}", "--author=Vanilla <auto@mated.null>").setupOut().execute()
// Apply patches // Apply patches
for (file in patchList) { for (file in patchList) {
val javaName = file.name.replaceAfterLast('.', "java") val javaName = file.name.replaceAfterLast('.', "java")
println("Patching ${javaName.removeSuffix(".java")}") if (printOutput.get()) {
git("apply", "--directory=${basePatchDirFile.relativeTo(outputDir.file).path}", file.absolutePath).executeOut() println("Patching ${javaName.removeSuffix(".java")}")
}
git("apply", "--directory=${basePatchDirFile.relativeTo(outputDir.file).path}", file.absolutePath).setupOut().execute()
} }
git("add", "src").executeOut() git("add", "src").setupOut().execute()
git("commit", "-m", "CraftBukkit $ ${Date()}", "--author=CraftBukkit <auto@mated.null>").executeOut() git("commit", "-m", "CraftBukkit $ ${Date()}", "--author=CraftBukkit <auto@mated.null>").setupOut().execute()
git("checkout", "-f", "HEAD~2").executeSilently() 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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.PaperweightException
import io.papermc.paperweight.util.Git import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.file import io.papermc.paperweight.util.file
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input 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.OutputDirectory
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.gradle.internal.os.OperatingSystem 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 @get:Input
val branch: Property<String> = project.objects.property() abstract val branch: Property<String>
@Input @get:Input
val upstreamBranch: Property<String> = project.objects.property() abstract val upstreamBranch: Property<String>
@InputDirectory @get:InputDirectory
val upstream: DirectoryProperty = project.objects.directoryProperty() abstract val upstream: DirectoryProperty
@InputDirectory @get:InputDirectory
val patchDir: DirectoryProperty = project.objects.directoryProperty() abstract val patchDir: DirectoryProperty
@OutputDirectory @get:OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty() abstract val outputDir: DirectoryProperty
override fun init() {
printOutput.convention(false)
}
@TaskAction @TaskAction
fun run() { fun run() {
Git(upstream.file).let { git -> Git(upstream.file).let { git ->
git("fetch").run() git("fetch").setupOut().run()
git("branch", "-f", upstreamBranch.get(), branch.get()).runSilently() git("branch", "-f", upstreamBranch.get(), branch.get()).runSilently()
} }
if (!outputDir.file.exists() || !outputDir.file.resolve(".git").exists()) { if (!outputDir.file.exists() || !outputDir.file.resolve(".git").exists()) {
outputDir.file.deleteRecursively() 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 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(outputDir.file).let { git ->
git("remote", "rm", "upstream").runSilently(silenceErr = true) git("remote", "rm", "upstream").runSilently(silenceErr = true)
git("remote", "add", "upstream", upstream.file.absolutePath).runSilently(silenceErr = true) git("remote", "add", "upstream", upstream.file.absolutePath).runSilently(silenceErr = true)
if (git("checkout", "master").runSilently(silenceOut = false, silenceErr = true) != 0) { if (git("checkout", "master").setupOut(showError = false).run() != 0) {
git("checkout", "-b", "master").runOut() git("checkout", "-b", "master").setupOut().run()
} }
git("fetch", "upstream").runSilently(silenceErr = true) 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...") applyGitPatches(git, target, outputDir.file, patchDir.file, printOutput.get())
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")
}
} }
} }
} }
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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,39 +23,27 @@
package io.papermc.paperweight.tasks package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Git import io.papermc.paperweight.util.Git
import io.papermc.paperweight.util.mcpConfig import org.gradle.api.file.DirectoryProperty
import io.papermc.paperweight.util.mcpFile
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFile
import java.io.File import java.io.File
open class ApplyMcpPatches : ZippedTask() { abstract class ApplyMcpPatches : ZippedTask() {
@InputFile @get:InputDirectory
val configFile: RegularFileProperty = project.objects.fileProperty() abstract val serverPatchDir: DirectoryProperty
@get:InputFile
init { abstract val configFile: RegularFileProperty
inputs.dir(configFile.map { mcpConfig(configFile) }.map { mcpFile(configFile, it.data.patches.server) })
}
override fun run(rootDir: File) { override fun run(rootDir: File) {
val config = mcpConfig(configFile)
val serverPatchDir = mcpFile(configFile, config.data.patches.server)
val git = Git(rootDir) val git = Git(rootDir)
val extension = ".java.patch" val extension = ".java.patch"
project.fileTree(serverPatchDir).matching { objects.fileTree().from(serverPatchDir).matching {
include("*$extension") include("**/*$extension")
}.forEach { patch -> }.forEach { patch ->
val patchName = patch.name git("apply", "--ignore-whitespace", patch.absolutePath).executeSilently()
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()
}
} }
} }
} }

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

View file

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

View file

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

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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.ensureParentExists
import io.papermc.paperweight.util.file import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.fileOrNull
import io.papermc.paperweight.util.getCsvReader 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 io.papermc.paperweight.util.writeMappings
import org.cadixdev.bombe.type.signature.MethodSignature
import org.cadixdev.lorenz.MappingSet import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.io.MappingFormats import org.cadixdev.lorenz.io.MappingFormats
import org.cadixdev.lorenz.merge.MappingSetMerger 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.DefaultTask
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
open class GenerateSrgs : DefaultTask() { abstract class GenerateSrgs : DefaultTask() {
@InputFile @get:InputFile
val configFile: RegularFileProperty = project.objects.fileProperty() abstract val methodsCsv: RegularFileProperty
@InputFile @get:InputFile
val methodsCsv: RegularFileProperty = project.objects.fileProperty() abstract val fieldsCsv: RegularFileProperty
@InputFile @get:Optional
val fieldsCsv: RegularFileProperty = project.objects.fileProperty() @get:InputFile
@InputFile abstract val extraNotchSrgMappings: RegularFileProperty
val extraNotchSrgMappings: RegularFileProperty = project.objects.fileProperty()
@OutputFile @get:InputFile
val notchToSrg: RegularFileProperty = project.objects.fileProperty() abstract val inSrg: RegularFileProperty
@OutputFile
val notchToMcp: RegularFileProperty = project.objects.fileProperty() @get:OutputFile
@OutputFile abstract val notchToSrg: RegularFileProperty
val mcpToNotch: RegularFileProperty = project.objects.fileProperty() @get:OutputFile
@OutputFile abstract val notchToMcp: RegularFileProperty
val mcpToSrg: RegularFileProperty = project.objects.fileProperty() @get:OutputFile
@OutputFile abstract val mcpToNotch: RegularFileProperty
val srgToNotch: RegularFileProperty = project.objects.fileProperty() @get:OutputFile
@OutputFile abstract val mcpToSrg: RegularFileProperty
val srgToMcp: RegularFileProperty = project.objects.fileProperty() @get:OutputFile
abstract val srgToNotch: RegularFileProperty
@get:OutputFile
abstract val srgToMcp: RegularFileProperty
@TaskAction @TaskAction
fun run() { fun run() {
val config = mcpConfig(configFile)
val inSrg = mcpFile(configFile, config.data.mappings)
val methods = HashMap<String, String>() val methods = HashMap<String, String>()
val fields = HashMap<String, String>() val fields = HashMap<String, String>()
readCsvs(methods, fields) readCsvs(methods, fields)
val inSet = MappingFormats.TSRG.createReader(inSrg.toPath()).use { it.read() } val inSet = MappingFormats.TSRG.createReader(inSrg.file.toPath()).use { it.read() }
MappingFormats.TSRG.createReader(extraNotchSrgMappings.file.toPath()).use { it.read(inSet) } extraNotchSrgMappings.fileOrNull?.toPath()?.let { path ->
MappingFormats.TSRG.createReader(path).use { it.read(inSet) }
}
ensureParentExists(notchToSrg, notchToMcp, mcpToNotch, mcpToSrg, srgToNotch, srgToMcp) ensureParentExists(notchToSrg, notchToMcp, mcpToNotch, mcpToSrg, srgToNotch, srgToMcp)
createMappings(inSet, methods, fields) 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>) { private fun createMappings(inSet: MappingSet, methods: Map<String, String>, fields: Map<String, String>) {
val notchToSrgSet = MappingSet.create() val notchToSrgSet = MappingSet.create()
for (mapping in inSet.topLevelClassMappings) { for (mapping in inSet.topLevelClassMappings) {
val newMapping = notchToSrgSet.createTopLevelClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName) val newMapping = notchToSrgSet.createTopLevelClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
remapMembers(mapping, newMapping) remapMembers(mapping, newMapping)
} }
handleKeywordMappings(notchToSrgSet)
// We have Notch -> SRG // We have Notch -> SRG
val srgToNotchSet = notchToSrgSet.reverse() 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>) { private fun mapClass(inClass: ClassMapping<*, *>, outClass: ClassMapping<*, *>, methods: Map<String, String>, fields: Map<String, String>) {
for (fieldMapping in inClass.fieldMappings) { for (fieldMapping in inClass.fieldMappings) {
val mcpName = fields[fieldMapping.deobfuscatedName] ?: fieldMapping.deobfuscatedName val mcpName = fields[fieldMapping.deobfuscatedName] ?: fieldMapping.deobfuscatedName
@ -155,13 +191,7 @@ open class GenerateSrgs : DefaultTask() {
} }
private fun remapAnonymousClasses(mapping: InnerClassMapping, target: ClassMapping<*, *>) { private fun remapAnonymousClasses(mapping: InnerClassMapping, target: ClassMapping<*, *>) {
val newMapping = if (mapping.obfuscatedName.toIntOrNull() != null) { val newMapping = target.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
// This is an anonymous class, keep the index
target.createInnerClassMapping(mapping.deobfuscatedName, mapping.deobfuscatedName)
} else {
target.createInnerClassMapping(mapping.obfuscatedName, mapping.deobfuscatedName)
}
remapMembers(mapping, newMapping) 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,42 +23,38 @@
package io.papermc.paperweight.tasks package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.defaultOutput 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.file
import org.cadixdev.atlas.Atlas import org.cadixdev.at.AccessTransformSet
import org.cadixdev.bombe.asm.jar.JarEntryRemappingTransformer import org.cadixdev.at.io.AccessTransformFormats
import org.cadixdev.lorenz.asm.LorenzRemapper import org.gradle.api.file.RegularFile
import org.cadixdev.lorenz.io.MappingFormats
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty 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.OutputFile
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
open class RemapVanillaJarSrg : DefaultTask() { abstract class MergeAccessTransforms : BaseTask() {
@InputFile @get:InputFiles
val inputJar: RegularFileProperty = project.objects.fileProperty() abstract val inputFiles: ListProperty<RegularFile>
@InputFile @get:OutputFile
val mappings: RegularFileProperty = project.objects.fileProperty() abstract val outputFile: RegularFileProperty
@OutputFile override fun init() {
val outputJar: RegularFileProperty = defaultOutput() outputFile.convention(defaultOutput("at"))
}
@TaskAction @TaskAction
fun run() { fun run() {
ensureParentExists(outputJar.file) val ats = inputFiles.get()
ensureDeleted(outputJar.file) .map { AccessTransformFormats.FML.read(it.asFile.toPath()) }
val mappings = MappingFormats.TSRG.createReader(mappings.file.toPath()).use { it.read() } val outputAt = AccessTransformSet.create()
Atlas().apply { for (at in ats) {
install { ctx -> outputAt.merge(at)
JarEntryRemappingTransformer(LorenzRemapper(mappings, ctx.inheritanceProvider()))
}
run(inputJar.file.toPath(), outputJar.file.toPath())
} }
AccessTransformFormats.FML.write(outputFile.file.toPath(), outputAt)
} }
} }

View file

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

View file

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

View file

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

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,57 +23,67 @@
package io.papermc.paperweight.tasks package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.Constants.paperTaskOutput import io.papermc.paperweight.util.Constants.paperTaskOutput
import io.papermc.paperweight.util.McpConfig
import io.papermc.paperweight.util.cache import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.decompile
import io.papermc.paperweight.util.defaultOutput import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file 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 io.papermc.paperweight.util.runJar
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty 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.InputFile
import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction 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 @get:InputFile
val configuration: Property<String> = project.objects.property() abstract val configFile: RegularFileProperty
@get:InputFile
abstract val executable: RegularFileProperty
@InputFile @get:InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty() abstract val inputJar: RegularFileProperty
@InputFile @get:InputFile
val libraries: RegularFileProperty = project.objects.fileProperty() abstract val libraries: RegularFileProperty
@InputFile @get:OutputFile
val configFile: RegularFileProperty = project.objects.fileProperty() abstract val outputJar: RegularFileProperty
@OutputFile override fun init() {
val outputJar: RegularFileProperty = defaultOutput() outputJar.convention(defaultOutput())
}
@TaskAction @TaskAction
fun run() { 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 config = gson.fromJson<McpConfig>(configFile)
val jvmArgs = config.functions.getValue("decompile").jvmargs ?: listOf()
val argList = forgeFlowerArgs.map { val argList = config.functions.decompile.args.map {
when (it) { when (it) {
"{libraries}" -> libraries.file.absolutePath "{libraries}" -> libraries.file.absolutePath
"{input}" -> inputJar.file.absolutePath "{input}" -> inputJar.file.absolutePath
"{output}" -> outputJar.file.absolutePath "{output}" -> target.absolutePath
else -> it else -> it
} }
} }
val logFile = project.cache.resolve(paperTaskOutput("log")) val logFile = layout.cache.resolve(paperTaskOutput("log"))
logFile.delete() logFile.delete()
val forgeFlowerJar = project.configurations[configuration.get()].resolve().single() val jvmArgs = config.functions.decompile.jvmargs ?: listOf()
runJar(forgeFlowerJar, project.cache, logFile, jvmArgs = jvmArgs, args = *argList.toTypedArray())
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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -23,60 +22,65 @@
package io.papermc.paperweight.tasks package io.papermc.paperweight.tasks
import io.papermc.paperweight.util.McpConfig
import io.papermc.paperweight.util.cache import io.papermc.paperweight.util.cache
import io.papermc.paperweight.util.defaultOutput import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.mcpConfig import io.papermc.paperweight.util.fromJson
import io.papermc.paperweight.util.mcpFile import io.papermc.paperweight.util.gson
import io.papermc.paperweight.util.mcinject
import io.papermc.paperweight.util.runJar import io.papermc.paperweight.util.runJar
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty 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.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction 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 @get:InputFile
val configuration: Property<String> = project.objects.property() abstract val configFile: RegularFileProperty
@InputFile @get:InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty() abstract val executable: RegularFileProperty
@InputFile
val configFile: RegularFileProperty = project.objects.fileProperty()
@OutputFile @get:InputFile
val outputJar: RegularFileProperty = defaultOutput() abstract val exceptions: RegularFileProperty
@OutputFile @get:InputFile
val logFile: RegularFileProperty = defaultOutput("log") 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 @TaskAction
fun run() { fun run() {
val config = mcpConfig(configFile) val config = gson.fromJson<McpConfig>(configFile)
val exceptions = mcpFile(configFile, config.data.exceptions)
val access = mcpFile(configFile, config.data.access)
val constructors = mcpFile(configFile, config.data.constructors)
val mcInjectorArgs = config.functions.getValue("mcinject").args val argList = config.functions.mcinject.args.map {
val jvmArgs = config.functions.getValue("mcinject").jvmargs ?: listOf()
val argList = mcInjectorArgs.map {
when (it) { when (it) {
"{input}" -> inputJar.file.absolutePath "{input}" -> inputJar.file.absolutePath
"{output}" -> outputJar.file.absolutePath "{output}" -> outputJar.file.absolutePath
"{log}" -> logFile.file.absolutePath "{log}" -> logFile.file.absolutePath
"{exceptions}" -> exceptions.absolutePath "{exceptions}" -> exceptions.file.absolutePath
"{access}" -> access.absolutePath "{access}" -> access.file.absolutePath
"{constructors}" -> constructors.absolutePath "{constructors}" -> constructors.file.absolutePath
else -> it 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -23,22 +22,30 @@
package io.papermc.paperweight.tasks package io.papermc.paperweight.tasks
import com.github.salomonbrys.kotson.fromJson import io.papermc.paperweight.util.file
import io.papermc.paperweight.util.gson
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty 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 org.gradle.api.tasks.OutputFile
import util.BuildDataInfo import org.gradle.api.tasks.TaskAction
open class GatherBuildData : DefaultTask() { abstract class SetupMcLibraries : DefaultTask() {
@OutputFile @get:Input
val buildDataInfoFile: RegularFileProperty = project.objects.fileProperty() abstract val dependencies: ListProperty<String>
val buildDataInfo: Provider<BuildDataInfo> = buildDataInfoFile.map { @get:OutputFile
it.asFile.bufferedReader().use { reader -> abstract val outputFile: RegularFileProperty
gson.fromJson(reader)
@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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -23,32 +22,31 @@
package io.papermc.paperweight.tasks package io.papermc.paperweight.tasks
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.util.defaultOutput import io.papermc.paperweight.util.defaultOutput
import io.papermc.paperweight.util.file 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.file.RegularFileProperty
import org.gradle.api.provider.Property import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction 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 @get:Classpath
val config: Property<String> = project.objects.property() abstract val libraries: DirectoryProperty
@OutputFile @get:OutputFile
val outputFile: RegularFileProperty = defaultOutput("txt") abstract val outputFile: RegularFileProperty
init { override fun init() {
outputs.upToDateWhen { false } outputFile.convention(defaultOutput("txt"))
} }
@TaskAction @TaskAction
fun run() { 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.delete()
outputFile.file.bufferedWriter().use { writer -> outputFile.file.bufferedWriter().use { writer ->

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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.fileOrNull
import io.papermc.paperweight.util.unzip import io.papermc.paperweight.util.unzip
import io.papermc.paperweight.util.zip import io.papermc.paperweight.util.zip
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional import org.gradle.api.tasks.Optional
@ -38,17 +36,21 @@ import org.gradle.api.tasks.TaskAction
import java.io.File import java.io.File
import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.ThreadLocalRandom
abstract class ZippedTask : DefaultTask() { abstract class ZippedTask : BaseTask() {
@InputFile @get:InputFile
@Optional @get:Optional
val inputZip: RegularFileProperty = project.objects.fileProperty() abstract val inputZip: RegularFileProperty
@OutputFile @get:OutputFile
val outputZip: RegularFileProperty = defaultOutput("zip") abstract val outputZip: RegularFileProperty
abstract fun run(rootDir: File) abstract fun run(rootDir: File)
override fun init() {
outputZip.convention(defaultOutput("zip"))
}
@TaskAction @TaskAction
fun exec() { fun exec() {
val outputZipFile = outputZip.file 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.defaultOutput
import io.papermc.paperweight.util.ensureDeleted import io.papermc.paperweight.util.ensureDeleted
import io.papermc.paperweight.util.ensureParentExists 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.JarClassEntry
import org.cadixdev.bombe.jar.JarEntryTransformer import org.cadixdev.bombe.jar.JarEntryTransformer
import org.cadixdev.bombe.type.signature.MethodSignature 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.file.RegularFileProperty
import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassReader
@ -28,19 +48,20 @@ import org.objectweb.asm.FieldVisitor
import org.objectweb.asm.MethodVisitor import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
open class ApplyAccessTransform : DefaultTask() { abstract class ApplyAccessTransform : BaseTask() {
@InputFile @get:InputFile
val inputJar: RegularFileProperty = project.objects.fileProperty() abstract val inputJar: RegularFileProperty
@InputFile @get:InputFile
val atFile: RegularFileProperty = project.objects.fileProperty() abstract val atFile: RegularFileProperty
@InputFile @get:OutputFile
val mapping: RegularFileProperty = project.objects.fileProperty() abstract val outputJar: RegularFileProperty
@OutputFile override fun init() {
val outputJar: RegularFileProperty = defaultOutput() outputJar.convention(defaultOutput())
}
@TaskAction @TaskAction
fun run() { fun run() {
@ -48,12 +69,10 @@ open class ApplyAccessTransform : DefaultTask() {
ensureDeleted(outputJar.file) ensureDeleted(outputJar.file)
val at = AccessTransformFormats.FML.read(atFile.file.toPath()) 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 { Atlas().apply {
install { install {
AtJarEntryTransformer(remappedAt) AtJarEntryTransformer(at)
} }
run(inputJar.file.toPath(), outputJar.file.toPath()) 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -21,7 +20,7 @@
* USA * USA
*/ */
package util package io.papermc.paperweight.util
data class BuildDataInfo( data class BuildDataInfo(
val minecraftVersion: String, val minecraftVersion: String,

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -28,14 +27,6 @@ import org.gradle.api.Task
object Constants { object Constants {
const val EXTENSION = "paperweight" 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 FORGE_MAVEN_URL = "https://files.minecraftforge.net/maven"
const val MC_LIBRARY_URL = "https://libraries.minecraft.net/" const val MC_LIBRARY_URL = "https://libraries.minecraft.net/"
const val MC_MANIFEST_URL = "https://launchermeta.mojang.com/mc/game/version_manifest.json" const val MC_MANIFEST_URL = "https://launchermeta.mojang.com/mc/game/version_manifest.json"
@ -43,9 +34,19 @@ object Constants {
const val CACHE_PATH = "caches" const val CACHE_PATH = "caches"
private const val PAPER_PATH = "paperweight" 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_DATA_DIR = "mcp/data"
const val MCP_MAPPINGS_DIR = "mcp/mappings" 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_FIELDS_CSV = "$MCP_MAPPINGS_DIR/paper_fields.csv"
const val PAPER_METHODS_CSV = "$MCP_MAPPINGS_DIR/paper_methods.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 MC_MANIFEST = "jsons/McManifest.json"
const val VERSION_JSON = "jsons/McVersion.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(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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,23 +23,66 @@
package io.papermc.paperweight.util package io.papermc.paperweight.util
import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.PaperweightException
import java.io.File
data class ArtifactDescriptor( class MavenArtifact(
val group: String, private val group: String,
val artifact: String, private val artifact: String,
val version: String, private val version: String,
val classifier: String?, private val classifier: String? = null,
val extension: String 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 { override fun toString(): String {
val path = group.replace('.', '/') return if (classifier == null) {
val classifierText = classifier?.let { "-$it" } ?: "" "$group:$artifact:$version"
val file = "$artifact-$version$classifierText.$extension" } else {
return "$path/$artifact/$version/$file" "$group:$artifact:$version:$classifier"
}
}
private fun addSlash(url: String): String {
return if (url.endsWith('/')) url else "$url/"
} }
companion object { companion object {
fun parse(text: String): ArtifactDescriptor { fun parse(text: String): MavenArtifact {
val (group, groupIndex) = text.nextSubstring(0, charArrayOf(':')) val (group, groupIndex) = text.nextSubstring(0, charArrayOf(':'))
val (artifact, artifactIndex) = text.nextSubstring(groupIndex, charArrayOf(':')) val (artifact, artifactIndex) = text.nextSubstring(groupIndex, charArrayOf(':'))
val (version, versionIndex) = text.nextSubstring(artifactIndex, charArrayOf(':', '@'), goToEnd = true) 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") artifact ?: throw PaperweightException("Invalid Maven artifact descriptor (no artifactId found): $text")
version ?: throw PaperweightException("Invalid Maven artifact descriptor (no version 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> { 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -23,6 +22,14 @@
package io.papermc.paperweight.util 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( data class McpConfig(
val spec: Int, val spec: Int,
val version: String, val version: String,

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -21,7 +20,7 @@
* USA * USA
*/ */
package util package io.papermc.paperweight.util
data class MinecraftManifest( data class MinecraftManifest(
internal val latest: Map<String, *>, 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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 { operator fun invoke(vararg args: String, disableGpg: Boolean = true): Command {
val cmd = if (disableGpg) { val cmd = if (disableGpg) {
arrayOf("git", "-c", "commit.gpgsign=false", *args) 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 { fun run(): Int {
outStream?.let { out -> try {
process.inputStream.copyTo(out) 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 { 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 { fun runOut(): Int {
setup(System.out, System.out) setup(System.out, System.err)
return run() return run()
} }
@ -93,8 +106,8 @@ class Command(internal val process: Process, private val command: String) {
} }
private fun silence(silenceOut: Boolean, silenceErr: Boolean) { private fun silence(silenceOut: Boolean, silenceErr: Boolean) {
val out = if (silenceOut) UselessOutputStream else System.out val out = if (silenceOut) null else System.out
val err = if (silenceErr) UselessOutputStream else System.err val err = if (silenceErr) null else System.err
setup(out, 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 { fun setup(out: OutputStream? = null, err: OutputStream? = null): Command {
outStream = out outStream = out ?: UselessOutputStream
if (err != null) { errStream = err ?: UselessOutputStream
redirect(process.errorStream, err)
}
return this return this
} }
fun getText(): String { fun getText(): String {
val out = ByteArrayOutputStream() val out = ByteArrayOutputStream()
setup(out, System.err) setup(out, System.err)
execute()
return String(out.toByteArray(), Charsets.UTF_8) return String(out.toByteArray(), Charsets.UTF_8)
} }

View file

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

View file

@ -3,7 +3,6 @@
* some code and systems originally from ForgeGradle. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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 com.google.gson.Gson
import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.ext.PaperweightExtension import io.papermc.paperweight.ext.PaperweightExtension
import io.papermc.paperweight.tasks.BaseTask
import io.papermc.paperweight.util.Constants.paperTaskOutput import io.papermc.paperweight.util.Constants.paperTaskOutput
import org.cadixdev.lorenz.MappingSet import org.cadixdev.lorenz.MappingSet
import org.cadixdev.lorenz.io.TextMappingFormat import org.cadixdev.lorenz.io.TextMappingFormat
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Provider 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.File
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import java.nio.file.Path
import java.util.Optional import java.util.Optional
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
val gson: Gson = Gson() 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 get() = extensions.getByName(Constants.EXTENSION) as PaperweightExtension
inline val Project.cache: File val ProjectLayout.cache: File
get() = file(".gradle").resolve(Constants.CACHE_PATH) get() = projectDirectory.file(".gradle/${Constants.CACHE_PATH}").asFile
fun writeMappings(format: TextMappingFormat, vararg mappings: Pair<MappingSet, File>) { fun writeMappings(format: TextMappingFormat, vararg mappings: Pair<MappingSet, File>) {
for ((set, file) in mappings) { for ((set, file) in mappings) {
@ -58,8 +65,8 @@ fun writeMappings(format: TextMappingFormat, vararg mappings: Pair<MappingSet, F
} }
} }
fun redirect(input: InputStream, out: OutputStream) { fun redirect(input: InputStream, out: OutputStream): Thread {
Thread { return Thread {
try { try {
input.copyTo(out) input.copyTo(out)
} catch (e: Exception) { } catch (e: Exception) {
@ -93,63 +100,81 @@ fun getCsvReader(file: File) = CSVReader(
false 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) { for (file in files) {
val parent = project.file(file).parentFile val parent = file.convertToFile().parentFile
if (!parent.exists() && !parent.mkdirs()) { if (!parent.exists() && !parent.mkdirs()) {
throw PaperweightException("Failed to create directory $parent") throw PaperweightException("Failed to create directory $parent")
} }
} }
} }
fun Task.ensureDeleted(vararg files: Any) { fun ensureDeleted(vararg files: Any) {
for (file in files) { for (file in files) {
val f = project.file(file) val f = file.convertToFile()
if (f.exists() && !f.deleteRecursively()) { if (f.exists() && !f.deleteRecursively()) {
throw PaperweightException("Failed to delete file $f") throw PaperweightException("Failed to delete file $f")
} }
} }
} }
inline fun Project.toProvider(crossinline func: () -> File): Provider<RegularFile> { fun BaseTask.defaultOutput(name: String, ext: String): RegularFileProperty {
return layout.file(provider { func() }) return objects.fileProperty().convention {
layout.cache.resolve(paperTaskOutput(name, ext))
}
} }
fun BaseTask.defaultOutput(ext: String): RegularFileProperty {
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 {
return defaultOutput(name, ext) return defaultOutput(name, ext)
} }
fun Task.defaultOutput(): RegularFileProperty { fun BaseTask.defaultOutput(): RegularFileProperty {
return defaultOutput("jar") return defaultOutput("jar")
} }
val <T> Optional<T>.orNull: T? val <T> Optional<T>.orNull: T?
get() = orElse(null) get() = orElse(null)
val RegularFileProperty.file val RegularFileProperty.file: File
get() = get().asFile get() = get().asFile
val RegularFileProperty.fileOrNull val RegularFileProperty.fileOrNull: File?
get() = orNull?.asFile get() = orNull?.asFile
val DirectoryProperty.file val RegularFileProperty.path: Path
get() = file.toPath()
val DirectoryProperty.file: File
get() = get().asFile get() = get().asFile
val DirectoryProperty.fileOrNull val DirectoryProperty.path: Path
get() = orNull?.asFile 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 // We have to create our own delegate because the ones Gradle provides don't work in plugin dev environments
fun mcpConfig(file: Provider<RegularFile>): McpConfig { inline fun <reified T : Task> TaskContainer.registering(noinline configure: T.() -> Unit): TaskDelegateProvider<T> {
if (parsedConfig != null) { return TaskDelegateProvider(this, T::class, configure)
return parsedConfig as McpConfig
}
parsedConfig = file.get().asFile.bufferedReader().use { reader ->
gson.fromJson(reader)
}
return parsedConfig as McpConfig
} }
fun mcpFile(configFile: RegularFileProperty, path: String): File { class TaskDelegateProvider<T : Task>(
return configFile.file.resolveSibling(path) 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. * some code and systems originally from ForgeGradle.
* *
* Copyright (C) 2020 Kyle Wood * Copyright (C) 2020 Kyle Wood
* Copyright (C) 2018 Forge Development LLC
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,7 +23,7 @@
package io.papermc.paperweight.util package io.papermc.paperweight.util
import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.PaperweightException
import org.gradle.api.Task import io.papermc.paperweight.tasks.BaseTask
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import java.nio.file.FileSystems import java.nio.file.FileSystems
@ -35,26 +34,26 @@ import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes import java.nio.file.attribute.BasicFileAttributes
import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.ThreadLocalRandom
fun Task.unzip(zip: Any, target: Any? = null): File { fun BaseTask.unzip(zip: Any, target: Any? = null): File {
val input = project.file(zip) val input = zip.convertToFile()
val outputDir = target?.let { project.file(it) } val outputDir = target?.convertToFile()
?: input.resolveSibling("${input.name}-" + ThreadLocalRandom.current().nextInt()) ?: input.resolveSibling("${input.name}-" + ThreadLocalRandom.current().nextInt())
project.copy { fs.copy {
from(project.zipTree(zip)) from(archives.zipTree(zip))
into(outputDir) into(outputDir)
} }
return outputDir return outputDir
} }
fun Task.zip(inputDir: Any, zip: Any) { fun zip(inputDir: Any, zip: Any) {
val outputZipFile = project.file(zip) val outputZipFile = zip.convertToFile()
if (outputZipFile.exists() && !outputZipFile.delete()) { if (outputZipFile.exists() && !outputZipFile.delete()) {
throw PaperweightException("Could not delete $outputZipFile") throw PaperweightException("Could not delete $outputZipFile")
} }
val dirPath = project.file(inputDir).toPath() val dirPath = inputDir.convertToFile().toPath()
val outUri = URI.create("jar:${outputZipFile.toURI()}") val outUri = URI.create("jar:${outputZipFile.toURI()}")
FileSystems.newFileSystem(outUri, mapOf("create" to "true")).use { fs -> FileSystems.newFileSystem(outUri, mapOf("create" to "true")).use { fs ->