diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8eca64d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# FabricMC editorconfig v1.0 + +root = true + +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{gradle,java}] +ij_continuation_indent_size = 8 +ij_java_imports_layout = $*,|,java.**,|,javax.**,|,*,|,net.fabricmc.** +ij_java_class_count_to_use_import_on_demand = 999 + +[*.{yml,yaml,json,toml,mcmeta}] +indent_size = 2 + +[*.{yml,yaml,properties}] +indent_style = space + +[*.bat] +end_of_line = crlf diff --git a/.gitignore b/.gitignore index e3ff6b0..2466c66 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,36 @@ -local/ +# FabricMC gitignore v1.0 + +# Gradle .gradle/ -out/ build/ +out/ +classes/ + +# IntelliJ Idea .idea/ +*.iml +*.ipr +*.iws -# eclipse +# Eclipse +.eclipse/ +*.launch + +# VS Code +.vscode/ .settings/ bin/ .classpath .project + +# Fleet +.fleet/ + +# MacOS +*.DS_Store + +# Java +hs_err_*.log +replay_*.log +*.hprof +*.jfr diff --git a/HEADER b/HEADER index d5f99fa..5a30d7f 100644 --- a/HEADER +++ b/HEADER @@ -1,13 +1,16 @@ -Copyright (c) 2016, 2017, 2018, 2019 FabricMC +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * 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 + * + * http://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. + */ -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 - - http://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. diff --git a/README.md b/README.md index 9aed8b9..c76ff6a 100644 --- a/README.md +++ b/README.md @@ -1 +1,8 @@ # Stitch +Stitch is a set of tools for working with and updating mappings in the `.tiny` format. + +Over the last few years, large parts of its functionality have been made redundant by other tools though, and nowadays, it's mostly only used for [intermediary generation and updating](https://fabricmc.net/wiki/tutorial:updating_yarn). + +Preferable alternatives: +- [Mapping IO](https://github.com/FabricMC/mapping-io) for reading/writing/converting mappings +- [Name Proposal](https://github.com/FabricMC/name-proposal) for proposing names in Enigma diff --git a/build.gradle b/build.gradle index 6beae2b..e9f35e3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,17 +1,20 @@ plugins { - id "java" - id "java-library" - id "maven-publish" - id "net.minecrell.licenser" version "0.4.1" + id 'java-library' + id 'maven-publish' + id 'com.diffplug.spotless' + id 'com.github.johnrengelman.shadow' + id 'checkstyle' } -sourceCompatibility = 1.8 +checkstyle { + configFile = file('checkstyle.xml') +} -def ENV = System.getenv() -version = "0.6.2" + (ENV.GITHUB_ACTIONS ? "" : "+local") +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 -group = 'net.fabricmc' -archivesBaseName = project.name.toLowerCase() +def ENV = System.getenv() +version += (ENV.GITHUB_ACTIONS ? '' : '+local') repositories { mavenCentral() @@ -23,53 +26,39 @@ repositories { configurations { ship - enigma implementation.extendsFrom ship - compileOnly.extendsFrom enigma - testImplementation.extendsFrom enigma } dependencies { - ship 'org.ow2.asm:asm:9.1' - ship 'org.ow2.asm:asm-commons:9.1' - ship 'org.ow2.asm:asm-tree:9.1' - ship 'org.ow2.asm:asm-util:9.1' - ship 'net.fabricmc:tiny-mappings-parser:0.3.0+build.17' - implementation 'com.google.guava:guava:28.0-jre' - compileOnly 'org.jetbrains:annotations:20.1.0' - - enigma 'cuchaz:enigma:0.23.2' - - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.1' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.1' + ship "org.ow2.asm:asm:${asm_version}" + ship "org.ow2.asm:asm-commons:${asm_version}" + ship "org.ow2.asm:asm-tree:${asm_version}" + ship "org.ow2.asm:asm-util:${asm_version}" + ship "net.fabricmc:tiny-mappings-parser:${tiny_mappings_parser_version}" + ship "net.fabricmc:mapping-io:${mappingio_version}" + compileOnly "org.jetbrains:annotations:${jetbrains_annotations_version}" + + testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" } -license { - header project.file("HEADER") - include "**/*.java" +spotless { + java { + licenseHeaderFile(rootProject.file('HEADER')) + } } jar { manifest { attributes 'Implementation-Title': 'Stitch', 'Implementation-Version': archiveVersion, - 'Main-Class': "net.fabricmc.stitch.Main" + 'Main-Class': 'net.fabricmc.stitch.Main' } } -task allJar(type: Jar) { - from { - configurations.ship.collect { - it.isDirectory() ? it : zipTree(it) - } - } - manifest { - attributes 'Implementation-Title': 'Stitch', - 'Implementation-Version': archiveVersion, - 'Main-Class': "net.fabricmc.stitch.Main" - } +shadowJar { + configurations = [project.configurations.ship] archiveClassifier = 'all' - with jar } java { @@ -77,7 +66,7 @@ java { } tasks.withType(JavaCompile).configureEach { - it.options.encoding = "UTF-8" + it.options.encoding = 'UTF-8' if (JavaVersion.current().isJava9Compatible()) { it.options.release = 8 @@ -88,7 +77,6 @@ publishing { publications { mavenJava(MavenPublication) { from components.java - artifact(allJar) } } @@ -96,7 +84,7 @@ publishing { repositories { if (ENV.MAVEN_URL) { repositories.maven { - name "fabric" + name 'fabric' url ENV.MAVEN_URL credentials { username ENV.MAVEN_USERNAME @@ -114,7 +102,7 @@ test { // A task to ensure that the version being released has not already been released. task checkVersion { doFirst { - def xml = new URL("https://maven.fabricmc.net/net/fabricmc/stitch/maven-metadata.xml").text + def xml = new URL('https://maven.fabricmc.net/net/fabricmc/stitch/maven-metadata.xml').text def metadata = new XmlSlurper().parseText(xml) def versions = metadata.versioning.versions.version*.text(); if (versions.contains(version)) { @@ -123,4 +111,4 @@ task checkVersion { } } -publish.mustRunAfter checkVersion \ No newline at end of file +publish.mustRunAfter checkVersion diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000..1d5aceb --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties index b103c9c..95c70c9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,23 @@ -name = stitch +# Gradle Properties +org.gradle.jvmargs = -Xmx2G +org.gradle.parallel = true +org.gradle.workers.max = 3 + +# Gradle Plugins +spotless_version = 6.13.0 +shadow_version = 7.1.2 + +# Project Properties +version = 0.6.2 +group = net.fabricmc +archivesBaseName = stitch description = Fabric auxillary Tiny tools -url = https://github.com/FabricMC/stitch \ No newline at end of file +url = https://github.com/FabricMC/stitch + +# Project Dependencies +asm_version = 9.5 +tiny_mappings_parser_version = 0.3.0+build.17 +mappingio_version = 0.4.0 +guava_version = 31.1 +jetbrains_annotations_version = 24.0.1 +junit_jupiter_version = 5.9.3 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c05..943f0cb 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d913..b8e0595 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +distributionBase = GRADLE_USER_HOME +distributionPath = wrapper/dists +distributionUrl = https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +networkTimeout = 10000 +zipStoreBase = GRADLE_USER_HOME +zipStorePath = wrapper/dists diff --git a/gradlew b/gradlew index fbd7c51..65dcd68 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# 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 -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 5093609..93e3f59 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +65,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,17 +72,19 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle index 6659293..8c6333a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,12 @@ -rootProject.name = 'stitch' +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral(); + } + plugins { + id 'com.diffplug.spotless' version "${spotless_version}" + id 'com.github.johnrengelman.shadow' version "${shadow_version}" + } +} +rootProject.name = 'stitch' diff --git a/src/main/java/net/fabricmc/stitch/Command.java b/src/main/java/net/fabricmc/stitch/Command.java index 9fbb549..21b2021 100644 --- a/src/main/java/net/fabricmc/stitch/Command.java +++ b/src/main/java/net/fabricmc/stitch/Command.java @@ -17,13 +17,13 @@ package net.fabricmc.stitch; public abstract class Command { - public final String name; + public final String name; - public Command(String name) { - this.name = name; - } + public Command(String name) { + this.name = name; + } - public abstract String getHelpString(); - public abstract boolean isArgumentCountValid(int count); - public abstract void run(String[] args) throws Exception; + public abstract String getHelpString(); + public abstract boolean isArgumentCountValid(int count); + public abstract void run(String[] args) throws Exception; } diff --git a/src/main/java/net/fabricmc/stitch/Main.java b/src/main/java/net/fabricmc/stitch/Main.java index 04eb5a4..c31ce03 100644 --- a/src/main/java/net/fabricmc/stitch/Main.java +++ b/src/main/java/net/fabricmc/stitch/Main.java @@ -16,63 +16,66 @@ package net.fabricmc.stitch; -import net.fabricmc.stitch.commands.*; -import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2; -import net.fabricmc.stitch.commands.tinyv2.CommandProposeV2FieldNames; -import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2; - import java.util.Locale; import java.util.Map; import java.util.TreeMap; +import net.fabricmc.stitch.commands.CommandAsmTrace; +import net.fabricmc.stitch.commands.CommandGenerateIntermediary; +import net.fabricmc.stitch.commands.CommandGeneratePrefixRemapper; +import net.fabricmc.stitch.commands.CommandMatcherToTiny; +import net.fabricmc.stitch.commands.CommandMergeJar; +import net.fabricmc.stitch.commands.CommandRewriteIntermediary; +import net.fabricmc.stitch.commands.CommandUpdateIntermediary; +import net.fabricmc.stitch.commands.CommandValidateRecords; + public class Main { - private static final Map COMMAND_MAP = new TreeMap<>(); + private static final Map COMMAND_MAP = new TreeMap<>(); + + public static void addCommand(Command command) { + COMMAND_MAP.put(command.name.toLowerCase(Locale.ROOT), command); + } + + static { + addCommand(new CommandAsmTrace()); + addCommand(new CommandGenerateIntermediary()); + addCommand(new CommandGeneratePrefixRemapper()); + addCommand(new CommandMatcherToTiny()); + addCommand(new CommandMergeJar()); + addCommand(new CommandRewriteIntermediary()); + addCommand(new CommandUpdateIntermediary()); + addCommand(new CommandValidateRecords()); + } + + public static void main(String[] args) { + if (args.length == 0 + || !COMMAND_MAP.containsKey(args[0].toLowerCase(Locale.ROOT)) + || !COMMAND_MAP.get(args[0].toLowerCase(Locale.ROOT)).isArgumentCountValid(args.length - 1)) { + if (args.length > 0) { + System.out.println("Invalid command: " + args[0]); + } + + System.out.println("Available commands:"); + + for (Command command : COMMAND_MAP.values()) { + System.out.println("\t" + command.name + " " + command.getHelpString()); + } - public static void addCommand(Command command) { - COMMAND_MAP.put(command.name.toLowerCase(Locale.ROOT), command); - } + System.out.println(); + return; + } - static { - addCommand(new CommandAsmTrace()); - addCommand(new CommandGenerateIntermediary()); - addCommand(new CommandGeneratePrefixRemapper()); - addCommand(new CommandMatcherToTiny()); - addCommand(new CommandMergeJar()); - addCommand(new CommandMergeTiny()); - addCommand(new CommandProposeFieldNames()); - addCommand(new CommandReorderTiny()); - addCommand(new CommandRewriteIntermediary()); - addCommand(new CommandUpdateIntermediary()); - addCommand(new CommandReorderTinyV2()); - addCommand(new CommandMergeTinyV2()); - addCommand(new CommandProposeV2FieldNames()); - addCommand(new CommandValidateRecords()); - } + try { + String[] argsCommand = new String[args.length - 1]; - public static void main(String[] args) { - if (args.length == 0 - || !COMMAND_MAP.containsKey(args[0].toLowerCase(Locale.ROOT)) - || !COMMAND_MAP.get(args[0].toLowerCase(Locale.ROOT)).isArgumentCountValid(args.length - 1)) { - if (args.length > 0) { - System.out.println("Invalid command: " + args[0]); - } - System.out.println("Available commands:"); - for (Command command : COMMAND_MAP.values()) { - System.out.println("\t" + command.name + " " + command.getHelpString()); - } - System.out.println(); - return; - } + if (args.length > 1) { + System.arraycopy(args, 1, argsCommand, 0, argsCommand.length); + } - try { - String[] argsCommand = new String[args.length - 1]; - if (args.length > 1) { - System.arraycopy(args, 1, argsCommand, 0, argsCommand.length); - } - COMMAND_MAP.get(args[0].toLowerCase(Locale.ROOT)).run(argsCommand); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } + COMMAND_MAP.get(args[0].toLowerCase(Locale.ROOT)).run(argsCommand); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandAsmTrace.java b/src/main/java/net/fabricmc/stitch/commands/CommandAsmTrace.java index ab82848..0ea1160 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandAsmTrace.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandAsmTrace.java @@ -16,34 +16,34 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; +import java.io.FileInputStream; +import java.io.PrintWriter; + import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceClassVisitor; -import java.io.FileInputStream; -import java.io.PrintWriter; +import net.fabricmc.stitch.Command; public class CommandAsmTrace extends Command { - public CommandAsmTrace() { - super("asmTrace"); - } - - @Override - public String getHelpString() { - return ""; - } - - @Override - public boolean isArgumentCountValid(int count) { - return count == 1; - } - - @Override - public void run(String[] args) throws Exception { - ClassReader cr = new ClassReader(new FileInputStream(args[0])); - ClassVisitor tcv = new TraceClassVisitor(new PrintWriter(System.out)); - cr.accept(tcv, 0); - } + public CommandAsmTrace() { + super("asmTrace"); + } + + @Override + public String getHelpString() { + return ""; + } + + @Override + public boolean isArgumentCountValid(int count) { + return count == 1; + } + + @Override + public void run(String[] args) throws Exception { + ClassReader cr = new ClassReader(new FileInputStream(args[0])); + ClassVisitor tcv = new TraceClassVisitor(new PrintWriter(System.out)); + cr.accept(tcv, 0); + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandGenerateIntermediary.java b/src/main/java/net/fabricmc/stitch/commands/CommandGenerateIntermediary.java index e1e6dd4..c6f8c97 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandGenerateIntermediary.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandGenerateIntermediary.java @@ -16,62 +16,66 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.representation.*; - -import java.io.*; +import java.io.File; +import java.io.IOException; import java.util.Locale; +import net.fabricmc.stitch.Command; +import net.fabricmc.stitch.representation.JarReader; +import net.fabricmc.stitch.representation.JarRootEntry; + public class CommandGenerateIntermediary extends Command { - public CommandGenerateIntermediary() { - super("generateIntermediary"); - } + public CommandGenerateIntermediary() { + super("generateIntermediary"); + } + + @Override + public String getHelpString() { + return " [-t|--target-namespace ] [-p|--obfuscation-pattern ]..."; + } - @Override - public String getHelpString() { - return " [-t|--target-namespace ] [-p|--obfuscation-pattern ]..."; - } + @Override + public boolean isArgumentCountValid(int count) { + return count >= 2; + } - @Override - public boolean isArgumentCountValid(int count) { - return count >= 2; - } + @Override + public void run(String[] args) throws Exception { + File file = new File(args[0]); + JarRootEntry jarEntry = new JarRootEntry(file); - @Override - public void run(String[] args) throws Exception { - File file = new File(args[0]); - JarRootEntry jarEntry = new JarRootEntry(file); - try { - JarReader reader = new JarReader(jarEntry); - reader.apply(); - } catch (IOException e) { - e.printStackTrace(); - } + try { + JarReader reader = new JarReader(jarEntry); + reader.apply(); + } catch (IOException e) { + e.printStackTrace(); + } - GenState state = new GenState(); - boolean clearedPatterns = false; + GenState state = new GenState(); + boolean clearedPatterns = false; - for (int i = 2; i < args.length; i++) { - switch (args[i].toLowerCase(Locale.ROOT)) { - case "-t": - case "--target-namespace": - state.setTargetNamespace(args[i + 1]); - i++; - break; - case "-p": - case "--obfuscation-pattern": - if (!clearedPatterns) - state.clearObfuscatedPatterns(); - clearedPatterns = true; + for (int i = 2; i < args.length; i++) { + switch (args[i].toLowerCase(Locale.ROOT)) { + case "-t": + case "--target-namespace": + state.setTargetPackage(args[i + 1]); + i++; + break; + case "-p": + case "--obfuscation-pattern": + if (!clearedPatterns) { + state.clearObfuscatedPatterns(); + } - state.addObfuscatedPattern(args[i + 1]); - i++; - break; - } - } + clearedPatterns = true; + state.addObfuscatedPattern(args[i + 1]); + i++; + break; + } + } - System.err.println("Generating new mappings..."); - state.generate(new File(args[1]), jarEntry, null); - System.err.println("Done!"); - } + System.err.println("Generating new mappings..."); + state.generate(new File(args[1]), jarEntry, null); + System.err.println("Done!"); + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandGeneratePrefixRemapper.java b/src/main/java/net/fabricmc/stitch/commands/CommandGeneratePrefixRemapper.java index 60bf59f..91bc449 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandGeneratePrefixRemapper.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandGeneratePrefixRemapper.java @@ -16,12 +16,16 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; - -import java.io.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; +import net.fabricmc.stitch.Command; + public class CommandGeneratePrefixRemapper extends Command { public CommandGeneratePrefixRemapper() { super("genPrefixedTiny"); @@ -40,10 +44,10 @@ public boolean isArgumentCountValid(int count) { @Override public void run(String[] args) throws Exception { try (FileInputStream fis = new FileInputStream(new File(args[0])); - FileOutputStream fos = new FileOutputStream(new File(args[2])); - OutputStreamWriter osw = new OutputStreamWriter(fos); - BufferedWriter writer = new BufferedWriter(osw)) { - writer.write("v1\t" + (args.length >= 5 ? args[3] : "input") + "\t" + (args.length >= 5 ? args[4] : "output") + "\n"); + FileOutputStream fos = new FileOutputStream(new File(args[2])); + OutputStreamWriter osw = new OutputStreamWriter(fos); + BufferedWriter writer = new BufferedWriter(osw)) { + writer.write("v1\t" + (args.length >= 5 ? args[3] : "input") + "\t" + (args.length >= 5 ? args[4] : "output") + "\n"); JarInputStream jis = new JarInputStream(fis); JarEntry entry; diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandMatcherToTiny.java b/src/main/java/net/fabricmc/stitch/commands/CommandMatcherToTiny.java index 43069e0..a514a46 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandMatcherToTiny.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandMatcherToTiny.java @@ -16,13 +16,19 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.util.MatcherUtil; - -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.util.HashMap; import java.util.Map; +import net.fabricmc.stitch.Command; +import net.fabricmc.stitch.util.MatcherUtil; + public class CommandMatcherToTiny extends Command { public CommandMatcherToTiny() { super("matcherToTiny"); @@ -45,26 +51,19 @@ public void run(String[] args) throws Exception { Map methodNames = new HashMap<>(); System.out.println("Loading..."); - try ( - FileInputStream fis = new FileInputStream(new File(args[0])); + try (FileInputStream fis = new FileInputStream(new File(args[0])); InputStreamReader isr = new InputStreamReader(fis); - BufferedReader reader = new BufferedReader(isr) - ) { - + BufferedReader reader = new BufferedReader(isr)) { MatcherUtil.read(reader, false, classNames::put, - (src, dst) -> fieldNames.put(src.getOwner() + "\t" + src.getDesc() + "\t" + src.getName(), dst.getName()), - (src, dst) -> methodNames.put(src.getOwner() + "\t" + src.getDesc() + "\t" + src.getName(), dst.getName()) - ); + (src, dst) -> fieldNames.put(src.getOwner() + "\t" + src.getDescriptor() + "\t" + src.getName(), dst.getName()), + (src, dst) -> methodNames.put(src.getOwner() + "\t" + src.getDescriptor() + "\t" + src.getName(), dst.getName())); } System.out.println("Saving..."); - try ( - FileOutputStream fos = new FileOutputStream(new File(args[1])); + try (FileOutputStream fos = new FileOutputStream(new File(args[1])); OutputStreamWriter osw = new OutputStreamWriter(fos); - BufferedWriter writer = new BufferedWriter(osw) - ) { - + BufferedWriter writer = new BufferedWriter(osw)) { writer.write("v1\t" + args[2] + "\t" + args[3] + "\n"); for (String s : classNames.keySet()) { diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandMergeJar.java b/src/main/java/net/fabricmc/stitch/commands/CommandMergeJar.java index 4ea1cd6..9768dcf 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandMergeJar.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandMergeJar.java @@ -16,75 +16,72 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.merge.JarMerger; - import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.util.Locale; -public class CommandMergeJar extends Command { - public CommandMergeJar() { - super("mergeJar"); - } +import net.fabricmc.stitch.Command; +import net.fabricmc.stitch.merge.JarMerger; - @Override - public String getHelpString() { - return " [--removeSnowman] [--syntheticparams]"; - } +public class CommandMergeJar extends Command { + public CommandMergeJar() { + super("mergeJar"); + } - @Override - public boolean isArgumentCountValid(int count) { - return count >= 3; - } + @Override + public String getHelpString() { + return " [--removeSnowman] [--syntheticparams]"; + } - @Override - public void run(String[] args) throws Exception { - File in1f = new File(args[0]); - File in2f = new File(args[1]); - File outf = new File(args[2]); - boolean removeSnowman = false, syntheticParams = false; + @Override + public boolean isArgumentCountValid(int count) { + return count >= 3; + } - for (int i = 3; i < args.length; i++) { - if (args[i].startsWith("--")) { - switch (args[i].substring(2).toLowerCase(Locale.ROOT)) { - case "removesnowman": - removeSnowman = true; - break; - case "syntheticparams": - syntheticParams = true; - break; - } - } - } + @Override + public void run(String[] args) throws Exception { + File in1f = new File(args[0]); + File in2f = new File(args[1]); + File outf = new File(args[2]); + boolean removeSnowman = false, syntheticParams = false; - if (!in1f.exists() || !in1f.isFile()) { - throw new FileNotFoundException("Client JAR could not be found!"); - } + for (int i = 3; i < args.length; i++) { + if (args[i].startsWith("--")) { + switch (args[i].substring(2).toLowerCase(Locale.ROOT)) { + case "removesnowman": + removeSnowman = true; + break; + case "syntheticparams": + syntheticParams = true; + break; + } + } + } - if (!in2f.exists() || !in2f.isFile()) { - throw new FileNotFoundException("Server JAR could not be found!"); - } + if (!in1f.exists() || !in1f.isFile()) { + throw new FileNotFoundException("Client JAR could not be found!"); + } - try (JarMerger merger = new JarMerger(in1f, in2f, outf)) { - if (removeSnowman) { - merger.enableSnowmanRemoval(); - } + if (!in2f.exists() || !in2f.isFile()) { + throw new FileNotFoundException("Server JAR could not be found!"); + } - if (syntheticParams) { - merger.enableSyntheticParamsOffset(); - } + try (JarMerger merger = new JarMerger(in1f, in2f, outf)) { + if (removeSnowman) { + merger.enableSnowmanRemoval(); + } - System.out.println("Merging..."); + if (syntheticParams) { + merger.enableSyntheticParamsOffset(); + } - merger.merge(); + System.out.println("Merging..."); + merger.merge(); - System.out.println("Merge completed!"); - } catch (IOException e) { - e.printStackTrace(); - } - } + System.out.println("Merge completed!"); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandMergeTiny.java b/src/main/java/net/fabricmc/stitch/commands/CommandMergeTiny.java deleted file mode 100644 index 29b1572..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/CommandMergeTiny.java +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands; - -import net.fabricmc.stitch.Command; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.*; - -// TODO: Remap descriptors on fields and methods. -public class CommandMergeTiny extends Command { - public enum TinyEntryType { - ROOT, - CLASS, - FIELD, - METHOD; - - private static Map BY_NAME = new HashMap<>(); - - public static TinyEntryType byName(String s) { - return BY_NAME.get(s); - } - - static { - for (TinyEntryType type : values()) { - BY_NAME.put(type.name(), type); - } - } - } - - public static class TinyEntry { - public final TinyEntryType type; - public final String header; - // Map - public final Map names = new HashMap<>(); - // Table - private final Map> children = new HashMap<>(); - private TinyEntry parent; - - public TinyEntry(TinyEntryType type, String header) { - this.type = type; - this.header = header; - } - - public TinyEntry getParent() { - return parent; - } - - public boolean containsChild(String key, String value) { - Map map = children.get(key); - return map != null && map.containsKey(value); - } - - public TinyEntry getChild(String key, String value) { - Map map = children.get(key); - return map != null ? map.get(value) : null; - } - - public void putChild(String key, String value, TinyEntry entry) { - children.computeIfAbsent(key, (s) -> new HashMap<>()).put(value, entry); - } - - public void addChild(TinyEntry entry, String nameSuffix) { - entry.parent = this; - - for (Map.Entry e : entry.names.entrySet()) { - String key = e.getKey(); - String value = e.getValue() + nameSuffix; - - if (containsChild(key, value)) { - throw new RuntimeException("Duplicate TinyEntry: (" + key + ", " + value + ")!"); - } - - putChild(key, value, entry); - } - } - - public Map getChildRow(String key) { - //noinspection unchecked - return children.getOrDefault(key, Collections.EMPTY_MAP); - } - } - - public static class TinyFile { - public final String[] indexList; - public final TinyEntry root = new TinyEntry(TinyEntryType.ROOT, ""); - public final int typeCount; - - public TinyFile(File f) throws IOException { - try (BufferedReader reader = Files.newBufferedReader(f.toPath(), Charset.forName("UTF-8"))) { - String[] header = reader.readLine().trim().split("\t"); - if (header.length < 3 || !header[0].trim().equals("v1")) { - throw new RuntimeException("Invalid header!"); - } - - typeCount = header.length - 1; - indexList = new String[typeCount]; - for (int i = 0; i < typeCount; i++) { - indexList[i] = header[i + 1].trim(); - } - - String line; - while ((line = reader.readLine()) != null) { - line = line.trim(); - if (line.length() == 0 || line.charAt(0) == '#') { - continue; - } - - String[] parts = line.split("\t"); - for (int i = 0; i < parts.length; i++) { - parts[i] = parts[i].trim(); - } - - StringBuilder prefix = new StringBuilder(); - prefix.append(parts[0]); - for (int i = 1; i < parts.length - typeCount; i++) { - prefix.append('\t'); - prefix.append(parts[i]); - } - - TinyEntryType type = TinyEntryType.byName(parts[0]); - String[] path = parts[1].split("\\$"); - TinyEntry parent = root; - - for (int i = 0; i < (type == TinyEntryType.CLASS ? path.length - 1 : path.length); i++) { - TinyEntry nextParent = parent.getChild(indexList[0], path[i]); - if (nextParent == null) { - nextParent = new TinyEntry(TinyEntryType.CLASS, "CLASS"); - nextParent.names.put(indexList[0], path[i]); - parent.addChild(nextParent, ""); - } - parent = nextParent; - } - - TinyEntry entry; - if (type == TinyEntryType.CLASS && parent.containsChild(indexList[0], path[path.length - 1])) { - entry = parent.getChild(indexList[0], path[path.length - 1]); - } else { - entry = new TinyEntry(type, prefix.toString()); - } - - String[] names = new String[typeCount]; - for (int i = 0; i < typeCount; i++) { - names[i] = parts[parts.length - typeCount + i]; - if (type == TinyEntryType.CLASS) { - // add classes by their final inner class name - String[] splitly = names[i].split("\\$"); - entry.names.put(indexList[i], splitly[splitly.length - 1]); - } else { - entry.names.put(indexList[i], names[i]); - } - } - - switch (type) { - case CLASS: - parent.addChild(entry, ""); - break; - case FIELD: - case METHOD: - parent.addChild(entry, parts[2]); - break; - } - } - } - } -/* - public String match(String[] entries, String key) { - if (indexMap.containsKey(key)) { - return entries[indexMap.get(key)]; - } else { - return null; - } - } -*/ - } - - private List mappingBlankFillOrder = new ArrayList<>(); - private String sharedIndexName; - - public CommandMergeTiny() { - super("mergeTiny"); - } - - @Override - public String getHelpString() { - return " [mappingBlankFillOrder...]"; - } - - @Override - public boolean isArgumentCountValid(int count) { - return count >= 4; - } - - private TinyFile inputA, inputB; - - private String fixMatch(TinyEntry a, TinyEntry b, String matchA, String index) { - if (a == null || matchA == null) { - return matchA; - } - - if (a.type == TinyEntryType.CLASS && a.getParent() != null && a.getParent().type == TinyEntryType.CLASS) { - // First, map to the shared index name (sharedIndexName) - String officialPath = a.names.get(sharedIndexName); - TinyEntry officialEntry = a.getParent(); - while (officialEntry.type == TinyEntryType.CLASS) { - officialPath = officialEntry.names.get(sharedIndexName) + "$" + officialPath; - officialEntry = officialEntry.getParent(); - } - - // Now, traverse it from the ROOT and get the names - Set matchingOrder = new LinkedHashSet<>(); - matchingOrder.add(index); - matchingOrder.addAll(mappingBlankFillOrder); - - String[] path = officialPath.split("\\$"); - a = inputA.root; - b = inputB.root; - - StringBuilder targetName = new StringBuilder(); - - for (int i = 0; i < path.length; i++) { - if (i > 0) { - targetName.append('$'); - } - - a = a != null ? a.getChild(sharedIndexName, path[i]) : null; - b = b != null ? b.getChild(sharedIndexName, path[i]) : null; - boolean appended = false; - - for (String mName : matchingOrder) { - String nameA = a != null ? a.names.get(mName) : null; - String nameB = b != null ? b.names.get(mName) : null; - - if (nameA != null) { - targetName.append(nameA); - appended = true; - break; - } else if (nameB != null) { - targetName.append(nameB); - appended = true; - break; - } - } - - if (!appended) { - throw new RuntimeException("Could not find mapping for " + officialPath + "!"); - } - } - - return targetName.toString(); - } - - return matchA; - } - - private String getMatch(TinyEntry a, TinyEntry b, String index, String realIndex) { - String matchA = a != null ? a.names.get(index) : null; - String matchB = b != null ? b.names.get(index) : null; - - assert a == null || b == null || a.type == b.type; - - matchA = fixMatch(a, b, matchA, realIndex); - matchB = fixMatch(b, a, matchB, realIndex); - - if (matchA != null) { - if (matchB != null && !matchA.equals(matchB)) { - throw new RuntimeException("No match: " + index + " " + matchA + " " + matchB); - } - - return matchA; - } else { - return matchB; - } - } - - private String getEntry(TinyEntry a, TinyEntry b, List totalIndexList) { - if (a != null && b != null && !(a.header.equals(b.header))) { - throw new RuntimeException("Header mismatch: " + a.header + " != " + b.header); - } else if (a != null && b != null && a.type != b.type) { - throw new RuntimeException("Type mismatch: " + a.type + " != " + b.type); - } - - String header = a != null ? a.header : b.header; - StringBuilder entry = new StringBuilder(); - entry.append(header); - - for (String index : totalIndexList) { - entry.append('\t'); - - String match = getMatch(a, b, index, index); - if (match == null) { - for (String s : mappingBlankFillOrder) { - match = getMatch(a, b, s, index); - if (match != null) { - break; - } - } - - if (match == null) { - throw new RuntimeException("TODO"); - } - } - - entry.append(match); - } - - entry.append('\n'); - return entry.toString(); - } - - public void write(TinyEntry inputA, TinyEntry inputB, String index, String c, BufferedWriter writer, List totalIndexList, int indent) throws IOException { - TinyEntry classA = inputA != null ? inputA.getChild(index, c) : null; - TinyEntry classB = inputB != null ? inputB.getChild(index, c) : null; - - /* for (int i = 0; i <= indent; i++) - System.out.print("-"); - System.out.println(" " + c + " " + (classA != null ? "Y" : "N") + " " + (classB != null ? "Y" : "N")); */ - - if ((classA == null || classA.names.size() == 0) && (classB == null || classB.names.size() == 0)) { - System.out.println("Warning: empty!"); - return; - } - - writer.write(getEntry(classA, classB, totalIndexList)); - - Set subKeys = new TreeSet<>(); - if (classA != null) subKeys.addAll(classA.getChildRow(index).keySet()); - if (classB != null) subKeys.addAll(classB.getChildRow(index).keySet()); - for (String cc : subKeys) { - write(classA, classB, index, cc, writer, totalIndexList, indent + 1); - } - } - - public void run(File inputAf, File inputBf, File outputf, String... mappingBlankFillOrderValues) throws IOException { - for (String s : mappingBlankFillOrderValues) { - if (!this.mappingBlankFillOrder.contains(s)) { - this.mappingBlankFillOrder.add(s); - } - } - - System.out.println("Reading " + inputAf.getName()); - inputA = new TinyFile(inputAf); - - System.out.println("Reading " + inputBf.getName()); - inputB = new TinyFile(inputBf); - - System.out.println("Processing..."); - try (BufferedWriter writer = Files.newBufferedWriter(outputf.toPath(), Charset.forName("UTF-8"))) { - if (!inputA.indexList[0].equals(inputB.indexList[0])) { - throw new RuntimeException("TODO"); - } - - sharedIndexName = inputA.indexList[0]; - - // Set matchedIndexes = Sets.intersection(inputA.indexMap.keySet(), inputB.indexMap.keySet()); - Set matchedIndexes = Collections.singleton(inputA.indexList[0]); - List totalIndexList = new ArrayList<>(Arrays.asList(inputA.indexList)); - for (String s : inputB.indexList) { - if (!totalIndexList.contains(s)) { - totalIndexList.add(s); - } - } - int totalIndexCount = totalIndexList.size(); - - // emit header - StringBuilder header = new StringBuilder(); - header.append("v1"); - for (String s : totalIndexList) { - header.append('\t'); - header.append(s); - } - writer.write(header.append('\n').toString()); - - // collect classes - String index = inputA.indexList[0]; - Set classKeys = new TreeSet<>(); - classKeys.addAll(inputA.root.getChildRow(index).keySet()); - classKeys.addAll(inputB.root.getChildRow(index).keySet()); - - // emit entries - for (String c : classKeys) { - write(inputA.root, inputB.root, index, c, writer, totalIndexList, 0); - } - } - System.out.println("Done!"); - } - - @Override - public void run(String[] args) throws Exception { - File inputAf = new File(args[0]); - File inputBf = new File(args[1]); - File outputf = new File(args[2]); - - String[] mbforder = new String[args.length - 3]; - for (int i = 3; i < args.length; i++) { - mbforder[i - 3] = args[i]; - } - - run(inputAf, inputBf, outputf, mbforder); - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandProposeFieldNames.java b/src/main/java/net/fabricmc/stitch/commands/CommandProposeFieldNames.java deleted file mode 100644 index ca72c02..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/CommandProposeFieldNames.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands; - -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.mappings.FieldEntry; -import net.fabricmc.mappings.Mappings; -import net.fabricmc.mappings.MappingsProvider; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.util.FieldNameFinder; - -import java.io.*; -import java.util.*; - -public class CommandProposeFieldNames extends Command { - public CommandProposeFieldNames() { - super("proposeFieldNames"); - } - - @Override - public String getHelpString() { - return " "; - } - - @Override - public boolean isArgumentCountValid(int count) { - return count == 3; - } - - @Override - public void run(String[] args) throws Exception { - Map fieldNamesO = new FieldNameFinder().findNames(new File(args[0])); - - System.err.println("Found " + fieldNamesO.size() + " interesting names."); - - // i didn't fuss too much on this... this needs a rewrite once we get a mapping writer library - Map fieldNames = new HashMap<>(); - - Mappings mappings; - try (FileInputStream fileIn = new FileInputStream(new File(args[1]))) { - mappings = MappingsProvider.readTinyMappings(fileIn, false); - } - - try (FileInputStream fileIn = new FileInputStream(new File(args[1])); - FileOutputStream fileOut = new FileOutputStream(new File(args[2])); - InputStreamReader fileInReader = new InputStreamReader(fileIn); - OutputStreamWriter fileOutWriter = new OutputStreamWriter(fileOut); - BufferedReader reader = new BufferedReader(fileInReader); - BufferedWriter writer = new BufferedWriter(fileOutWriter)) { - - int headerPos = -1; - - String line; - while ((line = reader.readLine()) != null) { - String[] tabSplit = line.split("\t"); - - if (headerPos < 0) { - // first line - if (tabSplit.length < 3) { - throw new RuntimeException("Invalid mapping file!"); - } - - for (int i = 2; i < tabSplit.length; i++) { - if (tabSplit[i].equals("named")) { - headerPos = i; - break; - } - } - - if (headerPos < 0) { - throw new RuntimeException("Could not find 'named' mapping position!"); - } - - if (!tabSplit[1].equals("official")) { - for (FieldEntry e : mappings.getFieldEntries()) { - EntryTriple officialFieldMapping = e.get("official"); - String name = fieldNamesO.get(officialFieldMapping); - if (name != null) { - fieldNames.put(e.get(tabSplit[1]), name); - } - } - } else { - fieldNames = fieldNamesO; - } - - mappings = null; // save memory - } else { - // second+ line - if (tabSplit[0].equals("FIELD")) { - EntryTriple key = new EntryTriple(tabSplit[1], tabSplit[3], tabSplit[2]); - String value = tabSplit[headerPos + 2]; - if (value.startsWith("field_") && fieldNames.containsKey(key)) { - tabSplit[headerPos + 2] = fieldNames.get(key); - - StringBuilder builder = new StringBuilder(tabSplit[0]); - for (int i = 1; i < tabSplit.length; i++) { - builder.append('\t'); - builder.append(tabSplit[i]); - } - line = builder.toString(); - } - } - } - - if (!line.endsWith("\n")) { - line = line + "\n"; - } - - writer.write(line); - } - } - } -} \ No newline at end of file diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandReorderTiny.java b/src/main/java/net/fabricmc/stitch/commands/CommandReorderTiny.java deleted file mode 100644 index 89bcf05..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/CommandReorderTiny.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands; - -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.mappings.Mappings; -import net.fabricmc.mappings.MappingsProvider; -import net.fabricmc.stitch.Command; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.util.Comparator; -import java.util.Locale; - -public class CommandReorderTiny extends Command { - public CommandReorderTiny() { - super("reorderTiny"); - } - - @Override - public String getHelpString() { - return " [name order...]"; - } - - @Override - public boolean isArgumentCountValid(int count) { - return count >= 4; - } - - private int compareTriples(EntryTriple a, EntryTriple b) { - int c = a.getOwner().compareTo(b.getOwner()); - if (c == 0) { - c = a.getDesc().compareTo(b.getDesc()); - if (c == 0) { - c = a.getName().compareTo(b.getName()); - } - } - return c; - } - - @Override - public void run(String[] args) throws Exception { - File fileOld = new File(args[0]); - File fileNew = new File(args[1]); - String[] names = new String[args.length - 2]; - System.arraycopy(args, 2, names, 0, names.length); - - System.err.println("Loading mapping file..."); - - Mappings input; - try (FileInputStream stream = new FileInputStream(fileOld)) { - input = MappingsProvider.readTinyMappings(stream, false); - } - - System.err.println("Rewriting mappings..."); - - try (FileOutputStream stream = new FileOutputStream(fileNew); - OutputStreamWriter osw = new OutputStreamWriter(stream); - BufferedWriter writer = new BufferedWriter(osw)) { - - StringBuilder firstLineBuilder = new StringBuilder("v1"); - for (String name : names) { - firstLineBuilder.append('\t').append(name); - } - writer.write(firstLineBuilder.append('\n').toString()); - input.getClassEntries().stream().sorted(Comparator.comparing((a) -> a.get(names[0]))).forEach((entry) -> { - try { - StringBuilder s = new StringBuilder("CLASS"); - for (String name : names) { - s.append('\t').append(entry.get(name)); - } - writer.write(s.append('\n').toString()); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - input.getFieldEntries().stream().sorted((a, b) -> compareTriples(a.get(names[0]), b.get(names[0]))).forEach((entry) -> { - try { - StringBuilder s = new StringBuilder("FIELD"); - EntryTriple first = entry.get(names[0]); - s.append('\t').append(first.getOwner()).append('\t').append(first.getDesc()); - for (String name : names) { - s.append('\t').append(entry.get(name).getName()); - } - writer.write(s.append('\n').toString()); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - input.getMethodEntries().stream().sorted((a, b) -> compareTriples(a.get(names[0]), b.get(names[0]))).forEach((entry) -> { - try { - StringBuilder s = new StringBuilder("METHOD"); - EntryTriple first = entry.get(names[0]); - s.append('\t').append(first.getOwner()).append('\t').append(first.getDesc()); - for (String name : names) { - s.append('\t').append(entry.get(name).getName()); - } - writer.write(s.append('\n').toString()); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - - System.err.println("Done!"); - } - -} diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandRewriteIntermediary.java b/src/main/java/net/fabricmc/stitch/commands/CommandRewriteIntermediary.java index b193733..c53ad09 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandRewriteIntermediary.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandRewriteIntermediary.java @@ -16,61 +16,62 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.representation.JarRootEntry; -import net.fabricmc.stitch.representation.JarReader; - import java.io.File; import java.io.IOException; import java.util.Locale; +import net.fabricmc.stitch.Command; +import net.fabricmc.stitch.representation.JarReader; +import net.fabricmc.stitch.representation.JarRootEntry; + public class CommandRewriteIntermediary extends Command { - public CommandRewriteIntermediary() { - super("rewriteIntermediary"); - } + public CommandRewriteIntermediary() { + super("rewriteIntermediary"); + } + + @Override + public String getHelpString() { + return " [--writeAll]"; + } - @Override - public String getHelpString() { - return " [--writeAll]"; - } + @Override + public boolean isArgumentCountValid(int count) { + return count >= 3; + } - @Override - public boolean isArgumentCountValid(int count) { - return count >= 3; - } + @Override + public void run(String[] args) throws Exception { + File fileOld = new File(args[0]); + JarRootEntry jarOld = new JarRootEntry(fileOld); - @Override - public void run(String[] args) throws Exception { - File fileOld = new File(args[0]); - JarRootEntry jarOld = new JarRootEntry(fileOld); - try { - JarReader reader = new JarReader(jarOld); - reader.apply(); - } catch (IOException e) { - e.printStackTrace(); - } + try { + JarReader reader = new JarReader(jarOld); + reader.apply(); + } catch (IOException e) { + e.printStackTrace(); + } - GenState state = new GenState(); + GenState state = new GenState(); - for (int i = 3; i < args.length; i++) { - switch (args[i].toLowerCase(Locale.ROOT)) { - case "--writeall": - state.setWriteAll(true); - break; - } - } + for (int i = 3; i < args.length; i++) { + switch (args[i].toLowerCase(Locale.ROOT)) { + case "--writeall": + state.setWriteAll(true); + break; + } + } - System.err.println("Loading mapping file..."); - state.prepareRewrite(new File(args[1])); + System.err.println("Loading mapping file..."); + state.prepareRewrite(new File(args[1])); - File outFile = new File(args[2]); - if (outFile.exists()) { - outFile.delete(); - } + File outFile = new File(args[2]); - System.err.println("Rewriting mappings..."); - state.generate(outFile, jarOld, jarOld); - System.err.println("Done!"); - } + if (outFile.exists()) { + outFile.delete(); + } + System.err.println("Rewriting mappings..."); + state.generate(outFile, jarOld, jarOld); + System.err.println("Done!"); + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandUpdateIntermediary.java b/src/main/java/net/fabricmc/stitch/commands/CommandUpdateIntermediary.java index 59a1265..6c01315 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandUpdateIntermediary.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandUpdateIntermediary.java @@ -16,76 +16,79 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.representation.*; - import java.io.File; import java.io.IOException; import java.util.Locale; +import net.fabricmc.stitch.Command; +import net.fabricmc.stitch.representation.JarReader; +import net.fabricmc.stitch.representation.JarRootEntry; + public class CommandUpdateIntermediary extends Command { - public CommandUpdateIntermediary() { - super("updateIntermediary"); - } + public CommandUpdateIntermediary() { + super("updateIntermediary"); + } + + @Override + public String getHelpString() { + return " [-t|--target-namespace ] [-p|--obfuscation-pattern ]"; + } - @Override - public String getHelpString() { - return " [-t|--target-namespace ] [-p|--obfuscation-pattern ]"; - } + @Override + public boolean isArgumentCountValid(int count) { + return count >= 5; + } - @Override - public boolean isArgumentCountValid(int count) { - return count >= 5; - } + @Override + public void run(String[] args) throws Exception { + File fileOld = new File(args[0]); + JarRootEntry jarOld = new JarRootEntry(fileOld); - @Override - public void run(String[] args) throws Exception { - File fileOld = new File(args[0]); - JarRootEntry jarOld = new JarRootEntry(fileOld); - try { - JarReader reader = new JarReader(jarOld); - reader.apply(); - } catch (IOException e) { - e.printStackTrace(); - } + try { + JarReader reader = new JarReader(jarOld); + reader.apply(); + } catch (IOException e) { + e.printStackTrace(); + } - File fileNew = new File(args[1]); - JarRootEntry jarNew = new JarRootEntry(fileNew); - try { - JarReader reader = new JarReader(jarNew); - reader.apply(); - } catch (IOException e) { - e.printStackTrace(); - } + File fileNew = new File(args[1]); + JarRootEntry jarNew = new JarRootEntry(fileNew); - GenState state = new GenState(); - boolean clearedPatterns = false; + try { + JarReader reader = new JarReader(jarNew); + reader.apply(); + } catch (IOException e) { + e.printStackTrace(); + } - for (int i = 5; i < args.length; i++) { - switch (args[i].toLowerCase(Locale.ROOT)) { - case "-t": - case "--target-namespace": - state.setTargetNamespace(args[i + 1]); - i++; - break; - case "-p": - case "--obfuscation-pattern": - if (!clearedPatterns) - state.clearObfuscatedPatterns(); - clearedPatterns = true; + GenState state = new GenState(); + boolean clearedPatterns = false; - state.addObfuscatedPattern(args[i + 1]); - i++; - break; - } - } + for (int i = 5; i < args.length; i++) { + switch (args[i].toLowerCase(Locale.ROOT)) { + case "-t": + case "--target-namespace": + state.setTargetPackage(args[i + 1]); + i++; + break; + case "-p": + case "--obfuscation-pattern": + if (!clearedPatterns) { + state.clearObfuscatedPatterns(); + } - System.err.println("Loading remapping files..."); - state.prepareUpdate(new File(args[2]), new File(args[4])); + clearedPatterns = true; + state.addObfuscatedPattern(args[i + 1]); + i++; + break; + } + } - System.err.println("Generating new mappings..."); - state.generate(new File(args[3]), jarNew, jarOld); - System.err.println("Done!"); - } + System.err.println("Loading remapping files..."); + state.prepareUpdate(new File(args[2]), new File(args[4])); + System.err.println("Generating new mappings..."); + state.generate(new File(args[3]), jarNew, jarOld); + System.err.println("Done!"); + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/CommandValidateRecords.java b/src/main/java/net/fabricmc/stitch/commands/CommandValidateRecords.java index f234ad2..015cf00 100644 --- a/src/main/java/net/fabricmc/stitch/commands/CommandValidateRecords.java +++ b/src/main/java/net/fabricmc/stitch/commands/CommandValidateRecords.java @@ -16,12 +16,12 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.util.RecordValidator; - import java.io.File; import java.io.FileNotFoundException; +import net.fabricmc.stitch.Command; +import net.fabricmc.stitch.util.RecordValidator; + public class CommandValidateRecords extends Command { public CommandValidateRecords() { super("validateRecords"); @@ -52,6 +52,7 @@ public void run(String[] args) throws Exception { for (String error : e.errors) { System.err.println(error); } + throw e; } } diff --git a/src/main/java/net/fabricmc/stitch/commands/GenMap.java b/src/main/java/net/fabricmc/stitch/commands/GenMap.java index eaf2937..d5ce634 100644 --- a/src/main/java/net/fabricmc/stitch/commands/GenMap.java +++ b/src/main/java/net/fabricmc/stitch/commands/GenMap.java @@ -15,121 +15,136 @@ */ package net.fabricmc.stitch.commands; -import net.fabricmc.mappings.*; -import org.checkerframework.checker.nullness.qual.Nullable; import java.util.HashMap; import java.util.Map; import java.util.function.Function; +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.mapping.util.EntryTriple; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; +import net.fabricmc.mappingio.tree.MappingTree.FieldMapping; +import net.fabricmc.mappingio.tree.MappingTree.MemberMapping; +import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; + public class GenMap { - private static class Class { - private final String name; - private final Map fieldMaps = new HashMap<>(); - private final Map methodMaps = new HashMap<>(); - - public Class(String name) { - this.name = name; - } - } - - private final Map map = new HashMap<>(); - - public GenMap() { - } - - public void addClass(String from, String to) { - map.put(from, new Class(to)); - } - - public void addField(EntryTriple from, EntryTriple to) { - map.get(from.getOwner()).fieldMaps.put(from, to); - } - - public void addMethod(EntryTriple from, EntryTriple to) { - map.get(from.getOwner()).methodMaps.put(from, to); - } - - public void load(Mappings mappings, String from, String to) { - for (ClassEntry classEntry : mappings.getClassEntries()) { - map.put(classEntry.get(from), new Class(classEntry.get(to))); - } - - for (FieldEntry fieldEntry : mappings.getFieldEntries()) { - map.get(fieldEntry.get(from).getOwner()).fieldMaps.put(fieldEntry.get(from), fieldEntry.get(to)); - } - - for (MethodEntry methodEntry : mappings.getMethodEntries()) { - map.get(methodEntry.get(from).getOwner()).methodMaps.put(methodEntry.get(from), methodEntry.get(to)); - } - } - - @Nullable - public String getClass(String from) { - return map.containsKey(from) ? map.get(from).name : null; - } - - @Nullable - private EntryTriple get(EntryTriple entry, Function> mapGetter) { - if (map.containsKey(entry.getOwner())) { - return mapGetter.apply(map.get(entry.getOwner())).get(entry); - } - - return null; - } - - @Nullable - public EntryTriple getField(String owner, String name, String desc) { - return get(new EntryTriple(owner, name, desc), (c) -> c.fieldMaps); - } - - @Nullable - public EntryTriple getField(EntryTriple entry) { - return get(entry, (c) -> c.fieldMaps); - } - - @Nullable - public EntryTriple getMethod(String owner, String name, String desc) { - return get(new EntryTriple(owner, name, desc), (c) -> c.methodMaps); - } - - @Nullable - public EntryTriple getMethod(EntryTriple entry) { - return get(entry, (c) -> c.methodMaps); - } - - public static class Dummy extends GenMap { - public Dummy() { - } - - @Nullable - @Override - public String getClass(String from) { - return from; - } - - @Nullable - @Override - public EntryTriple getField(String owner, String name, String desc) { - return new EntryTriple(owner, name, desc); - } - - @Nullable - @Override - public EntryTriple getField(EntryTriple entry) { - return entry; - } - - @Nullable - @Override - public EntryTriple getMethod(String owner, String name, String desc) { - return new EntryTriple(owner, name, desc); - } - - @Nullable - @Override - public EntryTriple getMethod(EntryTriple entry) { - return entry; - } - } + private static class Class { + private final String name; + private final Map fieldMaps = new HashMap<>(); + private final Map methodMaps = new HashMap<>(); + + Class(String name) { + this.name = name; + } + } + + private final Map map = new HashMap<>(); + + public GenMap() { + } + + public void addClass(String from, String to) { + map.put(from, new Class(to)); + } + + public void addField(EntryTriple from, EntryTriple to) { + map.get(from.getOwner()).fieldMaps.put(from, to); + } + + public void addMethod(EntryTriple from, EntryTriple to) { + map.get(from.getOwner()).methodMaps.put(from, to); + } + + public void load(MappingTree mappings) { + for (ClassMapping cls : mappings.getClasses()) { + map.put(cls.getSrcName(), new Class(cls.getDstName(0))); + + for (FieldMapping fld : cls.getFields()) { + map.get(fld.getOwner().getSrcName()).fieldMaps.put(srcEntryTripleOf(fld), dstEntryTripleOf(fld)); + } + + for (MethodMapping mth : cls.getMethods()) { + map.get(mth.getOwner().getSrcName()).methodMaps.put(srcEntryTripleOf(mth), dstEntryTripleOf(mth)); + } + } + } + + private EntryTriple srcEntryTripleOf(MemberMapping member) { + return new EntryTriple(member.getOwner().getSrcName(), member.getSrcName(), member.getSrcDesc()); + } + + private EntryTriple dstEntryTripleOf(MemberMapping member) { + return new EntryTriple(member.getOwner().getDstName(0), member.getDstName(0), member.getDstDesc(0)); + } + + @Nullable + public String getClass(String from) { + return map.containsKey(from) ? map.get(from).name : null; + } + + @Nullable + private EntryTriple get(EntryTriple entry, Function> mapGetter) { + if (map.containsKey(entry.getOwner())) { + return mapGetter.apply(map.get(entry.getOwner())).get(entry); + } + + return null; + } + + @Nullable + public EntryTriple getField(String owner, String name, String desc) { + return get(new EntryTriple(owner, name, desc), (c) -> c.fieldMaps); + } + + @Nullable + public EntryTriple getField(EntryTriple entry) { + return get(entry, (c) -> c.fieldMaps); + } + + @Nullable + public EntryTriple getMethod(String owner, String name, String desc) { + return get(new EntryTriple(owner, name, desc), (c) -> c.methodMaps); + } + + @Nullable + public EntryTriple getMethod(EntryTriple entry) { + return get(entry, (c) -> c.methodMaps); + } + + public static class Dummy extends GenMap { + public Dummy() { + } + + @Nullable + @Override + public String getClass(String from) { + return from; + } + + @Nullable + @Override + public EntryTriple getField(String owner, String name, String desc) { + return new EntryTriple(owner, name, desc); + } + + @Nullable + @Override + public EntryTriple getField(EntryTriple entry) { + return entry; + } + + @Nullable + @Override + public EntryTriple getMethod(String owner, String name, String desc) { + return new EntryTriple(owner, name, desc); + } + + @Nullable + @Override + public EntryTriple getMethod(EntryTriple entry) { + return entry; + } + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/GenState.java b/src/main/java/net/fabricmc/stitch/commands/GenState.java index beab5d8..ae32f1a 100644 --- a/src/main/java/net/fabricmc/stitch/commands/GenState.java +++ b/src/main/java/net/fabricmc/stitch/commands/GenState.java @@ -16,504 +16,608 @@ package net.fabricmc.stitch.commands; -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.mappings.MappingsProvider; -import net.fabricmc.stitch.representation.*; -import net.fabricmc.stitch.util.MatcherUtil; -import net.fabricmc.stitch.util.Pair; -import net.fabricmc.stitch.util.StitchUtil; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.objectweb.asm.Opcodes; - -import java.io.*; -import java.nio.charset.StandardCharsets; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.Set; +import java.util.TreeSet; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; + +import net.fabricmc.mapping.util.EntryTriple; +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingReader; +import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.adapter.MappingDstNsReorder; +import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; +import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; +import net.fabricmc.mappingio.tree.MappingTree.FieldMapping; +import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; +import net.fabricmc.stitch.representation.AbstractJarEntry; +import net.fabricmc.stitch.representation.ClassStorage; +import net.fabricmc.stitch.representation.JarClassEntry; +import net.fabricmc.stitch.representation.JarFieldEntry; +import net.fabricmc.stitch.representation.JarMethodEntry; +import net.fabricmc.stitch.representation.JarRootEntry; +import net.fabricmc.stitch.util.MatcherUtil; +import net.fabricmc.stitch.util.Pair; +import net.fabricmc.stitch.util.StitchUtil; + class GenState { - private final Map counters = new HashMap<>(); - private final Map values = new IdentityHashMap<>(); - private GenMap oldToIntermediary, newToOld; - private GenMap newToIntermediary; - private boolean interactive = true; - private boolean writeAll = false; - private Scanner scanner = new Scanner(System.in); - - private String targetNamespace = "net/minecraft/"; - private final List obfuscatedPatterns = new ArrayList(); - - public GenState() { - this.obfuscatedPatterns.add(Pattern.compile("^[^/]*$")); // Default ofbfuscation. Minecraft classes without a package are obfuscated. - } - - public void setWriteAll(boolean writeAll) { - this.writeAll = writeAll; - } - - public void disableInteractive() { - interactive = false; - } - - public String next(AbstractJarEntry entry, String name) { - return name + "_" + values.computeIfAbsent(entry, (e) -> { - int v = counters.getOrDefault(name, 1); - counters.put(name, v + 1); - return v; - }); - } - - public void setTargetNamespace(final String namespace) { - if (namespace.lastIndexOf("/") != (namespace.length() - 1)) - this.targetNamespace = namespace + "/"; - else - this.targetNamespace = namespace; - } - - public void clearObfuscatedPatterns() { - this.obfuscatedPatterns.clear(); - } - - public void addObfuscatedPattern(String regex) throws PatternSyntaxException { - this.obfuscatedPatterns.add(Pattern.compile(regex)); - } - - public void setCounter(String key, int value) { - counters.put(key, value); - } - - public Map getCounters() { - return Collections.unmodifiableMap(counters); - } - - public void generate(File file, JarRootEntry jarEntry, JarRootEntry jarOld) throws IOException { - if (file.exists()) { - System.err.println("Target file exists - loading..."); - newToIntermediary = new GenMap(); - try (FileInputStream inputStream = new FileInputStream(file)) { - newToIntermediary.load( - MappingsProvider.readTinyMappings(inputStream), - "official", - "intermediary" - ); - } - } - - try (FileWriter fileWriter = new FileWriter(file)) { - try (BufferedWriter writer = new BufferedWriter(fileWriter)) { - writer.write("v1\tofficial\tintermediary\n"); - - for (JarClassEntry c : jarEntry.getClasses()) { - addClass(writer, c, jarOld, jarEntry, this.targetNamespace); - } - - writeCounters(writer); - } - } - } - - public static boolean isMappedClass(ClassStorage storage, JarClassEntry c) { - return !c.isAnonymous(); - } - - public static boolean isMappedField(ClassStorage storage, JarClassEntry c, JarFieldEntry f) { - return isUnmappedFieldName(f.getName()); - } - - public static boolean isUnmappedFieldName(String name) { - return name.length() <= 2 || (name.length() == 3 && name.charAt(2) == '_'); - } - - public static boolean isMappedMethod(ClassStorage storage, JarClassEntry c, JarMethodEntry m) { - return isUnmappedMethodName(m.getName()) && m.isSource(storage, c); - } - - public static boolean isUnmappedMethodName(String name) { - return (name.length() <= 2 || (name.length() == 3 && name.charAt(2) == '_')) && name.charAt(0) != '<'; - } - - @Nullable - private String getFieldName(ClassStorage storage, JarClassEntry c, JarFieldEntry f) { - if (!isMappedField(storage, c, f)) { - return null; - } - - if (newToIntermediary != null) { - EntryTriple findEntry = newToIntermediary.getField(c.getFullyQualifiedName(), f.getName(), f.getDescriptor()); - if (findEntry != null) { - if (findEntry.getName().contains("field_")) { - return findEntry.getName(); - } else { - String newName = next(f, "field"); - System.out.println(findEntry.getName() + " is now " + newName); - return newName; - } - } - } - - if (newToOld != null) { - EntryTriple findEntry = newToOld.getField(c.getFullyQualifiedName(), f.getName(), f.getDescriptor()); - if (findEntry != null) { - findEntry = oldToIntermediary.getField(findEntry); - if (findEntry != null) { - if (findEntry.getName().contains("field_")) { - return findEntry.getName(); - } else { - String newName = next(f, "field"); - System.out.println(findEntry.getName() + " is now " + newName); - return newName; - } - } - } - } - - return next(f, "field"); - } - - private final Map methodNames = new IdentityHashMap<>(); - - private String getPropagation(ClassStorage storage, JarClassEntry classEntry) { - if (classEntry == null) { - return ""; - } - - StringBuilder builder = new StringBuilder(classEntry.getFullyQualifiedName()); - List strings = new ArrayList<>(); - String scs = getPropagation(storage, classEntry.getSuperClass(storage)); - if (!scs.isEmpty()) { - strings.add(scs); - } - - for (JarClassEntry ce : classEntry.getInterfaces(storage)) { - scs = getPropagation(storage, ce); - if (!scs.isEmpty()) { - strings.add(scs); - } - } - - if (!strings.isEmpty()) { - builder.append("<-"); - if (strings.size() == 1) { - builder.append(strings.get(0)); - } else { - builder.append("["); - builder.append(StitchUtil.join(",", strings)); - builder.append("]"); - } - } - - return builder.toString(); - } - - private String getNamesListEntry(ClassStorage storage, JarClassEntry classEntry) { - StringBuilder builder = new StringBuilder(getPropagation(storage, classEntry)); - if (classEntry.isInterface()) { - builder.append("(itf)"); - } - - return builder.toString(); - } - - private Set findNames(ClassStorage storageOld, ClassStorage storageNew, JarClassEntry c, JarMethodEntry m, Map> names) { - Set allEntries = new HashSet<>(); - findNames(storageOld, storageNew, c, m, names, allEntries); - return allEntries; - } - - private void findNames(ClassStorage storageOld, ClassStorage storageNew, JarClassEntry c, JarMethodEntry m, Map> names, Set usedMethods) { - if (!usedMethods.add(m)) { - return; - } - - String suffix = "." + m.getName() + m.getDescriptor(); - - if ((m.getAccess() & Opcodes.ACC_BRIDGE) != 0) { - suffix += "(bridge)"; - } - - List ccList = m.getMatchingEntries(storageNew, c); - - for (JarClassEntry cc : ccList) { - EntryTriple findEntry = null; - if (newToIntermediary != null) { - findEntry = newToIntermediary.getMethod(cc.getFullyQualifiedName(), m.getName(), m.getDescriptor()); - if (findEntry != null) { - names.computeIfAbsent(findEntry.getName(), (s) -> new TreeSet<>()).add(getNamesListEntry(storageNew, cc) + suffix); - } - } - - if (findEntry == null && newToOld != null) { - findEntry = newToOld.getMethod(cc.getFullyQualifiedName(), m.getName(), m.getDescriptor()); - if (findEntry != null) { - EntryTriple newToOldEntry = findEntry; - findEntry = oldToIntermediary.getMethod(newToOldEntry); - if (findEntry != null) { - names.computeIfAbsent(findEntry.getName(), (s) -> new TreeSet<>()).add(getNamesListEntry(storageNew, cc) + suffix); - } else { - // more involved... - JarClassEntry oldBase = storageOld.getClass(newToOldEntry.getOwner(), false); - if (oldBase != null) { - JarMethodEntry oldM = oldBase.getMethod(newToOldEntry.getName() + newToOldEntry.getDesc()); - List cccList = oldM.getMatchingEntries(storageOld, oldBase); - - for (JarClassEntry ccc : cccList) { - findEntry = oldToIntermediary.getMethod(ccc.getFullyQualifiedName(), oldM.getName(), oldM.getDescriptor()); - if (findEntry != null) { - names.computeIfAbsent(findEntry.getName(), (s) -> new TreeSet<>()).add(getNamesListEntry(storageOld, ccc) + suffix); - } - } - } - } - } - } - } - - for (JarClassEntry mc : ccList) { - for (Pair pair : mc.getRelatedMethods(m)) { - findNames(storageOld, storageNew, pair.getLeft(), pair.getLeft().getMethod(pair.getRight()), names, usedMethods); - } - } - } - - @Nullable - private String getMethodName(ClassStorage storageOld, ClassStorage storageNew, JarClassEntry c, JarMethodEntry m) { - if (!isMappedMethod(storageNew, c, m)) { - return null; - } - - if (methodNames.containsKey(m)) { - return methodNames.get(m); - } - - if (newToOld != null || newToIntermediary != null) { - Map> names = new HashMap<>(); - Set allEntries = findNames(storageOld, storageNew, c, m, names); - for (JarMethodEntry mm : allEntries) { - if (methodNames.containsKey(mm)) { - return methodNames.get(mm); - } - } - - if (names.size() > 1) { - System.out.println("Conflict detected - matched same target name!"); - List nameList = new ArrayList<>(names.keySet()); - Collections.sort(nameList); - - for (int i = 0; i < nameList.size(); i++) { - String s = nameList.get(i); - System.out.println((i+1) + ") " + s + " <- " + StitchUtil.join(", ", names.get(s))); - } - - if (!interactive) { - throw new RuntimeException("Conflict detected!"); - } - - while (true) { - String cmd = scanner.nextLine(); - int i; - try { - i = Integer.parseInt(cmd); - } catch (NumberFormatException e) { - e.printStackTrace(); - continue; - } - - if (i >= 1 && i <= nameList.size()) { - for (JarMethodEntry mm : allEntries) { - methodNames.put(mm, nameList.get(i - 1)); - } - System.out.println("OK!"); - return nameList.get(i - 1); - } - } - } else if (names.size() == 1) { - String s = names.keySet().iterator().next(); - for (JarMethodEntry mm : allEntries) { - methodNames.put(mm, s); - } - if (s.contains("method_")) { - return s; - } else { - String newName = next(m, "method"); - System.out.println(s + " is now " + newName); - return newName; - } - } - } - - return next(m, "method"); - } - - private void addClass(BufferedWriter writer, JarClassEntry c, ClassStorage storageOld, ClassStorage storage, String translatedPrefix) throws IOException { - String className = c.getName(); - String cname = ""; - String prefixSaved = translatedPrefix; - - if(!this.obfuscatedPatterns.stream().anyMatch(p -> p.matcher(className).matches())) { - translatedPrefix = c.getFullyQualifiedName(); - } else { - if (!isMappedClass(storage, c)) { - cname = c.getName(); - } else { - cname = null; - - if (newToIntermediary != null) { - String findName = newToIntermediary.getClass(c.getFullyQualifiedName()); - if (findName != null) { - String[] r = findName.split("\\$"); - cname = r[r.length - 1]; - if (r.length == 1) { - translatedPrefix = ""; - } - } - } - - if (cname == null && newToOld != null) { - String findName = newToOld.getClass(c.getFullyQualifiedName()); - if (findName != null) { - findName = oldToIntermediary.getClass(findName); - if (findName != null) { - String[] r = findName.split("\\$"); - cname = r[r.length - 1]; - if (r.length == 1) { - translatedPrefix = ""; - } - - } - } - } - - if (cname != null && !cname.contains("class_")) { - String newName = next(c, "class"); - System.out.println(cname + " is now " + newName); - cname = newName; - translatedPrefix = prefixSaved; - } - - if (cname == null) { - cname = next(c, "class"); - } - } - } - - writer.write("CLASS\t" + c.getFullyQualifiedName() + "\t" + translatedPrefix + cname + "\n"); - - for (JarFieldEntry f : c.getFields()) { - String fName = getFieldName(storage, c, f); - if (fName == null) { - fName = f.getName(); - } - - if (fName != null) { - writer.write("FIELD\t" + c.getFullyQualifiedName() - + "\t" + f.getDescriptor() - + "\t" + f.getName() - + "\t" + fName + "\n"); - } - } - - for (JarMethodEntry m : c.getMethods()) { - String mName = getMethodName(storageOld, storage, c, m); - if (mName == null) { - if (!m.getName().startsWith("<") && m.isSource(storage, c)) { - mName = m.getName(); - } - } - - if (mName != null) { - writer.write("METHOD\t" + c.getFullyQualifiedName() - + "\t" + m.getDescriptor() - + "\t" + m.getName() - + "\t" + mName + "\n"); - } - } - - for (JarClassEntry cc : c.getInnerClasses()) { - addClass(writer, cc, storageOld, storage, translatedPrefix + cname + "$"); - } - } - - public void prepareRewrite(File oldMappings) throws IOException { - oldToIntermediary = new GenMap(); - newToOld = new GenMap.Dummy(); - - // TODO: only read once - readCounters(oldMappings); - - try (FileInputStream inputStream = new FileInputStream(oldMappings)) { - oldToIntermediary.load( - MappingsProvider.readTinyMappings(inputStream), - "official", - "intermediary" - ); - } - } - - public void prepareUpdate(File oldMappings, File matches) throws IOException { - oldToIntermediary = new GenMap(); - newToOld = new GenMap(); - - // TODO: only read once - readCounters(oldMappings); - - try (FileInputStream inputStream = new FileInputStream(oldMappings)) { - oldToIntermediary.load( - MappingsProvider.readTinyMappings(inputStream), - "official", - "intermediary" - ); - } - - try (FileReader fileReader = new FileReader(matches)) { - try (BufferedReader reader = new BufferedReader(fileReader)) { - MatcherUtil.read(reader, true, newToOld::addClass, newToOld::addField, newToOld::addMethod); - } - } - } - - private void readCounters(File counterFile) throws IOException { - Path counterPath = getExternalCounterFile(); - - if (counterPath != null && Files.exists(counterPath)) { - counterFile = counterPath.toFile(); - } - - try (FileReader fileReader = new FileReader(counterFile)) { - try (BufferedReader reader = new BufferedReader(fileReader)) { - String line; - while ((line = reader.readLine()) != null) { - if (line.startsWith("# INTERMEDIARY-COUNTER")) { - String[] parts = line.split(" "); - counters.put(parts[2], Integer.parseInt(parts[3])); - } - } - } - } - } - - private void writeCounters(BufferedWriter writer) throws IOException { - StringJoiner counterLines = new StringJoiner("\n"); - - for (Map.Entry counter : counters.entrySet()) { - counterLines.add("# INTERMEDIARY-COUNTER " + counter.getKey() + " " + counter.getValue()); - } - - writer.write(counterLines.toString()); - Path counterPath = getExternalCounterFile(); - - if (counterPath != null) { - Files.write(counterPath, counterLines.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } - } - - private Path getExternalCounterFile() { - if (System.getProperty("stitch.counter") != null) { - return Paths.get(System.getProperty("stitch.counter")); - } - return null; - } + private static final String official = "official"; + private static final String intermediary = "intermediary"; + private static final int officialIndex = -1; + private static final int intermediaryIndex = 0; + private final MemoryMappingTree mappingTree = new MemoryMappingTree(); + private final Map counters = new HashMap<>(); + private final Map values = new IdentityHashMap<>(); + private MappingFormat counterFileFormat = MappingFormat.TINY; + private MappingFormat mappingFileFormat = MappingFormat.TINY; + private GenMap oldToIntermediary, newToOld; + private boolean targetFileMappingsPresent; + private boolean interactive = true; + private boolean writeAll = false; + private Scanner scanner = new Scanner(System.in); + + private String targetPackage = "net/minecraft/"; + private final List obfuscatedPatterns = new ArrayList(); + + GenState() throws IOException { + this.obfuscatedPatterns.add(Pattern.compile("^[^/]*$")); // Default obfuscation. Minecraft classes without a package are obfuscated. + mappingTree.visitNamespaces(official, Arrays.asList(intermediary, intermediary)); + } + + private void validateNamespaces(MappingTree tree) { + if (tree.getDstNamespaces().size() != 1 + || !tree.getSrcNamespace().equals(official) + || !tree.getDstNamespaces().contains(intermediary)) { + throw new RuntimeException("Existing namespaces don't match '" + official + "' + '" + intermediary + "'!"); + } + } + + // TODO: Remove this once mapping-io#30 is merged + private void clearCounterMetadata() { + boolean removedAny; + + do { + removedAny = false; + removedAny |= mappingTree.removeMetadata("next-intermediary-class") != null; + removedAny |= mappingTree.removeMetadata("next-intermediary-field") != null; + removedAny |= mappingTree.removeMetadata("next-intermediary-method") != null; + } while (removedAny); + } + + public void setWriteAll(boolean writeAll) { + this.writeAll = writeAll; + } + + public void disableInteractive() { + interactive = false; + } + + public String next(AbstractJarEntry entry, String name) { + return name + "_" + values.computeIfAbsent(entry, (e) -> { + int v = counters.getOrDefault(name, 1); + counters.put(name, v + 1); + return v; + }); + } + + public void setTargetPackage(final String pkg) { + if (pkg.lastIndexOf("/") != (pkg.length() - 1)) { + this.targetPackage = pkg + "/"; + } else { + this.targetPackage = pkg; + } + } + + public void clearObfuscatedPatterns() { + this.obfuscatedPatterns.clear(); + } + + public void addObfuscatedPattern(String regex) throws PatternSyntaxException { + this.obfuscatedPatterns.add(Pattern.compile(regex)); + } + + public void setCounter(String key, int value) { + counters.put(key, value); + } + + public Map getCounters() { + return Collections.unmodifiableMap(counters); + } + + public void generate(File file, JarRootEntry jarEntry, JarRootEntry jarOld) throws IOException { + if (file.exists()) { + // Target file already exists, re-use contained mappings. + System.out.println("Target file exists - loading..."); + + mappingFileFormat = MappingReader.detectFormat(file.toPath()); + MemoryMappingTree tempTree = new MemoryMappingTree(); + MappingReader.read(file.toPath(), mappingFileFormat, tempTree); + validateNamespaces(tempTree); + + if (tempTree.getClasses().size() > 0) { + targetFileMappingsPresent = true; + } + + readCountersFromTree(tempTree); + clearCounterMetadata(); + tempTree.accept(mappingTree); + } + + readCounterFileIfPresent(); + + for (JarClassEntry c : jarEntry.getClasses()) { + addClass(c, jarOld, jarEntry, this.targetPackage); + } + + writeCounters(); + mappingTree.visitEnd(); + + MappingWriter writer = MappingWriter.create(file.toPath(), mappingFileFormat); + MemoryMappingTree treeToWrite = new MemoryMappingTree(); + mappingTree.accept(new MappingDstNsReorder(treeToWrite, intermediary)); + treeToWrite.accept(writer); + writer.close(); + } + + public static boolean isMappedClass(ClassStorage storage, JarClassEntry c) { + return !c.isAnonymous(); + } + + public static boolean isMappedField(ClassStorage storage, JarClassEntry c, JarFieldEntry f) { + return isUnmappedFieldName(f.getName()); + } + + public static boolean isUnmappedFieldName(String name) { + return name.length() <= 2 || (name.length() == 3 && name.charAt(2) == '_'); + } + + public static boolean isMappedMethod(ClassStorage storage, JarClassEntry c, JarMethodEntry m) { + return isUnmappedMethodName(m.getName()) && m.isSource(storage, c); + } + + public static boolean isUnmappedMethodName(String name) { + return (name.length() <= 2 || (name.length() == 3 && name.charAt(2) == '_')) + && name.charAt(0) != '<'; + } + + @Nullable + private String getFieldName(ClassStorage storage, JarClassEntry c, JarFieldEntry f) { + if (!isMappedField(storage, c, f)) { + return null; + } + + Object existingMapping; + String existingName = null; + + // Check for existing name from target file + if ((existingMapping = mappingTree.getField(c.getFullyQualifiedName(), f.getName(), f.getDescriptor())) != null) { + existingName = ((FieldMapping) existingMapping).getDstName(intermediaryIndex); + } + + // Check for existing name from supplied old mappings file + if (existingName == null + && newToOld != null + && (existingMapping = newToOld.getField(c.getFullyQualifiedName(), f.getName(), f.getDescriptor())) != null + && (existingMapping = oldToIntermediary.getField((EntryTriple) existingMapping)) != null) { + existingName = ((EntryTriple) existingMapping).getName(); + } + + if (existingName != null) { + if (existingName.contains("field_")) { + return existingName; + } else { + String newName = next(f, "field"); + System.out.println(existingName + " is now " + newName); + return newName; + } + } + + return next(f, "field"); + } + + private final Map methodNames = new IdentityHashMap<>(); + + private String getPropagation(ClassStorage storage, JarClassEntry classEntry) { + if (classEntry == null) { + return ""; + } + + StringBuilder builder = new StringBuilder(classEntry.getFullyQualifiedName()); + List strings = new ArrayList<>(); + String scs = getPropagation(storage, classEntry.getSuperClass(storage)); + + if (!scs.isEmpty()) { + strings.add(scs); + } + + for (JarClassEntry ce : classEntry.getInterfaces(storage)) { + scs = getPropagation(storage, ce); + + if (!scs.isEmpty()) { + strings.add(scs); + } + } + + if (!strings.isEmpty()) { + builder.append("<-"); + + if (strings.size() == 1) { + builder.append(strings.get(0)); + } else { + builder.append("["); + builder.append(StitchUtil.join(",", strings)); + builder.append("]"); + } + } + + return builder.toString(); + } + + private String getNamesListEntry(ClassStorage storage, JarClassEntry classEntry) { + StringBuilder builder = new StringBuilder(getPropagation(storage, classEntry)); + + if (classEntry.isInterface()) { + builder.append("(itf)"); + } + + return builder.toString(); + } + + private Set findNames(ClassStorage storageOld, ClassStorage storageNew, JarClassEntry c, JarMethodEntry m, Map> names) { + Set allEntries = new HashSet<>(); + findNames(storageOld, storageNew, c, m, names, allEntries); + return allEntries; + } + + private void findNames(ClassStorage storageOld, ClassStorage storageNew, JarClassEntry c, JarMethodEntry m, Map> names, Set usedMethods) { + if (!usedMethods.add(m)) { + return; + } + + String suffix = "." + m.getName() + m.getDescriptor(); + + if ((m.getAccess() & Opcodes.ACC_BRIDGE) != 0) { + suffix += "(bridge)"; + } + + List ccList = m.getMatchingEntries(storageNew, c); + + for (JarClassEntry cc : ccList) { + Object existingMapping = mappingTree.getMethod(cc.getFullyQualifiedName(), m.getName(), m.getDescriptor()); + String existingName = null; + + // Check for existing name from target file + if ((existingMapping = mappingTree.getMethod(cc.getFullyQualifiedName(), m.getName(), m.getDescriptor())) != null) { + existingName = ((MethodMapping) existingMapping).getDstName(intermediaryIndex); + } + + // Check for existing name from supplied old mappings file + if (existingName == null + && newToOld != null + && (existingMapping = newToOld.getMethod(cc.getFullyQualifiedName(), m.getName(), m.getDescriptor())) != null) { + EntryTriple mapping = oldToIntermediary.getMethod((EntryTriple) existingMapping); + + if (mapping != null) { + existingName = ((EntryTriple) mapping).getName(); + } + } + + if (existingName != null) { + names.computeIfAbsent(existingName, (s) -> new TreeSet<>()).add(getNamesListEntry(storageNew, cc) + suffix); + } else if (existingMapping != null) { + // Check old method's entire hierarchy for potential mappings + EntryTriple entry = (EntryTriple) existingMapping; + JarClassEntry oldBase = storageOld.getClass(entry.getOwner(), false); + + if (oldBase != null) { + JarMethodEntry oldM = oldBase.getMethod(entry.getName() + entry.getDescriptor()); + List cccList = oldM.getMatchingEntries(storageOld, oldBase); + + for (JarClassEntry ccc : cccList) { + entry = oldToIntermediary.getMethod(ccc.getFullyQualifiedName(), oldM.getName(), oldM.getDescriptor()); + + if (entry != null) { + names.computeIfAbsent(entry.getName(), (s) -> new TreeSet<>()).add(getNamesListEntry(storageOld, ccc) + suffix); + } + } + } + } + } + + for (JarClassEntry mc : ccList) { + for (Pair pair : mc.getRelatedMethods(m)) { + findNames(storageOld, storageNew, pair.getLeft(), pair.getLeft().getMethod(pair.getRight()), names, usedMethods); + } + } + } + + @Nullable + private String getMethodName(ClassStorage storageOld, ClassStorage storageNew, JarClassEntry c, JarMethodEntry m) { + if (!isMappedMethod(storageNew, c, m)) { + return null; + } + + if (methodNames.containsKey(m)) { + return methodNames.get(m); + } + + if (newToOld != null || targetFileMappingsPresent) { + Map> names = new HashMap<>(); + Set allEntries = findNames(storageOld, storageNew, c, m, names); + + for (JarMethodEntry mm : allEntries) { + if (methodNames.containsKey(mm)) { + return methodNames.get(mm); + } + } + + if (names.size() > 1) { + System.out.println("Conflict detected - matched same target name!"); + List nameList = new ArrayList<>(names.keySet()); + Collections.sort(nameList); + + for (int i = 0; i < nameList.size(); i++) { + String s = nameList.get(i); + System.out.println((i+1) + ") " + s + " <- " + StitchUtil.join(", ", names.get(s))); + } + + if (!interactive) { + throw new RuntimeException("Conflict detected!"); + } + + while (true) { + String cmd = scanner.nextLine(); + int i; + + try { + i = Integer.parseInt(cmd); + } catch (NumberFormatException e) { + e.printStackTrace(); + continue; + } + + if (i >= 1 && i <= nameList.size()) { + for (JarMethodEntry mm : allEntries) { + methodNames.put(mm, nameList.get(i - 1)); + } + + System.out.println("OK!"); + return nameList.get(i - 1); + } + } + } else if (names.size() == 1) { + String s = names.keySet().iterator().next(); + + for (JarMethodEntry mm : allEntries) { + methodNames.put(mm, s); + } + + if (s.contains("method_")) { + return s; + } else { + String newName = next(m, "method"); + System.out.println(s + " is now " + newName); + return newName; + } + } + } + + return next(m, "method"); + } + + private void addClass(JarClassEntry c, ClassStorage storageOld, ClassStorage storage, String prefix) throws IOException { + String cName = ""; + String origPrefix = prefix; + + if (!this.obfuscatedPatterns.stream().anyMatch(p -> p.matcher(c.getName()).matches())) { + // Class name is not obfuscated. We don't need to generate + // an intermediary name, so we just leave it as is and + // don't add a prefix. + prefix = ""; + } else if (!isMappedClass(storage, c)) { + cName = c.getName(); + } else { + cName = null; + + if (newToOld != null || targetFileMappingsPresent) { + Object existingMapping = mappingTree.getClass(c.getFullyQualifiedName()); + String existingName = null; + + // Check for existing name from target file + if (existingMapping != null) { + existingName = ((ClassMapping) existingMapping).getDstName(intermediaryIndex); + } + + // Check for existing name from supplied old mappings file + if (existingName == null + && newToOld != null + && (existingMapping = newToOld.getClass(c.getFullyQualifiedName())) != null) { + existingName = oldToIntermediary.getClass((String) existingMapping); + } + + if (existingName != null) { + // There is an existing name, so we reuse that. + // If we're looking at a subclass, only reuse the + // subclass's name, not the parent classes' ones too. + String[] r = existingName.split("\\$"); + cName = r[r.length - 1]; + + if (r.length == 1) { + // We aren't looking at a subclass; + // reuse entire fully qualified name. + prefix = ""; + } + } + } + + if (cName != null && !cName.contains("class_")) { + System.out.println(cName + " is now " + (cName = next(c, "class"))); + prefix = origPrefix; + } else if (cName == null) { + cName = next(c, "class"); + } + } + + mappingTree.visitClass(c.getFullyQualifiedName()); + mappingTree.visitDstName(MappedElementKind.CLASS, intermediaryIndex, prefix + cName); + + for (JarFieldEntry f : c.getFields()) { + String fName = getFieldName(storage, c, f); + + if (fName == null) { + fName = f.getName(); + } + + if (fName != null) { + mappingTree.visitField(f.getName(), f.getDescriptor()); + mappingTree.visitDstName(MappedElementKind.FIELD, intermediaryIndex, fName); + } + } + + for (JarMethodEntry m : c.getMethods()) { + String mName = getMethodName(storageOld, storage, c, m); + + if (mName == null) { + if (!m.getName().startsWith("<") && m.isSource(storage, c)) { + mName = m.getName(); + } + } + + if (mName != null) { + mappingTree.visitMethod(m.getName(), m.getDescriptor()); + mappingTree.visitDstName(MappedElementKind.METHOD, intermediaryIndex, mName); + } + } + + for (JarClassEntry cc : c.getInnerClasses()) { + addClass(cc, storageOld, storage, prefix + cName + "$"); + } + } + + public void prepareRewrite(File oldMappings) throws IOException { + oldToIntermediary = new GenMap(); + newToOld = new GenMap.Dummy(); + + readOldMappings(oldMappings).accept(mappingTree); + } + + public void prepareUpdate(File oldMappings, File matches) throws IOException { + oldToIntermediary = new GenMap(); + newToOld = new GenMap(); + + oldToIntermediary.load(readOldMappings(oldMappings)); + + try (FileReader fileReader = new FileReader(matches)) { + try (BufferedReader reader = new BufferedReader(fileReader)) { + MatcherUtil.read(reader, true, newToOld::addClass, newToOld::addField, newToOld::addMethod); + } + } + } + + private MappingTree readOldMappings(File oldMappings) throws IOException { + MemoryMappingTree tempTree = new MemoryMappingTree(); + mappingFileFormat = MappingReader.detectFormat(oldMappings.toPath()); + MappingReader.read(oldMappings.toPath(), mappingFileFormat, tempTree); + + validateNamespaces(tempTree); + readCountersFromTree(tempTree); + + return tempTree; + } + + private void readCounterFileIfPresent() throws IOException { + Path counterPath = getExternalCounterFile(); + + if (counterPath == null || !Files.exists(counterPath)) { + return; + } + + MappingFormat format = MappingReader.detectFormat(counterPath); + + if (format != null) { + MemoryMappingTree mappingTree = new MemoryMappingTree(); + MappingReader.read(counterPath, format, mappingTree); + readCountersFromTree(mappingTree); + counterFileFormat = format; + return; + } + + System.err.println("Counter file isn't a valid mapping file! Switching to fallback mode..."); + + try (FileReader fileReader = new FileReader(counterPath.toFile())) { + try (BufferedReader reader = new BufferedReader(fileReader)) { + String line; + + while ((line = reader.readLine()) != null) { + if (line.startsWith("# INTERMEDIARY-COUNTER")) { + String[] parts = line.split(" "); + counters.put(parts[2], Integer.parseInt(parts[3])); + } + } + } + } + } + + private void readCountersFromTree(MappingTree tree) { + String counter = tree.getMetadata("next-intermediary-class"); + if (counter != null) counters.put("class", Integer.parseInt(counter)); + + counter = tree.getMetadata("next-intermediary-field"); + if (counter != null) counters.put("field", Integer.parseInt(counter)); + + counter = tree.getMetadata("next-intermediary-method"); + if (counter != null) counters.put("method", Integer.parseInt(counter)); + } + + private void writeCounters() throws IOException { + clearCounterMetadata(); + Path counterPath = getExternalCounterFile(); + MemoryMappingTree mappingTree; + + if (counterPath == null) { + mappingTree = this.mappingTree; + } else { + mappingTree = new MemoryMappingTree(); + mappingTree.visitNamespaces(official, Arrays.asList(intermediary)); + } + + mappingTree.visitMetadata("next-intermediary-class", counters.getOrDefault("class", 0).toString()); + mappingTree.visitMetadata("next-intermediary-field", counters.getOrDefault("field", 0).toString()); + mappingTree.visitMetadata("next-intermediary-method", counters.getOrDefault("method", 0).toString()); + + if (counterPath != null) { + MappingWriter writer = MappingWriter.create(counterPath, counterFileFormat); + mappingTree.accept(writer); + writer.close(); + } + } + + private Path getExternalCounterFile() { + if (System.getProperty("stitch.counter") != null) { + return Paths.get(System.getProperty("stitch.counter")); + } + + return null; + } } diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandMergeTinyV2.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandMergeTinyV2.java deleted file mode 100644 index 4257ec0..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandMergeTinyV2.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.util.Pair; - -/** - * Merges a tiny file with 2 columns (namespaces) of mappings, with another tiny file that has - * the same namespace as the first column and a different namespace as the second column. - * The first column of the output will contain the shared namespace, - * the second column of the output would be the second namespace of input a, - * and the third column of the output would be the second namespace of input b - *

- * Descriptors will remain as-is (using the namespace of the first column) - *

- *

- * For example: - *

- * Input A: - * intermediary named - * c net/minecraft/class_123 net/minecraft/somePackage/someClass - * m (Lnet/minecraft/class_124;)V method_1234 someMethod - *

- * Input B: - * intermediary official - * c net/minecraft/class_123 a - * m (Lnet/minecraft/class_124;)V method_1234 a - *

- * The output will be: - *

- * intermediary named official - * c net/minecraft/class_123 net/minecraft/somePackage/someClass a - * m (Lnet/minecraft/class_124;)V method_1234 someMethod a - *

- *

- * After intermediary-named mappings are obtained, - * and official-intermediary mappings are obtained and swapped using CommandReorderTinyV2, Loom merges them using this command, - * and then reorders it to official-intermediary-named using CommandReorderTinyV2 again. - * This is a convenient way of storing all the mappings in Loom. - */ -public class CommandMergeTinyV2 extends Command { - public CommandMergeTinyV2() { - super("mergeTinyV2"); - } - - /** - * and are the tiny files to be merged. The result will be written to . - */ - @Override - public String getHelpString() { - return " "; - } - - @Override - public boolean isArgumentCountValid(int count) { - return count == 3; - } - - @Override - public void run(String[] args) throws IOException { - Path inputA = Paths.get(args[0]); - Path inputB = Paths.get(args[1]); - System.out.println("Reading " + inputA); - TinyFile tinyFileA = TinyV2Reader.read(inputA); - System.out.println("Reading " + inputB); - TinyFile tinyFileB = TinyV2Reader.read(inputB); - TinyHeader headerA = tinyFileA.getHeader(); - TinyHeader headerB = tinyFileB.getHeader(); - if (headerA.getNamespaces().size() != 2) { - throw new IllegalArgumentException(inputA + " must have exactly 2 namespaces."); - } - if (headerB.getNamespaces().size() != 2) { - throw new IllegalArgumentException(inputB + " must have exactly 2 namespaces."); - } - - if (!headerA.getNamespaces().get(0).equals(headerB.getNamespaces().get(0))) { - throw new IllegalArgumentException( - String.format("The input tiny files must have the same namespaces as the first column. " + - "(%s has %s while %s has %s)", - inputA, headerA.getNamespaces().get(0), inputB, headerB.getNamespaces().get(0)) - ); - } - System.out.println("Merging " + inputA + " with " + inputB); - TinyFile mergedFile = merge(tinyFileA, tinyFileB); - - TinyV2Writer.write(mergedFile, Paths.get(args[2])); - System.out.println("Merged mappings written to " + Paths.get(args[2])); - } - - - private TinyFile merge(TinyFile inputA, TinyFile inputB) { - //TODO: how to merge properties? - - TinyHeader mergedHeader = mergeHeaders(inputA.getHeader(), inputB.getHeader()); - - List keyUnion = keyUnion(inputA.getClassEntries(), inputB.getClassEntries()); - - Map inputAClasses = inputA.mapClassesByFirstNamespace(); - Map inputBClasses = inputB.mapClassesByFirstNamespace(); - List mergedClasses = map(keyUnion, key -> { - TinyClass classA = inputAClasses.get(key); - TinyClass classB = inputBClasses.get(key); - - classA = matchEnclosingClassIfNeeded(key, classA, inputAClasses); - classB = matchEnclosingClassIfNeeded(key, classB, inputBClasses); - return mergeClasses(key, classA, classB); - }); - - return new TinyFile(mergedHeader, mergedClasses); - } - - private TinyClass matchEnclosingClassIfNeeded(String key, TinyClass tinyClass, Map mappings) { - if (tinyClass == null) { - String partlyMatchedClassName = matchEnclosingClass(key, mappings); - return new TinyClass(Arrays.asList(key, partlyMatchedClassName)); - } else { - return tinyClass; - } - } - - /** - * Takes something like net/minecraft/class_123$class_124 that doesn't have a mapping, tries to find net/minecraft/class_123 - * , say the mapping of net/minecraft/class_123 is path/to/someclass and then returns a class of the form - * path/to/someclass$class124 - */ - @Nonnull - private String matchEnclosingClass(String sharedName, Map inputBClassBySharedNamespace) { - String[] path = sharedName.split(escape("$")); - int parts = path.length; - for (int i = parts - 2; i >= 0; i--) { - String currentPath = String.join("$", Arrays.copyOfRange(path, 0, i + 1)); - TinyClass match = inputBClassBySharedNamespace.get(currentPath); - - if (match != null && !match.getClassNames().get(1).isEmpty()) { - return match.getClassNames().get(1) - + "$" + String.join("$", Arrays.copyOfRange(path, i + 1, path.length)); - - } - } - - return sharedName; - } - - - private TinyClass mergeClasses(String sharedClassName, @Nonnull TinyClass classA, @Nonnull TinyClass classB) { - List mergedNames = mergeNames(sharedClassName, classA, classB); - List mergedComments = mergeComments(classA.getComments(), classB.getComments()); - - List> methodKeyUnion = union(mapToFirstNamespaceAndDescriptor(classA), mapToFirstNamespaceAndDescriptor(classB)); - Map, TinyMethod> methodsA = classA.mapMethodsByFirstNamespaceAndDescriptor(); - Map, TinyMethod> methodsB = classB.mapMethodsByFirstNamespaceAndDescriptor(); - List mergedMethods = map(methodKeyUnion, - (Pair k) -> mergeMethods(k.getLeft(), methodsA.get(k), methodsB.get(k))); - - List fieldKeyUnion = keyUnion(classA.getFields(), classB.getFields()); - Map fieldsA = classA.mapFieldsByFirstNamespace(); - Map fieldsB = classB.mapFieldsByFirstNamespace(); - List mergedFields = map(fieldKeyUnion, k -> mergeFields(k, fieldsA.get(k), fieldsB.get(k))); - - return new TinyClass(mergedNames, mergedMethods, mergedFields, mergedComments); - } - - private static final TinyMethod EMPTY_METHOD = new TinyMethod(null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); - - - private TinyMethod mergeMethods(String sharedMethodName, @Nullable TinyMethod methodA, @Nullable TinyMethod methodB) { - List mergedNames = mergeNames(sharedMethodName, methodA, methodB); - if (methodA == null) methodA = EMPTY_METHOD; - if (methodB == null) methodB = EMPTY_METHOD; - List mergedComments = mergeComments(methodA.getComments(), methodB.getComments()); - - String descriptor = methodA.getMethodDescriptorInFirstNamespace() != null ? methodA.getMethodDescriptorInFirstNamespace() - : methodB.getMethodDescriptorInFirstNamespace(); - if (descriptor == null) throw new RuntimeException("no descriptor for key " + sharedMethodName); - - - //TODO: this won't work too well when the first namespace is named or there is more than one named namespace (hack) - List mergedParameters = new ArrayList<>(); - addParameters(methodA, mergedParameters, 2); - addParameters(methodB, mergedParameters, 1); - - List mergedLocalVariables = new ArrayList<>(); - addLocalVariables(methodA, mergedLocalVariables, 2); - addLocalVariables(methodB, mergedLocalVariables, 1); - - return new TinyMethod(descriptor, mergedNames, mergedParameters, mergedLocalVariables, mergedComments); - } - - private void addParameters(TinyMethod method, List addTo, int emptySpacePos) { - for (TinyMethodParameter localVariable : method.getParameters()) { - List names = new ArrayList<>(localVariable.getParameterNames()); - names.add(emptySpacePos, ""); - addTo.add(new TinyMethodParameter(localVariable.getLvIndex(), names, localVariable.getComments())); - } - } - - private void addLocalVariables(TinyMethod method, List addTo, int emptySpacePos) { - for (TinyLocalVariable localVariable : method.getLocalVariables()) { - List names = new ArrayList<>(localVariable.getLocalVariableNames()); - names.add(emptySpacePos, ""); - addTo.add(new TinyLocalVariable(localVariable.getLvIndex(), localVariable.getLvStartOffset(), - localVariable.getLvTableIndex(), names, localVariable.getComments())); - } - } - - - private TinyField mergeFields(String sharedFieldName, @Nullable TinyField fieldA, @Nullable TinyField fieldB) { - List mergedNames = mergeNames(sharedFieldName, fieldA, fieldB); - List mergedComments = mergeComments(fieldA != null ? fieldA.getComments() : Collections.emptyList(), - fieldB != null ? fieldB.getComments() : Collections.emptyList()); - - String descriptor = fieldA != null ? fieldA.getFieldDescriptorInFirstNamespace() - : fieldB != null ? fieldB.getFieldDescriptorInFirstNamespace() : null; - if (descriptor == null) throw new RuntimeException("no descriptor for key " + sharedFieldName); - - return new TinyField(descriptor, mergedNames, mergedComments); - } - - private TinyHeader mergeHeaders(TinyHeader headerA, TinyHeader headerB) { - List namespaces = new ArrayList<>(headerA.getNamespaces()); - namespaces.add(headerB.getNamespaces().get(1)); - // TODO: how should versions and properties be merged? - return new TinyHeader(namespaces, headerA.getMajorVersion(), headerA.getMinorVersion(), headerA.getProperties()); - } - - private List mergeComments(Collection commentsA, Collection commentsB) { - return union(commentsA, commentsB); - } - - private List keyUnion(Collection mappingsA, Collection mappingB) { - return union(mappingsA.stream().map(m -> m.getMapping().get(0)), mappingB.stream().map(m -> m.getMapping().get(0))); - } - - private Stream> mapToFirstNamespaceAndDescriptor(TinyClass tinyClass) { - return tinyClass.getMethods().stream().map(m -> Pair.of(m.getMapping().get(0), m.getMethodDescriptorInFirstNamespace())); - } - - - private List mergeNames(String key, @Nullable Mapping mappingA, @Nullable Mapping mappingB) { - List merged = new ArrayList<>(); - merged.add(key); - merged.add(mappingExists(mappingA) ? mappingA.getMapping().get(1) : key); - merged.add(mappingExists(mappingB) ? mappingB.getMapping().get(1) : key); - - return merged; - } - - private boolean mappingExists(@Nullable Mapping mapping) { - return mapping != null && !mapping.getMapping().get(1).isEmpty(); - } - - private List union(Stream list1, Stream list2) { - return union(list1.collect(Collectors.toList()), list2.collect(Collectors.toList())); - } - - private List union(Collection list1, Collection list2) { - Set set = new HashSet(); - - set.addAll(list1); - set.addAll(list2); - - return new ArrayList(set); - } - - private static String escape(String str) { - return Pattern.quote(str); - } - - private List map(List from, Function mapper) { - return from.stream().map(mapper).collect(Collectors.toList()); - } - -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandProposeV2FieldNames.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandProposeV2FieldNames.java deleted file mode 100644 index 6e74d77..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandProposeV2FieldNames.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -import com.google.common.collect.Lists; - -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.util.FieldNameFinder; - -import javax.annotation.Nullable; - -/** - * Java stores the names of enums in the bytecode, and obfuscation doesn't get rid of it. We can use this for easy mappings. - * This command adds all of the field mappings that FieldNameFinder finds (it overwrites existing mappings for those names). - * This gets called as the last step after merging and reordering in loom. - */ -public class CommandProposeV2FieldNames extends Command { - public CommandProposeV2FieldNames() { - super("proposeV2FieldNames"); - } - - /** - * is any Minecraft jar, and are mappings of that jar (the same version). - * with the additional field names will be written to .+ - * Assumes the input mappings are intermediary->yarn mappings! - * is a boolean ("true" or "false") deciding if existing yarn names should be replaced by the generated names. - */ - @Override - public String getHelpString() { - return " "; - } - - @Override - public boolean isArgumentCountValid(int count) { - return count == 4; - } - - private Map generatedNamesOfClass(TinyClass tinyClass) { - return tinyClass.getFields().stream().collect(Collectors.toMap( - (TinyField field) -> new EntryTriple(tinyClass.getClassNames().get(0), field.getFieldNames().get(0), field.getFieldDescriptorInFirstNamespace()) - , field -> field)); - } - - @Override - public void run(String[] args) throws Exception { - File inputJar = new File(args[0]); - Path inputMappings = Paths.get(args[1]); - Path outputMappings = Paths.get(args[2]); - Boolean shouldReplace = parseBooleanOrNull(args[3]); - - // Validation - if(!inputJar.exists()) throw new IllegalArgumentException("Cannot find input jar at " + inputJar); - if(!Files.exists(inputMappings)) throw new IllegalArgumentException("Cannot find input mappings at " + inputMappings); - if(Files.exists(outputMappings)) System.out.println("Warning: existing file will be replaced by output mappings"); - if(shouldReplace == null) throw new IllegalArgumentException(" must be 'true' or 'false'"); - - // entrytriple from the input jar namespace - Map generatedFieldNames = new FieldNameFinder().findNames(new File(args[0])); - System.err.println("Found " + generatedFieldNames.size() + " interesting names."); - - TinyFile tinyFile = TinyV2Reader.read(Paths.get(args[1])); - Map fieldsMap = new HashMap<>(); - tinyFile.getClassEntries().stream().map(this::generatedNamesOfClass).forEach(map -> map.forEach(fieldsMap::put)); - Map classMap = tinyFile.mapClassesByFirstNamespace(); - - int replaceCount = 0; - for (Map.Entry entry : generatedFieldNames.entrySet()) { - EntryTriple key = entry.getKey(); - String newName = entry.getValue(); - TinyField field = fieldsMap.get(key); - // If the field name exists, replace the name with the auto-generated name, as long as is true. - if (field != null) { - if (shouldReplace) { - field.getFieldNames().set(1, newName); - replaceCount++; - } - } else { - TinyClass tinyClass = classMap.get(key.getOwner()); - // If field name does not exist, but its class does exist, create a new mapping with the supplied generated name. - if (tinyClass != null) { - tinyClass.getFields().add(new TinyField(key.getDesc(), Lists.newArrayList(key.getName(), newName), Lists.newArrayList())); - replaceCount++; - } - } - - } - - System.err.println("Replaced " + replaceCount + " names in the mappings."); - - Path newMappingsLocation = Paths.get(args[2]); - - TinyV2Writer.write(tinyFile, newMappingsLocation); - } - - @Nullable - private Boolean parseBooleanOrNull(String booleanLiteral) { - String lowerCase = booleanLiteral.toLowerCase(); - if (lowerCase.equals("true")) return Boolean.TRUE; - else if (lowerCase.equals("false")) return Boolean.FALSE; - else return null; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandReorderTinyV2.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandReorderTinyV2.java deleted file mode 100644 index bcf1e36..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/CommandReorderTinyV2.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import com.google.common.base.Strings; - -import net.fabricmc.stitch.Command; - -/** - * - Reorders the columns in the tiny file - * - Remaps the descriptors to use the newly first column. - *

- * For example: - *

- * This: - * intermediary named official - * c net/minecraft/class_123 net/minecraft/somePackage/someClass a - * m (Lnet/minecraft/class_124;)V method_1234 someMethod a - *

- * Reordered to official intermediary named: - * official intermediary named - * c a net/minecraft/class_123 net/minecraft/somePackage/someClass - * m (La;)V a method_1234 someMethod - *

- * This is used to reorder the the official-intermediary mappings to be intermediary-official, so they can be merged with - * intermediary-named in CommandMergeTinyV2, and then reorder the outputted intermediary-official-named to official-intermediary-named. - */ -public class CommandReorderTinyV2 extends Command { - public CommandReorderTinyV2() { - super("reorderTinyV2"); - } - - /** - * Reorders the columns in according to [new name order...] and puts the result in . - * new name order is for example "official intermediary named" - */ - @Override - public String getHelpString() { - return " [new name order...]"; - } - - @Override - public boolean isArgumentCountValid(int count) { - return count >= 4; - } - - @Override - public void run(String[] args) throws Exception { - Path oldMappingFile = Paths.get(args[0]); - Path newMappingFile = Paths.get(args[1]); - List newOrder = Arrays.asList(Arrays.copyOfRange(args, 2, args.length)); - - TinyFile tinyFile = TinyV2Reader.read(oldMappingFile); - validateNamespaces(newOrder, tinyFile); - - Map mappingCopy = tinyFile.getClassEntries().stream() - .collect(Collectors.toMap(c -> c.getClassNames().get(0), - c -> new TinyClass(new ArrayList<>(c.getClassNames()), c.getMethods(), c.getFields(), c.getComments()))); - int newFirstNamespaceOldIndex = tinyFile.getHeader().getNamespaces().indexOf(newOrder.get(0)); - - reorder(tinyFile, newOrder); - remapDescriptors(tinyFile, mappingCopy, newFirstNamespaceOldIndex); - - TinyV2Writer.write(tinyFile, newMappingFile); - } - - private void validateNamespaces(List newOrder, TinyFile tinyFile) { - HashSet fileNamespacesOrderless = new HashSet<>(tinyFile.getHeader().getNamespaces()); - HashSet providedNamespacesOrderless = new HashSet<>(newOrder); - - if (!fileNamespacesOrderless.equals(providedNamespacesOrderless)) { - throw new IllegalArgumentException("The tiny file has different namespaces than those specified." + - " specified: " + providedNamespacesOrderless.toString() + ", file: " + fileNamespacesOrderless.toString()); - } - } - - private void reorder(TinyFile tinyFile, List newOrder) { - Map indexMapping = new HashMap<>(); - for (int i = 0; i < newOrder.size(); i++) { - indexMapping.put(tinyFile.getHeader().getNamespaces().indexOf(newOrder.get(i)), i); - } - - visitNames(tinyFile, (names) -> { - // This way empty names won't be skipped - for (int i = names.size(); i < newOrder.size(); i++) { - names.add(""); - } - List namesCopy = new ArrayList<>(names); - for (int i = 0; i < namesCopy.size(); i++) { - names.set(indexMapping.get(i), namesCopy.get(i)); - } - }); - } - - private void remapDescriptors(TinyFile tinyFile, Map mappings, int targetNamespace) { - for (TinyClass tinyClass : tinyFile.getClassEntries()) { - for (TinyMethod method : tinyClass.getMethods()) { - remapMethodDescriptor(method, mappings, targetNamespace); - } - for (TinyField field : tinyClass.getFields()) { - remapFieldDescriptor(field, mappings, targetNamespace); - } - } - } - - - /** - * In this case the visitor is not a nice man and reorganizes the house as he sees fit - */ - private void visitNames(TinyFile tinyFile, Consumer> namesVisitor) { - namesVisitor.accept(tinyFile.getHeader().getNamespaces()); - for (TinyClass tinyClass : tinyFile.getClassEntries()) { - namesVisitor.accept(tinyClass.getClassNames()); - for (TinyMethod method : tinyClass.getMethods()) { - namesVisitor.accept(method.getMethodNames()); - for (TinyMethodParameter parameter : method.getParameters()) { - namesVisitor.accept(parameter.getParameterNames()); - } - for (TinyLocalVariable localVariable : method.getLocalVariables()) { - namesVisitor.accept(localVariable.getLocalVariableNames()); - } - } - for (TinyField field : tinyClass.getFields()) { - namesVisitor.accept(field.getFieldNames()); - } - } - } - - private void remapFieldDescriptor(TinyField field, Map mappings, int targetNamespace) { - String newDescriptor = remapType(field.getFieldDescriptorInFirstNamespace(), mappings, targetNamespace); - field.setFieldDescriptorInFirstNamespace(newDescriptor); - } - - ////////////////// This part can be replaced with a descriptor parser library - // (I already have one, not sure if I should add it) - - private void remapMethodDescriptor(TinyMethod method, Map mappings, int targetNamespace) { - String descriptor = method.getMethodDescriptorInFirstNamespace(); - String[] paramsAndReturnType = descriptor.split(Pattern.quote(")")); - if (paramsAndReturnType.length != 2) { - throw new IllegalArgumentException( - "method descriptor '" + descriptor + "' is of an unknown format."); - } - List params = parseParameterDescriptors(paramsAndReturnType[0].substring(1)); - String returnType = paramsAndReturnType[1]; - - List paramsMapped = params.stream().map(p -> remapType(p, mappings, targetNamespace)).collect(Collectors.toList()); - String returnTypeMapped = returnType.equals("V") ? "V" : remapType(returnType, mappings, targetNamespace); - - String newDescriptor = "(" + String.join("", paramsMapped) + ")" + returnTypeMapped; - method.setMethodDescriptorInFirstNamespace(newDescriptor); - - } - - private static final Collection primitiveTypeNames = Arrays.asList("B", "C", "D", "F", "I", "J", "S", "Z"); - - - private List parseParameterDescriptors(String concatenatedParameterDescriptors) { - List parameterDescriptors = new ArrayList<>(); - boolean inClassName = false; - int inArrayNestingLevel = 0; - StringBuilder currentClassName = new StringBuilder(); - - for (int i = 0; i < concatenatedParameterDescriptors.length(); i++) { - char c = concatenatedParameterDescriptors.charAt(i); - if (inClassName) { - if (c == ';') { - if (currentClassName.length() == 0) { - throw new IllegalArgumentException( - "Empty class name in parameter list " + concatenatedParameterDescriptors + " at position " + i); - } - parameterDescriptors.add(Strings.repeat("[", inArrayNestingLevel) + "L" + currentClassName.toString() + ";"); - inArrayNestingLevel = 0; - currentClassName = new StringBuilder(); - inClassName = false; - } else { - currentClassName.append(c); - } - } else { - if (primitiveTypeNames.contains(Character.toString(c))) { - parameterDescriptors.add(Strings.repeat("[", inArrayNestingLevel) + c); - inArrayNestingLevel = 0; - } else if (c == '[') { - inArrayNestingLevel++; - } else if (c == 'L') { - inClassName = true; - } else { - throw new IllegalArgumentException( - "Unexpected special character " + c + " in parameter descriptor list " - + concatenatedParameterDescriptors); - } - } - - } - - return parameterDescriptors; - - } - - - /** - * Remaps type from namespace X, to the namespace of targetNamespaceIndex in mappings, where mappings - * is a mapping from names in namespace X to the names in all other namespaces. - */ - private String remapType(String type, Map mappings, int targetNamespaceIndex) { - if (type.isEmpty()) throw new IllegalArgumentException("types cannot be empty strings"); - if (primitiveTypeNames.contains(type)) return type; - if (type.charAt(0) == '[') { - return "[" + remapType(type.substring(1), mappings, targetNamespaceIndex); - } - if (type.charAt(0) == 'L' && type.charAt(type.length() - 1) == ';') { - String className = type.substring(1, type.length() - 1); - TinyClass mapping = mappings.get(className); - String remappedName = mapping != null ? mapping.getClassNames().get(targetNamespaceIndex) : className; - return "L" + remappedName + ";"; - } - - throw new IllegalArgumentException("type descriptor '" + type + "' is of an unknown format."); - - } - - -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/Mapping.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/Mapping.java deleted file mode 100644 index 6502baa..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/Mapping.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.List; - -public interface Mapping { - List getMapping(); -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyClass.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyClass.java deleted file mode 100644 index 2b7c9f6..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyClass.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import net.fabricmc.stitch.util.Pair; - -public class TinyClass implements Comparable, Mapping { - @Override - public String toString() { - return "TinyClass(names = [" + String.join(", ", classNames) + "], " + methods.size() + " methods, " - + fields.size() + " fields, " + comments.size() + " comments)"; - } - - private final List classNames; - private final Collection methods; - private final Collection fields; - private final Collection comments; - - public TinyClass(List classNames, Collection methods, Collection fields, Collection comments) { - this.classNames = classNames; - this.methods = methods; - this.fields = fields; - this.comments = comments; - } - - public TinyClass(List classNames) { - this.classNames = classNames; - this.methods = new ArrayList<>(); - this.fields = new ArrayList<>(); - this.comments = new ArrayList<>(); - } - - - /** - * Descriptors are also taken into account because methods can overload. - * The key format is firstMethodName + descriptor - */ - public Map, TinyMethod> mapMethodsByFirstNamespaceAndDescriptor() { - return methods.stream().collect(Collectors.toMap(m -> Pair.of(m.getMethodNames().get(0), m.getMethodDescriptorInFirstNamespace()), m -> m)); - } - - public Map mapFieldsByFirstNamespace() { - return fields.stream().collect(Collectors.toMap(f -> f.getFieldNames().get(0), f -> f)); - } - - - public List getClassNames() { - return classNames; - } - - public Collection getMethods() { - return methods; - } - - public Collection getFields() { - return fields; - } - - public Collection getComments() { - return comments; - } - - @Override - public int compareTo(TinyClass o) { - return classNames.get(0).compareTo(o.classNames.get(0)); - } - - @Override - public List getMapping() { - return classNames; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyField.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyField.java deleted file mode 100644 index 543faa2..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyField.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.Collection; -import java.util.List; - -public class TinyField implements Comparable, Mapping { - - /** - * For example when we have official -> named mappings the descriptor will be in official, but in named -> official - * the descriptor will be in named. - */ - private String fieldDescriptorInFirstNamespace; - private final List fieldNames; - private final Collection comments; - - public TinyField(String fieldDescriptorInFirstNamespace, List fieldNames, Collection comments) { - this.fieldDescriptorInFirstNamespace = fieldDescriptorInFirstNamespace; - this.fieldNames = fieldNames; - this.comments = comments; - } - - public String getFieldDescriptorInFirstNamespace() { - return fieldDescriptorInFirstNamespace; - } - - public List getFieldNames() { - return fieldNames; - } - - public Collection getComments() { - return comments; - } - - @Override - public int compareTo(TinyField o) { - return fieldNames.get(0).compareTo(o.fieldNames.get(0)); - } - - public void setFieldDescriptorInFirstNamespace(String fieldDescriptorInFirstNamespace) { - this.fieldDescriptorInFirstNamespace = fieldDescriptorInFirstNamespace; - } - - @Override - public List getMapping() { - return fieldNames; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyFile.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyFile.java deleted file mode 100644 index 9e12721..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyFile.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.Collection; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * All lists and collections in this AST are mutable. - */ -public class TinyFile { - private final TinyHeader header; - private final Collection classEntries; - - public TinyFile(TinyHeader header, Collection classEntries) { - this.header = header; - this.classEntries = classEntries; - } - - /** - * The key will be the name of the class in the first namespace, the value is the same as classEntries. - * Useful for quickly retrieving a class based on a known name in the first namespace. - */ - public Map mapClassesByFirstNamespace() { - return classEntries.stream().collect(Collectors.toMap(c -> c.getClassNames().get(0), c -> c)); - } - - public TinyHeader getHeader() { - return header; - } - - public Collection getClassEntries() { - return classEntries; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyHeader.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyHeader.java deleted file mode 100644 index a6be00d..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyHeader.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.List; -import java.util.Map; - -public class TinyHeader { - - private final List namespaces; - private final int majorVersion; - private final int minorVersion; - private final Map properties; - - public TinyHeader(List namespaces, int majorVersion, int minorVersion, Map properties) { - this.namespaces = namespaces; - this.majorVersion = majorVersion; - this.minorVersion = minorVersion; - this.properties = properties; - } - - public List getNamespaces() { - return namespaces; - } - - public int getMajorVersion() { - return majorVersion; - } - - public int getMinorVersion() { - return minorVersion; - } - - public Map getProperties() { - return properties; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyLocalVariable.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyLocalVariable.java deleted file mode 100644 index 56e0495..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyLocalVariable.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.Collection; -import java.util.List; - -public class TinyLocalVariable implements Comparable, Mapping { - - private final int lvIndex; - private final int lvStartOffset; - /** - * Will be -1 when there is no lvt index - */ - private final int lvTableIndex; - private final List localVariableNames; - private final Collection comments; - - public TinyLocalVariable(int lvIndex, int lvStartOffset, int lvTableIndex, List localVariableNames, Collection comments) { - this.lvIndex = lvIndex; - this.lvStartOffset = lvStartOffset; - this.lvTableIndex = lvTableIndex; - this.localVariableNames = localVariableNames; - this.comments = comments; - } - - - public int getLvIndex() { - return lvIndex; - } - - public int getLvStartOffset() { - return lvStartOffset; - } - - public int getLvTableIndex() { - return lvTableIndex; - } - - public List getLocalVariableNames() { - return localVariableNames; - } - - public Collection getComments() { - return comments; - } - - @Override - public int compareTo(TinyLocalVariable o) { - return localVariableNames.get(0).compareTo(o.localVariableNames.get(0)); - } - - @Override - public List getMapping() { - return localVariableNames; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyMethod.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyMethod.java deleted file mode 100644 index 14c2796..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyMethod.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -public class TinyMethod implements Comparable, Mapping { - - @Override - public String toString() { - return "TinyMethod(names = [" + String.join(", ", methodNames) + "], desc = " + methodDescriptorInFirstNamespace - + ", " + parameters.size() + " params, " - + localVariables.size() + " vars, " + comments.size() + " comments)"; - } - - /** - * For example when we have official -> named mappings the descriptor will be in official, but in named -> official - * the descriptor will be in named. - */ - private String methodDescriptorInFirstNamespace; - private final List methodNames; - private final Collection parameters; - private final Collection localVariables; - private final Collection comments; - - public TinyMethod(String methodDescriptorInFirstNamespace, List methodNames, Collection parameters, Collection localVariables, Collection comments) { - this.methodDescriptorInFirstNamespace = methodDescriptorInFirstNamespace; - this.methodNames = methodNames; - this.parameters = parameters; - this.localVariables = localVariables; - this.comments = comments; - } - - public Map mapParametersByFirstNamespace() { - return parameters.stream().collect(Collectors.toMap(p -> p.getParameterNames().get(0), p -> p)); - } - - public Map mapLocalVariablesByFirstNamespace() { - return localVariables.stream().collect(Collectors.toMap(lv -> lv.getLocalVariableNames().get(0), lv -> lv)); - } - - public String getMethodDescriptorInFirstNamespace() { - return methodDescriptorInFirstNamespace; - } - - public List getMethodNames() { - return methodNames; - } - - public Collection getParameters() { - return parameters; - } - - public Collection getLocalVariables() { - return localVariables; - } - - public Collection getComments() { - return comments; - } - - @Override - public int compareTo(TinyMethod o) { - return (methodNames.get(0) + methodDescriptorInFirstNamespace) - .compareTo(o.methodNames.get(0) + o.methodDescriptorInFirstNamespace); - } - - public void setMethodDescriptorInFirstNamespace(String methodDescriptorInFirstNamespace) { - this.methodDescriptorInFirstNamespace = methodDescriptorInFirstNamespace; - } - - @Override - public List getMapping() { - return methodNames; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyMethodParameter.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyMethodParameter.java deleted file mode 100644 index b4bc21d..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyMethodParameter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.util.Collection; -import java.util.List; - -public class TinyMethodParameter implements Comparable, Mapping { - private final int lvIndex; - private final List parameterNames; - private final Collection comments; - - public TinyMethodParameter(int lvIndex, List parameterNames, Collection comments) { - this.lvIndex = lvIndex; - this.parameterNames = parameterNames; - this.comments = comments; - } - - public int getLvIndex() { - return lvIndex; - } - - public List getParameterNames() { - return parameterNames; - } - - public Collection getComments() { - return comments; - } - - @Override - public int compareTo(TinyMethodParameter o) { - return lvIndex - o.lvIndex; - } - - @Override - public List getMapping() { - return parameterNames; - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyV2Reader.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyV2Reader.java deleted file mode 100644 index 1d935d4..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyV2Reader.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.io.BufferedReader; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.google.common.collect.Lists; - -import net.fabricmc.mapping.reader.v2.MappingGetter; -import net.fabricmc.mapping.reader.v2.TinyMetadata; -import net.fabricmc.mapping.reader.v2.TinyV2Factory; -import net.fabricmc.mapping.reader.v2.TinyVisitor; - -public class TinyV2Reader { - private static class Visitor implements TinyVisitor { - private enum CommentType { - CLASS, - FIELD, - METHOD, - PARAMETER, - LOCAL_VARIABLE - } - - private TinyHeader header; - private int namespaceAmount; - // private String - private Set classes = new HashSet<>(); - - private TinyClass currentClass; - private TinyField currentField; - private TinyMethod currentMethod; - private TinyMethodParameter currentParameter; - private TinyLocalVariable currentLocalVariable; - private CommentType currentCommentType; - private boolean inComment = false; - - private List getNames(MappingGetter getter) { - return Lists.newArrayList(getter.getRawNames()); - } - - @Override - public void start(TinyMetadata metadata) { - header = new TinyHeader(new ArrayList<>(metadata.getNamespaces()), metadata.getMajorVersion(), metadata.getMinorVersion(), - metadata.getProperties()); - namespaceAmount = header.getNamespaces().size(); - } - - @Override - public void pushClass(MappingGetter name) { - currentClass = new TinyClass(getNames(name), new HashSet<>(), new HashSet<>(), new ArrayList<>()); - classes.add(currentClass); - currentCommentType = CommentType.CLASS; - } - - @Override - public void pushField(MappingGetter name, String descriptor) { - currentField = new TinyField(descriptor, getNames(name), new ArrayList<>()); - currentClass.getFields().add(currentField); - currentCommentType = CommentType.FIELD; - } - - @Override - public void pushMethod(MappingGetter name, String descriptor) { - currentMethod = new TinyMethod( - descriptor, getNames(name), new HashSet<>(), new HashSet<>(), new ArrayList<>() - ); - currentClass.getMethods().add(currentMethod); - currentCommentType = CommentType.METHOD; - } - - @Override - public void pushParameter(MappingGetter name, int localVariableIndex) { - currentParameter = new TinyMethodParameter( - localVariableIndex, getNames(name), new ArrayList<>() - ); - currentMethod.getParameters().add(currentParameter); - currentCommentType = CommentType.PARAMETER; - } - - @Override - public void pushLocalVariable(MappingGetter name, int localVariableIndex, int localVariableStartOffset, int localVariableTableIndex) { - currentLocalVariable = new TinyLocalVariable( - localVariableIndex, localVariableStartOffset, localVariableTableIndex, getNames(name), new ArrayList<>() - ); - currentMethod.getLocalVariables().add(currentLocalVariable); - currentCommentType = CommentType.LOCAL_VARIABLE; - } - - @Override - public void pushComment(String comment) { - if (inComment) - throw new RuntimeException("commenting on comment"); - switch (currentCommentType) { - case CLASS: - currentClass.getComments().add(comment); - break; - case FIELD: - currentField.getComments().add(comment); - break; - case METHOD: - currentMethod.getComments().add(comment); - break; - case PARAMETER: - currentParameter.getComments().add(comment); - break; - case LOCAL_VARIABLE: - currentLocalVariable.getComments().add(comment); - break; - default: - throw new RuntimeException("unexpected comment without parent"); - } - inComment = true; - } - - @Override - public void pop(int count) { - for (int i = 0; i < count; i++) { - if (inComment) { - inComment = false; - continue; - } - - CommentType last = currentCommentType; - switch (last) { - case CLASS: - currentCommentType = null; - break; - case FIELD: - case METHOD: - currentCommentType = CommentType.CLASS; - break; - case PARAMETER: - case LOCAL_VARIABLE: - currentCommentType = CommentType.METHOD; - break; - default: - throw new IllegalStateException("visit stack is empty!"); - } - } - } - - private TinyFile getAST() { - return new TinyFile(header, classes); - } - } - - public static TinyFile read(Path readFrom) throws IOException { - Visitor visitor = new Visitor(); - try (BufferedReader reader = Files.newBufferedReader(readFrom)) { - TinyV2Factory.visit(reader, visitor); - } - - return visitor.getAST(); - } -} diff --git a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyV2Writer.java b/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyV2Writer.java deleted file mode 100644 index c27de9a..0000000 --- a/src/main/java/net/fabricmc/stitch/commands/tinyv2/TinyV2Writer.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.commands.tinyv2; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -public class TinyV2Writer { - public static void write(TinyFile tinyFile, Path writeTo) throws IOException { - new TinyV2Writer().instanceWrite(tinyFile, writeTo); - } - - private static class Prefixes { - private Prefixes() { - } - - public static final String PARAMETER = "p"; - public static final String METHOD = "m"; - public static final String VARIABLE = "v"; - public static final String HEADER = "tiny"; - public static final String FIELD = "f"; - public static final String COMMENT = "c"; - public static final String CLASS = "c"; - } - - private static class Indents { - private Indents() { - } - - public static final int HEADER = 0; - public static final int PROPERTY = 1; - public static final int CLASS = 0; - public static final int METHOD = 1; - public static final int FIELD = 1; - public static final int PARAMETER = 2; - public static final int LOCAL_VARIABLE = 2; - - public static final int CLASS_COMMENT = 1; - public static final int METHOD_COMMENT = 2; - public static final int FIELD_COMMENT = 2; - public static final int PARAMETER_COMMENT = 3; - public static final int LOCAL_VARIABLE_COMMENT = 3; - - - } - - private TinyV2Writer() { - } - - private BufferedWriter writer; - - private void instanceWrite(TinyFile tinyFile, Path writeTo) throws IOException { - try { - writer = Files.newBufferedWriter(writeTo); - writeHeader(tinyFile.getHeader()); - tinyFile.getClassEntries().stream().sorted().forEach(this::writeClass); - } finally { - writer.close(); - } - } - - - private void writeHeader(TinyHeader header) { - writeLine(Indents.HEADER, header.getNamespaces(), Prefixes.HEADER, - Integer.toString(header.getMajorVersion()), Integer.toString(header.getMinorVersion())); - header.getProperties().forEach((key, value) -> writeLine(Indents.PROPERTY, value)); - } - - private void writeClass(TinyClass tinyClass) { - writeLine(Indents.CLASS, tinyClass.getClassNames(), Prefixes.CLASS); - - for (String comment : tinyClass.getComments()) writeComment(Indents.CLASS_COMMENT, comment); - - tinyClass.getMethods().stream().sorted().forEach(this::writeMethod); - tinyClass.getFields().stream().sorted().forEach(this::writeField); - - } - - private void writeMethod(TinyMethod method) { - writeLine(Indents.METHOD, method.getMethodNames(), Prefixes.METHOD, method.getMethodDescriptorInFirstNamespace()); - - for (String comment : method.getComments()) writeComment(Indents.METHOD_COMMENT, comment); - - method.getParameters().stream().sorted().forEach(this::writeMethodParameter); - method.getLocalVariables().stream().sorted().forEach(this::writeLocalVariable); - - } - - private void writeMethodParameter(TinyMethodParameter parameter) { - writeLine(Indents.PARAMETER, parameter.getParameterNames(), Prefixes.PARAMETER, Integer.toString(parameter.getLvIndex())); - for (String comment : parameter.getComments()) { - writeComment(Indents.PARAMETER_COMMENT, comment); - } - - } - - private void writeLocalVariable(TinyLocalVariable localVariable) { - writeLine(Indents.LOCAL_VARIABLE, localVariable.getLocalVariableNames(), Prefixes.VARIABLE, - Integer.toString(localVariable.getLvIndex()), Integer.toString(localVariable.getLvStartOffset()), - Integer.toString(localVariable.getLvTableIndex()) - ); - - for (String comment : localVariable.getComments()) { - writeComment(Indents.LOCAL_VARIABLE_COMMENT, comment); - } - } - - private void writeField(TinyField field) { - writeLine(Indents.FIELD, field.getFieldNames(), Prefixes.FIELD, field.getFieldDescriptorInFirstNamespace()); - for (String comment : field.getComments()) writeComment(Indents.FIELD_COMMENT, comment); - } - - - private void writeComment(int indentLevel, String comment) { - writeLine(indentLevel, Prefixes.COMMENT, escapeComment(comment)); - } - - private static String escapeComment(String old) { - StringBuilder sb = new StringBuilder(old.length()); - for (int i = 0; i < old.length(); i++) { - char c = old.charAt(i); - int t = TO_ESCAPE.indexOf(c); - if (t == -1) { - sb.append(c); - } else { - sb.append('\\').append(ESCAPED.charAt(t)); - } - } - return sb.toString(); - } - - private static final String TO_ESCAPE = "\\\n\r\0\t"; - private static final String ESCAPED = "\\nr0t"; - - - private void write(int indentLevel, String... tabSeparatedStrings) { - try { - for (int i = 0; i < indentLevel; i++) writer.write('\t'); - - writer.write(String.join("\t", tabSeparatedStrings)); - } catch (IOException e) { - e.printStackTrace(); - } - } - - // names are written after the other strings - private void write(int indentLevel, List names, String... tabSeparatedStrings) { - try { - write(indentLevel, tabSeparatedStrings); - writer.write("\t"); - writer.write(String.join("\t", names)); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void writeLine() { - try { - writer.write('\n'); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void writeLine(int indentLevel, List names, String... tabSeparatedStrings) { - write(indentLevel, names, tabSeparatedStrings); - writeLine(); - } - - private void writeLine(int indentLevel, String... tabSeparatedStrings) { - write(indentLevel, tabSeparatedStrings); - writeLine(); - } -} diff --git a/src/main/java/net/fabricmc/stitch/enigma/StitchEnigmaPlugin.java b/src/main/java/net/fabricmc/stitch/enigma/StitchEnigmaPlugin.java deleted file mode 100644 index 8a820ec..0000000 --- a/src/main/java/net/fabricmc/stitch/enigma/StitchEnigmaPlugin.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.enigma; - -import cuchaz.enigma.api.EnigmaPlugin; -import cuchaz.enigma.api.EnigmaPluginContext; -import cuchaz.enigma.api.service.ObfuscationTestService; - -public class StitchEnigmaPlugin implements EnigmaPlugin { - - @Override - public void init(EnigmaPluginContext ctx) { - StitchNameProposalService.register(ctx); - ctx.registerService("stitch:intermediary_obfuscation_test", ObfuscationTestService.TYPE, StitchIntermediaryObfuscationTestService::new); - } - -} diff --git a/src/main/java/net/fabricmc/stitch/enigma/StitchIntermediaryObfuscationTestService.java b/src/main/java/net/fabricmc/stitch/enigma/StitchIntermediaryObfuscationTestService.java deleted file mode 100644 index 4580a47..0000000 --- a/src/main/java/net/fabricmc/stitch/enigma/StitchIntermediaryObfuscationTestService.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.enigma; - -import cuchaz.enigma.api.service.EnigmaServiceContext; -import cuchaz.enigma.api.service.ObfuscationTestService; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.translation.representation.entry.FieldEntry; -import cuchaz.enigma.translation.representation.entry.MethodEntry; - -public class StitchIntermediaryObfuscationTestService implements ObfuscationTestService { - private final String prefix, classPrefix, classPackagePrefix, fieldPrefix, methodPrefix; - - public StitchIntermediaryObfuscationTestService(EnigmaServiceContext context) { - this.prefix = context.getArgument("package").orElse("net/minecraft") + "/"; - this.classPrefix = context.getArgument("classPrefix").orElse("class_"); - this.fieldPrefix = context.getArgument("fieldPrefix").orElse("field_"); - this.methodPrefix = context.getArgument("methodPrefix").orElse("method_"); - - this.classPackagePrefix = this.prefix + this.classPrefix; - } - - @Override - public boolean testDeobfuscated(Entry entry) { - if (entry instanceof ClassEntry) { - ClassEntry ce = (ClassEntry) entry; - String[] components = ce.getFullName().split("\\$"); - - // all obfuscated components are, at their outermost, class_ - String lastComponent = components[components.length - 1]; - if (lastComponent.startsWith(this.classPrefix) || lastComponent.startsWith(this.classPackagePrefix)) { - return false; - } - } else if (entry instanceof FieldEntry) { - if (entry.getName().startsWith(this.fieldPrefix)) { - return false; - } - } else if (entry instanceof MethodEntry) { - if (entry.getName().startsWith(this.methodPrefix)) { - return false; - } - } else { - // unknown type - return false; - } - - // known type, not obfuscated - return true; - } -} diff --git a/src/main/java/net/fabricmc/stitch/enigma/StitchNameProposalService.java b/src/main/java/net/fabricmc/stitch/enigma/StitchNameProposalService.java deleted file mode 100644 index 52fda16..0000000 --- a/src/main/java/net/fabricmc/stitch/enigma/StitchNameProposalService.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.enigma; - -import cuchaz.enigma.analysis.index.JarIndex; -import cuchaz.enigma.api.EnigmaPluginContext; -import cuchaz.enigma.api.service.JarIndexerService; -import cuchaz.enigma.api.service.NameProposalService; -import cuchaz.enigma.classprovider.ClassProvider; -import cuchaz.enigma.translation.representation.entry.FieldEntry; -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.stitch.util.FieldNameFinder; -import net.fabricmc.stitch.util.NameFinderVisitor; -import net.fabricmc.stitch.util.StitchUtil; -import org.objectweb.asm.tree.MethodNode; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -public class StitchNameProposalService { - private Map fieldNames; - - private StitchNameProposalService(EnigmaPluginContext ctx) { - ctx.registerService("stitch:jar_indexer", JarIndexerService.TYPE, ctx1 -> new JarIndexerService() { - @Override - public void acceptJar(Set classNames, ClassProvider classProvider, JarIndex jarIndex) { - - Map> enumFields = new HashMap<>(); - Map> methods = new HashMap<>(); - - for (String className : classNames) { - classProvider.get(className).accept(new NameFinderVisitor(StitchUtil.ASM_VERSION, enumFields, methods)); - } - - try { - fieldNames = new FieldNameFinder().findNames(enumFields, methods); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - - ctx.registerService("stitch:name_proposal", NameProposalService.TYPE, ctx12 -> (obfEntry, remapper) -> { - if(obfEntry instanceof FieldEntry){ - FieldEntry fieldEntry = (FieldEntry) obfEntry; - EntryTriple key = new EntryTriple(fieldEntry.getContainingClass().getFullName(), fieldEntry.getName(), fieldEntry.getDesc().toString()); - return Optional.ofNullable(fieldNames.get(key)); - } - return Optional.empty(); - }); - } - - public static void register(EnigmaPluginContext ctx) { - new StitchNameProposalService(ctx); - } -} diff --git a/src/main/java/net/fabricmc/stitch/merge/ClassMerger.java b/src/main/java/net/fabricmc/stitch/merge/ClassMerger.java index 738a195..a739845 100644 --- a/src/main/java/net/fabricmc/stitch/merge/ClassMerger.java +++ b/src/main/java/net/fabricmc/stitch/merge/ClassMerger.java @@ -16,210 +16,226 @@ package net.fabricmc.stitch.merge; -import net.fabricmc.stitch.util.StitchUtil; -import org.objectweb.asm.*; -import org.objectweb.asm.tree.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InnerClassNode; +import org.objectweb.asm.tree.MethodNode; -import java.util.*; +import net.fabricmc.stitch.util.StitchUtil; public class ClassMerger { - private static final String SIDE_DESCRIPTOR = "Lnet/fabricmc/api/EnvType;"; - private static final String ITF_DESCRIPTOR = "Lnet/fabricmc/api/EnvironmentInterface;"; - private static final String ITF_LIST_DESCRIPTOR = "Lnet/fabricmc/api/EnvironmentInterfaces;"; - private static final String SIDED_DESCRIPTOR = "Lnet/fabricmc/api/Environment;"; - - private abstract class Merger { - private final Map entriesClient, entriesServer; - private final List entryNames; - - public Merger(List entriesClient, List entriesServer) { - this.entriesClient = new LinkedHashMap<>(); - this.entriesServer = new LinkedHashMap<>(); - - List listClient = toMap(entriesClient, this.entriesClient); - List listServer = toMap(entriesServer, this.entriesServer); - - this.entryNames = StitchUtil.mergePreserveOrder(listClient, listServer); - } - - public abstract String getName(T entry); - public abstract void applySide(T entry, String side); - - private final List toMap(List entries, Map map) { - List list = new ArrayList<>(entries.size()); - for (T entry : entries) { - String name = getName(entry); - map.put(name, entry); - list.add(name); - } - return list; - } - - public void merge(List list) { - for (String s : entryNames) { - T entryClient = entriesClient.get(s); - T entryServer = entriesServer.get(s); - - if (entryClient != null && entryServer != null) { - list.add(entryClient); - } else if (entryClient != null) { - applySide(entryClient, "CLIENT"); - list.add(entryClient); - } else { - applySide(entryServer, "SERVER"); - list.add(entryServer); - } - } - } - } - - private static void visitSideAnnotation(AnnotationVisitor av, String side) { - av.visitEnum("value", SIDE_DESCRIPTOR, side.toUpperCase(Locale.ROOT)); - av.visitEnd(); - } - - private static void visitItfAnnotation(AnnotationVisitor av, String side, List itfDescriptors) { - for (String itf : itfDescriptors) { - AnnotationVisitor avItf = av.visitAnnotation(null, ITF_DESCRIPTOR); - avItf.visitEnum("value", SIDE_DESCRIPTOR, side.toUpperCase(Locale.ROOT)); - avItf.visit("itf", Type.getType("L" + itf + ";")); - avItf.visitEnd(); - } - } - - public static class SidedClassVisitor extends ClassVisitor { - private final String side; - - public SidedClassVisitor(int api, ClassVisitor cv, String side) { - super(api, cv); - this.side = side; - } - - @Override - public void visitEnd() { - AnnotationVisitor av = cv.visitAnnotation(SIDED_DESCRIPTOR, true); - visitSideAnnotation(av, side); - super.visitEnd(); - } - } - - public ClassMerger() { - - } - - public byte[] merge(byte[] classClient, byte[] classServer) { - ClassReader readerC = new ClassReader(classClient); - ClassReader readerS = new ClassReader(classServer); - ClassWriter writer = new ClassWriter(0); - - ClassNode nodeC = new ClassNode(StitchUtil.ASM_VERSION); - readerC.accept(nodeC, 0); - - ClassNode nodeS = new ClassNode(StitchUtil.ASM_VERSION); - readerS.accept(nodeS, 0); - - ClassNode nodeOut = new ClassNode(StitchUtil.ASM_VERSION); - nodeOut.version = nodeC.version; - nodeOut.access = nodeC.access; - nodeOut.name = nodeC.name; - nodeOut.signature = nodeC.signature; - nodeOut.superName = nodeC.superName; - nodeOut.sourceFile = nodeC.sourceFile; - nodeOut.sourceDebug = nodeC.sourceDebug; - nodeOut.outerClass = nodeC.outerClass; - nodeOut.outerMethod = nodeC.outerMethod; - nodeOut.outerMethodDesc = nodeC.outerMethodDesc; - nodeOut.module = nodeC.module; - nodeOut.nestHostClass = nodeC.nestHostClass; - nodeOut.nestMembers = nodeC.nestMembers; - nodeOut.attrs = nodeC.attrs; - - if (nodeC.invisibleAnnotations != null) { - nodeOut.invisibleAnnotations = new ArrayList<>(); - nodeOut.invisibleAnnotations.addAll(nodeC.invisibleAnnotations); - } - if (nodeC.invisibleTypeAnnotations != null) { - nodeOut.invisibleTypeAnnotations = new ArrayList<>(); - nodeOut.invisibleTypeAnnotations.addAll(nodeC.invisibleTypeAnnotations); - } - if (nodeC.visibleAnnotations != null) { - nodeOut.visibleAnnotations = new ArrayList<>(); - nodeOut.visibleAnnotations.addAll(nodeC.visibleAnnotations); - } - if (nodeC.visibleTypeAnnotations != null) { - nodeOut.visibleTypeAnnotations = new ArrayList<>(); - nodeOut.visibleTypeAnnotations.addAll(nodeC.visibleTypeAnnotations); - } - - List itfs = StitchUtil.mergePreserveOrder(nodeC.interfaces, nodeS.interfaces); - nodeOut.interfaces = new ArrayList<>(); - - List clientItfs = new ArrayList<>(); - List serverItfs = new ArrayList<>(); - - for (String s : itfs) { - boolean nc = nodeC.interfaces.contains(s); - boolean ns = nodeS.interfaces.contains(s); - nodeOut.interfaces.add(s); - if (nc && !ns) { - clientItfs.add(s); - } else if (ns && !nc) { - serverItfs.add(s); - } - } - - if (!clientItfs.isEmpty() || !serverItfs.isEmpty()) { - AnnotationVisitor envInterfaces = nodeOut.visitAnnotation(ITF_LIST_DESCRIPTOR, false); - AnnotationVisitor eiArray = envInterfaces.visitArray("value"); - - if (!clientItfs.isEmpty()) { - visitItfAnnotation(eiArray, "CLIENT", clientItfs); - } - if (!serverItfs.isEmpty()) { - visitItfAnnotation(eiArray, "SERVER", serverItfs); - } - eiArray.visitEnd(); - envInterfaces.visitEnd(); - } - - new Merger(nodeC.innerClasses, nodeS.innerClasses) { - @Override - public String getName(InnerClassNode entry) { - return entry.name; - } - - @Override - public void applySide(InnerClassNode entry, String side) { - } - }.merge(nodeOut.innerClasses); - - new Merger(nodeC.fields, nodeS.fields) { - @Override - public String getName(FieldNode entry) { - return entry.name + ";;" + entry.desc; - } - - @Override - public void applySide(FieldNode entry, String side) { - AnnotationVisitor av = entry.visitAnnotation(SIDED_DESCRIPTOR, false); - visitSideAnnotation(av, side); - } - }.merge(nodeOut.fields); - - new Merger(nodeC.methods, nodeS.methods) { - @Override - public String getName(MethodNode entry) { - return entry.name + entry.desc; - } - - @Override - public void applySide(MethodNode entry, String side) { - AnnotationVisitor av = entry.visitAnnotation(SIDED_DESCRIPTOR, false); - visitSideAnnotation(av, side); - } - }.merge(nodeOut.methods); - - nodeOut.accept(writer); - return writer.toByteArray(); - } + private static final String SIDE_DESCRIPTOR = "Lnet/fabricmc/api/EnvType;"; + private static final String ITF_DESCRIPTOR = "Lnet/fabricmc/api/EnvironmentInterface;"; + private static final String ITF_LIST_DESCRIPTOR = "Lnet/fabricmc/api/EnvironmentInterfaces;"; + private static final String SIDED_DESCRIPTOR = "Lnet/fabricmc/api/Environment;"; + + private abstract class Merger { + private final Map entriesClient, entriesServer; + private final List entryNames; + + Merger(List entriesClient, List entriesServer) { + this.entriesClient = new LinkedHashMap<>(); + this.entriesServer = new LinkedHashMap<>(); + + List listClient = toMap(entriesClient, this.entriesClient); + List listServer = toMap(entriesServer, this.entriesServer); + + this.entryNames = StitchUtil.mergePreserveOrder(listClient, listServer); + } + + public abstract String getName(T entry); + public abstract void applySide(T entry, String side); + + private List toMap(List entries, Map map) { + List list = new ArrayList<>(entries.size()); + + for (T entry : entries) { + String name = getName(entry); + map.put(name, entry); + list.add(name); + } + + return list; + } + + public void merge(List list) { + for (String s : entryNames) { + T entryClient = entriesClient.get(s); + T entryServer = entriesServer.get(s); + + if (entryClient != null && entryServer != null) { + list.add(entryClient); + } else if (entryClient != null) { + applySide(entryClient, "CLIENT"); + list.add(entryClient); + } else { + applySide(entryServer, "SERVER"); + list.add(entryServer); + } + } + } + } + + private static void visitSideAnnotation(AnnotationVisitor av, String side) { + av.visitEnum("value", SIDE_DESCRIPTOR, side.toUpperCase(Locale.ROOT)); + av.visitEnd(); + } + + private static void visitItfAnnotation(AnnotationVisitor av, String side, List itfDescriptors) { + for (String itf : itfDescriptors) { + AnnotationVisitor avItf = av.visitAnnotation(null, ITF_DESCRIPTOR); + avItf.visitEnum("value", SIDE_DESCRIPTOR, side.toUpperCase(Locale.ROOT)); + avItf.visit("itf", Type.getType("L" + itf + ";")); + avItf.visitEnd(); + } + } + + public static class SidedClassVisitor extends ClassVisitor { + private final String side; + + public SidedClassVisitor(int api, ClassVisitor cv, String side) { + super(api, cv); + this.side = side; + } + + @Override + public void visitEnd() { + AnnotationVisitor av = cv.visitAnnotation(SIDED_DESCRIPTOR, true); + visitSideAnnotation(av, side); + super.visitEnd(); + } + } + + public byte[] merge(byte[] classClient, byte[] classServer) { + ClassReader readerC = new ClassReader(classClient); + ClassReader readerS = new ClassReader(classServer); + ClassWriter writer = new ClassWriter(0); + + ClassNode nodeC = new ClassNode(StitchUtil.ASM_VERSION); + readerC.accept(nodeC, 0); + + ClassNode nodeS = new ClassNode(StitchUtil.ASM_VERSION); + readerS.accept(nodeS, 0); + + ClassNode nodeOut = new ClassNode(StitchUtil.ASM_VERSION); + nodeOut.version = nodeC.version; + nodeOut.access = nodeC.access; + nodeOut.name = nodeC.name; + nodeOut.signature = nodeC.signature; + nodeOut.superName = nodeC.superName; + nodeOut.sourceFile = nodeC.sourceFile; + nodeOut.sourceDebug = nodeC.sourceDebug; + nodeOut.outerClass = nodeC.outerClass; + nodeOut.outerMethod = nodeC.outerMethod; + nodeOut.outerMethodDesc = nodeC.outerMethodDesc; + nodeOut.module = nodeC.module; + nodeOut.nestHostClass = nodeC.nestHostClass; + nodeOut.nestMembers = nodeC.nestMembers; + nodeOut.attrs = nodeC.attrs; + + if (nodeC.invisibleAnnotations != null) { + nodeOut.invisibleAnnotations = new ArrayList<>(); + nodeOut.invisibleAnnotations.addAll(nodeC.invisibleAnnotations); + } + + if (nodeC.invisibleTypeAnnotations != null) { + nodeOut.invisibleTypeAnnotations = new ArrayList<>(); + nodeOut.invisibleTypeAnnotations.addAll(nodeC.invisibleTypeAnnotations); + } + + if (nodeC.visibleAnnotations != null) { + nodeOut.visibleAnnotations = new ArrayList<>(); + nodeOut.visibleAnnotations.addAll(nodeC.visibleAnnotations); + } + + if (nodeC.visibleTypeAnnotations != null) { + nodeOut.visibleTypeAnnotations = new ArrayList<>(); + nodeOut.visibleTypeAnnotations.addAll(nodeC.visibleTypeAnnotations); + } + + List itfs = StitchUtil.mergePreserveOrder(nodeC.interfaces, nodeS.interfaces); + nodeOut.interfaces = new ArrayList<>(); + + List clientItfs = new ArrayList<>(); + List serverItfs = new ArrayList<>(); + + for (String s : itfs) { + boolean nc = nodeC.interfaces.contains(s); + boolean ns = nodeS.interfaces.contains(s); + nodeOut.interfaces.add(s); + + if (nc && !ns) { + clientItfs.add(s); + } else if (ns && !nc) { + serverItfs.add(s); + } + } + + if (!clientItfs.isEmpty() || !serverItfs.isEmpty()) { + AnnotationVisitor envInterfaces = nodeOut.visitAnnotation(ITF_LIST_DESCRIPTOR, false); + AnnotationVisitor eiArray = envInterfaces.visitArray("value"); + + if (!clientItfs.isEmpty()) { + visitItfAnnotation(eiArray, "CLIENT", clientItfs); + } + + if (!serverItfs.isEmpty()) { + visitItfAnnotation(eiArray, "SERVER", serverItfs); + } + + eiArray.visitEnd(); + envInterfaces.visitEnd(); + } + + new Merger(nodeC.innerClasses, nodeS.innerClasses) { + @Override + public String getName(InnerClassNode entry) { + return entry.name; + } + + @Override + public void applySide(InnerClassNode entry, String side) { + } + }.merge(nodeOut.innerClasses); + + new Merger(nodeC.fields, nodeS.fields) { + @Override + public String getName(FieldNode entry) { + return entry.name + ";;" + entry.desc; + } + + @Override + public void applySide(FieldNode entry, String side) { + AnnotationVisitor av = entry.visitAnnotation(SIDED_DESCRIPTOR, false); + visitSideAnnotation(av, side); + } + }.merge(nodeOut.fields); + + new Merger(nodeC.methods, nodeS.methods) { + @Override + public String getName(MethodNode entry) { + return entry.name + entry.desc; + } + + @Override + public void applySide(MethodNode entry, String side) { + AnnotationVisitor av = entry.visitAnnotation(SIDED_DESCRIPTOR, false); + visitSideAnnotation(av, side); + } + }.merge(nodeOut.methods); + + nodeOut.accept(writer); + return writer.toByteArray(); + } } diff --git a/src/main/java/net/fabricmc/stitch/merge/JarMerger.java b/src/main/java/net/fabricmc/stitch/merge/JarMerger.java index addf53b..94fc34c 100644 --- a/src/main/java/net/fabricmc/stitch/merge/JarMerger.java +++ b/src/main/java/net/fabricmc/stitch/merge/JarMerger.java @@ -16,211 +16,226 @@ package net.fabricmc.stitch.merge; -import net.fabricmc.stitch.util.SnowmanClassVisitor; -import net.fabricmc.stitch.util.StitchUtil; -import net.fabricmc.stitch.util.SyntheticParameterClassVisitor; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; - -import java.io.*; +import java.io.File; +import java.io.IOException; import java.nio.charset.Charset; -import java.nio.file.*; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.BasicFileAttributes; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; + +import net.fabricmc.stitch.util.SnowmanClassVisitor; +import net.fabricmc.stitch.util.StitchUtil; +import net.fabricmc.stitch.util.SyntheticParameterClassVisitor; + public class JarMerger implements AutoCloseable { - public class Entry { - public final Path path; - public final BasicFileAttributes metadata; - public final byte[] data; - - public Entry(Path path, BasicFileAttributes metadata, byte[] data) { - this.path = path; - this.metadata = metadata; - this.data = data; - } - } - - private static final ClassMerger CLASS_MERGER = new ClassMerger(); - private final StitchUtil.FileSystemDelegate inputClientFs, inputServerFs, outputFs; - private final Path inputClient, inputServer; - private final Map entriesClient, entriesServer; - private final Set entriesAll; - private boolean removeSnowmen = false; - private boolean offsetSyntheticsParams = false; - - public JarMerger(File inputClient, File inputServer, File output) throws IOException { - if (output.exists()) { - if (!output.delete()) { - throw new IOException("Could not delete " + output.getName()); - } - } - - this.inputClient = (inputClientFs = StitchUtil.getJarFileSystem(inputClient, false)).get().getPath("/"); - this.inputServer = (inputServerFs = StitchUtil.getJarFileSystem(inputServer, false)).get().getPath("/"); - this.outputFs = StitchUtil.getJarFileSystem(output, true); - - this.entriesClient = new HashMap<>(); - this.entriesServer = new HashMap<>(); - this.entriesAll = new TreeSet<>(); - } - - public void enableSnowmanRemoval() { - removeSnowmen = true; - } - - public void enableSyntheticParamsOffset() { - offsetSyntheticsParams = true; - } - - @Override - public void close() throws IOException { - inputClientFs.close(); - inputServerFs.close(); - outputFs.close(); - } - - private void readToMap(Map map, Path input, boolean isServer) { - try { - Files.walkFileTree(input, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attr) throws IOException { - if (attr.isDirectory()) { - return FileVisitResult.CONTINUE; - } - - if (!path.getFileName().toString().endsWith(".class")) { - if (path.toString().equals("/META-INF/MANIFEST.MF")) { - map.put("META-INF/MANIFEST.MF", new Entry(path, attr, - "Manifest-Version: 1.0\nMain-Class: net.minecraft.client.Main\n".getBytes(Charset.forName("UTF-8")))); - } else { - if (path.toString().startsWith("/META-INF/")) { - if (path.toString().endsWith(".SF") || path.toString().endsWith(".RSA")) { - return FileVisitResult.CONTINUE; - } - } - - map.put(path.toString().substring(1), new Entry(path, attr, null)); - } - - return FileVisitResult.CONTINUE; - } - - byte[] output = Files.readAllBytes(path); - map.put(path.toString().substring(1), new Entry(path, attr, output)); - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void add(Entry entry) throws IOException { - Path outPath = outputFs.get().getPath(entry.path.toString()); - if (outPath.getParent() != null) { - Files.createDirectories(outPath.getParent()); - } - - if (entry.data != null) { - Files.write(outPath, entry.data, StandardOpenOption.CREATE_NEW); - } else { - Files.copy(entry.path, outPath); - } - - Files.getFileAttributeView(outPath, BasicFileAttributeView.class) - .setTimes( - entry.metadata.creationTime(), - entry.metadata.lastAccessTime(), - entry.metadata.lastModifiedTime() - ); - } - - public void merge() throws IOException { - ExecutorService service = Executors.newFixedThreadPool(2); - service.submit(() -> readToMap(entriesClient, inputClient, false)); - service.submit(() -> readToMap(entriesServer, inputServer, true)); - service.shutdown(); - try { - service.awaitTermination(1, TimeUnit.HOURS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - entriesAll.addAll(entriesClient.keySet()); - entriesAll.addAll(entriesServer.keySet()); - - List entries = entriesAll.parallelStream().map((entry) -> { - boolean isClass = entry.endsWith(".class"); - boolean isMinecraft = entriesClient.containsKey(entry) || entry.startsWith("net/minecraft") || !entry.contains("/"); - Entry result; - String side = null; - - Entry entry1 = entriesClient.get(entry); - Entry entry2 = entriesServer.get(entry); - - if (entry1 != null && entry2 != null) { - if (Arrays.equals(entry1.data, entry2.data)) { - result = entry1; - } else { - if (isClass) { - result = new Entry(entry1.path, entry1.metadata, CLASS_MERGER.merge(entry1.data, entry2.data)); - } else { - // FIXME: More heuristics? - result = entry1; - } - } - } else if ((result = entry1) != null) { - side = "CLIENT"; - } else if ((result = entry2) != null) { - side = "SERVER"; - } - - if (isClass && !isMinecraft && "SERVER".equals(side)) { - // Server bundles libraries, client doesn't - skip them - return null; - } - - if (result != null) { - if (isMinecraft && isClass) { - byte[] data = result.data; - ClassReader reader = new ClassReader(data); - ClassWriter writer = new ClassWriter(0); - ClassVisitor visitor = writer; - - if (side != null) { - visitor = new ClassMerger.SidedClassVisitor(StitchUtil.ASM_VERSION, visitor, side); - } - - if (removeSnowmen) { - visitor = new SnowmanClassVisitor(StitchUtil.ASM_VERSION, visitor); - } - - if (offsetSyntheticsParams) { - visitor = new SyntheticParameterClassVisitor(StitchUtil.ASM_VERSION, visitor); - } - - if (visitor != writer) { - reader.accept(visitor, 0); - data = writer.toByteArray(); - result = new Entry(result.path, result.metadata, data); - } - } - - return result; - } else { - return null; - } - }).filter(Objects::nonNull).collect(Collectors.toList()); - - for (Entry e : entries) { - add(e); - } - } + public class Entry { + public final Path path; + public final BasicFileAttributes metadata; + public final byte[] data; + + public Entry(Path path, BasicFileAttributes metadata, byte[] data) { + this.path = path; + this.metadata = metadata; + this.data = data; + } + } + + private static final ClassMerger CLASS_MERGER = new ClassMerger(); + private final StitchUtil.FileSystemDelegate inputClientFs, inputServerFs, outputFs; + private final Path inputClient, inputServer; + private final Map entriesClient, entriesServer; + private final Set entriesAll; + private boolean removeSnowmen = false; + private boolean offsetSyntheticsParams = false; + + public JarMerger(File inputClient, File inputServer, File output) throws IOException { + if (output.exists()) { + if (!output.delete()) { + throw new IOException("Could not delete " + output.getName()); + } + } + + this.inputClient = (inputClientFs = StitchUtil.getJarFileSystem(inputClient, false)).get().getPath("/"); + this.inputServer = (inputServerFs = StitchUtil.getJarFileSystem(inputServer, false)).get().getPath("/"); + this.outputFs = StitchUtil.getJarFileSystem(output, true); + + this.entriesClient = new HashMap<>(); + this.entriesServer = new HashMap<>(); + this.entriesAll = new TreeSet<>(); + } + + public void enableSnowmanRemoval() { + removeSnowmen = true; + } + + public void enableSyntheticParamsOffset() { + offsetSyntheticsParams = true; + } + + @Override + public void close() throws IOException { + inputClientFs.close(); + inputServerFs.close(); + outputFs.close(); + } + + private void readToMap(Map map, Path input, boolean isServer) { + try { + Files.walkFileTree(input, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attr) throws IOException { + if (attr.isDirectory()) { + return FileVisitResult.CONTINUE; + } + + if (!path.getFileName().toString().endsWith(".class")) { + if (path.toString().equals("/META-INF/MANIFEST.MF")) { + map.put("META-INF/MANIFEST.MF", new Entry(path, attr, + "Manifest-Version: 1.0\nMain-Class: net.minecraft.client.Main\n".getBytes(Charset.forName("UTF-8")))); + } else { + if (path.toString().startsWith("/META-INF/")) { + if (path.toString().endsWith(".SF") || path.toString().endsWith(".RSA")) { + return FileVisitResult.CONTINUE; + } + } + + map.put(path.toString().substring(1), new Entry(path, attr, null)); + } + + return FileVisitResult.CONTINUE; + } + + byte[] output = Files.readAllBytes(path); + map.put(path.toString().substring(1), new Entry(path, attr, output)); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void add(Entry entry) throws IOException { + Path outPath = outputFs.get().getPath(entry.path.toString()); + + if (outPath.getParent() != null) { + Files.createDirectories(outPath.getParent()); + } + + if (entry.data != null) { + Files.write(outPath, entry.data, StandardOpenOption.CREATE_NEW); + } else { + Files.copy(entry.path, outPath); + } + + Files.getFileAttributeView(outPath, BasicFileAttributeView.class) + .setTimes( + entry.metadata.creationTime(), + entry.metadata.lastAccessTime(), + entry.metadata.lastModifiedTime()); + } + + public void merge() throws IOException { + ExecutorService service = Executors.newFixedThreadPool(2); + service.submit(() -> readToMap(entriesClient, inputClient, false)); + service.submit(() -> readToMap(entriesServer, inputServer, true)); + service.shutdown(); + + try { + service.awaitTermination(1, TimeUnit.HOURS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + entriesAll.addAll(entriesClient.keySet()); + entriesAll.addAll(entriesServer.keySet()); + + List entries = entriesAll.parallelStream().map((entry) -> { + boolean isClass = entry.endsWith(".class"); + boolean isMinecraft = entriesClient.containsKey(entry) + || entry.startsWith("net/minecraft") + || !entry.contains("/"); + Entry result; + String side = null; + + Entry entry1 = entriesClient.get(entry); + Entry entry2 = entriesServer.get(entry); + + if (entry1 != null && entry2 != null) { + if (Arrays.equals(entry1.data, entry2.data)) { + result = entry1; + } else { + if (isClass) { + result = new Entry(entry1.path, entry1.metadata, CLASS_MERGER.merge(entry1.data, entry2.data)); + } else { + // FIXME: More heuristics? + result = entry1; + } + } + } else if ((result = entry1) != null) { + side = "CLIENT"; + } else if ((result = entry2) != null) { + side = "SERVER"; + } + + if (isClass && !isMinecraft && "SERVER".equals(side)) { + // Server bundles libraries, client doesn't - skip them + return null; + } + + if (result != null) { + if (isMinecraft && isClass) { + byte[] data = result.data; + ClassReader reader = new ClassReader(data); + ClassWriter writer = new ClassWriter(0); + ClassVisitor visitor = writer; + + if (side != null) { + visitor = new ClassMerger.SidedClassVisitor(StitchUtil.ASM_VERSION, visitor, side); + } + + if (removeSnowmen) { + visitor = new SnowmanClassVisitor(StitchUtil.ASM_VERSION, visitor); + } + + if (offsetSyntheticsParams) { + visitor = new SyntheticParameterClassVisitor(StitchUtil.ASM_VERSION, visitor); + } + + if (visitor != writer) { + reader.accept(visitor, 0); + data = writer.toByteArray(); + result = new Entry(result.path, result.metadata, data); + } + } + + return result; + } else { + return null; + } + }).filter(Objects::nonNull).collect(Collectors.toList()); + + for (Entry e : entries) { + add(e); + } + } } diff --git a/src/main/java/net/fabricmc/stitch/representation/AbstractJarEntry.java b/src/main/java/net/fabricmc/stitch/representation/AbstractJarEntry.java index 9ff051a..8e6249a 100644 --- a/src/main/java/net/fabricmc/stitch/representation/AbstractJarEntry.java +++ b/src/main/java/net/fabricmc/stitch/representation/AbstractJarEntry.java @@ -17,41 +17,41 @@ package net.fabricmc.stitch.representation; public abstract class AbstractJarEntry { - protected String name; - protected int access; - - public AbstractJarEntry(String name) { - this.name = name; - } - - public int getAccess() { - return access; - } - - protected void setAccess(int value) { - this.access = value; - } - - public String getName() { - return name; - } - - protected String getKey() { - return name; - } - - @Override - public boolean equals(Object other) { - return other != null && other.getClass() == getClass() && ((AbstractJarEntry) other).getKey().equals(getKey()); - } - - @Override - public int hashCode() { - return getKey().hashCode(); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "(" + getKey() + ")"; - } + protected String name; + protected int access; + + public AbstractJarEntry(String name) { + this.name = name; + } + + public int getAccess() { + return access; + } + + protected void setAccess(int value) { + this.access = value; + } + + public String getName() { + return name; + } + + protected String getKey() { + return name; + } + + @Override + public boolean equals(Object other) { + return other != null && other.getClass() == getClass() && ((AbstractJarEntry) other).getKey().equals(getKey()); + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "(" + getKey() + ")"; + } } diff --git a/src/main/java/net/fabricmc/stitch/representation/Access.java b/src/main/java/net/fabricmc/stitch/representation/Access.java index 3b3088b..095303d 100644 --- a/src/main/java/net/fabricmc/stitch/representation/Access.java +++ b/src/main/java/net/fabricmc/stitch/representation/Access.java @@ -19,27 +19,26 @@ import org.objectweb.asm.Opcodes; public final class Access { - private Access() { + public static boolean isStatic(int access) { + return (access & Opcodes.ACC_STATIC) != 0; + } - } + public static boolean isPrivate(int access) { + return (access & Opcodes.ACC_PRIVATE) != 0; + } - public static boolean isStatic(int access) { - return (access & Opcodes.ACC_STATIC) != 0; - } + public static boolean isPrivateOrStatic(int access) { + return (access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) != 0; + } - public static boolean isPrivate(int access) { - return (access & Opcodes.ACC_PRIVATE) != 0; - } + public static boolean isInterface(int access) { + return (access & Opcodes.ACC_INTERFACE) != 0; + } - public static boolean isPrivateOrStatic(int access) { - return (access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) != 0; - } + public static boolean isNative(int access) { + return (access & (Opcodes.ACC_NATIVE)) != 0; + } - public static boolean isInterface(int access) { - return (access & Opcodes.ACC_INTERFACE) != 0; - } - - public static boolean isNative(int access) { - return (access & (Opcodes.ACC_NATIVE)) != 0; - } + private Access() { + } } diff --git a/src/main/java/net/fabricmc/stitch/representation/ClassPropagationTree.java b/src/main/java/net/fabricmc/stitch/representation/ClassPropagationTree.java index d46d13f..c9d0d68 100644 --- a/src/main/java/net/fabricmc/stitch/representation/ClassPropagationTree.java +++ b/src/main/java/net/fabricmc/stitch/representation/ClassPropagationTree.java @@ -16,9 +16,12 @@ package net.fabricmc.stitch.representation; -import net.fabricmc.stitch.util.StitchUtil; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.Set; -import java.util.*; +import net.fabricmc.stitch.util.StitchUtil; /** * TODO: This doesn't try to follow the JVM's logic at all. @@ -26,45 +29,48 @@ * where it could get away with naming them differently. */ public class ClassPropagationTree { - private final ClassStorage jar; - private final Set relevantClasses; - private final Set topmostClasses; + private final ClassStorage jar; + private final Set relevantClasses; + private final Set topmostClasses; + + public ClassPropagationTree(ClassStorage jar, JarClassEntry baseClass) { + this.jar = jar; + relevantClasses = StitchUtil.newIdentityHashSet(); + topmostClasses = StitchUtil.newIdentityHashSet(); + + LinkedList queue = new LinkedList<>(); + queue.add(baseClass); + + while (!queue.isEmpty()) { + JarClassEntry entry = queue.remove(); - public ClassPropagationTree(ClassStorage jar, JarClassEntry baseClass) { - this.jar = jar; - relevantClasses = StitchUtil.newIdentityHashSet(); - topmostClasses = StitchUtil.newIdentityHashSet(); + if (entry == null || relevantClasses.contains(entry)) { + continue; + } - LinkedList queue = new LinkedList<>(); - queue.add(baseClass); + relevantClasses.add(entry); + queue.addAll(entry.getSubclasses(jar)); + queue.addAll(entry.getImplementers(jar)); + int qSize = queue.size(); - while (!queue.isEmpty()) { - JarClassEntry entry = queue.remove(); - if (entry == null || relevantClasses.contains(entry)) { - continue; - } - relevantClasses.add(entry); + if (qSize == queue.size()) { + topmostClasses.add(entry); + } - int qSize = queue.size(); - queue.addAll(entry.getSubclasses(jar)); - queue.addAll(entry.getImplementers(jar)); - if (qSize == queue.size()) { - topmostClasses.add(entry); - } + queue.addAll(entry.getInterfaces(jar)); + JarClassEntry superClass = entry.getSuperClass(jar); - queue.addAll(entry.getInterfaces(jar)); - JarClassEntry superClass = entry.getSuperClass(jar); - if (superClass != null) { - queue.add(superClass); - } - } - } + if (superClass != null) { + queue.add(superClass); + } + } + } - public Collection getClasses() { - return Collections.unmodifiableSet(relevantClasses); - } + public Collection getClasses() { + return Collections.unmodifiableSet(relevantClasses); + } - public Collection getTopmostClasses() { - return Collections.unmodifiableSet(topmostClasses); - } + public Collection getTopmostClasses() { + return Collections.unmodifiableSet(topmostClasses); + } } diff --git a/src/main/java/net/fabricmc/stitch/representation/ClassStorage.java b/src/main/java/net/fabricmc/stitch/representation/ClassStorage.java index a06f72e..112ccc5 100644 --- a/src/main/java/net/fabricmc/stitch/representation/ClassStorage.java +++ b/src/main/java/net/fabricmc/stitch/representation/ClassStorage.java @@ -17,5 +17,5 @@ package net.fabricmc.stitch.representation; public interface ClassStorage { - JarClassEntry getClass(String name, boolean create); + JarClassEntry getClass(String name, boolean create); } diff --git a/src/main/java/net/fabricmc/stitch/representation/JarClassEntry.java b/src/main/java/net/fabricmc/stitch/representation/JarClassEntry.java index 90a0074..c2523f0 100644 --- a/src/main/java/net/fabricmc/stitch/representation/JarClassEntry.java +++ b/src/main/java/net/fabricmc/stitch/representation/JarClassEntry.java @@ -16,197 +16,209 @@ package net.fabricmc.stitch.representation; -import net.fabricmc.stitch.util.Pair; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + import org.objectweb.asm.commons.Remapper; -import java.util.*; -import java.util.stream.Collectors; +import net.fabricmc.stitch.util.Pair; public class JarClassEntry extends AbstractJarEntry { - String fullyQualifiedName; - final Map innerClasses; - final Map fields; - final Map methods; - final Map>> relatedMethods; - - String signature; - String superclass; - List interfaces; - List subclasses; - List implementers; - - protected JarClassEntry(String name, String fullyQualifiedName) { - super(name); - - this.fullyQualifiedName = fullyQualifiedName; - this.innerClasses = new TreeMap<>(Comparator.naturalOrder()); - this.fields = new TreeMap<>(Comparator.naturalOrder()); - this.methods = new TreeMap<>(Comparator.naturalOrder()); - this.relatedMethods = new HashMap<>(); - - this.subclasses = new ArrayList<>(); - this.implementers = new ArrayList<>(); - } - - protected void populate(int access, String signature, String superclass, String[] interfaces) { - this.setAccess(access); - this.signature = signature; - this.superclass = superclass; - this.interfaces = Arrays.asList(interfaces); - } - - protected void populateParents(ClassStorage storage) { - JarClassEntry superEntry = getSuperClass(storage); - if (superEntry != null) { - superEntry.subclasses.add(fullyQualifiedName); - } - - for (JarClassEntry itf : getInterfaces(storage)) { - if (itf != null) { - itf.implementers.add(fullyQualifiedName); - } - } - } - - // unstable - public Collection> getRelatedMethods(JarMethodEntry m) { - //noinspection unchecked - return relatedMethods.getOrDefault(m.getKey(), Collections.EMPTY_SET); - } - - public String getFullyQualifiedName() { - return fullyQualifiedName; - } - - public String getSignature() { - return signature; - } - - public String getSuperClassName() { - return superclass; - } - - public JarClassEntry getSuperClass(ClassStorage storage) { - return storage.getClass(superclass, false); - } - - public List getInterfaceNames() { - return Collections.unmodifiableList(interfaces); - } - - public List getInterfaces(ClassStorage storage) { - return toClassEntryList(storage, interfaces); - } - - public List getSubclassNames() { - return Collections.unmodifiableList(subclasses); - } - - public List getSubclasses(ClassStorage storage) { - return toClassEntryList(storage, subclasses); - } - - public List getImplementerNames() { - return Collections.unmodifiableList(implementers); - } - - public List getImplementers(ClassStorage storage) { - return toClassEntryList(storage, implementers); - } - - private List toClassEntryList(ClassStorage storage, List stringList) { - if (stringList == null) { - return Collections.emptyList(); - } - - return stringList.stream() - .map((s) -> storage.getClass(s, false)) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - public JarClassEntry getInnerClass(String name) { - return innerClasses.get(name); - } - - public JarFieldEntry getField(String name) { - return fields.get(name); - } - - public JarMethodEntry getMethod(String name) { - return methods.get(name); - } - - public Collection getInnerClasses() { - return innerClasses.values(); - } - - public Collection getFields() { - return fields.values(); - } - - public Collection getMethods() { - return methods.values(); - } - - public boolean isInterface() { - return Access.isInterface(getAccess()); - } - - public boolean isAnonymous() { - return getName().matches("[0-9]+"); - } - - @Override - public String getKey() { - return getFullyQualifiedName(); - } - - public void remap(Remapper remapper) { - String oldName = fullyQualifiedName; - fullyQualifiedName = remapper.map(fullyQualifiedName); - String[] s = fullyQualifiedName.split("\\$"); - name = s[s.length - 1]; - - if (superclass != null) { - superclass = remapper.map(superclass); - } - - interfaces = interfaces.stream().map(remapper::map).collect(Collectors.toList()); - subclasses = subclasses.stream().map(remapper::map).collect(Collectors.toList()); - implementers = implementers.stream().map(remapper::map).collect(Collectors.toList()); - - Map innerClassOld = new HashMap<>(innerClasses); - Map fieldsOld = new HashMap<>(fields); - Map methodsOld = new HashMap<>(methods); - Map methodKeyRemaps = new HashMap<>(); - - innerClasses.clear(); - fields.clear(); - methods.clear(); - - for (Map.Entry entry : innerClassOld.entrySet()) { - entry.getValue().remap(remapper); - innerClasses.put(entry.getValue().name, entry.getValue()); - } - - for (Map.Entry entry : fieldsOld.entrySet()) { - entry.getValue().remap(this, oldName, remapper); - fields.put(entry.getValue().getKey(), entry.getValue()); - } - - for (Map.Entry entry : methodsOld.entrySet()) { - entry.getValue().remap(this, oldName, remapper); - methods.put(entry.getValue().getKey(), entry.getValue()); - methodKeyRemaps.put(entry.getKey(), entry.getValue().getKey()); - } - - // TODO: remap relatedMethods strings??? - Map>> relatedMethodsOld = new HashMap<>(relatedMethods); - relatedMethods.clear(); - - for (Map.Entry>> entry : relatedMethodsOld.entrySet()) { - relatedMethods.put(methodKeyRemaps.getOrDefault(entry.getKey(), entry.getKey()), entry.getValue()); - } - } + String fullyQualifiedName; + final Map innerClasses; + final Map fields; + final Map methods; + final Map>> relatedMethods; + + String signature; + String superclass; + List interfaces; + List subclasses; + List implementers; + + protected JarClassEntry(String name, String fullyQualifiedName) { + super(name); + + this.fullyQualifiedName = fullyQualifiedName; + this.innerClasses = new TreeMap<>(Comparator.naturalOrder()); + this.fields = new TreeMap<>(Comparator.naturalOrder()); + this.methods = new TreeMap<>(Comparator.naturalOrder()); + this.relatedMethods = new HashMap<>(); + + this.subclasses = new ArrayList<>(); + this.implementers = new ArrayList<>(); + } + + protected void populate(int access, String signature, String superclass, String[] interfaces) { + this.setAccess(access); + this.signature = signature; + this.superclass = superclass; + this.interfaces = Arrays.asList(interfaces); + } + + protected void populateParents(ClassStorage storage) { + JarClassEntry superEntry = getSuperClass(storage); + + if (superEntry != null) { + superEntry.subclasses.add(fullyQualifiedName); + } + + for (JarClassEntry itf : getInterfaces(storage)) { + if (itf != null) { + itf.implementers.add(fullyQualifiedName); + } + } + } + + // unstable + public Collection> getRelatedMethods(JarMethodEntry m) { + //noinspection unchecked + return relatedMethods.getOrDefault(m.getKey(), Collections.EMPTY_SET); + } + + public String getFullyQualifiedName() { + return fullyQualifiedName; + } + + public String getSignature() { + return signature; + } + + public String getSuperClassName() { + return superclass; + } + + public JarClassEntry getSuperClass(ClassStorage storage) { + return storage.getClass(superclass, false); + } + + public List getInterfaceNames() { + return Collections.unmodifiableList(interfaces); + } + + public List getInterfaces(ClassStorage storage) { + return toClassEntryList(storage, interfaces); + } + + public List getSubclassNames() { + return Collections.unmodifiableList(subclasses); + } + + public List getSubclasses(ClassStorage storage) { + return toClassEntryList(storage, subclasses); + } + + public List getImplementerNames() { + return Collections.unmodifiableList(implementers); + } + + public List getImplementers(ClassStorage storage) { + return toClassEntryList(storage, implementers); + } + + private List toClassEntryList(ClassStorage storage, List stringList) { + if (stringList == null) { + return Collections.emptyList(); + } + + return stringList.stream() + .map((s) -> storage.getClass(s, false)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + public JarClassEntry getInnerClass(String name) { + return innerClasses.get(name); + } + + public JarFieldEntry getField(String name) { + return fields.get(name); + } + + public JarMethodEntry getMethod(String name) { + return methods.get(name); + } + + public Collection getInnerClasses() { + return innerClasses.values(); + } + + public Collection getFields() { + return fields.values(); + } + + public Collection getMethods() { + return methods.values(); + } + + public boolean isInterface() { + return Access.isInterface(getAccess()); + } + + public boolean isAnonymous() { + return getName().matches("[0-9]+"); + } + + @Override + public String getKey() { + return getFullyQualifiedName(); + } + + public void remap(Remapper remapper) { + String oldName = fullyQualifiedName; + fullyQualifiedName = remapper.map(fullyQualifiedName); + String[] s = fullyQualifiedName.split("\\$"); + name = s[s.length - 1]; + + if (superclass != null) { + superclass = remapper.map(superclass); + } + + interfaces = interfaces.stream().map(remapper::map).collect(Collectors.toList()); + subclasses = subclasses.stream().map(remapper::map).collect(Collectors.toList()); + implementers = implementers.stream().map(remapper::map).collect(Collectors.toList()); + + Map innerClassOld = new HashMap<>(innerClasses); + Map fieldsOld = new HashMap<>(fields); + Map methodsOld = new HashMap<>(methods); + Map methodKeyRemaps = new HashMap<>(); + + innerClasses.clear(); + fields.clear(); + methods.clear(); + + for (Map.Entry entry : innerClassOld.entrySet()) { + entry.getValue().remap(remapper); + innerClasses.put(entry.getValue().name, entry.getValue()); + } + + for (Map.Entry entry : fieldsOld.entrySet()) { + entry.getValue().remap(this, oldName, remapper); + fields.put(entry.getValue().getKey(), entry.getValue()); + } + + for (Map.Entry entry : methodsOld.entrySet()) { + entry.getValue().remap(this, oldName, remapper); + methods.put(entry.getValue().getKey(), entry.getValue()); + methodKeyRemaps.put(entry.getKey(), entry.getValue().getKey()); + } + + // TODO: remap relatedMethods strings??? + Map>> relatedMethodsOld = new HashMap<>(relatedMethods); + relatedMethods.clear(); + + for (Map.Entry>> entry : relatedMethodsOld.entrySet()) { + relatedMethods.put(methodKeyRemaps.getOrDefault(entry.getKey(), entry.getKey()), entry.getValue()); + } + } } diff --git a/src/main/java/net/fabricmc/stitch/representation/JarFieldEntry.java b/src/main/java/net/fabricmc/stitch/representation/JarFieldEntry.java index 9577cd8..52fd2c7 100644 --- a/src/main/java/net/fabricmc/stitch/representation/JarFieldEntry.java +++ b/src/main/java/net/fabricmc/stitch/representation/JarFieldEntry.java @@ -19,33 +19,33 @@ import org.objectweb.asm.commons.Remapper; public class JarFieldEntry extends AbstractJarEntry { - protected String desc; - protected String signature; - - JarFieldEntry(int access, String name, String desc, String signature) { - super(name); - this.setAccess(access); - this.desc = desc; - this.signature = signature; - } - - public String getDescriptor() { - return desc; - } - - public String getSignature() { - return signature; - } - - @Override - protected String getKey() { - return super.getKey() + desc; - } - - public void remap(JarClassEntry classEntry, String oldOwner, Remapper remapper) { - String pastDesc = desc; - - name = remapper.mapFieldName(oldOwner, name, pastDesc); - desc = remapper.mapDesc(pastDesc); - } + protected String desc; + protected String signature; + + JarFieldEntry(int access, String name, String desc, String signature) { + super(name); + this.setAccess(access); + this.desc = desc; + this.signature = signature; + } + + public String getDescriptor() { + return desc; + } + + public String getSignature() { + return signature; + } + + @Override + protected String getKey() { + return super.getKey() + desc; + } + + public void remap(JarClassEntry classEntry, String oldOwner, Remapper remapper) { + String pastDesc = desc; + + name = remapper.mapFieldName(oldOwner, name, pastDesc); + desc = remapper.mapDesc(pastDesc); + } } diff --git a/src/main/java/net/fabricmc/stitch/representation/JarMethodEntry.java b/src/main/java/net/fabricmc/stitch/representation/JarMethodEntry.java index ce45fae..123ff8d 100644 --- a/src/main/java/net/fabricmc/stitch/representation/JarMethodEntry.java +++ b/src/main/java/net/fabricmc/stitch/representation/JarMethodEntry.java @@ -16,111 +16,120 @@ package net.fabricmc.stitch.representation; -import net.fabricmc.stitch.util.StitchUtil; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + import org.objectweb.asm.commons.Remapper; -import java.util.*; +import net.fabricmc.stitch.util.StitchUtil; public class JarMethodEntry extends AbstractJarEntry { - protected String desc; - protected String signature; - - protected JarMethodEntry(int access, String name, String desc, String signature) { - super(name); - this.setAccess(access); - this.desc = desc; - this.signature = signature; - } - - public String getDescriptor() { - return desc; - } - - public String getSignature() { - return signature; - } - - @Override - protected String getKey() { - return super.getKey() + desc; - } - - public boolean isSource(ClassStorage storage, JarClassEntry c) { - if (Access.isPrivateOrStatic(getAccess())) { - return true; - } - - Set entries = StitchUtil.newIdentityHashSet(); - entries.add(c); - getMatchingSources(entries, storage, c); - return entries.size() == 1; - } - - public List getMatchingEntries(ClassStorage storage, JarClassEntry c) { - if (Access.isPrivateOrStatic(getAccess())) { - return Collections.singletonList(c); - } - - Set entries = StitchUtil.newIdentityHashSet(); - Set entriesNew = StitchUtil.newIdentityHashSet(); - entries.add(c); - int lastSize = 0; - - while (entries.size() > lastSize) { - lastSize = entries.size(); - - for (JarClassEntry cc : entries) { - getMatchingSources(entriesNew, storage, cc); - } - entries.addAll(entriesNew); - entriesNew.clear(); - - for (JarClassEntry cc : entries) { - getMatchingEntries(entriesNew, storage, cc, 0); - } - entries.addAll(entriesNew); - entriesNew.clear(); - } - - entries.removeIf(cc -> cc.getMethod(getKey()) == null); - - return new ArrayList<>(entries); - } - - void getMatchingSources(Collection entries, ClassStorage storage, JarClassEntry c) { - JarMethodEntry m = c.getMethod(getKey()); - if (m != null) { - if (!Access.isPrivateOrStatic(m.getAccess())) { - entries.add(c); - } - } - - JarClassEntry superClass = c.getSuperClass(storage); - if (superClass != null) { - getMatchingSources(entries, storage, superClass); - } - - for (JarClassEntry itf : c.getInterfaces(storage)) { - getMatchingSources(entries, storage, itf); - } - } - - void getMatchingEntries(Collection entries, ClassStorage storage, JarClassEntry c, int indent) { - entries.add(c); - - for (JarClassEntry cc : c.getSubclasses(storage)) { - getMatchingEntries(entries, storage, cc, indent + 1); - } - - for (JarClassEntry cc : c.getImplementers(storage)) { - getMatchingEntries(entries, storage, cc, indent + 1); - } - } - - public void remap(JarClassEntry classEntry, String oldOwner, Remapper remapper) { - String pastDesc = desc; - - name = remapper.mapMethodName(oldOwner, name, pastDesc); - desc = remapper.mapMethodDesc(pastDesc); - } -} \ No newline at end of file + protected String desc; + protected String signature; + + protected JarMethodEntry(int access, String name, String desc, String signature) { + super(name); + this.setAccess(access); + this.desc = desc; + this.signature = signature; + } + + public String getDescriptor() { + return desc; + } + + public String getSignature() { + return signature; + } + + @Override + protected String getKey() { + return super.getKey() + desc; + } + + public boolean isSource(ClassStorage storage, JarClassEntry c) { + if (Access.isPrivateOrStatic(getAccess())) { + return true; + } + + Set entries = StitchUtil.newIdentityHashSet(); + entries.add(c); + getMatchingSources(entries, storage, c); + return entries.size() == 1; + } + + public List getMatchingEntries(ClassStorage storage, JarClassEntry c) { + if (Access.isPrivateOrStatic(getAccess())) { + return Collections.singletonList(c); + } + + Set entries = StitchUtil.newIdentityHashSet(); + Set entriesNew = StitchUtil.newIdentityHashSet(); + entries.add(c); + int lastSize = 0; + + while (entries.size() > lastSize) { + lastSize = entries.size(); + + for (JarClassEntry cc : entries) { + getMatchingSources(entriesNew, storage, cc); + } + + entries.addAll(entriesNew); + entriesNew.clear(); + + for (JarClassEntry cc : entries) { + getMatchingEntries(entriesNew, storage, cc, 0); + } + + entries.addAll(entriesNew); + entriesNew.clear(); + } + + entries.removeIf(cc -> cc.getMethod(getKey()) == null); + + return new ArrayList<>(entries); + } + + void getMatchingSources(Collection entries, ClassStorage storage, JarClassEntry c) { + JarMethodEntry m = c.getMethod(getKey()); + + if (m != null) { + if (!Access.isPrivateOrStatic(m.getAccess())) { + entries.add(c); + } + } + + JarClassEntry superClass = c.getSuperClass(storage); + + if (superClass != null) { + getMatchingSources(entries, storage, superClass); + } + + for (JarClassEntry itf : c.getInterfaces(storage)) { + getMatchingSources(entries, storage, itf); + } + } + + void getMatchingEntries(Collection entries, ClassStorage storage, JarClassEntry c, int indent) { + entries.add(c); + + for (JarClassEntry cc : c.getSubclasses(storage)) { + getMatchingEntries(entries, storage, cc, indent + 1); + } + + for (JarClassEntry cc : c.getImplementers(storage)) { + getMatchingEntries(entries, storage, cc, indent + 1); + } + } + + public void remap(JarClassEntry classEntry, String oldOwner, Remapper remapper) { + String pastDesc = desc; + + name = remapper.mapMethodName(oldOwner, name, pastDesc); + desc = remapper.mapMethodDesc(pastDesc); + } +} diff --git a/src/main/java/net/fabricmc/stitch/representation/JarReader.java b/src/main/java/net/fabricmc/stitch/representation/JarReader.java index 4f4c048..886b0cb 100644 --- a/src/main/java/net/fabricmc/stitch/representation/JarReader.java +++ b/src/main/java/net/fabricmc/stitch/representation/JarReader.java @@ -16,293 +16,305 @@ package net.fabricmc.stitch.representation; -import net.fabricmc.stitch.util.StitchUtil; -import org.objectweb.asm.*; -import org.objectweb.asm.commons.Remapper; - import java.io.FileInputStream; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.jar.JarInputStream; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.commons.Remapper; + +import net.fabricmc.stitch.util.StitchUtil; + public class JarReader { - public static class Builder { - private final JarReader reader; - - private Builder(JarReader reader) { - this.reader = reader; - } - - public static Builder create(JarRootEntry jar) { - return new Builder(new JarReader(jar)); - } - - public Builder joinMethodEntries(boolean value) { - reader.joinMethodEntries = value; - return this; - } - - public Builder withRemapper(Remapper remapper) { - reader.remapper = remapper; - return this; - } - - public JarReader build() { - return reader; - } - } - - private final JarRootEntry jar; - private boolean joinMethodEntries = true; - private Remapper remapper; - - public JarReader(JarRootEntry jar) { - this.jar = jar; - } - - private class VisitorClass extends ClassVisitor { - private JarClassEntry entry; - - public VisitorClass(int api, ClassVisitor classVisitor) { - super(api, classVisitor); - } - - @Override - public void visit(final int version, final int access, final String name, final String signature, - final String superName, final String[] interfaces) { - this.entry = jar.getClass(name, true); - this.entry.populate(access, signature, superName, interfaces); - - super.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public FieldVisitor visitField(final int access, final String name, final String descriptor, - final String signature, final Object value) { - JarFieldEntry field = new JarFieldEntry(access, name, descriptor, signature); - this.entry.fields.put(field.getKey(), field); - - return new VisitorField(api, super.visitField(access, name, descriptor, signature, value), - entry, field); - } - - @Override - public MethodVisitor visitMethod(final int access, final String name, final String descriptor, - final String signature, final String[] exceptions) { - JarMethodEntry method = new JarMethodEntry(access, name, descriptor, signature); - this.entry.methods.put(method.getKey(), method); - - return new VisitorMethod(api, super.visitMethod(access, name, descriptor, signature, exceptions), - entry, method); - } - } - - private class VisitorClassStageTwo extends ClassVisitor { - private JarClassEntry entry; - - public VisitorClassStageTwo(int api, ClassVisitor classVisitor) { - super(api, classVisitor); - } - - @Override - public void visit(final int version, final int access, final String name, final String signature, - final String superName, final String[] interfaces) { - this.entry = jar.getClass(name, true); - super.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public MethodVisitor visitMethod(final int access, final String name, final String descriptor, - final String signature, final String[] exceptions) { - JarMethodEntry method = new JarMethodEntry(access, name, descriptor, signature); - this.entry.methods.put(method.getKey(), method); - - if ((access & (Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC)) != 0) { - return new VisitorBridge(api, access, super.visitMethod(access, name, descriptor, signature, exceptions), - entry, method); - } else { - return super.visitMethod(access, name, descriptor, signature, exceptions); - } - } - } - - private class VisitorField extends FieldVisitor { - private final JarClassEntry classEntry; - private final JarFieldEntry entry; - - public VisitorField(int api, FieldVisitor fieldVisitor, JarClassEntry classEntry, JarFieldEntry entry) { - super(api, fieldVisitor); - this.classEntry = classEntry; - this.entry = entry; - } - } - - private static class MethodRef { - final String owner, name, descriptor; - - MethodRef(String owner, String name, String descriptor) { - this.owner = owner; - this.name = name; - this.descriptor = descriptor; - } - } - - private class VisitorBridge extends VisitorMethod { - private final boolean hasBridgeFlag; - private final List methodRefs = new ArrayList<>(); - - public VisitorBridge(int api, int access, MethodVisitor methodVisitor, JarClassEntry classEntry, JarMethodEntry entry) { - super(api, methodVisitor, classEntry, entry); - hasBridgeFlag = ((access & Opcodes.ACC_BRIDGE) != 0); - } - - @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - methodRefs.add(new MethodRef(owner, name, descriptor)); - } - - @Override - public void visitEnd() { - /* boolean isBridge = hasBridgeFlag; - - if (!isBridge && methodRefs.size() == 1) { - System.out.println("Found suspicious bridge-looking method: " + classEntry.getFullyQualifiedName() + ":" + entry); - } - - if (isBridge) { - for (MethodRef ref : methodRefs) { - JarClassEntry targetClass = jar.getClass(ref.owner, true); - JarMethodEntry targetMethod = new JarMethodEntry(0, ref.name, ref.descriptor, null); - String targetKey = targetMethod.getKey(); - - targetClass.relatedMethods.computeIfAbsent(targetKey, (a) -> new HashSet<>()).add(Pair.of(classEntry, entry.getKey())); - classEntry.relatedMethods.computeIfAbsent(entry.getKey(), (a) -> new HashSet<>()).add(Pair.of(targetClass, targetKey)); - } - } */ - } - } - - private class VisitorMethod extends MethodVisitor { - final JarClassEntry classEntry; - final JarMethodEntry entry; - - public VisitorMethod(int api, MethodVisitor methodVisitor, JarClassEntry classEntry, JarMethodEntry entry) { - super(api, methodVisitor); - this.classEntry = classEntry; - this.entry = entry; - } - } - - public void apply() throws IOException { - // Stage 1: read .JAR class/field/method meta - try (FileInputStream fileStream = new FileInputStream(jar.file)) { - try (JarInputStream jarStream = new JarInputStream(fileStream)) { - java.util.jar.JarEntry entry; - - while ((entry = jarStream.getNextJarEntry()) != null) { - if (!entry.getName().endsWith(".class")) { - continue; - } - - ClassReader reader = new ClassReader(jarStream); - ClassVisitor visitor = new VisitorClass(StitchUtil.ASM_VERSION, null); - reader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - } - } - } - - System.err.println("Read " + this.jar.getAllClasses().size() + " (" + this.jar.getClasses().size() + ") classes."); - - // Stage 2: find subclasses - this.jar.getAllClasses().forEach((c) -> c.populateParents(jar)); - System.err.println("Populated subclass entries."); - - // Stage 3: join identical MethodEntries - if (joinMethodEntries) { - System.err.println("Joining MethodEntries..."); - Set traversedClasses = StitchUtil.newIdentityHashSet(); - - int joinedMethods = 1; - int uniqueMethods = 0; - - Collection checkedMethods = StitchUtil.newIdentityHashSet(); - - for (JarClassEntry entry : jar.getAllClasses()) { - if (traversedClasses.contains(entry)) { - continue; - } - - ClassPropagationTree tree = new ClassPropagationTree(jar, entry); - if (tree.getClasses().size() == 1) { - traversedClasses.add(entry); - continue; - } - - for (JarClassEntry c : tree.getClasses()) { - for (JarMethodEntry m : c.getMethods()) { - if (!checkedMethods.add(m)) { - continue; - } - - // get all matching entries - List mList = m.getMatchingEntries(jar, c); - - if (mList.size() > 1) { - for (int i = 0; i < mList.size(); i++) { - JarClassEntry key = mList.get(i); - JarMethodEntry value = key.getMethod(m.getKey()); - if (value != m) { - key.methods.put(m.getKey(), m); - joinedMethods++; - } - } - } - } - } - - traversedClasses.addAll(tree.getClasses()); - } - - System.err.println("Joined " + joinedMethods + " MethodEntries (" + uniqueMethods + " unique, " + traversedClasses.size() + " classes)."); - } - - System.err.println("Collecting additional information..."); - - // Stage 4: collect additional info - /* try (FileInputStream fileStream = new FileInputStream(jar.file)) { - try (JarInputStream jarStream = new JarInputStream(fileStream)) { - java.util.jar.JarEntry entry; - - while ((entry = jarStream.getNextJarEntry()) != null) { - if (!entry.getName().endsWith(".class")) { - continue; - } - - ClassReader reader = new ClassReader(jarStream); - ClassVisitor visitor = new VisitorClassStageTwo(StitchUtil.ASM_VERSION, null); - reader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - } - } - } */ - - if (remapper != null) { - System.err.println("Remapping..."); - - Map classTree = new HashMap<>(jar.classTree); - jar.classTree.clear(); - - for (Map.Entry entry : classTree.entrySet()) { - entry.getValue().remap(remapper); - jar.classTree.put(entry.getValue().getKey(), entry.getValue()); - } - } - - System.err.println("- Done. -"); - } + public static class Builder { + private final JarReader reader; + + private Builder(JarReader reader) { + this.reader = reader; + } + + public static Builder create(JarRootEntry jar) { + return new Builder(new JarReader(jar)); + } + + public Builder joinMethodEntries(boolean value) { + reader.joinMethodEntries = value; + return this; + } + + public Builder withRemapper(Remapper remapper) { + reader.remapper = remapper; + return this; + } + + public JarReader build() { + return reader; + } + } + + private final JarRootEntry jar; + private boolean joinMethodEntries = true; + private Remapper remapper; + + public JarReader(JarRootEntry jar) { + this.jar = jar; + } + + private class VisitorClass extends ClassVisitor { + private JarClassEntry entry; + + VisitorClass(int api, ClassVisitor classVisitor) { + super(api, classVisitor); + } + + @Override + public void visit(final int version, final int access, final String name, final String signature, + final String superName, final String[] interfaces) { + this.entry = jar.getClass(name, true); + this.entry.populate(access, signature, superName, interfaces); + + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public FieldVisitor visitField(final int access, final String name, final String descriptor, + final String signature, final Object value) { + JarFieldEntry field = new JarFieldEntry(access, name, descriptor, signature); + this.entry.fields.put(field.getKey(), field); + + return new VisitorField(api, super.visitField(access, name, descriptor, signature, value), + entry, field); + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, final String descriptor, + final String signature, final String[] exceptions) { + JarMethodEntry method = new JarMethodEntry(access, name, descriptor, signature); + this.entry.methods.put(method.getKey(), method); + + return new VisitorMethod(api, super.visitMethod(access, name, descriptor, signature, exceptions), + entry, method); + } + } + + private class VisitorClassStageTwo extends ClassVisitor { + private JarClassEntry entry; + + VisitorClassStageTwo(int api, ClassVisitor classVisitor) { + super(api, classVisitor); + } + + @Override + public void visit(final int version, final int access, final String name, final String signature, + final String superName, final String[] interfaces) { + this.entry = jar.getClass(name, true); + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, final String descriptor, + final String signature, final String[] exceptions) { + JarMethodEntry method = new JarMethodEntry(access, name, descriptor, signature); + this.entry.methods.put(method.getKey(), method); + + if ((access & (Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC)) != 0) { + return new VisitorBridge(api, access, super.visitMethod(access, name, descriptor, signature, exceptions), + entry, method); + } else { + return super.visitMethod(access, name, descriptor, signature, exceptions); + } + } + } + + private class VisitorField extends FieldVisitor { + private final JarClassEntry classEntry; + private final JarFieldEntry entry; + + VisitorField(int api, FieldVisitor fieldVisitor, JarClassEntry classEntry, JarFieldEntry entry) { + super(api, fieldVisitor); + this.classEntry = classEntry; + this.entry = entry; + } + } + + private static class MethodRef { + final String owner, name, descriptor; + + MethodRef(String owner, String name, String descriptor) { + this.owner = owner; + this.name = name; + this.descriptor = descriptor; + } + } + + private class VisitorBridge extends VisitorMethod { + private final boolean hasBridgeFlag; + private final List methodRefs = new ArrayList<>(); + + VisitorBridge(int api, int access, MethodVisitor methodVisitor, JarClassEntry classEntry, JarMethodEntry entry) { + super(api, methodVisitor, classEntry, entry); + hasBridgeFlag = ((access & Opcodes.ACC_BRIDGE) != 0); + } + + @Override + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + methodRefs.add(new MethodRef(owner, name, descriptor)); + } + + @Override + public void visitEnd() { + /* boolean isBridge = hasBridgeFlag; + + if (!isBridge && methodRefs.size() == 1) { + System.out.println("Found suspicious bridge-looking method: " + classEntry.getFullyQualifiedName() + ":" + entry); + } + + if (isBridge) { + for (MethodRef ref : methodRefs) { + JarClassEntry targetClass = jar.getClass(ref.owner, true); + JarMethodEntry targetMethod = new JarMethodEntry(0, ref.name, ref.descriptor, null); + String targetKey = targetMethod.getKey(); + + targetClass.relatedMethods.computeIfAbsent(targetKey, (a) -> new HashSet<>()).add(Pair.of(classEntry, entry.getKey())); + classEntry.relatedMethods.computeIfAbsent(entry.getKey(), (a) -> new HashSet<>()).add(Pair.of(targetClass, targetKey)); + } + } */ + } + } + + private class VisitorMethod extends MethodVisitor { + final JarClassEntry classEntry; + final JarMethodEntry entry; + + VisitorMethod(int api, MethodVisitor methodVisitor, JarClassEntry classEntry, JarMethodEntry entry) { + super(api, methodVisitor); + this.classEntry = classEntry; + this.entry = entry; + } + } + + public void apply() throws IOException { + // Stage 1: read .JAR class/field/method meta + try (FileInputStream fileStream = new FileInputStream(jar.file)) { + try (JarInputStream jarStream = new JarInputStream(fileStream)) { + java.util.jar.JarEntry entry; + + while ((entry = jarStream.getNextJarEntry()) != null) { + if (!entry.getName().endsWith(".class")) { + continue; + } + + ClassReader reader = new ClassReader(jarStream); + ClassVisitor visitor = new VisitorClass(StitchUtil.ASM_VERSION, null); + reader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + } + } + } + + System.err.println("Read " + this.jar.getAllClasses().size() + " (" + this.jar.getClasses().size() + ") classes."); + + // Stage 2: find subclasses + this.jar.getAllClasses().forEach((c) -> c.populateParents(jar)); + System.err.println("Populated subclass entries."); + + // Stage 3: join identical MethodEntries + if (joinMethodEntries) { + System.err.println("Joining MethodEntries..."); + Set traversedClasses = StitchUtil.newIdentityHashSet(); + + int joinedMethods = 1; + int uniqueMethods = 0; + + Collection checkedMethods = StitchUtil.newIdentityHashSet(); + + for (JarClassEntry entry : jar.getAllClasses()) { + if (traversedClasses.contains(entry)) { + continue; + } + + ClassPropagationTree tree = new ClassPropagationTree(jar, entry); + + if (tree.getClasses().size() == 1) { + traversedClasses.add(entry); + continue; + } + + for (JarClassEntry c : tree.getClasses()) { + for (JarMethodEntry m : c.getMethods()) { + if (!checkedMethods.add(m)) { + continue; + } + + // get all matching entries + List mList = m.getMatchingEntries(jar, c); + + if (mList.size() > 1) { + for (int i = 0; i < mList.size(); i++) { + JarClassEntry key = mList.get(i); + JarMethodEntry value = key.getMethod(m.getKey()); + + if (value != m) { + key.methods.put(m.getKey(), m); + joinedMethods++; + } + } + } + } + } + + traversedClasses.addAll(tree.getClasses()); + } + + System.err.println("Joined " + joinedMethods + " MethodEntries (" + uniqueMethods + " unique, " + traversedClasses.size() + " classes)."); + } + + System.err.println("Collecting additional information..."); + + // Stage 4: collect additional info + /* try (FileInputStream fileStream = new FileInputStream(jar.file)) { + try (JarInputStream jarStream = new JarInputStream(fileStream)) { + java.util.jar.JarEntry entry; + + while ((entry = jarStream.getNextJarEntry()) != null) { + if (!entry.getName().endsWith(".class")) { + continue; + } + + ClassReader reader = new ClassReader(jarStream); + ClassVisitor visitor = new VisitorClassStageTwo(StitchUtil.ASM_VERSION, null); + reader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + } + } + } */ + + if (remapper != null) { + System.err.println("Remapping..."); + + Map classTree = new HashMap<>(jar.classTree); + jar.classTree.clear(); + + for (Map.Entry entry : classTree.entrySet()) { + entry.getValue().remap(remapper); + jar.classTree.put(entry.getValue().getKey(), entry.getValue()); + } + } + + System.err.println("- Done. -"); + } } diff --git a/src/main/java/net/fabricmc/stitch/representation/JarRootEntry.java b/src/main/java/net/fabricmc/stitch/representation/JarRootEntry.java index 169ecb5..86689e2 100644 --- a/src/main/java/net/fabricmc/stitch/representation/JarRootEntry.java +++ b/src/main/java/net/fabricmc/stitch/representation/JarRootEntry.java @@ -17,67 +17,74 @@ package net.fabricmc.stitch.representation; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; public class JarRootEntry extends AbstractJarEntry implements ClassStorage { - final Object syncObject = new Object(); - final File file; - final Map classTree; - final List allClasses; - - public JarRootEntry(File file) { - super(file.getName()); - - this.file = file; - this.classTree = new TreeMap<>(Comparator.naturalOrder()); - this.allClasses = new ArrayList<>(); - } - - @Override - public JarClassEntry getClass(String name, boolean create) { - if (name == null) { - return null; - } - - String[] nameSplit = name.split("\\$"); - int i = 0; - - JarClassEntry parent; - JarClassEntry entry = classTree.get(nameSplit[i++]); - if (entry == null && create) { - entry = new JarClassEntry(nameSplit[0], nameSplit[0]); - synchronized (syncObject) { - allClasses.add(entry); - classTree.put(entry.getName(), entry); - } - } - - StringBuilder fullyQualifiedBuilder = new StringBuilder(nameSplit[0]); - - while (i < nameSplit.length && entry != null) { - fullyQualifiedBuilder.append('$'); - fullyQualifiedBuilder.append(nameSplit[i]); - - parent = entry; - entry = entry.getInnerClass(nameSplit[i++]); - - if (entry == null && create) { - entry = new JarClassEntry(nameSplit[i - 1], fullyQualifiedBuilder.toString()); - synchronized (syncObject) { - allClasses.add(entry); - parent.innerClasses.put(entry.getName(), entry); - } - } - } - - return entry; - } - - public Collection getClasses() { - return classTree.values(); - } - - public Collection getAllClasses() { - return Collections.unmodifiableList(allClasses); - } + final Object syncObject = new Object(); + final File file; + final Map classTree; + final List allClasses; + + public JarRootEntry(File file) { + super(file.getName()); + + this.file = file; + this.classTree = new TreeMap<>(Comparator.naturalOrder()); + this.allClasses = new ArrayList<>(); + } + + @Override + public JarClassEntry getClass(String name, boolean create) { + if (name == null) { + return null; + } + + String[] nameSplit = name.split("\\$"); + int i = 0; + + JarClassEntry parent; + JarClassEntry entry = classTree.get(nameSplit[i++]); + + if (entry == null && create) { + entry = new JarClassEntry(nameSplit[0], nameSplit[0]); + synchronized (syncObject) { + allClasses.add(entry); + classTree.put(entry.getName(), entry); + } + } + + StringBuilder fullyQualifiedBuilder = new StringBuilder(nameSplit[0]); + + while (i < nameSplit.length && entry != null) { + fullyQualifiedBuilder.append('$'); + fullyQualifiedBuilder.append(nameSplit[i]); + + parent = entry; + entry = entry.getInnerClass(nameSplit[i++]); + + if (entry == null && create) { + entry = new JarClassEntry(nameSplit[i - 1], fullyQualifiedBuilder.toString()); + synchronized (syncObject) { + allClasses.add(entry); + parent.innerClasses.put(entry.getName(), entry); + } + } + } + + return entry; + } + + public Collection getClasses() { + return classTree.values(); + } + + public Collection getAllClasses() { + return Collections.unmodifiableList(allClasses); + } } diff --git a/src/main/java/net/fabricmc/stitch/util/FieldNameFinder.java b/src/main/java/net/fabricmc/stitch/util/FieldNameFinder.java deleted file mode 100644 index 8e3ef6d..0000000 --- a/src/main/java/net/fabricmc/stitch/util/FieldNameFinder.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.util; - -import net.fabricmc.mappings.EntryTriple; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.analysis.Analyzer; -import org.objectweb.asm.tree.analysis.Frame; -import org.objectweb.asm.tree.analysis.SourceInterpreter; -import org.objectweb.asm.tree.analysis.SourceValue; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; - -public class FieldNameFinder { - - public Map findNames(Iterable classes) throws Exception { - Map> methods = new HashMap<>(); - Map> enumFields = new HashMap<>(); - - for (byte[] data : classes) { - ClassReader reader = new ClassReader(data); - NameFinderVisitor vClass = new NameFinderVisitor(StitchUtil.ASM_VERSION, enumFields, methods); - reader.accept(vClass, ClassReader.SKIP_FRAMES); - } - - return findNames(enumFields, methods); - } - - public Map findNames(Map> allEnumFields, Map> classes) throws Exception { - Analyzer analyzer = new Analyzer<>(new SourceInterpreter()); - Map fieldNames = new HashMap<>(); - Map> fieldNamesUsed = new HashMap<>(); - Map> fieldNamesDuplicate = new HashMap<>(); - - for (Map.Entry> entry : classes.entrySet()) { - String owner = entry.getKey(); - Set enumFields = allEnumFields.getOrDefault(owner, Collections.emptySet()); - for (MethodNode mn : entry.getValue()) { - Frame[] frames = analyzer.analyze(owner, mn); - - InsnList instrs = mn.instructions; - for (int i = 1; i < instrs.size(); i++) { - AbstractInsnNode instr1 = instrs.get(i - 1); - AbstractInsnNode instr2 = instrs.get(i); - String s = null; - - if (instr2.getOpcode() == Opcodes.PUTSTATIC && ((FieldInsnNode) instr2).owner.equals(owner) - && (instr1 instanceof MethodInsnNode && ((MethodInsnNode) instr1).owner.equals(owner) || enumFields.contains(((FieldInsnNode) instr2).desc + ((FieldInsnNode) instr2).name)) - && (instr1.getOpcode() == Opcodes.INVOKESTATIC || (instr1.getOpcode() == Opcodes.INVOKESPECIAL && "".equals(((MethodInsnNode) instr1).name)))) { - - for (int j = 0; j < frames[i - 1].getStackSize(); j++) { - SourceValue sv = frames[i - 1].getStack(j); - for (AbstractInsnNode ci : sv.insns) { - if (ci instanceof LdcInsnNode && ((LdcInsnNode) ci).cst instanceof String) { - //if (s == null || !s.equals(((LdcInsnNode) ci).cst)) { - if (s == null) { - s = (String) (((LdcInsnNode) ci).cst); - // stringsFound++; - } - } - } - } - } - - if (s != null) { - if (s.contains(":")) { - s = s.substring(s.indexOf(':') + 1); - } - - if (s.contains("/")) { - int separator = s.indexOf('/'); - String sFirst = s.substring(0, separator); - String sLast; - if (s.contains(".") && s.indexOf('.') > separator) { - sLast = s.substring(separator + 1, s.indexOf('.')); - } else { - sLast = s.substring(separator + 1); - } - if (sFirst.endsWith("s")) { - sFirst = sFirst.substring(0, sFirst.length() - 1); - } - s = sLast + "_" + sFirst; - } - - String oldS = s; - boolean hasAlpha = false; - - for (int j = 0; j < s.length(); j++) { - char c = s.charAt(j); - - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { - hasAlpha = true; - } - - if (!(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') && !(c >= '0' && c <= '9') && !(c == '_')) { - s = s.substring(0, j) + "_" + s.substring(j + 1); - } else if (j > 0 && Character.isUpperCase(s.charAt(j)) && Character.isLowerCase(s.charAt(j - 1))) { - s = s.substring(0, j) + "_" + s.substring(j, j + 1).toLowerCase(Locale.ROOT) + s.substring(j + 1); - } - } - - if (hasAlpha) { - s = s.toUpperCase(Locale.ROOT); - - Set usedNames = fieldNamesUsed.computeIfAbsent(((FieldInsnNode) instr2).owner, (a) -> new HashSet<>()); - Set usedNamesDuplicate = fieldNamesDuplicate.computeIfAbsent(((FieldInsnNode) instr2).owner, (a) -> new HashSet<>()); - - if (!usedNamesDuplicate.contains(s)) { - if (!usedNames.add(s)) { - System.err.println("Warning: Duplicate key: " + s + " (" + oldS + ")!"); - usedNamesDuplicate.add(s); - usedNames.remove(s); - } - } - - if (usedNames.contains(s)) { - fieldNames.put(new EntryTriple(((FieldInsnNode) instr2).owner, ((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc), s); - } - } - } - } - } - } - - return fieldNames; - } - - public Map findNames(File file) { - List byteArrays = new ArrayList<>(); - - try { - try (FileInputStream fis = new FileInputStream(file); - JarInputStream jis = new JarInputStream(fis)) { - byte[] buffer = new byte[32768]; - JarEntry entry; - - while ((entry = jis.getNextJarEntry()) != null) { - if (!entry.getName().endsWith(".class")) { - continue; - } - - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - int l; - while ((l = jis.read(buffer, 0, buffer.length)) > 0) { - stream.write(buffer, 0, l); - } - - byteArrays.add(stream.toByteArray()); - } - } - - return findNames(byteArrays); - } catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/net/fabricmc/stitch/util/MatcherUtil.java b/src/main/java/net/fabricmc/stitch/util/MatcherUtil.java index d5865c6..f1f687b 100644 --- a/src/main/java/net/fabricmc/stitch/util/MatcherUtil.java +++ b/src/main/java/net/fabricmc/stitch/util/MatcherUtil.java @@ -16,73 +16,74 @@ package net.fabricmc.stitch.util; -import net.fabricmc.mappings.EntryTriple; - import java.io.BufferedReader; import java.io.IOException; import java.util.function.BiConsumer; -import java.util.function.UnaryOperator; + +import net.fabricmc.mapping.util.EntryTriple; public final class MatcherUtil { - private MatcherUtil() { + public static void read(BufferedReader reader, boolean invert, BiConsumer classMappingConsumer, BiConsumer fieldMappingConsumer, BiConsumer methodMappingConsumer) throws IOException { + String line; + String ownerFrom = null, ownerTo = null; + + while ((line = reader.readLine()) != null) { + String[] parts = line.split("\t"); + + if (parts[0].equals("c") && parts.length == 3) { + // class + ownerFrom = parts[1].substring(1, parts[1].length() - 1); + ownerTo = parts[2].substring(1, parts[2].length() - 1); - } + if (invert) { + classMappingConsumer.accept(ownerTo, ownerFrom); + } else { + classMappingConsumer.accept(ownerFrom, ownerTo); + } + } else if (parts[0].equals("") && ownerFrom != null && parts.length >= 2) { + if (parts[1].equals("f") && parts.length == 4) { + String[] fieldFrom = parts[2].split(";;"); + String[] fieldTo = parts[3].split(";;"); - public static void read(BufferedReader reader, boolean invert, BiConsumer classMappingConsumer, BiConsumer fieldMappingConsumer, BiConsumer methodMappingConsumer) throws IOException { - String line; - String ownerFrom = null, ownerTo = null; + if (invert) { + fieldMappingConsumer.accept( + new EntryTriple(ownerTo, fieldTo[0], fieldTo[1]), + new EntryTriple(ownerFrom, fieldFrom[0], fieldFrom[1]) + ); + } else { + fieldMappingConsumer.accept( + new EntryTriple(ownerFrom, fieldFrom[0], fieldFrom[1]), + new EntryTriple(ownerTo, fieldTo[0], fieldTo[1]) + ); + } + } else if (parts[1].equals("m") && parts.length == 4) { + String[] methodFrom = toMethodArray(parts[2]); + String[] methodTo = toMethodArray(parts[3]); - while ((line = reader.readLine()) != null) { - String[] parts = line.split("\t"); + if (invert) { + methodMappingConsumer.accept( + new EntryTriple(ownerTo, methodTo[0], methodTo[1]), + new EntryTriple(ownerFrom, methodFrom[0], methodFrom[1]) + ); + } else { + methodMappingConsumer.accept( + new EntryTriple(ownerFrom, methodFrom[0], methodFrom[1]), + new EntryTriple(ownerTo, methodTo[0], methodTo[1]) + ); + } + } + } + } + } - if (parts[0].equals("c") && parts.length == 3) { - // class - ownerFrom = parts[1].substring(1, parts[1].length() - 1); - ownerTo = parts[2].substring(1, parts[2].length() - 1); - if (invert) { - classMappingConsumer.accept(ownerTo, ownerFrom); - } else { - classMappingConsumer.accept(ownerFrom, ownerTo); - } - } else if (parts[0].equals("") && ownerFrom != null && parts.length >= 2) { - if (parts[1].equals("f") && parts.length == 4) { - String[] fieldFrom = parts[2].split(";;"); - String[] fieldTo = parts[3].split(";;"); - if (invert) { - fieldMappingConsumer.accept( - new EntryTriple(ownerTo, fieldTo[0], fieldTo[1]), - new EntryTriple(ownerFrom, fieldFrom[0], fieldFrom[1]) - ); - } else { - fieldMappingConsumer.accept( - new EntryTriple(ownerFrom, fieldFrom[0], fieldFrom[1]), - new EntryTriple(ownerTo, fieldTo[0], fieldTo[1]) - ); - } - } else if (parts[1].equals("m") && parts.length == 4) { - String[] methodFrom = toMethodArray(parts[2]); - String[] methodTo = toMethodArray(parts[3]); - if (invert) { - methodMappingConsumer.accept( - new EntryTriple(ownerTo, methodTo[0], methodTo[1]), - new EntryTriple(ownerFrom, methodFrom[0], methodFrom[1]) - ); - } else { - methodMappingConsumer.accept( - new EntryTriple(ownerFrom, methodFrom[0], methodFrom[1]), - new EntryTriple(ownerTo, methodTo[0], methodTo[1]) - ); - } - } - } - } - } + private static String[] toMethodArray(String part) { + int parenPos = part.indexOf('('); + return new String[] { + part.substring(0, parenPos), + part.substring(parenPos) + }; + } - private static String[] toMethodArray(String part) { - int parenPos = part.indexOf('('); - return new String[] { - part.substring(0, parenPos), - part.substring(parenPos) - }; - } -} \ No newline at end of file + private MatcherUtil() { + } +} diff --git a/src/main/java/net/fabricmc/stitch/util/NameFinderVisitor.java b/src/main/java/net/fabricmc/stitch/util/NameFinderVisitor.java index 79b62c7..f128ae5 100644 --- a/src/main/java/net/fabricmc/stitch/util/NameFinderVisitor.java +++ b/src/main/java/net/fabricmc/stitch/util/NameFinderVisitor.java @@ -16,18 +16,18 @@ package net.fabricmc.stitch.util; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.MethodNode; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.MethodNode; + public class NameFinderVisitor extends ClassVisitor { private String owner; private final Map> allEnumFields; @@ -52,6 +52,7 @@ public FieldVisitor visitField(int access, String name, String descriptor, Strin throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\"!"); } } + return super.visitField(access, name, descriptor, signature, value); } diff --git a/src/main/java/net/fabricmc/stitch/util/Pair.java b/src/main/java/net/fabricmc/stitch/util/Pair.java index 1025f67..4d490a1 100644 --- a/src/main/java/net/fabricmc/stitch/util/Pair.java +++ b/src/main/java/net/fabricmc/stitch/util/Pair.java @@ -19,57 +19,57 @@ import java.util.Objects; public final class Pair { - private final K left; - private final V right; + private final K left; + private final V right; - private Pair(K left, V right) { - this.left = left; - this.right = right; - } + private Pair(K left, V right) { + this.left = left; + this.right = right; + } - public static Pair of(K left, V right) { - return new Pair<>(left, right); - } + public static Pair of(K left, V right) { + return new Pair<>(left, right); + } - public K getLeft() { - return left; - } + public K getLeft() { + return left; + } - public V getRight() { - return right; - } + public V getRight() { + return right; + } - @Override - protected Object clone() throws CloneNotSupportedException { - //noinspection unchecked - return new Pair(left, right); - } + @Override + protected Object clone() throws CloneNotSupportedException { + //noinspection unchecked + return new Pair(left, right); + } - @Override - public boolean equals(Object o) { - if (!(o instanceof Pair)) { - return false; - } else { - Pair other = (Pair) o; - return Objects.equals(other.left, left) && Objects.equals(other.right, right); - } - } + @Override + public boolean equals(Object o) { + if (!(o instanceof Pair)) { + return false; + } else { + Pair other = (Pair) o; + return Objects.equals(other.left, left) && Objects.equals(other.right, right); + } + } - @Override - public int hashCode() { - if (left == null && right == null) { - return 0; - } else if (left == null) { - return right.hashCode(); - } else if (right == null) { - return left.hashCode(); - } else { - return left.hashCode() * 19 + right.hashCode(); - } - } + @Override + public int hashCode() { + if (left == null && right == null) { + return 0; + } else if (left == null) { + return right.hashCode(); + } else if (right == null) { + return left.hashCode(); + } else { + return left.hashCode() * 19 + right.hashCode(); + } + } - @Override - public String toString() { - return "Pair(" + left + "," + right + ")"; - } + @Override + public String toString() { + return "Pair(" + left + "," + right + ")"; + } } diff --git a/src/main/java/net/fabricmc/stitch/util/RecordValidator.java b/src/main/java/net/fabricmc/stitch/util/RecordValidator.java index 35fad3d..e8c7ff4 100644 --- a/src/main/java/net/fabricmc/stitch/util/RecordValidator.java +++ b/src/main/java/net/fabricmc/stitch/util/RecordValidator.java @@ -16,15 +16,6 @@ package net.fabricmc.stitch.util; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.RecordComponentNode; - import java.io.File; import java.io.IOException; import java.nio.file.FileVisitResult; @@ -35,6 +26,15 @@ import java.util.LinkedList; import java.util.List; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.RecordComponentNode; + public class RecordValidator implements AutoCloseable { private static final String[] REQUIRED_METHOD_SIGNATURES = new String[]{ "toString()Ljava/lang/String;", @@ -45,7 +45,6 @@ public class RecordValidator implements AutoCloseable { private final StitchUtil.FileSystemDelegate inputFs; private final Path inputJar; private final boolean printInfo; - private final List errors = new LinkedList<>(); public RecordValidator(File jarFile, boolean printInfo) throws IOException { @@ -89,6 +88,7 @@ private boolean validateClass(byte[] classBytes) { for (RecordComponentNode component : classNode.recordComponents) { // Ensure that a matching method is present boolean foundMethod = false; + for (MethodNode method : classNode.methods) { if (method.name.equals(component.name) && method.desc.equals("()" +component.descriptor)) { foundMethod = true; @@ -98,6 +98,7 @@ private boolean validateClass(byte[] classBytes) { // Ensure that a matching field is present boolean foundField = false; + for (FieldNode field : classNode.fields) { if (field.name.equals(component.name) && field.desc.equals(component.descriptor)) { foundField = true; @@ -117,6 +118,7 @@ private boolean validateClass(byte[] classBytes) { // Ensure that all of the expected methods are present for (String requiredMethodSignature : REQUIRED_METHOD_SIGNATURES) { boolean foundMethod = false; + for (MethodNode method : classNode.methods) { if ((method.name + method.desc).equals(requiredMethodSignature)) { foundMethod = true; @@ -140,7 +142,6 @@ private boolean validateClass(byte[] classBytes) { // Just print some info out about the record. private void printInfo(ClassNode classNode) { StringBuilder sb = new StringBuilder(); - sb.append("Found record ").append(classNode.name).append(" with components:\n"); for (RecordComponentNode componentNode : classNode.recordComponents) { @@ -174,12 +175,10 @@ private String extractToString(ClassNode classNode) { for (AbstractInsnNode insnNode : methodNode.instructions) { if (insnNode instanceof InvokeDynamicInsnNode) { InvokeDynamicInsnNode invokeDynamic = (InvokeDynamicInsnNode) insnNode; - if ( - !invokeDynamic.name.equals("toString") || - !invokeDynamic.desc.equals(String.format("(L%s;)Ljava/lang/String;", classNode.name)) || - !invokeDynamic.bsm.getName().equals("bootstrap") || - !invokeDynamic.bsm.getOwner().equals("java/lang/runtime/ObjectMethods") - ) { + if (!invokeDynamic.name.equals("toString") + || !invokeDynamic.desc.equals(String.format("(L%s;)Ljava/lang/String;", classNode.name)) + || !invokeDynamic.bsm.getName().equals("bootstrap") + || !invokeDynamic.bsm.getOwner().equals("java/lang/runtime/ObjectMethods")) { // Not what we are looking for continue; } diff --git a/src/main/java/net/fabricmc/stitch/util/SnowmanClassVisitor.java b/src/main/java/net/fabricmc/stitch/util/SnowmanClassVisitor.java index 7e165f3..fba3333 100644 --- a/src/main/java/net/fabricmc/stitch/util/SnowmanClassVisitor.java +++ b/src/main/java/net/fabricmc/stitch/util/SnowmanClassVisitor.java @@ -44,9 +44,11 @@ public void visitLocalVariable( final Label end, final int index) { String newName = name; + if (name != null && name.startsWith("\u2603")) { newName = "lvt" + index; } + super.visitLocalVariable(newName, descriptor, signature, start, end, index); } } diff --git a/src/main/java/net/fabricmc/stitch/util/StitchUtil.java b/src/main/java/net/fabricmc/stitch/util/StitchUtil.java index 3052ea6..69e32ce 100644 --- a/src/main/java/net/fabricmc/stitch/util/StitchUtil.java +++ b/src/main/java/net/fabricmc/stitch/util/StitchUtil.java @@ -16,114 +16,121 @@ package net.fabricmc.stitch.util; -import org.objectweb.asm.Opcodes; - import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLEncoder; import java.nio.file.FileSystem; import java.nio.file.FileSystemAlreadyExistsException; import java.nio.file.FileSystems; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; -public final class StitchUtil { +import org.objectweb.asm.Opcodes; - public static int ASM_VERSION = Opcodes.ASM9; - - public static class FileSystemDelegate implements AutoCloseable { - private final FileSystem fileSystem; - private final boolean owner; - - public FileSystemDelegate(FileSystem fileSystem, boolean owner) { - this.fileSystem = fileSystem; - this.owner = owner; - } - - public FileSystem get() { - return fileSystem; - } - - @Override - public void close() throws IOException { - if (owner) { - fileSystem.close(); - } - } - } - - private StitchUtil() { - - } - - private static final Map jfsArgsCreate = new HashMap<>(); - private static final Map jfsArgsEmpty = new HashMap<>(); - - static { - jfsArgsCreate.put("create", "true"); - } - - public static FileSystemDelegate getJarFileSystem(File f, boolean create) throws IOException { - URI jarUri; - try { - jarUri = new URI("jar:file", null, f.toURI().getPath(), ""); - } catch (URISyntaxException e) { - throw new IOException(e); - } - - try { - return new FileSystemDelegate(FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty), true); - } catch (FileSystemAlreadyExistsException e) { - return new FileSystemDelegate(FileSystems.getFileSystem(jarUri), false); - } - } - - public static String join(String joiner, Collection c) { - StringBuilder builder = new StringBuilder(); - int i = 0; - for (String s : c) { - if ((i++) > 0) { - builder.append(joiner); - } - - builder.append(s); - } - return builder.toString(); - } - - public static Set newIdentityHashSet() { - return Collections.newSetFromMap(new IdentityHashMap<>()); - } - - public static List mergePreserveOrder(List first, List second) { - List out = new ArrayList<>(); - int i = 0; - int j = 0; - - while (i < first.size() || j < second.size()) { - while (i < first.size() && j < second.size() - && first.get(i).equals(second.get(j))) { - out.add(first.get(i)); - i++; - j++; - } - - while (i < first.size() && !second.contains(first.get(i))) { - out.add(first.get(i)); - i++; - } - - while (j < second.size() && !first.contains(second.get(j))) { - out.add(second.get(j)); - j++; - } - } - - return out; - } - - public static long getTime() { - return new Date().getTime(); - } +public final class StitchUtil { + private static final Map jfsArgsCreate = new HashMap<>(); + private static final Map jfsArgsEmpty = new HashMap<>(); + public static final int ASM_VERSION = Opcodes.ASM9; + + static { + jfsArgsCreate.put("create", "true"); + } + + public static class FileSystemDelegate implements AutoCloseable { + private final FileSystem fileSystem; + private final boolean owner; + + public FileSystemDelegate(FileSystem fileSystem, boolean owner) { + this.fileSystem = fileSystem; + this.owner = owner; + } + + public FileSystem get() { + return fileSystem; + } + + @Override + public void close() throws IOException { + if (owner) { + fileSystem.close(); + } + } + } + + public static FileSystemDelegate getJarFileSystem(File f, boolean create) throws IOException { + URI jarUri; + + try { + jarUri = new URI("jar:file", null, f.toURI().getPath(), ""); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + try { + return new FileSystemDelegate(FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty), true); + } catch (FileSystemAlreadyExistsException e) { + return new FileSystemDelegate(FileSystems.getFileSystem(jarUri), false); + } + } + + public static String join(String joiner, Collection c) { + StringBuilder builder = new StringBuilder(); + int i = 0; + + for (String s : c) { + if ((i++) > 0) { + builder.append(joiner); + } + + builder.append(s); + } + + return builder.toString(); + } + + public static Set newIdentityHashSet() { + return Collections.newSetFromMap(new IdentityHashMap<>()); + } + + public static List mergePreserveOrder(List first, List second) { + List out = new ArrayList<>(); + int i = 0; + int j = 0; + + while (i < first.size() || j < second.size()) { + while (i < first.size() && j < second.size() + && first.get(i).equals(second.get(j))) { + out.add(first.get(i)); + i++; + j++; + } + + while (i < first.size() && !second.contains(first.get(i))) { + out.add(first.get(i)); + i++; + } + + while (j < second.size() && !first.contains(second.get(j))) { + out.add(second.get(j)); + j++; + } + } + + return out; + } + + public static long getTime() { + return new Date().getTime(); + } + + private StitchUtil() { + } } diff --git a/src/main/java/net/fabricmc/stitch/util/SyntheticParameterClassVisitor.java b/src/main/java/net/fabricmc/stitch/util/SyntheticParameterClassVisitor.java index 96934a5..2c5c3fd 100644 --- a/src/main/java/net/fabricmc/stitch/util/SyntheticParameterClassVisitor.java +++ b/src/main/java/net/fabricmc/stitch/util/SyntheticParameterClassVisitor.java @@ -25,81 +25,87 @@ * ProGuard has a bug where parameter annotations are applied incorrectly in the presence of * synthetic arguments. This causes javac to balk when trying to load affected classes. * - * We use several heuristics to guess what the synthetic arguments may be for a particular + *

We use several heuristics to guess what the synthetic arguments may be for a particular * constructor. We then check if the constructor matches our guess, and if so, offset all - * parameter annotations. + * parameter annotations.

*/ public class SyntheticParameterClassVisitor extends ClassVisitor { - private class SyntheticMethodVisitor extends MethodVisitor { - private final int offset; - - SyntheticMethodVisitor(int api, int offset, MethodVisitor methodVisitor) { - super(api, methodVisitor); - this.offset = offset; - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) { - return super.visitParameterAnnotation(parameter - offset, descriptor, visible); - } - - @Override - public void visitAnnotableParameterCount(int parameterCount, boolean visible) { - super.visitAnnotableParameterCount(parameterCount - offset, visible); - } - } - - private String className; - private int synthetic; - private String syntheticArgs; - private boolean backoff = false; - - public SyntheticParameterClassVisitor(int api, ClassVisitor cv) { - super(api, cv); - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - super.visit(version, access, name, signature, superName, interfaces); - - this.className = name; - - // Enums will always have a string name and then the ordinal - if ((access & Opcodes.ACC_ENUM) != 0) { - synthetic = 2; - syntheticArgs = "(Ljava/lang/String;I"; - } - - if (version >= 55) { - // Backoff on java 11 or newer due to nest mates being used. - backoff = true; - } - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - super.visitInnerClass(name, outerName, innerName, access); - - // If we're a non-static, non-anonymous inner class then we can assume the first argument - // is the parent class. - // See https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#jls-8.8.1 - if (synthetic == 0 && name.equals(this.className) && innerName != null && outerName != null && (access & Opcodes.ACC_STATIC) == 0) { - this.synthetic = 1; - this.syntheticArgs = "(L" + outerName + ";"; - } - } - - @Override - public MethodVisitor visitMethod( - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); - - return mv != null && synthetic != 0 && name.equals("") && descriptor.startsWith(syntheticArgs) && !backoff - ? new SyntheticMethodVisitor(api, synthetic, mv) - : mv; - } + private class SyntheticMethodVisitor extends MethodVisitor { + private final int offset; + + SyntheticMethodVisitor(int api, int offset, MethodVisitor methodVisitor) { + super(api, methodVisitor); + this.offset = offset; + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) { + return super.visitParameterAnnotation(parameter - offset, descriptor, visible); + } + + @Override + public void visitAnnotableParameterCount(int parameterCount, boolean visible) { + super.visitAnnotableParameterCount(parameterCount - offset, visible); + } + } + + private String className; + private int synthetic; + private String syntheticArgs; + private boolean backoff = false; + + public SyntheticParameterClassVisitor(int api, ClassVisitor cv) { + super(api, cv); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + super.visit(version, access, name, signature, superName, interfaces); + + this.className = name; + + // Enums will always have a string name and then the ordinal + if ((access & Opcodes.ACC_ENUM) != 0) { + synthetic = 2; + syntheticArgs = "(Ljava/lang/String;I"; + } + + if (version >= 55) { + // Backoff on java 11 or newer due to nest mates being used. + backoff = true; + } + } + + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + super.visitInnerClass(name, outerName, innerName, access); + + // If we're a non-static, non-anonymous inner class then we can assume the first argument + // is the parent class. + // See https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#jls-8.8.1 + if (synthetic == 0 && name.equals(this.className) && innerName != null && outerName != null && (access & Opcodes.ACC_STATIC) == 0) { + this.synthetic = 1; + this.syntheticArgs = "(L" + outerName + ";"; + } + } + + @Override + public MethodVisitor visitMethod( + final int access, + final String name, + final String descriptor, + final String signature, + final String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); + + if (mv != null + && synthetic != 0 + && name.equals("") + && descriptor.startsWith(syntheticArgs) + && !backoff) { + return new SyntheticMethodVisitor(api, synthetic, mv); + } + + return mv; + } } diff --git a/src/main/resources/META-INF/services/cuchaz.enigma.api.EnigmaPlugin b/src/main/resources/META-INF/services/cuchaz.enigma.api.EnigmaPlugin deleted file mode 100644 index 5c2c654..0000000 --- a/src/main/resources/META-INF/services/cuchaz.enigma.api.EnigmaPlugin +++ /dev/null @@ -1 +0,0 @@ -net.fabricmc.stitch.enigma.StitchEnigmaPlugin \ No newline at end of file diff --git a/src/test/java/net/fabricmc/stitch/tinyv1/Commands.java b/src/test/java/net/fabricmc/stitch/tinyv1/Commands.java deleted file mode 100644 index 7464e85..0000000 --- a/src/test/java/net/fabricmc/stitch/tinyv1/Commands.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.tinyv1; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import net.fabricmc.stitch.commands.CommandProposeFieldNames; -import net.fabricmc.stitch.commands.CommandReorderTiny; - -public class Commands { - @Test - @Disabled - public void testOrdering() throws Exception { - String[] args = { - "local\\unordered-merged-mappings.tiny", - "local\\merged-mappings.tiny", - "official", "intermediary", "named" - }; - - new CommandReorderTiny().run(args); - } - - @Test - @Disabled - public void testProposing() throws Exception { - String[] args = { - "local\\19w37a-merged.jar", - "local\\merged-mappings.tiny", - "local\\merged-mappings-proposed.tiny" - }; - - new CommandProposeFieldNames().run(args); - } -} diff --git a/src/test/java/net/fabricmc/stitch/tinyv2/Commands.java b/src/test/java/net/fabricmc/stitch/tinyv2/Commands.java deleted file mode 100644 index 8d6a55e..0000000 --- a/src/test/java/net/fabricmc/stitch/tinyv2/Commands.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.tinyv2; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2; -import net.fabricmc.stitch.commands.tinyv2.CommandProposeV2FieldNames; -import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2; - -public class Commands { - public static void reorder(String toInvert, String outputTo, String... newOrder) throws Exception { - List args = new ArrayList<>(); - args.add(toInvert); - args.add(outputTo); - args.addAll(Arrays.asList(newOrder)); - - new CommandReorderTinyV2().run(args.toArray(new String[0])); - } - - - public static void merge(String mappingA, String mappingB, String mergedLocation) throws Exception { - new CommandMergeTinyV2().run(new String[] {mappingA, mappingB, mergedLocation}); - } - - - public static void proposeFieldNames(String mergedJar, String mergedTinyFile, String newTinyFile) throws Exception { - new CommandProposeV2FieldNames().run(new String[] {mergedJar, mergedTinyFile, newTinyFile}); - } - - -} diff --git a/src/test/java/net/fabricmc/stitch/tinyv2/Snapshot37a.java b/src/test/java/net/fabricmc/stitch/tinyv2/Snapshot37a.java deleted file mode 100644 index 1e3b4d3..0000000 --- a/src/test/java/net/fabricmc/stitch/tinyv2/Snapshot37a.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.tinyv2; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Paths; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -public class Snapshot37a { - - private static final String DIR = new File(Snapshot37a.class.getClassLoader().getResource("snapshot-37a").getPath()).getAbsolutePath() + "/"; -// - @Test - public void testMerge() throws Exception { - Commands.merge(DIR + "intermediate-mappings-inverted-stitch.tinyv2", - DIR + "yarn-mappings-stitch.tinyv2", - DIR + "merged-unordered.tinyv2" - ); - } - - @Test - public void testReorder2() throws Exception { - Commands.reorder(DIR + "intermediate-mappings-stitch.tinyv2", - DIR + "intermediate-mappings-inverted-stitch.tinyv2", - "intermediary", "official" - ); - } - - @Test - public void testReorder3() throws Exception { - String path = DIR + "merged-unordered.tinyv2"; - if(!Files.exists(Paths.get(path))) testMerge(); - Commands.reorder(path, - DIR + "merged.tinyv2", - "official", "intermediary", "named" - ); - } - - /** You need the 19w37a-merged.jar file under local/ */ - @Test - @Disabled - public void testFieldNameProposal() throws Exception { - Commands.proposeFieldNames("local/19w37a-merged.jar", - DIR + "merged.tinyv2", DIR + "merged-proposed.tinyv2"); - } -} diff --git a/src/test/java/net/fabricmc/stitch/tinyv2/Stable1_14_4.java b/src/test/java/net/fabricmc/stitch/tinyv2/Stable1_14_4.java deleted file mode 100644 index 63056af..0000000 --- a/src/test/java/net/fabricmc/stitch/tinyv2/Stable1_14_4.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.tinyv2; - -import java.io.BufferedReader; -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.Optional; -import java.util.function.Predicate; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import net.fabricmc.mapping.tree.ClassDef; -import net.fabricmc.mapping.tree.MethodDef; -import net.fabricmc.mapping.tree.ParameterDef; -import net.fabricmc.mapping.tree.TinyMappingFactory; -import net.fabricmc.mapping.tree.TinyTree; - -public class Stable1_14_4 { - private static final String DIR = new File(Stable1_14_4.class.getClassLoader().getResource("stable-1.14.4").getPath()).getAbsolutePath() + "/"; - - @Test - public void testReorder2() throws Exception { - Commands.reorder(DIR + "intermediary-mappings.tinyv2", - DIR + "intermediary-mappings-inverted.tinyv2", - "intermediary", "official" - ); - } - - @Test - @Disabled - public void testMerge() throws Exception { - String target = DIR + "merged-unordered.tinyv2"; - Commands.merge(DIR + "intermediary-mappings-inverted.tinyv2", - DIR + "yarn-mappings.tinyv2", - target - ); - try (BufferedReader reader = Files.newBufferedReader(Paths.get(target))) { - TinyTree mappings = TinyMappingFactory.load(reader); - - ParameterDef blockInitParam = findMethodParameterMapping("intermediary", "net/minecraft/class_2248", - "", "(Lnet/minecraft/class_2248$class_2251;)V", 1, mappings); - - Assertions.assertEquals("settings", blockInitParam.getName("named")); - - } - - } - - private ClassDef findClassMapping(String column, String key, TinyTree mappings) { - return find(mappings.getClasses(), c -> c.getName(column).equals(key)) - .orElseThrow(() -> new AssertionError("Could not find key " + key + " in namespace " + column)); - } - - private MethodDef findMethodMapping(String column, String className, String methodName, String descriptor, TinyTree mappings) { - return find(findClassMapping(column, className, mappings).getMethods(), - m -> m.getName(column).equals(methodName) && m.getDescriptor(column).equals(descriptor) - - ).orElseThrow(() -> new AssertionError("Could not find key " + className + " " + descriptor + " " + methodName + " in namespace " + column)); - } - - - private ParameterDef findMethodParameterMapping(String column, String className, String methodName, String descriptor, - int lvIndex, TinyTree mappings) { - MethodDef method = findMethodMapping(column, className, methodName, descriptor, mappings); - return find(method.getParameters(), - p -> p.getLocalVariableIndex() == lvIndex) - .orElseThrow(() -> new AssertionError("Could not find key" + className + " " + descriptor + " " + methodName + " " + lvIndex + " in namespace " + column)); - } - - private Optional find(Collection list, Predicate predicate) { - return list.stream().filter(predicate).findFirst(); - } - - - @Test - @Disabled - public void testReorder3() throws Exception { - Commands.reorder(DIR + "merged-unordered.tinyv2", - DIR + "merged.tinyv2", - "official", "intermediary", "named" - ); - } - - @Test - @Disabled - public void testFieldNameProposal() throws Exception { - Commands.proposeFieldNames("local/1.14.4-merged.jar", - DIR + "merged.tinyv2", DIR + "merged-proposed.tinyv2"); - } - - // Requirements: - // - Official -> Intermediary mappings "intermediary-mappings.tinyv2" from enigma - // - Intermediary -> Named mappings "yarn-mappings.tinyv2" from yarn - // - 1.14.4 merged jar from yarn at local/1.14.4-merge.jar - @Test - @Disabled - public void testFullProcess() throws Exception { - testReorder2(); - testMerge(); - testReorder3(); - testFieldNameProposal(); - } -} diff --git a/src/test/java/net/fabricmc/stitch/tinyv2/TestTinyV2ReadAndWrite.java b/src/test/java/net/fabricmc/stitch/tinyv2/TestTinyV2ReadAndWrite.java deleted file mode 100644 index dbd74fb..0000000 --- a/src/test/java/net/fabricmc/stitch/tinyv2/TestTinyV2ReadAndWrite.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.tinyv2; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import net.fabricmc.stitch.commands.tinyv2.TinyFile; -import net.fabricmc.stitch.commands.tinyv2.TinyV2Reader; -import net.fabricmc.stitch.commands.tinyv2.TinyV2Writer; - -public class TestTinyV2ReadAndWrite { - private static final String DIR = new File(TestTinyV2ReadAndWrite.class.getClassLoader().getResource("sorted").getPath()).getAbsolutePath() + "/"; - - private void tryToReadAndWrite(String path) throws IOException { - Path intMappings = Paths.get(path); - TinyFile tinyFile = TinyV2Reader.read(intMappings); - - Path tempLocation = Paths.get(path + ".temp"); -// tempLocation.toFile().deleteOnExit(); - TinyV2Writer.write(tinyFile, tempLocation); - String originalIntMappings = new String(Files.readAllBytes(intMappings)); - String writtenIntMappings = new String(Files.readAllBytes(tempLocation)); - - // Ensure the file has not changed - Assertions.assertEquals(originalIntMappings.replace("\r\n","\n"), writtenIntMappings.replace("\r\n","\n")); - - } - - @Test - public void ReadingAndWritingAV2FileLeavesItUnchanged() throws IOException { - tryToReadAndWrite(DIR + "intermediary-mappings.tinyv2"); - tryToReadAndWrite(DIR + "yarn-mappings.tinyv2"); - tryToReadAndWrite(DIR + "merged-proposed.tinyv2"); - tryToReadAndWrite(DIR + "test-skip"); - } -} diff --git a/src/test/java/net/fabricmc/stitch/tinyv2/TestToString.java b/src/test/java/net/fabricmc/stitch/tinyv2/TestToString.java deleted file mode 100644 index bb5065f..0000000 --- a/src/test/java/net/fabricmc/stitch/tinyv2/TestToString.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * 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 - * - * http://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. - */ - -package net.fabricmc.stitch.tinyv2; - -import java.util.Arrays; -import java.util.Collections; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import net.fabricmc.stitch.commands.tinyv2.TinyClass; -import net.fabricmc.stitch.commands.tinyv2.TinyField; -import net.fabricmc.stitch.commands.tinyv2.TinyMethod; - -public class TestToString { - - @Test - public void testTinyClassToString() { - TinyClass tinyClass = new TinyClass( - Arrays.asList("name1", "name2", "name3"), - Collections.singletonList(new TinyMethod("", - Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList())), - Collections.singletonList(new TinyField("", Collections.emptyList(), Collections.emptyList())), - Collections.singletonList("Asdf") - ); - - String expected = "TinyClass(names = [name1, name2, name3], 1 methods, 1 fields, 1 comments)"; - - Assertions.assertEquals(expected, tinyClass.toString()); - } - -} diff --git a/src/test/resources/snapshot-37a/intermediate-mappings-inverted-stitch.tinyv2 b/src/test/resources/snapshot-37a/intermediate-mappings-inverted-stitch.tinyv2 deleted file mode 100644 index 8f230c9..0000000 --- a/src/test/resources/snapshot-37a/intermediate-mappings-inverted-stitch.tinyv2 +++ /dev/null @@ -1,11 +0,0 @@ -tiny 2 0 intermediary official -c com/mojang/realmsclient/dto/RealmsServer com/mojang/realmsclient/dto/RealmsServer -c com/mojang/realmsclient/dto/RealmsServer$class_4319 com/mojang/realmsclient/dto/RealmsServer$a - m (Lcom/mojang/realmsclient/dto/RealmsServer;Lcom/mojang/realmsclient/dto/RealmsServer;)I method_20830 a - f Ljava/lang/String; field_19432 a -c net/minecraft/class_1043 dyo - m ()V method_4524 a - m ()Lnet/minecraft/class_1011; method_4525 e - m (Lnet/minecraft/class_1011;)V method_4526 a - m (Lnet/minecraft/class_3300;)V method_4625 a - f Lnet/minecraft/class_1011; field_5200 f \ No newline at end of file diff --git a/src/test/resources/snapshot-37a/intermediate-mappings-stitch.tinyv2 b/src/test/resources/snapshot-37a/intermediate-mappings-stitch.tinyv2 deleted file mode 100644 index ad2ecf5..0000000 --- a/src/test/resources/snapshot-37a/intermediate-mappings-stitch.tinyv2 +++ /dev/null @@ -1,11 +0,0 @@ -tiny 2 0 official intermediary -c a net/minecraft/class_1158 - m ()F a method_4921 - m (F)F a method_16003 - m (La;)V a method_4925 - m ()F b method_4922 - m (F)F b method_16002 - m ()F c method_4923 - m ()F d method_4924 - m ()V e method_4926 - f [F a field_5656 \ No newline at end of file diff --git a/src/test/resources/snapshot-37a/yarn-mappings-stitch.tinyv2 b/src/test/resources/snapshot-37a/yarn-mappings-stitch.tinyv2 deleted file mode 100644 index 4913d60..0000000 --- a/src/test/resources/snapshot-37a/yarn-mappings-stitch.tinyv2 +++ /dev/null @@ -1,38 +0,0 @@ -tiny 2 0 intermediary named -c com/mojang/realmsclient/dto/RealmsServer com/mojang/realmsclient/dto/RealmsServer - m (Ljava/util/Map;)Ljava/util/Map; cloneSlots cloneSlots - p 1 slots - m (Ljava/lang/Object;)Z equals equals - p 1 obj - m (Ljava/lang/String;)Lcom/mojang/realmsclient/dto/RealmsServer$class_4320; getState getState - p 0 state - m (Ljava/lang/String;)Lcom/mojang/realmsclient/dto/RealmsServer$class_4321; getWorldType getWorldType - p 0 state - m (Lcom/google/gson/JsonObject;)Lcom/mojang/realmsclient/dto/RealmsServer; parse parse - p 0 node - m (Ljava/lang/String;)Lcom/mojang/realmsclient/dto/RealmsServer; parse parse - p 0 json - m (Lcom/google/gson/JsonArray;)Ljava/util/List; parseInvited parseInvited - p 0 jsonArray - m (Lcom/google/gson/JsonArray;)Ljava/util/Map; parseSlots parseSlots - p 0 jsonArray - m (Ljava/lang/String;)V setDescription setDescription - p 1 motd - m (Ljava/lang/String;)V setName setName - p 1 name - m (Lcom/mojang/realmsclient/dto/RealmsServer;)V sortInvited sortInvited - p 0 server - m (Lcom/mojang/realmsclient/dto/RealmsServerPlayerList;)V updateServerPing updateServerPing - p 1 serverPlayerList -c com/mojang/realmsclient/dto/RealmsServer$class_4319 com/mojang/realmsclient/dto/RealmsServer$McoServerComparator - m (Ljava/lang/String;)V - p 1 owner - m (Lcom/mojang/realmsclient/dto/RealmsServer;Lcom/mojang/realmsclient/dto/RealmsServer;)I method_20830 compare - p 1 server1 - p 2 server2 - f Ljava/lang/String; field_19432 refOwner -c net/minecraft/class_1043 net/minecraft/client/texture/NativeImageBackedTexture - m ()V method_4524 upload - m ()Lnet/minecraft/class_1011; method_4525 getImage - m (Lnet/minecraft/class_1011;)V method_4526 setImage - f Lnet/minecraft/class_1011; field_5200 image \ No newline at end of file diff --git a/src/test/resources/sorted/intermediary-mappings.tinyv2 b/src/test/resources/sorted/intermediary-mappings.tinyv2 deleted file mode 100644 index 3daf75a..0000000 --- a/src/test/resources/sorted/intermediary-mappings.tinyv2 +++ /dev/null @@ -1,70 +0,0 @@ -tiny 2 0 official intermediary -c a net/minecraft/class_1158 - m ()F a method_4921 - m (F)F a method_16003 - m (La;)V a method_4925 - m ()F b method_4922 - m (F)F b method_16002 - m ()F c method_4923 - m ()F d method_4924 - m ()V e method_4926 - m (Ljava/lang/Object;)Z equals equals - m ()I hashCode hashCode - m ()Ljava/lang/String; toString toString - f [F a field_5656 -c aa net/minecraft/class_189 - m ()Ljava/lang/String; a method_831 - m (Ljava/lang/String;)Laa; a method_833 - m ()I b method_832 - m ()Lc; c method_830 - m (Ljava/lang/String;)Laa; valueOf valueOf - m ()[Laa; values values - f Laa; a field_1254 - f Laa; b field_1250 - f Laa; c field_1249 - f Ljava/lang/String; d field_1251 - f I e field_1252 - f Lc; f field_1255 - f [Laa; g field_1253 -c aaa net/minecraft/class_3538 - m ()Ljava/util/stream/Stream; a method_15418 - m (Laaa;)Ljava/util/List; a method_15419 - m (Laaa;)Ljava/util/Spliterator; b method_15420 - f Ljava/util/List; a field_15745 - f Ljava/util/Spliterator; b field_15746 -c aaa$1 net/minecraft/class_3538$1 - m (Ljava/util/function/Consumer;)Z tryAdvance tryAdvance - f Laaa; a field_15748 - f I b field_15747 -c aab net/minecraft/class_4213 - m (Lcom/mojang/datafixers/types/DynamicOps;)Ljava/lang/Object; a method_19508 -c aac net/minecraft/class_3540 - m ()V a method_15428 - m (DD)D a method_15429 - f D a field_15760 - f D b field_15759 - f D c field_15758 -c aad net/minecraft/class_3542 - m ()Ljava/lang/String; m method_15434 -c aae net/minecraft/class_3544 - m (I)Ljava/lang/String; a method_15439 - m (Ljava/lang/String;)Ljava/lang/String; a method_15440 - m (Ljava/lang/String;)Z b method_15438 - f Ljava/util/regex/Pattern; a field_15771 -c aaf net/minecraft/class_3545 - m ()Ljava/lang/Object; a method_15442 - m ()Ljava/lang/Object; b method_15441 - f Ljava/lang/Object; a field_15772 - f Ljava/lang/Object; b field_15773 -c aag net/minecraft/class_3902 - m (Ljava/lang/String;)Laag; valueOf valueOf - m ()[Laag; values values - f Laag; a field_17274 - f [Laag; b field_17275 -c aai net/minecraft/class_3549 - m (Ljava/util/List;)I a method_15445 - m (Ljava/util/List;I)Laai$a; a method_15447 - m (Ljava/util/Random;Ljava/util/List;)Laai$a; a method_15446 - m (Ljava/util/Random;Ljava/util/List;I)Laai$a; a method_15444 -c aai$a net/minecraft/class_3549$class_3550 - f I a field_15774 diff --git a/src/test/resources/sorted/merged-proposed.tinyv2 b/src/test/resources/sorted/merged-proposed.tinyv2 deleted file mode 100644 index 9c7f02b..0000000 --- a/src/test/resources/sorted/merged-proposed.tinyv2 +++ /dev/null @@ -1,56 +0,0 @@ -tiny 2 0 official intermediary named -c aak net/minecraft/class_3551 net/minecraft/datafixers/Schemas - m ()Lcom/mojang/datafixers/DataFixer; a method_15450 getFixer - m (Lcom/mojang/datafixers/DataFixerBuilder;)V a method_15451 build - p 0 builder - m (Ljava/lang/String;)Ljava/lang/String; a method_18051 method_18051 - m ()Lcom/mojang/datafixers/DataFixer; b method_15471 create - m (Ljava/lang/String;)Ljava/lang/String; b method_15460 method_15460 - m (Ljava/lang/String;)Ljava/lang/String; c method_15461 method_15461 - m (Ljava/lang/String;)Ljava/lang/String; d method_15456 method_15456 - m (Ljava/lang/String;)Ljava/lang/String; e method_15457 method_15457 - m (Ljava/lang/String;)Ljava/lang/String; f method_15463 method_15463 - m (Ljava/lang/String;)Ljava/lang/String; g method_15464 method_15464 - m (Ljava/lang/String;)Ljava/lang/String; h method_15468 method_15468 - m (Ljava/lang/String;)Ljava/lang/String; i method_15469 method_15469 - m (Ljava/lang/String;)Ljava/lang/String; j method_15472 method_15472 - m (Ljava/lang/String;)Ljava/lang/String; k method_15473 method_15473 - m (Ljava/lang/String;)Ljava/lang/String; l method_15466 method_15466 - m (Ljava/lang/String;)Ljava/lang/String; m method_15470 method_15470 - m (Ljava/lang/String;)Ljava/lang/String; n method_15467 method_15467 - m (Ljava/lang/String;)Ljava/lang/String; o method_15465 method_15465 - m (Ljava/lang/String;)Ljava/lang/String; p method_15452 method_15452 - m (Ljava/lang/String;)Ljava/lang/String; q method_15458 method_15458 - m (Ljava/lang/String;)Ljava/lang/String; r method_15453 method_15453 - m (Ljava/lang/String;)Ljava/lang/String; s method_15462 method_15462 - m (Ljava/lang/String;)Ljava/lang/String; t method_15454 method_15454 - m (Ljava/lang/String;)Ljava/lang/String; u method_15459 method_15459 - m (Ljava/lang/String;)Ljava/lang/String; v method_15455 method_15455 - m (Ljava/lang/String;)Ljava/lang/String; w method_15448 method_15448 - m (Ljava/lang/String;)Ljava/lang/String; x method_15449 method_15449 - f Ljava/util/function/BiFunction; a field_15776 empty - f Ljava/util/function/BiFunction; b field_15775 identNormalize - f Lcom/mojang/datafixers/DataFixer; c field_15777 fixer -c aak$1 net/minecraft/class_3551$1 net/minecraft/class_3551$1 -c aak$2 net/minecraft/class_3551$2 net/minecraft/class_3551$2 -c aal net/minecraft/class_4299 net/minecraft/datafixers/fixes/OminousBannerBlockEntityRenameFix - m (Lcom/mojang/datafixers/Dynamic;)Lcom/mojang/datafixers/Dynamic; a method_20481 fixBannerName -c aam net/minecraft/class_4294 net/minecraft/datafixers/fixes/OminousBannerItemRenameFix - m (Lcom/mojang/datafixers/Dynamic;)Lcom/mojang/datafixers/Dynamic; a method_20445 fixBannerName - p 1 tag - m (Lcom/mojang/datafixers/OpticFinder;Lcom/mojang/datafixers/OpticFinder;Lcom/mojang/datafixers/Typed;)Lcom/mojang/datafixers/Typed; a method_20446 method_20446 - m ()Lcom/mojang/datafixers/TypeRewriteRule; makeRule makeRule makeRule -c aan net/minecraft/class_3553 net/minecraft/datafixers/fixes/FixChoiceTypes - m (Lcom/mojang/datafixers/types/templates/TaggedChoice$TaggedChoiceType;Lcom/mojang/datafixers/types/DynamicOps;)Ljava/util/function/Function; a method_15477 method_15477 - m (Lcom/mojang/datafixers/types/templates/TaggedChoice$TaggedChoiceType;Lcom/mojang/datafixers/util/Pair;)Lcom/mojang/datafixers/util/Pair; a method_15475 method_15475 - m (Ljava/lang/String;Lcom/mojang/datafixers/types/templates/TaggedChoice$TaggedChoiceType;Lcom/mojang/datafixers/types/templates/TaggedChoice$TaggedChoiceType;)Lcom/mojang/datafixers/TypeRewriteRule; a method_15476 method_15476 - m ()Lcom/mojang/datafixers/TypeRewriteRule; makeRule makeRule makeRule - f Ljava/lang/String; a field_15779 name - f Lcom/mojang/datafixers/DSL$TypeReference; b field_15780 types -c aao net/minecraft/class_3555 net/minecraft/datafixers/fixes/AdvancementsFix - m (Lcom/mojang/datafixers/Dynamic;)Lcom/mojang/datafixers/Dynamic; a method_15496 method_15496 - m (Lcom/mojang/datafixers/Dynamic;Lcom/mojang/datafixers/util/Pair;)Lcom/mojang/datafixers/util/Pair; a method_15497 method_15497 - m (Lcom/mojang/datafixers/Dynamic;Ljava/lang/String;Lcom/mojang/datafixers/Dynamic;)Lcom/mojang/datafixers/Dynamic; a method_15495 method_15495 - m (Lcom/mojang/datafixers/Typed;)Lcom/mojang/datafixers/Typed; a method_15498 method_15498 - m ()Lcom/mojang/datafixers/TypeRewriteRule; makeRule makeRule makeRule - f Ljava/util/Map; a field_15788 RENAMED_ADVANCEMENTS diff --git a/src/test/resources/sorted/test-skip b/src/test/resources/sorted/test-skip deleted file mode 100644 index a32d575..0000000 --- a/src/test/resources/sorted/test-skip +++ /dev/null @@ -1,2 +0,0 @@ -tiny 2 0 official intermediary named -c a net/minecraft/util/math/Quaternion diff --git a/src/test/resources/sorted/yarn-mappings.tinyv2 b/src/test/resources/sorted/yarn-mappings.tinyv2 deleted file mode 100644 index ce540bd..0000000 --- a/src/test/resources/sorted/yarn-mappings.tinyv2 +++ /dev/null @@ -1,205 +0,0 @@ -tiny 2 0 intermediary named -c com/mojang/blaze3d/platform/GLX - m (I)V glActiveTexture glActiveTexture - p 0 texture - m (II)V glAttachShader glAttachShader - p 0 program - p 1 shader - m (II)V glBindBuffer glBindBuffer - p 0 target - p 1 bufferId - m (II)V glBindFramebuffer glBindFramebuffer - p 0 target - p 1 framebuffer - m (II)V glBindRenderbuffer glBindRenderbuffer - p 0 target - p 1 renderbuffer - m (IIII)V glBlendFuncSeparate glBlendFuncSeparate - p 0 sFactorRGB - p 1 dFactorRGB - p 2 sFactorAlpha - p 3 dFactorAlpha - m (ILjava/nio/ByteBuffer;I)V glBufferData glBufferData - p 0 target - p 1 data - p 2 usage - m (I)I glCheckFramebufferStatus glCheckFramebufferStatus - p 0 target - m (I)V glClientActiveTexture glClientActiveTexture - p 0 texture - m (I)V glCompileShader glCompileShader - p 0 shader - m (I)I glCreateShader glCreateShader - p 0 type - m (I)V glDeleteBuffers glDeleteBuffers - p 0 buffer - m (I)V glDeleteFramebuffers glDeleteFramebuffers - p 0 framebuffer - m (I)V glDeleteProgram glDeleteProgram - p 0 program - m (I)V glDeleteRenderbuffers glDeleteRenderbuffers - p 0 renderbuffer - m (I)V glDeleteShader glDeleteShader - p 0 shader - m (IIII)V glFramebufferRenderbuffer glFramebufferRenderbuffer - p 0 target - p 1 attachment - p 2 renderbufferTarget - p 3 renderbuffer - m (IIIII)V glFramebufferTexture2D glFramebufferTexture2D - p 0 target - p 1 attachment - p 2 texTarget - p 3 texture - p 4 level - m (ILjava/lang/CharSequence;)I glGetAttribLocation glGetAttribLocation - p 0 program - p 1 name - m (II)Ljava/lang/String; glGetProgramInfoLog glGetProgramInfoLog - p 0 program - p 1 maxLength - m (II)I glGetProgrami glGetProgrami - p 0 program - p 1 programName - m (II)Ljava/lang/String; glGetShaderInfoLog glGetShaderInfoLog - p 0 shader - p 1 maxLength - m (II)I glGetShaderi glGetShaderi - p 0 shader - p 1 programName - m (ILjava/lang/CharSequence;)I glGetUniformLocation glGetUniformLocation - p 0 program - p 1 name - m (I)V glLinkProgram glLinkProgram - p 0 program - m (IFF)V glMultiTexCoord2f glMultiTexCoord2f - p 0 target - p 1 s - p 2 t - m (IIII)V glRenderbufferStorage glRenderbufferStorage - p 0 target - p 1 internalFormat - p 2 width - p 3 height - m (ILjava/nio/FloatBuffer;)V glUniform1 glUniform1 - p 0 location - p 1 values - m (ILjava/nio/IntBuffer;)V glUniform1 glUniform1 - p 0 location - p 1 values - m (II)V glUniform1i glUniform1i - p 0 location - p 1 value - m (ILjava/nio/FloatBuffer;)V glUniform2 glUniform2 - p 0 location - p 1 values - m (ILjava/nio/IntBuffer;)V glUniform2 glUniform2 - p 0 location - p 1 values - m (ILjava/nio/FloatBuffer;)V glUniform3 glUniform3 - p 0 location - p 1 values - m (ILjava/nio/IntBuffer;)V glUniform3 glUniform3 - p 0 location - p 1 values - m (ILjava/nio/FloatBuffer;)V glUniform4 glUniform4 - p 0 location - p 1 values - m (ILjava/nio/IntBuffer;)V glUniform4 glUniform4 - p 0 location - p 1 values - m (IZLjava/nio/FloatBuffer;)V glUniformMatrix2 glUniformMatrix2 - p 0 location - p 1 transpose - p 2 matrices - m (IZLjava/nio/FloatBuffer;)V glUniformMatrix3 glUniformMatrix3 - p 0 location - p 1 transpose - p 2 matrices - m (IZLjava/nio/FloatBuffer;)V glUniformMatrix4 glUniformMatrix4 - p 0 location - p 1 transpose - p 2 matrices - m (I)V glUseProgram glUseProgram - p 0 program -c com/mojang/blaze3d/platform/GLX$class_1010 $FBOMode -c com/mojang/blaze3d/platform/GlStateManager - m (IF)V alphaFunc alphaFunc - p 0 func - p 1 ref - m (I)V bindTexture bindTexture - p 0 texture - m (I)V blendEquation blendEquation - p 0 mode - m (II)V blendFunc blendFunc - p 0 sfactor - p 1 dfactor - m (IIII)V blendFuncSeparate blendFuncSeparate - p 0 sFactorRGB - p 1 dFactorRGB - p 2 sFactorAlpha - p 3 dFactorAlpha - m (FFF)V color3f color3f - p 0 red - p 1 green - p 2 blue - m (FFFF)V color4f color4f - p 0 red - p 1 green - p 2 blue - p 3 alpha - m (II)V colorMaterial colorMaterial - p 0 face - p 1 mode - m (I)V depthFunc depthFunc - p 0 func - m (Z)V depthMask depthMask - p 0 mask - m (III)V drawArrays drawArrays - p 0 mode - p 1 first - p 2 count - m (IILjava/nio/FloatBuffer;)V light light - p 0 light - p 1 pname - p 2 params - m (ILjava/nio/FloatBuffer;)V lightModel lightModel - p 0 pname - p 1 params - m (FFF)V normal3f normal3f - p 0 nx - p 1 ny - p 2 nz - m (II)V pixelStore pixelStore - p 0 pname - p 1 param - m (FF)V polygonOffset polygonOffset - p 0 factor - p 1 units - m (FFFF)V rotatef rotatef - p 0 angle - p 1 x - p 2 y - p 3 z - m (I)V setupSolidRenderingTextureCombine setupSolidRenderingTextureCombine - p 0 color - m (IIIIIIIILjava/nio/IntBuffer;)V texImage2D texImage2D - p 0 target - p 1 level - p 2 internalFormat - p 3 width - p 4 height - p 5 border - p 6 format - p 7 type - p 8 pixels - m (IIIIIIIIJ)V texSubImage2D texSubImage2D - p 0 target - p 1 level - p 2 xOffset - p 3 yOffset - p 4 width - p 5 height - p 6 format - p 7 type - p 8 pixels diff --git a/src/test/resources/stable-1.14.4/intermediary-mappings.tinyv2 b/src/test/resources/stable-1.14.4/intermediary-mappings.tinyv2 deleted file mode 100644 index 7f4b80f..0000000 --- a/src/test/resources/stable-1.14.4/intermediary-mappings.tinyv2 +++ /dev/null @@ -1,252 +0,0 @@ -tiny 2 0 official intermediary -c byd net/minecraft/class_2843 - m (Lbxt;)V b method_12348 - f Ljava/util/Set; g field_12954 - f [Lfc; c field_12952 - m ()Ljava/util/Set; d method_12355 - m ()Z a method_12349 - m (Lbxt;)V a method_12356 - f [[I e field_12955 - m (Lbhr;Lbyd$a;)V a method_12353 - f Ljava/util/Map; f field_12953 - m (Lbvt;Lfb;Lbhs;Lew;Lew;)Lbvt; a method_12351 - m (Lbxt;Lfc;)V a method_12352 - f Lbyd; a field_12950 - m ()Lid; b method_12350 - f Ljava/util/EnumSet; d field_12951 - m ()Ljava/util/Map; c method_12354 - f Lorg/apache/logging/log4j/Logger; b field_12956 -c byd$1 net/minecraft/class_2843$1 -c byd$b net/minecraft/class_2843$class_2845 - m (Ljava/lang/String;)Lbyd$b; valueOf valueOf - f Lbyd$b; a field_12957 - f [Lfb; f field_12959 - m ()[Lbyd$b; values values - f [Lbyd$b; g field_12961 - f Lbyd$b; e field_12958 - f Lbyd$b; c field_12960 - f Lbyd$b; b field_12962 - f Lbyd$b; d field_12963 -c byd$b$1 net/minecraft/class_2843$class_2845$1 -c dds net/minecraft/class_481 - f Z p field_2892 - m (Lazx;)Z a method_2470 - f Z u field_2888 - m ()Laho; d method_2472 - m (Lzh;Lqv;)V a method_15873 - m (Lbba;DD)Z a method_2463 - f Lczo; q field_2894 - m (Lbce;Ljava/util/List;Lqv;Lzg;)V a method_15872 - m ()V e method_2464 - f Lddr; t field_2891 - m (Ljava/lang/String;)V a method_15871 - m ()Z f method_2465 - f Ljava/util/Map; w field_16201 - m (Lcyc;IZZ)V a method_2462 - f F o field_2890 - f I n field_2896 - m (DD)Z c method_2467 - f Lqv; l field_2893 - f Ljava/util/List; r field_2886 - m (Lbba;II)Z a method_2471 - m ()I c method_2469 - f Lazx; s field_2889 - m (Lbba;)V b method_2466 - f Z v field_2887 - m (Ljava/lang/String;Ljava/lang/String;Lqv;)Z a method_15874 - m (Ljava/lang/String;Lqv;)Z a method_15875 - m (Lbba;)V a method_2468 - f Laho; m field_2895 -c dds$a net/minecraft/class_481$class_482 -c bmv net/minecraft/class_2248 - m (Lbvt;)Lclk; g method_9545 - m (DDDDDD)Lctc; a method_9541 - m (Lbhr;Lawg;Lew;Lbvt;Lbtw;Lbcj;)V a method_9556 - f Z q field_10641 - m (Lbvt;Lbhb;Lew;Lfb;)Z c method_9607 - m (Lbvt;Lbhb;Lew;)Z c method_16362 - m (Lbvu$a;)V a method_9515 - m (Lbhr;Lbvt;Lcsd;Laio;)V a method_19286 - f Lbry; r field_10643 - m (Lbvt;Lbhb;Lew;)I k method_9505 - m (Lbvt;Lbgz;Lew;)I a method_9546 - m (Lbvt;Lbhb;Lew;)Z g method_9552 - m (Lvk;Lew;Lbcj;)V a method_9613 - m (Lbvt;Lbhb;Lew;)Lclp; e method_9602 - m (Lbvt;Lbhb;Lew;)Z j method_9557 - m ()Lqv; i method_9580 - m (Lbvt;Lbhr;Lew;Ljava/util/Random;)V c method_9514 - m ()F j method_9520 - m (Lbhr;Lew;Lbcj;)V b method_9544 - m (Lbvt;Lbhr;Lew;II)Z a method_9592 - m (Lbhr;Lew;Lbvt;Laix;Lbcj;)V a method_9567 - f Lqv; h field_10636 - m (Lbvt;)V o method_9590 - m (Lbvt;)I k method_9507 - m (Lbhr;Lew;)V c method_9504 - m (Lbvt;Lbhr;Lew;Lawg;)V a method_9606 - m (Lbvt;Lbhb;Lew;Lais;)Z a method_9523 - m ()Ljava/lang/String; l method_9539 - f Lbce; j field_17562 - m (Lbvt;Lbhb;Lew;Lcns;)Z a method_9516 - m (Lbmv;)Z a method_9581 - f Lff; m field_10651 - m (Lbvt;Lbhb;Lew;Lfb;)Z d method_20045 - m (Lbvt;)Z d method_9589 - m (Lbhb;Lew;)Z c method_16361 - m (Lbvt;Lbvt;Lbhr;Lew;)Lbvt; a method_9582 - m (Lbvt;)Lclo; l method_9597 - m (Lbvt;Lbrg;)Lbvt; a method_9598 - m (Lbvt;Lbhu;Lew;)Z a method_9558 - f Lbvt; f field_10646 - m (Lbvt;Lbhb;Lew;)Z d method_9521 - f Lctc; c field_18966 - m (Lbvt;Lbhb;Lew;)Lctc; h method_9571 - f Z v field_10640 - m ()Lbvu; n method_9595 - f Lclp; t field_10639 - m (Lbvt;Lcoy$a;)Ljava/util/List; a method_9560 - m (Lbvt;Lbhb;Lew;)Lcsi; l method_9540 - m ()Ljava/lang/String; toString toString - m (Lbhk;)Z a method_9533 - m (Lbvt;Lbhr;Lew;Laio;)V a method_9548 - f Lbvu; u field_10647 - m (Lbhr;Lew;Lbcj;)V c method_9596 - m (Lzg;)Z a method_9525 - m (Lbvt;Lbhr;Lew;)V c method_9497 - m (Lbce;)Lbmv; a method_9503 - m (Lbmv;)Z b method_9608 - m (Lbvt;Lbhr;Lew;)Lahm; b method_17454 - f I n field_10634 - m (Lbvt;)Z h method_9506 - m ()Lbvt; o method_9564 - m (Lbvt;Lbhb;Lew;Lcsn;)Lctc; a method_9530 - m (Lbhr;Lew;Laio;F)V a method_9554 - m (Lbhu;)I a method_9563 - m ()Z S_ method_9538 - m (Lbvt;Lbhr;Lew;Lbtw;Laio;Lbcj;)V a method_9511 - m (Lbvt;Lawg;Lbhb;Lew;)F a method_9594 - f Ljava/lang/ThreadLocal; k field_10649 - m (Lbvt;Lbhb;Lew;Lfb;)I a method_9524 - f Lcom/google/common/cache/LoadingCache; b field_19312 - m ()Z p method_9543 - m (Lbvt;)I a method_9593 - f Lctc; d field_19061 - m ()Ljo; k method_9518 - m (Lbvt;Lbhb;Lew;)Lctc; i method_9584 - f Ljava/lang/String; i field_10642 - m (Lbhb;Lew;Lbvt;)Lbcj; a method_9574 - m (Lbhr;Lew;Lbcj;)V d method_9587 - m (Lbvt;Lvk;Lew;Lbtw;)Ljava/util/List; a method_9562 - m (Lbvt;)Z m method_9542 - m (Lbvt;Lbhs;Lew;I)V b method_9517 - m (Lbvt;Lban;)Z a method_9616 - f Z g field_10645 - m (Lctc;)Z a method_9614 - m (Lbvt;Lbhr;Lew;Lbmv;Lew;Z)V a method_9612 - m (Lbvt;)Z e method_9500 - m (Lbmv;)Z c method_9519 - m (Lbvt;Lcoy$a;)V b method_9566 - m (Lbhr;Lew;Laio;)V a method_9591 - m (Lbhr;Lew;I)V a method_9583 - f F o field_10650 - m (Lbvt;Lbhr;Lew;Lbvt;Z)V a method_9536 - m (Lbba;Lfk;)V a method_9578 - m ()Lbhc; c method_9551 - m (Lbvt;Lbhr;Lew;Ljava/util/Random;)V a method_9496 - m ()Z h method_9570 - m (Lbvt;Lbhb;Lew;)F a method_9575 - m ()Lbmv$b; R_ method_16841 - m (Lbvt;Lbhb;Lew;Lcsn;)Lctc; b method_9549 - m (Lbvt;Lbhs;Lew;)Lbvt; b method_9510 - m (Lbhr;Lew;Lbhk;)V a method_9586 - m (Lbvt;Lbhr;Lew;Lbcj;)V a method_9565 - m (Lbvt;Lbvt;Lbhs;Lew;I)V a method_9611 - m (Lbcj;Lbhb;Ljava/util/List;Lbdr;)V a method_9568 - m (Lbvt;)Lclq; i method_9527 - m (Lbvt;Lbhb;Lew;)F f method_9537 - m (Lbvt;Lvk;Lew;Lbtw;Laio;Lbcj;)Ljava/util/List; a method_9609 - m (Lbvt;)Lbrd; c method_9604 - m (Lbvt;)Z b method_9498 - m (Lbvt;Lbhb;Lew;)Z b method_9579 - m (I)Lbvt; a method_9531 - m (Lbvt;Lbqg;)Lbvt; a method_9569 - m (Lbvt;Lbhb;Lew;Lfb;)I b method_9603 - f F e field_10637 - m (Lbvt;)Lbry; p method_9573 - m (Lbhr;Lew;Lbvt;Lawg;)V a method_9576 - m (Lbhu;Lew;Lfb;)Z a method_20044 - f [Lfb; a field_10644 - m (Lbhs;Lew;Lbvt;)V a method_9585 - m (Lbvt;Lbhs;Lew;I)V a method_9528 - m (Lbhr;Lew;Lbcj;)V a method_9577 - f Lorg/apache/logging/log4j/Logger; l field_10638 - m (Lban;)Lbvt; a method_9605 - m (Lbvt;)Z n method_9526 - m ()Lit/unimi/dsi/fastutil/objects/Object2ByteLinkedOpenHashMap; d method_9508 - m (Lctc;Lfb;)Z a method_9501 - m ()F m method_9499 - m (Lbvt;Lbhr;Lew;Lbvt;Z)V b method_9615 - m (Lbvt;Lew;)J a method_9535 - f F p field_10648 - m (Lbmv;)Z d method_9547 - m (Lbvt;Lbhr;Lew;Lawg;Lahi;Lcsd;)Z a method_9534 - m (Lbvt;)Z f method_9601 - m (Lbvt;Lbhr;Lew;)I a method_9572 - m (Lbvt;Lbhr;Lew;Ljava/util/Random;)V b method_9588 - m (Lbvt;Lbvt;Lfb;)Z a method_9522 - m (Lbvt;Lbhr;Lew;Lbtw;)V a method_9610 - m (Lbvt;Lfb;Lbvt;Lbhs;Lew;Lew;)Lbvt; a method_9559 - f Lclo; s field_10635 - m (Lbhb;Laio;)V a method_9502 -c bmv$a net/minecraft/class_2248$class_2249 - f Lfb; c field_10653 - m ()I hashCode hashCode - m (Ljava/lang/Object;)Z equals equals - f Lbvt; b field_10654 - f Lbvt; a field_10652 -c bmv$b net/minecraft/class_2248$class_2250 - f Lbmv$b; c field_10655 - f Lbmv$b; b field_10657 - f [Lbmv$b; d field_10658 - m ()[Lbmv$b; values values - m (Ljava/lang/String;)Lbmv$b; valueOf valueOf - f Lbmv$b; a field_10656 -c bmv$c net/minecraft/class_2248$class_2251 - m (Lbmv$c;)Lqv; k method_9641 - m (I)Lbmv$c; a method_9631 - m (F)Lbmv$c; b method_9632 - m (Lbry;)Lbmv$c; a method_9626 - m (Lbmv$c;)Lbry; d method_9638 - m (Lclo;)Lbmv$c; a method_9637 - m (Lbmv$c;)F i method_9627 - m (Lbmv$c;)Z c method_9635 - m (Lbmv$c;)Lclp; b method_9620 - f Z h field_10661 - m (Lbmv$c;)F f method_9625 - m (Lbmv$c;)I e method_9636 - m (Lbmv$c;)F g method_9633 - m (F)Lbmv$c; a method_9628 - f Z k field_10670 - f Lclo; a field_10668 - m (Lbmv$c;)Lclo; a method_9623 - f F f field_10660 - f I e field_10663 - m (Lbmv;)Lbmv$c; b method_16228 - m (Lclo;Lbbg;)Lbmv$c; a method_9617 - m ()Lbmv$c; b method_9618 - f Lqv; j field_10666 - f Z c field_10664 - m (Lbmv$c;)Z j method_9621 - m ()Lbmv$c; c method_9640 - m ()Lbmv$c; a method_9634 - m (FF)Lbmv$c; a method_9629 - m (Lbmv;)Lbmv$c; a method_9630 - m ()Lbmv$c; e method_16229 - f F g field_10669 - f Lbry; d field_10665 - m (Lbmv$c;)Z h method_9619 - f Lclp; b field_10662 - m ()Lbmv$c; d method_9624 - m (Lclo;Lclp;)Lbmv$c; a method_9639 - f F i field_10667 diff --git a/src/test/resources/stable-1.14.4/yarn-mappings.tinyv2 b/src/test/resources/stable-1.14.4/yarn-mappings.tinyv2 deleted file mode 100644 index a2bf353..0000000 --- a/src/test/resources/stable-1.14.4/yarn-mappings.tinyv2 +++ /dev/null @@ -1,544 +0,0 @@ -tiny 2 0 intermediary named -c net/minecraft/class_2843 net/minecraft/world/chunk/UpgradeData - m (Lnet/minecraft/class_2487;)V - p 1 tag - m ()Lnet/minecraft/class_2487; method_12350 toTag - f Ljava/util/EnumSet; field_12951 sides - f [[I field_12955 indices - f Lnet/minecraft/class_2843; field_12950 NO_UPGRADE_DATA - f Lorg/apache/logging/log4j/Logger; field_12956 LOGGER -c net/minecraft/class_481 net/minecraft/client/gui/screen/ingame/CreativeInventoryScreen - f Lnet/minecraft/class_342; field_2894 searchBox - m (Lnet/minecraft/class_1799;II)V renderTooltip - p 2 x - p 1 stack - p 3 y - m (Lnet/minecraft/class_1761;)V method_2466 setSelectedTab - m (DDI)Z mouseReleased - p 3 mouseY - p 1 mouseX - p 5 button - m (DDI)Z mouseClicked - p 5 button - p 1 mouseX - p 3 mouseY - m (III)Z keyPressed - p 1 keyCode - p 3 modifiers - p 2 scanCode - f I field_2896 selectedTab - m (Lnet/minecraft/class_310;IZZ)V method_2462 onHotbarKeyPress - m (Lnet/minecraft/class_1761;DD)Z method_2463 isClickInTab - f Lnet/minecraft/class_2960; field_2893 TEXTURE - f Lnet/minecraft/class_1735; field_2889 deleteItemSlot - f Ljava/util/List; field_2886 slots - m ()Z method_2465 doRenderScrollBar - m (IIF)V render - p 1 mouseX - p 3 delta - p 2 mouseY - m (DDD)Z mouseScrolled - p 5 amount - f Lnet/minecraft/class_1277; field_2895 inventory - m (DDIDD)Z mouseDragged - p 5 button - p 3 mouseY - p 8 deltaY - p 6 deltaX - p 1 mouseX - m (CI)Z charTyped - p 1 chr - p 2 keyCode - f F field_2890 scrollPosition - m (Lnet/minecraft/class_310;II)V resize - p 1 client - p 2 width - p 3 height -c net/minecraft/class_481$class_484 net/minecraft/client/gui/screen/ingame/CreativeInventoryScreen$CreativeSlot - f Lnet/minecraft/class_1735; field_2898 slot -c net/minecraft/class_481$class_483 net/minecraft/client/gui/screen/ingame/CreativeInventoryScreen$CreativeContainer - f Lnet/minecraft/class_2371; field_2897 itemList -c net/minecraft/class_481$class_482 net/minecraft/client/gui/screen/ingame/CreativeInventoryScreen$class_482 - m (Lnet/minecraft/class_1263;III)V - p 2 xPosition - p 3 - p 1 settings - m ()Z method_9570 hasBlockEntity - f Lnet/minecraft/class_265; field_18966 SOLID_MEDIUM_SQUARE_SHAPE - f Ljava/lang/String; field_10642 translationKey - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)Lnet/minecraft/class_3620; method_9602 getMapColor - p 3 pos - p 2 view - p 1 state - f Lnet/minecraft/class_3614; field_10635 material - m (Lnet/minecraft/class_2680;)Lnet/minecraft/class_3610; method_9545 getFluidState - p 1 state - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)I method_9505 getLightSubtracted - p 2 view - p 1 state - p 3 pos - m (Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_1799;)V method_9577 dropStack - p 2 stack - p 1 pos - p 0 world - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_2248;Lnet/minecraft/class_2338;Z)V method_9612 neighborUpdate - p 3 pos - p 4 block - p 1 state - p 2 world - p 5 neighborPos - p 6 moved - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_1657;Lnet/minecraft/class_1268;Lnet/minecraft/class_3965;)Z method_9534 activate - p 1 state - p 2 world - p 5 hand - p 6 hit - p 3 pos - p 4 player - m (Lnet/minecraft/class_1750;)Lnet/minecraft/class_2680; method_9605 getPlacementState - p 1 ctx - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;Lnet/minecraft/class_1299;)Z method_9523 allowsSpawning - p 4 type - p 3 pos - p 2 view - p 1 state - m (Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_2680;Lnet/minecraft/class_1309;Lnet/minecraft/class_1799;)V method_9567 onPlaced - p 2 pos - p 1 world - p 5 itemStack - p 4 placer - p 3 state - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_2338;)J method_9535 getRenderingSeed - p 1 state - p 2 pos - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;Lnet/minecraft/class_2350;)Z method_9607 shouldDrawSide - p 3 facing - p 0 state - p 2 pos - p 1 view - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_1297;)V method_9548 onEntityCollision - p 2 world - p 3 pos - p 4 entity - p 1 state - m (Lnet/minecraft/class_1937;Lnet/minecraft/class_2680;Lnet/minecraft/class_3965;Lnet/minecraft/class_1297;)V method_19286 onProjectileHit - p 2 state - p 1 world - p 4 entity - p 3 hitResult - f Lnet/minecraft/class_2361; field_10651 STATE_IDS - m ()Lnet/minecraft/class_2680; method_9564 getDefaultState - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1936;Lnet/minecraft/class_2338;I)V method_9528 updateNeighborStates - p 2 world - p 1 state - p 4 flags - p 3 pos - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_2586;Lnet/minecraft/class_1297;Lnet/minecraft/class_1799;)V method_9511 dropStacks - p 5 stack - p 3 blockEntity - p 4 entity - p 1 world - p 2 pos - p 0 state - m (Lnet/minecraft/class_3494;)Z method_9525 matches - p 1 tag - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)Z method_16362 canSuffocate - p 3 pos - p 1 state - p 2 view - m (Lnet/minecraft/class_2680;)Lnet/minecraft/class_2464; method_9604 getRenderType - p 1 state - m (Lnet/minecraft/class_2248;)Z method_9581 canConnect - p 0 block - m ()Lnet/minecraft/class_2248$class_2250; method_16841 getOffsetType - m (DDDDDD)Lnet/minecraft/class_265; method_9541 createCuboidShape - p 2 yMin - p 0 xMin - p 10 zMax - p 8 yMax - p 6 xMax - p 4 zMin - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_2415;)Lnet/minecraft/class_2680; method_9569 mirror - p 1 state - p 2 mirror - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_2680;Lnet/minecraft/class_2350;)Z method_9522 isSideInvisible - p 3 facing - p 1 state - p 2 neighbor - f Z field_10641 randomTicks - f Lnet/minecraft/class_2689; field_10647 stateFactory - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1936;Lnet/minecraft/class_2338;)Lnet/minecraft/class_2680; method_9510 getRenderingState - p 0 state - p 2 pos - p 1 world - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1657;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)F method_9594 calcBlockBreakingDelta - p 3 world - p 4 pos - p 1 state - p 2 player - m (Lnet/minecraft/class_2680;)Z method_9500 isAir - p 1 state - m (Lnet/minecraft/class_2680;)V method_9590 setDefaultState - p 1 state - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_2680;Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;)Lnet/minecraft/class_2680; method_9582 pushEntitiesUpBeforeBlockChange - p 2 world - p 1 to - p 0 from - p 3 pos - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)Z method_9557 isFullOpaque - p 1 state - p 2 view - p 3 pos - m (Lnet/minecraft/class_2680;)Z method_9542 hasRandomTicks - p 1 state - f I field_10634 lightLevel - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)Lnet/minecraft/class_265; method_9571 - p 1 state - p 2 view - p 3 pos - m ()F method_9520 getBlastResistance - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;II)Z method_9592 onBlockAction - p 5 data - p 4 type - p 1 state - p 3 pos - p 2 world - m (Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_1297;)V method_9591 onSteppedOn - p 3 entity - p 2 pos - p 1 world - m (Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;Lnet/minecraft/class_2680;)Lnet/minecraft/class_1799; method_9574 getPickStack - p 2 pos - p 3 state - p 1 world - m ()Lnet/minecraft/class_2689; method_9595 getStateFactory - f Lnet/minecraft/class_2960; field_10636 dropTableId - m (Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_1297;F)V method_9554 onLandedUpon - p 1 world - p 2 pos - p 3 entity - p 4 distance - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1750;)Z method_9616 canReplace - p 1 state - p 2 ctx - f Lorg/apache/logging/log4j/Logger; field_10638 LOGGER - m (Lnet/minecraft/class_1927;)Z method_9533 shouldDropItemsOnExplosion - p 1 explosion - m ()Lnet/minecraft/class_2561; method_9518 getName - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;Lnet/minecraft/class_3726;)Lnet/minecraft/class_265; method_9530 getOutlineShape - p 2 view - p 1 state - p 4 ePos - p 3 pos - m (Lnet/minecraft/class_2248;)Z method_9519 isNaturalDirt - p 0 block - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)F method_9575 getAmbientOcclusionLightLevel - p 3 pos - p 1 state - p 2 view - m ()Lnet/minecraft/class_2960; method_9580 getDropTableId - f Z field_10640 collidable - m (Lnet/minecraft/class_2680;)Lnet/minecraft/class_3619; method_9527 getPistonBehavior - p 1 state - m (Lnet/minecraft/class_2680;)Lnet/minecraft/class_2498; method_9573 getSoundGroup - p 1 state - f F field_10650 hardness - m (Lnet/minecraft/class_265;)Z method_9614 isShapeFullCube - p 0 shape - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_3218;Lnet/minecraft/class_2338;Lnet/minecraft/class_2586;)Ljava/util/List; method_9562 getDroppedStacks - p 3 blockEntity - p 2 pos - p 1 world - p 0 state - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1941;Lnet/minecraft/class_2338;)Z method_9558 canPlaceAt - p 1 state - p 2 world - p 3 pos - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)Z method_9552 shouldPostProcess - p 1 state - p 2 view - p 3 pos - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)Lnet/minecraft/class_265; method_9584 getRayTraceShape - p 2 view - p 3 pos - p 1 state - m (Lnet/minecraft/class_1922;Lnet/minecraft/class_1297;)V method_9502 onEntityLand - p 2 entity - p 1 world - m ()Z method_9543 hasDynamicBounds - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)F method_9537 getHardness - p 1 state - p 2 world - p 3 pos - f F field_10648 resistance - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;Lnet/minecraft/class_2350;)I method_9603 getStrongRedstonePower - p 3 pos - p 2 view - p 4 facing - p 1 state - f Lnet/minecraft/class_3620; field_10639 materialColor - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1937;Lnet/minecraft/class_2338;Lnet/minecraft/class_2586;)V method_9610 dropStacks - p 3 blockEntity - p 2 pos - p 1 world - p 0 state - m (Lnet/minecraft/class_2680;)Z method_9589 hasBlockEntityBreakingRender - p 1 state - m (Lnet/minecraft/class_1937;Lnet/minecraft/class_1657;Lnet/minecraft/class_2338;Lnet/minecraft/class_2680;Lnet/minecraft/class_2586;Lnet/minecraft/class_1799;)V method_9556 afterBreak - p 6 stack - p 4 state - p 5 blockEntity - p 2 player - p 3 pos - p 1 world - m (I)Lnet/minecraft/class_2680; method_9531 getStateFromRawId - p 0 stateId - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;Lnet/minecraft/class_2350;)I method_9524 getWeakRedstonePower - p 4 facing - p 3 pos - p 2 view - p 1 state - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_1922;Lnet/minecraft/class_2338;)Z method_9579 isTranslucent - p 3 pos - p 2 view - p 1 state - m (Lnet/minecraft/class_1792;)Lnet/minecraft/class_2248; method_9503 getBlockFromItem - p 0 item -c net/minecraft/class_2248$class_2251 net/minecraft/block/Block$Settings - m (Lnet/minecraft/class_3614;Lnet/minecraft/class_1767;)Lnet/minecraft/class_2248$class_2251; method_9617 of - p 0 material - p 1 color - m (F)Lnet/minecraft/class_2248$class_2251; method_9628 slipperiness - p 1 slipperiness - m ()Lnet/minecraft/class_2248$class_2251; method_16229 dropsNothing - m ()Lnet/minecraft/class_2248$class_2251; method_9640 ticksRandomly - m (Lnet/minecraft/class_2248;)Lnet/minecraft/class_2248$class_2251; method_9630 copy - p 0 source - f I field_10663 luminance - m ()Lnet/minecraft/class_2248$class_2251; method_9618 breakInstantly - m ()Lnet/minecraft/class_2248$class_2251; method_9634 noCollision - f F field_10660 resistance - f Lnet/minecraft/class_2960; field_10666 dropTableId - m (Lnet/minecraft/class_2248;)Lnet/minecraft/class_2248$class_2251; method_16228 dropsLike - p 1 source - m (Lnet/minecraft/class_3614;Lnet/minecraft/class_3620;)V - p 1 material - p 2 materialColor - f Lnet/minecraft/class_2498; field_10665 soundGroup - f Z field_10670 dynamicBounds - m (FF)Lnet/minecraft/class_2248$class_2251; method_9629 strength - p 1 hardness - p 2 resistance - m (Lnet/minecraft/class_3614;Lnet/minecraft/class_3620;)Lnet/minecraft/class_2248$class_2251; method_9639 of - p 0 material - p 1 color - f Lnet/minecraft/class_3614; field_10668 material - m (Lnet/minecraft/class_2498;)Lnet/minecraft/class_2248$class_2251; method_9626 sounds - p 1 soundGroup - m (F)Lnet/minecraft/class_2248$class_2251; method_9632 strength - p 1 strength - f Z field_10661 randomTicks - m (I)Lnet/minecraft/class_2248$class_2251; method_9631 lightLevel - p 1 luminance - f F field_10667 slipperiness - f Z field_10664 collidable - m (Lnet/minecraft/class_3614;)Lnet/minecraft/class_2248$class_2251; method_9637 of - p 0 material - f Lnet/minecraft/class_3620; field_10662 materialColor - m ()Lnet/minecraft/class_2248$class_2251; method_9624 hasDynamicBounds - f F field_10669 hardness -c net/minecraft/class_2248$class_2250 net/minecraft/block/Block$OffsetType -c net/minecraft/class_2248$class_2249 net/minecraft/block/Block$NeighborGroup - f Lnet/minecraft/class_2350; field_10653 facing - f Lnet/minecraft/class_2680; field_10654 other - m (Ljava/lang/Object;)Z equals - p 1 o - f Lnet/minecraft/class_2680; field_10652 self - m (Lnet/minecraft/class_2680;Lnet/minecraft/class_2680;Lnet/minecraft/class_2350;)V - p 3 facing - p 1 self - p 2 other