├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── doc └── README.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java ├── com │ └── fox2code │ │ └── fabriczero │ │ ├── FabricZeroConfig.java │ │ ├── FabricZeroPlugin.java │ │ ├── FabricZeroRules.java │ │ ├── FabricZeroTransformerASM.java │ │ ├── FabricZeroTransformerHook.java │ │ ├── access │ │ ├── FabricBackport.java │ │ ├── FastGL.java │ │ ├── FastMath.java │ │ ├── FastString.java │ │ ├── Helper.java │ │ ├── MCResources.java │ │ ├── emc │ │ │ ├── EMCCompact.java │ │ │ └── EMCHashMap.java │ │ └── modupdater │ │ │ ├── UpdateAll.java │ │ │ └── UpdateAllButton.java │ │ ├── api │ │ ├── FabricZeroAPI.java │ │ ├── FabricZeroTransformer.java │ │ └── LoggerWrapper.java │ │ ├── impl │ │ ├── BytecodeOptimizer.java │ │ ├── ImplFabricZeroAPI.java │ │ └── ModHideMap.java │ │ ├── mixins │ │ ├── DefaultResourcePackMixin.java │ │ ├── ModUpdaterScreenMixin_ModUpdater.java │ │ └── ResourcePackProfileMixin.java │ │ ├── mod │ │ ├── FabricZero.java │ │ ├── FabricZeroClient.java │ │ ├── FabricZeroModMenu.java │ │ ├── FabricZeroModUpdater.java │ │ └── GuiConfig.java │ │ └── reflectutils │ │ ├── AutoFixer.java │ │ ├── AutoFixer9.java │ │ ├── Java9Fix.java │ │ ├── ReflectUtil.java │ │ └── ReflectedClass.java └── javax │ └── xml │ └── bind │ ├── DatatypeConverter.java │ └── annotation │ └── adapters │ ├── HexBinaryAdapter.java │ └── XmlAdapter.java └── resources ├── assets └── fabriczero │ ├── icon.png │ └── lang │ ├── en_us.json │ └── fr_fr.json ├── fabric.mod.json └── fabriczero.mixins.json /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | # mpeltonen/sbt-idea plugin 11 | .idea_modules/ 12 | 13 | # JIRA plugin 14 | atlassian-ide-plugin.xml 15 | 16 | # Compiled class file 17 | *.class 18 | 19 | # Log file 20 | *.log 21 | 22 | # BlueJ files 23 | *.ctxt 24 | 25 | # Package Files # 26 | *.jar 27 | *.war 28 | *.nar 29 | *.ear 30 | *.zip 31 | *.tar.gz 32 | *.rar 33 | 34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 35 | hs_err_pid* 36 | 37 | *~ 38 | 39 | # temporary files which can be created if a process still has a handle open of a deleted file 40 | .fuse_hidden* 41 | 42 | # KDE directory preferences 43 | .directory 44 | 45 | # Linux trash folder which might appear on any partition or disk 46 | .Trash-* 47 | 48 | # .nfs files are created when an open file is removed but is still being accessed 49 | .nfs* 50 | 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | # Windows thumbnail cache files 79 | Thumbs.db 80 | Thumbs.db:encryptable 81 | ehthumbs.db 82 | ehthumbs_vista.db 83 | 84 | # Dump file 85 | *.stackdump 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows Installer files 94 | *.cab 95 | *.msi 96 | *.msix 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | 103 | .gradle 104 | build/ 105 | 106 | # Ignore Gradle GUI config 107 | gradle-app.setting 108 | 109 | # Cache of project 110 | .gradletasknamecache 111 | 112 | **/build/ 113 | 114 | # Common working directory 115 | run/ 116 | 117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 118 | !gradle-wrapper.jar 119 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Fox2Code 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fabric Zero 2 | 3 | Compatibility and performance enhancement mod 4 | *(Made for large mod-pack)* 5 | 6 | # The mod is Discontinued 7 | I have no longer the time to continue working on it, 8 | I might make a lite version that is less hard to maintain 9 | but less complete if I have the time to do that 10 | 0.2.1 should be the latest version 11 | (No updates or support will be given after this point) 12 | 13 | I might make a 0.2.2 to fix bugs if needed -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '0.5-SNAPSHOT' 3 | id 'maven-publish' 4 | } 5 | 6 | sourceCompatibility = 1.8 7 | targetCompatibility = 1.8 8 | 9 | archivesBaseName = project.archives_base_name 10 | version = project.mod_version 11 | group = project.maven_group 12 | 13 | repositories {// 14 | jcenter() 15 | maven { url 'https://maven.thebrokenrail.com' } 16 | maven { url 'https://maven.dblsaiko.net' } 17 | } 18 | 19 | configurations { 20 | shadow 21 | } 22 | 23 | dependencies { 24 | //to change the versions see the gradle.properties file 25 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 26 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 27 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 28 | 29 | // Fabric API. This is technically optional, but you probably want it anyway. 30 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 31 | 32 | // GudASM 33 | //modImplementation include("net.gudenau.minecraft:gudasm:${project.gudasm_version}") 34 | modImplementation "net.gudenau.minecraft:gudasm:${project.gudasm_version}" 35 | 36 | // Sodium 37 | // modCompileOnly "com.github.jellysquid3:sodium-fabric:mc1.16.1-0.1.0" 38 | // Dark loading screen 39 | // modCompileOnly "com.github.A5b84:dark-loading-screen:1.3.3" 40 | 41 | modCompileOnly 'com.thebrokenrail:modupdater:1.1.11+1.16.2-rc2' 42 | 43 | modCompileOnly "io.github.prospector:modmenu:$project.modmenu" 44 | modRuntime "io.github.prospector:modmenu:$project.modmenu" 45 | 46 | implementation("io.github.karlatemp:unsafe-accessor:1.2.2") 47 | shadow("io.github.karlatemp:unsafe-accessor:1.2.2") 48 | 49 | // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. 50 | // You may need to force-disable transitiveness on them. 51 | } 52 | 53 | processResources { 54 | inputs.property "version", project.version 55 | 56 | from(sourceSets.main.resources.srcDirs) { 57 | include "fabric.mod.json" 58 | expand "version": project.version 59 | } 60 | 61 | from(sourceSets.main.resources.srcDirs) { 62 | exclude "fabric.mod.json" 63 | } 64 | } 65 | 66 | // ensure that the encoding is set to UTF-8, no matter what the system default is 67 | // this fixes some edge cases with special characters not displaying correctly 68 | // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html 69 | tasks.withType(JavaCompile) { 70 | options.encoding = "UTF-8" 71 | } 72 | 73 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 74 | // if it is present. 75 | // If you remove this task, sources will not be generated. 76 | 77 | task sourcesJar(type: Jar, dependsOn: classes) { 78 | classifier = "sources" 79 | from sourceSets.main.allSource 80 | } 81 | 82 | compileJava { 83 | doFirst { 84 | new File("$project.buildDir/classes/java/main").mkdirs() 85 | } 86 | } 87 | 88 | jar { 89 | from "LICENSE" 90 | } 91 | 92 | afterEvaluate { 93 | jar { 94 | from { 95 | configurations.shadow.collect { it.isDirectory() ? it : zipTree(it) } 96 | } 97 | } 98 | } 99 | 100 | // configure the maven publication 101 | publishing { 102 | publications { 103 | mavenJava(MavenPublication) { 104 | // add all the jars that should be included when publishing to maven 105 | artifact(remapJar) { 106 | builtBy remapJar 107 | } 108 | artifact(sourcesJar) { 109 | builtBy remapSourcesJar 110 | } 111 | } 112 | } 113 | 114 | // select the repositories you want to publish to 115 | repositories { 116 | // uncomment to publish to the local maven 117 | // mavenLocal() 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Fabric Zero Doc 2 | 3 | TODO -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx2G -XX:-UseGCOverheadLimit 3 | org.gradle.parallel=true 4 | # Fabric Properties 5 | # check these on https://modmuss50.me/fabric.html 6 | # minecraft_version=1.16.1 7 | # yarn_mappings=1.16.1+build.21 8 | # loader_version=0.9.0+build.204 9 | minecraft_version=1.16.4 10 | yarn_mappings=1.16.4+build.7 11 | loader_version=0.10.8 12 | # Mod Properties 13 | mod_version=0.2.1 14 | maven_group=com.fox2code 15 | archives_base_name=fabriczero 16 | # Dependencies 17 | # check this on https://modmuss50.me/fabric.html 18 | #fabric_version=0.16.2+build.385-1.16.1 19 | fabric_version=0.26.1+1.16 20 | modmenu=1.14.9+build.13 21 | gudasm_version=0.2.10 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fox2Code/FabricZero/0519c12e3f56c9c10b3a1e90fb9c909ea296d3fb/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | jcenter() 4 | maven { 5 | name = 'Fabric' 6 | url = 'https://maven.fabricmc.net/' 7 | } 8 | gradlePluginPortal() 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/FabricZeroConfig.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero; 2 | 3 | import com.fox2code.fabriczero.api.FabricZeroAPI; 4 | 5 | import java.io.*; 6 | 7 | public class FabricZeroConfig { 8 | private static final File cfgFile = FabricZeroAPI.getInstance().getFabricZeroConfigFile(); 9 | private static final int configRev = 1; 10 | public static boolean dumpClasses = false; 11 | public static boolean disableAccessMod = false; // Implement https://github.com/Fox2Code/FabricZero/issues/5 12 | public static boolean disableStringRedirect = false; 13 | public static boolean disableUnsafeRedirect = false; 14 | 15 | static { 16 | if (load()) { 17 | save(); 18 | } 19 | } 20 | 21 | private static boolean load() { 22 | if (!cfgFile.exists()) { 23 | return true; 24 | } 25 | boolean update = false, flag2 = true; 26 | try(BufferedReader bufferedReader = new BufferedReader(new FileReader(cfgFile))) { 27 | String line; 28 | while ((line = bufferedReader.readLine()) != null) { 29 | if (line.isEmpty() || line.charAt(0) == '#') continue; 30 | int i = line.indexOf('='); 31 | if (i != -1) { 32 | String value = line.substring(i + 1); 33 | switch (line.substring(0, i)) { 34 | case "dump": 35 | dumpClasses = Boolean.parseBoolean(value); 36 | break; 37 | case "disableAccessMod": 38 | disableAccessMod = Boolean.parseBoolean(value); 39 | break; 40 | case "disableStringRedirect": 41 | disableStringRedirect = Boolean.parseBoolean(value); 42 | break; 43 | case "disableUnsafeRedirect": 44 | disableUnsafeRedirect = Boolean.parseBoolean(value); 45 | break; 46 | case "configRev": 47 | if (flag2) { 48 | flag2 = false; 49 | update = parseIntSafe(value) < configRev; 50 | } else update = true; 51 | } 52 | } 53 | } 54 | } catch (IOException ioe) { 55 | FabricZeroPlugin.LOGGER.error("Couldn't read config!",ioe); 56 | } 57 | return flag2 || update; 58 | } 59 | 60 | public static void save() { 61 | try (FileOutputStream fileOutputStream = new FileOutputStream(cfgFile)){ 62 | PrintStream printStream = new PrintStream(fileOutputStream); 63 | printStream.println("# Fabriczero Config. (Java version: "+System.getProperty("java.version")+")"); 64 | printStream.println("# Note: UnsafeRedirect is only effective on Java9+"); 65 | printStream.println("dump="+dumpClasses); 66 | printStream.println("disableAccessMod="+disableAccessMod); 67 | printStream.println("disableStringRedirect="+disableStringRedirect); 68 | printStream.println("disableUnsafeRedirect="+disableUnsafeRedirect); 69 | printStream.println("configRev="+configRev); 70 | printStream.flush(); 71 | } catch (IOException ioe) { 72 | FabricZeroPlugin.LOGGER.error("Couldn't write config!",ioe); 73 | } 74 | } 75 | 76 | private static int parseIntSafe(String text) { 77 | try { 78 | return Integer.parseInt(text); 79 | } catch (Exception e) { 80 | return Boolean.parseBoolean(text)?1:0; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/FabricZeroPlugin.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero; 2 | 3 | import com.fox2code.fabriczero.api.FabricZeroAPI; 4 | import com.fox2code.fabriczero.api.FabricZeroTransformer; 5 | import com.fox2code.fabriczero.impl.ModHideMap; 6 | import com.fox2code.fabriczero.reflectutils.ReflectUtil; 7 | import com.fox2code.fabriczero.reflectutils.ReflectedClass; 8 | import net.fabricmc.loader.api.FabricLoader; 9 | import net.fabricmc.loader.ModContainer; 10 | import net.fabricmc.loader.api.metadata.ModMetadata; 11 | import net.fabricmc.loader.launch.common.FabricLauncherBase; 12 | import org.apache.logging.log4j.LogManager; 13 | import org.apache.logging.log4j.Logger; 14 | import org.objectweb.asm.tree.ClassNode; 15 | import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; 16 | import org.spongepowered.asm.mixin.extensibility.IMixinInfo; 17 | import org.spongepowered.asm.mixin.transformer.FabricMixinTransformerProxy; 18 | 19 | import java.lang.reflect.Field; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.Set; 23 | 24 | @SuppressWarnings("unchecked") 25 | public final class FabricZeroPlugin implements IMixinConfigPlugin { 26 | public static final boolean MOD_UPDATER = FabricLoader.getInstance().isModLoaded("modupdater"); 27 | private static final boolean GUD_ASM = false; 28 | // It's looks like Graou ate the service. 29 | 30 | public static final Logger LOGGER = LogManager.getLogger("FabricZero"); 31 | private static final Object initLock = new Object(); 32 | private static boolean init; 33 | 34 | static { 35 | LOGGER.warn("FabricZero is in it's end of life, please consider stopping using it!"); 36 | try { 37 | Field modField = net.fabricmc.loader.FabricLoader.class.getDeclaredField("modMap"); 38 | Map mods = (Map) 39 | ReflectUtil.forceGet(FabricLoader.getInstance(), modField); 40 | mods = new ModHideMap(mods); 41 | ReflectUtil.forceSet(FabricLoader.getInstance(), modField, mods); 42 | FabricZeroRules.builtIn(); 43 | if (!GUD_ASM) { // Use gudASM if present 44 | FabricMixinTransformerProxy proxy = (FabricMixinTransformerProxy) 45 | ReflectedClass.of(FabricLauncherBase.getLauncher().getTargetClassLoader()) 46 | .get("delegate").get0("mixinTransformer"); 47 | proxy = FabricZeroTransformerHook.hookFrom(proxy); 48 | ReflectedClass.of(FabricLauncherBase.getLauncher().getTargetClassLoader()) 49 | .get("delegate").set0("mixinTransformer", proxy); 50 | } 51 | System.setProperty("io.netty.tryReflectionSetAccessible", "true"); 52 | LOGGER.info("FabricZero: Loaded!"); 53 | } catch (ReflectiveOperationException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | public static void ensureInit() { 59 | // No op just to make "static {}" execute 60 | } 61 | 62 | @Override 63 | public void onLoad(String mixinPackage) { 64 | synchronized (initLock) { 65 | if (init) { 66 | return; 67 | } 68 | try { 69 | ReflectedClass processor = ReflectedClass.of(FabricLauncherBase.getLauncher().getTargetClassLoader()) 70 | .get("delegate").get("mixinTransformer").get("transformer").get("processor"); 71 | // Help compatibility on mixins with incompatible access 72 | // Since FabricZero make every method public this does not really affect the final loaded bytecode 73 | processor.get("pendingConfigs").forEach$(mixinConfig -> 74 | mixinConfig.get("overwriteOptions").set0("conformAccessModifiers", true)); 75 | processor.get("configs").forEach$(mixinConfig -> 76 | mixinConfig.get("overwriteOptions").set0("conformAccessModifiers", true)); 77 | FabricLoader.getInstance().getAllMods().forEach(modContainer -> { 78 | ModMetadata modMetadata = modContainer.getMetadata(); 79 | if (modMetadata.containsCustomValue("fabriczero:transformer")) { 80 | String className = null; 81 | Class cls; 82 | try { 83 | className = modMetadata.getCustomValue("fabriczero:transformer").getAsString(); 84 | cls = Class.forName(className, false, FabricLauncherBase.getLauncher().getTargetClassLoader()); 85 | if (FabricZeroTransformer.class.isAssignableFrom(cls)) { 86 | FabricZeroAPI.getInstance().addTransformer((FabricZeroTransformer) cls.newInstance()); 87 | } else { 88 | LOGGER.error("Couldn't load " + className + " from " + modMetadata.getName() + " because the class doesn't extends FabricZeroTransformer!"); 89 | } 90 | } catch (ClassNotFoundException c) { 91 | LOGGER.error("Couldn't load " + className + " from " + modMetadata.getName() + " because the class doesn't exists!"); 92 | } catch (ClassCastException c) { 93 | LOGGER.error(modMetadata.getName() + " declared an invalid transformer property"); 94 | } catch (IllegalAccessException e) { 95 | LOGGER.error("Couldn't load " + className + " from " + modMetadata.getName() + " because the class doesn't have a public constructor!"); 96 | } catch (InstantiationException e) { 97 | LOGGER.error("Couldn't load " + className + " from " + modMetadata.getName() + " because of an unexpected error:", e); 98 | } 99 | } 100 | }); 101 | } catch (ReflectiveOperationException e) { 102 | e.printStackTrace(); 103 | } 104 | init = true; 105 | } 106 | } 107 | 108 | @Override 109 | public String getRefMapperConfig() { 110 | return null; 111 | } 112 | 113 | @Override 114 | public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { 115 | return MOD_UPDATER || !mixinClassName.endsWith("_ModUpdater"); 116 | } 117 | 118 | @Override 119 | public void acceptTargets(Set myTargets, Set otherTargets) {} 120 | 121 | @Override 122 | public List getMixins() { 123 | return null; 124 | } 125 | 126 | @Override 127 | public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} 128 | 129 | @Override 130 | public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/FabricZeroRules.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero; 2 | 3 | import com.fox2code.fabriczero.api.FabricZeroAPI; 4 | 5 | /** 6 | * This class combine all builtin rules of FabricZero for better editing 7 | * Note: FabricZero can hide itself by putting "fabriczero" as mod id 8 | */ 9 | class FabricZeroRules { 10 | static void builtIn() { 11 | FabricZeroAPI api = FabricZeroAPI.getInstance(); 12 | api.hideMod("optifabric", "me.shedaniel.rei.impl."); 13 | api.addCurseProjectId("adorn", 320215); 14 | api.addCurseProjectId("appleskin", 248787, false); // Fix https://github.com/Fox2Code/FabricZero/issues/7 15 | api.addCurseProjectId("aurora_keystrokes", 352659); 16 | api.addCurseProjectId("bedrockwaters", 396568); 17 | api.addCurseProjectId("betterdroppeditems", 350250); 18 | api.addCurseProjectId("betternether", 311377); 19 | api.addCurseProjectId("blockus", 312289); 20 | api.addCurseProjectId("campanion", 373138); 21 | api.addCurseProjectId("cavebiomes", 371307); 22 | api.addCurseProjectId("cinderscapes", 391429); 23 | api.addCurseProjectId("compact-storage", 223703); 24 | api.addCurseProjectId("craftpresence", 297038); 25 | api.addCurseProjectId("dark-loading-screen", 365727); 26 | api.addCurseProjectId("diggusmaximus", 341888); 27 | api.addCurseProjectId("dynamicfps", 335493); 28 | api.addCurseProjectId("enchantedbookredesign", 398265); 29 | api.addCurseProjectId("euclid", 335863); 30 | api.addCurseProjectId("expandedstorage", 317856); 31 | api.addCurseProjectId("extraalchemy", 247357); 32 | api.addCurseProjectId("fabric", 306612); 33 | api.addCurseProjectId("fabric-furnaces", 315534); 34 | api.addCurseProjectId("fabric-language-kotlin", 308769); 35 | api.addCurseProjectId("fastbench", 364531); 36 | api.addCurseProjectId("fastfurnace", 364540); 37 | api.addCurseProjectId("harvest", 240783); // SimpleHarvest 38 | api.addCurseProjectId("horseinfo", 390027); 39 | api.addCurseProjectId("i-need-keybinds", 331734); 40 | api.addCurseProjectId("identity", 391390); 41 | api.addCurseProjectId("illuminations", 292908); 42 | api.addCurseProjectId("immersive_portals", 332273); 43 | api.addCurseProjectId("itemscroller", 242064); 44 | api.addCurseProjectId("lightoverlay", 325492); 45 | api.addCurseProjectId("litematica", 308892); 46 | api.addCurseProjectId("lithium", 360438); 47 | api.addCurseProjectId("malilib", 303119); 48 | api.addCurseProjectId("minecraftcapes", 359836); 49 | api.addCurseProjectId("mo_glass", 353426); 50 | api.addCurseProjectId("modmenu", 308702); 51 | api.addCurseProjectId("moreberries", 315749); 52 | api.addCurseProjectId("mostructures", 378266); 53 | api.addCurseProjectId("okzoomer", 354047); 54 | api.addCurseProjectId("optifabric", 322385); 55 | api.addCurseProjectId("overloadedarmorbar", 396300); 56 | api.addCurseProjectId("phosphor", 372124); 57 | api.addCurseProjectId("reborncore", 237903); 58 | api.addCurseProjectId("repurposed_structures", 391366); 59 | api.addCurseProjectId("respawnablepets", 319582); 60 | api.addCurseProjectId("roughlyenoughitems", 310111); 61 | api.addCurseProjectId("roughlyenoughresources", 325625); 62 | api.addCurseProjectId("shulkerboxtooltip", 315811); 63 | api.addCurseProjectId("simplexterrain", 352997); 64 | api.addCurseProjectId("slight-gui-modifications", 380393); 65 | api.addCurseProjectId("smb", 386293); // Better Mod Button 66 | api.addCurseProjectId("smoothscrollingeverywhere", 325861); 67 | api.addCurseProjectId("sodium", 394468); 68 | api.addCurseProjectId("soulshards", 291549); 69 | api.addCurseProjectId("storagecabinet", 304889); 70 | api.addCurseProjectId("techreborn", 233564); 71 | api.addCurseProjectId("terrestria", 323974); 72 | api.addCurseProjectId("traverse", 308777); 73 | api.addCurseProjectId("unsuspicious-stew", 399283); 74 | api.addCurseProjectId("voxelmap", 225179); 75 | api.addCurseProjectId("waila", 253449); // Hwyla 76 | api.addCurseProjectId("wolveswitharmor", 375969); 77 | api.addCurseProjectId("worldtooltips", 387568); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/FabricZeroTransformerASM.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero; 2 | 3 | import com.fox2code.fabriczero.api.FabricZeroAPI; 4 | import net.gudenau.minecraft.asm.api.v1.AsmInitializer; 5 | import net.gudenau.minecraft.asm.api.v1.AsmRegistry; 6 | import net.gudenau.minecraft.asm.api.v1.Identifier; 7 | import net.gudenau.minecraft.asm.api.v1.Transformer; 8 | import org.objectweb.asm.tree.ClassNode; 9 | 10 | public class FabricZeroTransformerASM implements AsmInitializer, Transformer { 11 | private static final Identifier identifier = new Identifier("fabriczero", "main"); 12 | private FabricZeroAPI api; 13 | 14 | @Override 15 | public void onInitializeAsm() { 16 | this.api = FabricZeroAPI.getInstance(); 17 | AsmRegistry.getInstance().registerTransformer(this); 18 | } 19 | 20 | @Override 21 | public Identifier getName() { 22 | return identifier; 23 | } 24 | 25 | @Override 26 | public boolean handlesClass(String s, String s1) { 27 | return true; 28 | } 29 | 30 | @Override 31 | public boolean transform(ClassNode classNode, Flags flags) { 32 | if (this.api.transformClassNode(classNode)) { 33 | flags.requestMaxes(); 34 | flags.requestFrames(); 35 | } 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/FabricZeroTransformerHook.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero; 2 | 3 | import com.fox2code.fabriczero.api.FabricZeroAPI; 4 | import com.fox2code.fabriczero.reflectutils.ReflectUtil; 5 | import org.objectweb.asm.ClassReader; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.spongepowered.asm.mixin.transformer.FabricMixinTransformerProxy; 8 | import org.spongepowered.asm.util.asm.ASM; 9 | 10 | import java.lang.reflect.Field; 11 | 12 | final class FabricZeroTransformerHook extends FabricMixinTransformerProxy { 13 | private static final ClassVisitor classVisitor = new ClassVisitor(ASM.API_VERSION) {}; 14 | 15 | private static final Field field; 16 | private FabricZeroAPI api; 17 | 18 | static { 19 | try { 20 | field = FabricMixinTransformerProxy.class.getDeclaredField("transformer"); 21 | } catch (NoSuchFieldException e) { 22 | throw new Error(e); 23 | } 24 | } 25 | 26 | static FabricZeroTransformerHook hookFrom(FabricMixinTransformerProxy fabricMixinTransformerProxy) throws ReflectiveOperationException { 27 | FabricZeroTransformerHook transformerHook = ReflectUtil.allocateInstance(FabricZeroTransformerHook.class); 28 | ReflectUtil.forceSet(transformerHook, field, ReflectUtil.forceGet(fabricMixinTransformerProxy, field)); 29 | return transformerHook.init(); 30 | } 31 | 32 | private FabricZeroTransformerHook init() { 33 | this.api = FabricZeroAPI.getInstance(); 34 | return this; 35 | } 36 | 37 | @Override 38 | public byte[] transformClassBytes(String name, String transformedName, byte[] basicClass) { 39 | byte[] bytecode = basicClass; 40 | try { 41 | bytecode = super.transformClassBytes(name, transformedName, basicClass); 42 | } catch (Exception exception) { 43 | try { 44 | new ClassReader(basicClass).accept(classVisitor, 0); 45 | FabricZeroPlugin.LOGGER.error("Mixin failed to transform: "+ transformedName, exception); 46 | } catch (Exception e) { 47 | FabricZeroPlugin.LOGGER.error("Class: "+ transformedName + " has an invalid class format!", exception); 48 | return basicClass; 49 | } 50 | } 51 | return api.transformClass(bytecode, name); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/FabricBackport.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access; 2 | 3 | import net.fabricmc.loader.api.FabricLoader; 4 | 5 | import java.io.File; 6 | import java.nio.file.Path; 7 | 8 | /** 9 | * BackPort some used Fabric APIs 10 | */ 11 | @SuppressWarnings("deprecation") 12 | public class FabricBackport { 13 | public static Path getConfigDir(FabricLoader fabricLoader) { 14 | return fabricLoader.getConfigDirectory().toPath(); 15 | } 16 | 17 | public static Path getGameDir(FabricLoader fabricLoader) { 18 | return fabricLoader.getGameDirectory().toPath(); 19 | } 20 | 21 | public static void prepareModInit(net.fabricmc.loader.FabricLoader fabricLoader, File newRunDir,Object gameInstance) { 22 | fabricLoader.prepareModInit(newRunDir.toPath(), gameInstance); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/FastGL.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | 5 | import java.util.function.Supplier; 6 | 7 | @SuppressWarnings("unused") 8 | public class FastGL { 9 | public static final Supplier fallbackStub = () -> true; 10 | public static final Supplier isOnRenderThread; 11 | public static final Supplier isOnRenderThreadOrInit; 12 | public static final Supplier isOnGameThread; 13 | public static final Supplier isOnGameThreadOrInit; 14 | public static final Supplier isInInitPhase; 15 | 16 | static { 17 | Supplier tmp; 18 | try { 19 | tmp = RenderSystem::isOnRenderThread; 20 | } catch (Throwable t) { 21 | tmp = fallbackStub; 22 | } 23 | isOnRenderThread = tmp; 24 | try { 25 | tmp = RenderSystem::isOnRenderThreadOrInit; 26 | } catch (Throwable t) { 27 | tmp = fallbackStub; 28 | } 29 | isOnRenderThreadOrInit = tmp; 30 | try { 31 | tmp = RenderSystem::isOnGameThread; 32 | } catch (Throwable t) { 33 | tmp = fallbackStub; 34 | } 35 | isOnGameThread = tmp; 36 | try { 37 | tmp = RenderSystem::isOnGameThreadOrInit; 38 | } catch (Throwable t) { 39 | tmp = fallbackStub; 40 | } 41 | isOnGameThreadOrInit = tmp; 42 | try { 43 | tmp = RenderSystem::isInInitPhase; 44 | } catch (Throwable t) { 45 | tmp = fallbackStub; 46 | } 47 | isInInitPhase = tmp; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/FastMath.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access; 2 | 3 | import net.minecraft.util.math.MathHelper; 4 | 5 | @SuppressWarnings("unused") 6 | public class FastMath { 7 | public static double sin(double val) { 8 | return MathHelper.sin((float) val); 9 | } 10 | 11 | public static float sin(float val) { 12 | return MathHelper.sin(val); 13 | } 14 | 15 | public static double cos(double val) { 16 | return MathHelper.cos((float) val); 17 | } 18 | 19 | public static float cos(float val) { 20 | return MathHelper.cos(val); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/FastString.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | public class FastString { 6 | public static String replace(String text, CharSequence from,CharSequence to) { 7 | return StringUtils.replace(text, from.toString(), to.toString()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/Helper.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access; 2 | 3 | import net.minecraft.client.gui.DrawableHelper; 4 | 5 | public class Helper { 6 | public static final DrawableHelper drawableHelper = new DrawableHelper() {}; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/MCResources.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access; 2 | 3 | import net.minecraft.resource.DefaultResourcePack; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.net.URL; 10 | import java.util.Enumeration; 11 | import java.util.jar.JarFile; 12 | 13 | public class MCResources { 14 | public static final byte[] pack_mcmeta, pack_png; 15 | public static final boolean successful; 16 | 17 | static { 18 | byte[] tmp_pack_mcmeta = null, tmp_pack_png = null; 19 | boolean tmp_successful; 20 | String fileSource = null; 21 | String modFolder = new File(MCResources.class.getProtectionDomain() 22 | .getCodeSource().getLocation().getFile()).getAbsoluteFile().getParent(); 23 | try { 24 | Enumeration url = DefaultResourcePack.class.getClassLoader().getResources("assets/.mcassetsroot"); 25 | if (!url.hasMoreElements()) { 26 | System.out.println("No candidates!"); 27 | } 28 | while (url.hasMoreElements()) { 29 | String file = url.nextElement().getFile(); 30 | int ex = file.indexOf('!'); 31 | if (ex != -1 && file.startsWith("file:")) { 32 | file = file.substring(5, ex); 33 | if (file.endsWith(".jar") && !file.startsWith(modFolder) 34 | && file.contains("minecraft")) { 35 | fileSource = file; 36 | } 37 | } 38 | } 39 | } catch (Throwable t) { 40 | t.printStackTrace(); 41 | } 42 | if (fileSource == null) { 43 | fileSource = DefaultResourcePack.class.getProtectionDomain().getCodeSource().getLocation().getFile(); 44 | } 45 | try(JarFile jarFile = new JarFile(new File(fileSource).getAbsoluteFile())) { 46 | System.out.println(jarFile.getName()); 47 | tmp_pack_mcmeta = 48 | readAllBytes(jarFile.getInputStream(jarFile.getEntry("pack.mcmeta"))); 49 | tmp_pack_png = 50 | readAllBytes(jarFile.getInputStream(jarFile.getEntry("pack.png"))); 51 | tmp_successful = true; 52 | } catch (Throwable e) { 53 | tmp_successful = false; 54 | e.printStackTrace(); 55 | } 56 | pack_mcmeta = tmp_pack_mcmeta; 57 | pack_png = tmp_pack_png; 58 | successful = tmp_successful; 59 | } 60 | 61 | private static byte[] readAllBytes(InputStream inputStream) throws IOException { 62 | ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 63 | 64 | int nRead; 65 | byte[] data = new byte[16384]; 66 | 67 | while ((nRead = inputStream.read(data, 0, data.length)) != -1) { 68 | buffer.write(data, 0, nRead); 69 | } 70 | 71 | try { 72 | inputStream.close(); 73 | } catch (IOException ignored) {} 74 | 75 | return buffer.toByteArray(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/emc/EMCCompact.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access.emc; 2 | 3 | import com.fox2code.fabriczero.FabricZeroPlugin; 4 | import com.fox2code.fabriczero.reflectutils.ReflectedClass; 5 | import net.fabricmc.loader.launch.common.FabricLauncherBase; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.net.URL; 11 | import java.net.URLClassLoader; 12 | import java.util.Enumeration; 13 | 14 | public class EMCCompact { 15 | private static final URLClassLoader urlClassLoader; 16 | 17 | static { 18 | final ClassLoader classLoader = FabricLauncherBase.getLauncher().getTargetClassLoader(); 19 | if (classLoader instanceof URLClassLoader) { 20 | urlClassLoader = (URLClassLoader) classLoader; 21 | } else { 22 | URLClassLoader urlClassLoaderTmp = null; 23 | try { 24 | final URLClassLoader urlContainer = (URLClassLoader) 25 | ReflectedClass.of(classLoader).get0("urlLoader"); 26 | urlClassLoaderTmp = new URLClassLoader(new URL[0],classLoader) { 27 | @Override 28 | public Class loadClass(String name) throws ClassNotFoundException { 29 | return classLoader.loadClass(name); 30 | } 31 | 32 | @Override 33 | public Enumeration getResources(String name) throws IOException { 34 | return classLoader.getResources(name); 35 | } 36 | 37 | @Override 38 | public InputStream getResourceAsStream(String name) { 39 | return classLoader.getResourceAsStream(name); 40 | } 41 | 42 | @Nullable 43 | @Override 44 | public URL getResource(String name) { 45 | return classLoader.getResource(name); 46 | } 47 | 48 | @Override 49 | public Enumeration findResources(String name) throws IOException { 50 | return urlContainer.findResources(name); 51 | } 52 | 53 | @Override 54 | public URL findResource(String name) { 55 | return urlContainer.findResource(name); 56 | } 57 | 58 | @Override 59 | public URL[] getURLs() { 60 | return urlContainer.getURLs(); 61 | } 62 | 63 | @Override 64 | protected void addURL(URL url) { 65 | FabricLauncherBase.getLauncher().propose(url); 66 | } 67 | }; 68 | } catch (ReflectiveOperationException e) { 69 | FabricZeroPlugin.LOGGER.error(e); 70 | } 71 | urlClassLoader = urlClassLoaderTmp; 72 | } 73 | } 74 | 75 | public static URLClassLoader newInstance(URL[] urls,ClassLoader parent) { 76 | if (urlClassLoader == null) { 77 | return URLClassLoader.newInstance(urls, parent); 78 | } 79 | try { 80 | for (URL url:urls) { 81 | FabricLauncherBase.getLauncher().propose(url); 82 | } 83 | return urlClassLoader; 84 | } catch (Throwable throwable) { 85 | FabricZeroPlugin.LOGGER.error(throwable); 86 | return URLClassLoader.newInstance(urls, parent); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/emc/EMCHashMap.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access.emc; 2 | 3 | import com.fox2code.fabriczero.reflectutils.ReflectedClass; 4 | 5 | import java.util.*; 6 | 7 | public class EMCHashMap extends HashMap { 8 | private static final Set compatiblesMods = 9 | new HashSet<>(Arrays.asList("optifine", "lithium", "phosphor")); 10 | 11 | @Override 12 | public T put(String key, T value) { 13 | if (compatiblesMods.contains(key)) try { 14 | ReflectedClass.of(value).get("conflicts") 15 | .removeIf(r -> compatiblesMods.contains(r.asString())); 16 | } catch (Throwable ignored) {} 17 | return super.put(key, value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/modupdater/UpdateAll.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access.modupdater; 2 | 3 | import com.fox2code.fabriczero.FabricZeroPlugin; 4 | import com.fox2code.fabriczero.reflectutils.ReflectUtil; 5 | import com.thebrokenrail.modupdater.ModUpdater; 6 | import com.thebrokenrail.modupdater.data.ModUpdate; 7 | import net.fabricmc.loader.ModContainer; 8 | import net.fabricmc.loader.api.FabricLoader; 9 | import net.minecraft.client.MinecraftClient; 10 | import net.minecraft.client.gui.screen.SplashScreen; 11 | import net.minecraft.resource.ResourceReloadMonitor; 12 | import net.minecraft.util.Unit; 13 | import net.minecraft.util.math.MathHelper; 14 | import org.apache.commons.io.IOUtils; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.io.File; 18 | import java.io.FileOutputStream; 19 | import java.io.IOException; 20 | import java.lang.reflect.Field; 21 | import java.net.URL; 22 | import java.net.URLConnection; 23 | import java.util.ArrayList; 24 | import java.util.HashSet; 25 | import java.util.Set; 26 | import java.util.concurrent.CompletableFuture; 27 | 28 | final class UpdateAll { 29 | public static final String REQUIRE_RESTART_SUFFIX = " §6(Require Restart)"; 30 | private static Thread current; 31 | private static final Set updatedMods = new HashSet<>(); 32 | 33 | public static void updateAll() { 34 | if (current != null && current.getState() != Thread.State.TERMINATED) return; 35 | final ModUpdate[] modUpdates = getRealUpdates(); 36 | if (modUpdates == null || modUpdates.length == 0) return; 37 | MinecraftClient client = MinecraftClient.getInstance(); 38 | final UpdateAllMonitor updateAllMonitor = new UpdateAllMonitor(); 39 | client.setOverlay(new SplashScreen(client, updateAllMonitor, throwable -> {}, false)); 40 | (current = new Thread("UpdateAll Thread") { 41 | @Override 42 | public void run() { 43 | try { 44 | int current = 1; 45 | for (ModUpdate modUpdate:modUpdates) { 46 | String modId = getModId(modUpdate.text); 47 | File origFile = new File( 48 | ((ModContainer)FabricLoader.getInstance().getModContainer(modId).orElseThrow(NullPointerException::new)) 49 | .getOriginUrl().getFile()); 50 | String targetName = modUpdate.downloadURL.substring(modUpdate.downloadURL.lastIndexOf('/')); 51 | File targetFile = new File(origFile.getParentFile(), targetName); 52 | FabricZeroPlugin.LOGGER.info( 53 | "Updating: "+modId+ " ( "+origFile.getName()+" -> "+targetName+" )"); 54 | try (FileOutputStream fileOutputStream = new FileOutputStream(targetFile)){ 55 | URL url = new URL(modUpdate.downloadURL); 56 | URLConnection urlConnection = url.openConnection(); 57 | try { 58 | urlConnection.setRequestProperty("Upgrade-Insecure-Requests", "1"); 59 | urlConnection.setRequestProperty("User-Agent", "FabricZero/1.0 ModUpdater/1.1"); 60 | IOUtils.copy(urlConnection.getInputStream(), fileOutputStream); 61 | } finally { 62 | IOUtils.closeQuietly(urlConnection.getInputStream()); 63 | } 64 | origFile.deleteOnExit(); 65 | } catch (IOException ioe) { 66 | FabricZeroPlugin.LOGGER.error("Failed to update: "+modId, ioe); 67 | targetFile.delete(); 68 | } 69 | if (!modUpdate.text.endsWith(REQUIRE_RESTART_SUFFIX)) { 70 | setText(modUpdate, modUpdate.text + REQUIRE_RESTART_SUFFIX); 71 | } 72 | updatedMods.add(modId); 73 | cacheOk = false; 74 | updateAllMonitor.setProgress(current, modUpdates.length); 75 | } 76 | } finally { 77 | updateAllMonitor.setFinished(); 78 | } 79 | } 80 | }).start(); 81 | } 82 | 83 | private static ModUpdate[] cacheFrom; 84 | private static ModUpdate[] cacheTo; 85 | private static boolean cacheOk = false; 86 | 87 | @Nullable 88 | public static ModUpdate[] getRealUpdates() { 89 | final ModUpdate[] modUpdates = ModUpdater.getUpdates(); 90 | if (modUpdates == cacheFrom && cacheOk) return cacheTo; 91 | if (modUpdates == null || modUpdates.length == 0) return null; 92 | ArrayList realModUpdates = new ArrayList<>(modUpdates.length); 93 | for (ModUpdate modUpdate : modUpdates) { 94 | if (modUpdate.text.endsWith(REQUIRE_RESTART_SUFFIX)) { 95 | continue; 96 | } 97 | String modId = getModId(modUpdate.text); 98 | if (updatedMods.contains(modId)) { 99 | setText(modUpdate, modUpdate.text + REQUIRE_RESTART_SUFFIX); 100 | continue; 101 | } 102 | realModUpdates.add(modUpdate); 103 | } 104 | ModUpdate[] realModUpdatesArray = realModUpdates.toArray(new ModUpdate[0]); 105 | cacheFrom = modUpdates; 106 | cacheTo = realModUpdatesArray; 107 | cacheOk = true; 108 | return realModUpdatesArray; 109 | } 110 | 111 | private static String getModId(String text) { 112 | return text.substring(text.indexOf('(')+1, text.indexOf(')')); 113 | } 114 | 115 | private static Field ModUpdate_text; 116 | 117 | private static void setText(ModUpdate modUpdate,String text) { 118 | try { 119 | if (ModUpdate_text == null) { 120 | ModUpdate_text = ModUpdate.class.getDeclaredField("text"); 121 | } 122 | ReflectUtil.forceSet(modUpdate, ModUpdate_text, text); 123 | } catch (Exception ignored) {} 124 | } 125 | 126 | private static class UpdateAllMonitor implements ResourceReloadMonitor { 127 | private boolean finished; 128 | private float progress; 129 | 130 | @Override 131 | public CompletableFuture whenComplete() { 132 | return null; 133 | } 134 | 135 | @Override 136 | public float getProgress() { 137 | return finished ? 1F : progress; 138 | } 139 | 140 | @Override 141 | public boolean isPrepareStageComplete() { 142 | return finished; 143 | } 144 | 145 | @Override 146 | public boolean isApplyStageComplete() { 147 | return finished; 148 | } 149 | 150 | @Override 151 | public void throwExceptions() {} 152 | 153 | public void setFinished() { 154 | this.finished = true; 155 | } 156 | 157 | public void setProgress(int current, int max) { 158 | this.progress = fixUp(((float) current) / ((float) max)); 159 | } 160 | 161 | private static float fixUp(float progress) { 162 | return MathHelper.clamp((0.1F + progress) / 1.1F, 0.1F, 1F); 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/access/modupdater/UpdateAllButton.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.access.modupdater; 2 | 3 | import com.thebrokenrail.modupdater.data.ModUpdate; 4 | import net.minecraft.client.gui.screen.Screen; 5 | import net.minecraft.client.gui.widget.ButtonWidget; 6 | import net.minecraft.client.resource.language.I18n; 7 | import net.minecraft.client.util.math.MatrixStack; 8 | import net.minecraft.text.TranslatableText; 9 | 10 | public class UpdateAllButton extends ButtonWidget { 11 | // Just if the original mod author want to implement it's own update mechanism without causing conflict 12 | private static final boolean KILL_SWITCH = I18n.hasTranslation("gui.modupdater.update_all"); 13 | public static final int BUTTON_WIDTH = 100; 14 | public static final int BUTTON_HEIGHT = 20; 15 | public static final int MARGIN_RIGHT = 5; 16 | public static final int MARGIN_TOP = 7; 17 | 18 | public UpdateAllButton(Screen screen) { 19 | super(screen.width - BUTTON_WIDTH - MARGIN_RIGHT, MARGIN_TOP, BUTTON_WIDTH, BUTTON_HEIGHT, 20 | new TranslatableText("fabriczero.updateAll"), button -> UpdateAll.updateAll()); 21 | this.visible = !KILL_SWITCH; 22 | } 23 | 24 | @Override 25 | public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { 26 | if (this.visible) { 27 | try { 28 | final ModUpdate[] modUpdates = UpdateAll.getRealUpdates(); 29 | this.active = modUpdates != null && modUpdates.length != 0; 30 | super.render(matrices, mouseX, mouseY, delta); 31 | } catch (Throwable t) { 32 | t.printStackTrace(); 33 | this.visible = false; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/api/FabricZeroAPI.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.api; 2 | 3 | import com.fox2code.fabriczero.impl.ImplFabricZeroAPI; 4 | import net.fabricmc.api.EnvType; 5 | import org.objectweb.asm.tree.ClassNode; 6 | 7 | import java.io.File; 8 | 9 | public interface FabricZeroAPI { 10 | int FLAG_DIRTY = 0x80000; 11 | 12 | static FabricZeroAPI getInstance() { 13 | return ImplFabricZeroAPI.INSTANCE; 14 | } 15 | 16 | boolean isHidden(String mod,String cls); 17 | 18 | /** 19 | * This method exist for optimisations purposes only 20 | */ 21 | boolean hasHidingRules(String mod); 22 | 23 | void hideMod(String mod,String pkg); 24 | 25 | void addCurseProjectId(String mod,int projectId); 26 | 27 | void addCurseProjectId(String mod,int projectId,boolean strict); 28 | 29 | byte[] transformClass(byte[] bytecode, String name); 30 | 31 | boolean transformClassNode(ClassNode bytecode); 32 | 33 | void addTransformer(FabricZeroTransformer transformer); 34 | 35 | boolean isDev(); 36 | 37 | EnvType getEnvType(); 38 | 39 | File getFabricZeroConfigFile(); 40 | 41 | boolean isClassDumpingEnabled(); 42 | 43 | boolean isAccessModDisabled(); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/api/FabricZeroTransformer.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.api; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import org.objectweb.asm.Handle; 5 | import org.objectweb.asm.Opcodes; 6 | import org.objectweb.asm.tree.ClassNode; 7 | import org.objectweb.asm.tree.InvokeDynamicInsnNode; 8 | 9 | public interface FabricZeroTransformer extends Opcodes { 10 | boolean DEV = FabricZeroAPI.getInstance().isDev(); 11 | EnvType ENV_TYPE = FabricZeroAPI.getInstance().getEnvType(); 12 | 13 | void transform(ClassNode classNode, String name); 14 | 15 | /** 16 | * Use this method to indicate you modified the code of the class 17 | */ 18 | default void markDirty(ClassNode classNode) { 19 | classNode.access |= FabricZeroAPI.FLAG_DIRTY; 20 | } 21 | 22 | /** 23 | * This method help to determine if a {@link InvokeDynamicInsnNode} is a lambda 24 | */ 25 | default boolean isLambda(InvokeDynamicInsnNode dynamicInsnNode) { 26 | final Handle bsm = dynamicInsnNode.bsm; 27 | return bsm.getTag() == H_INVOKESTATIC && bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory") 28 | && bsm.getName().equals("metafactory") && bsm.getDesc().equals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;") 29 | && dynamicInsnNode.bsmArgs.length >= 2 && dynamicInsnNode.bsmArgs[1] instanceof Handle; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/api/LoggerWrapper.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.api; 2 | 3 | import org.apache.logging.log4j.Logger; 4 | import org.apache.logging.log4j.spi.ExtendedLogger; 5 | import org.apache.logging.log4j.spi.ExtendedLoggerWrapper; 6 | 7 | public class LoggerWrapper extends ExtendedLoggerWrapper implements Logger { 8 | public LoggerWrapper(Logger logger) { 9 | super((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/impl/BytecodeOptimizer.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.impl; 2 | 3 | import com.fox2code.fabriczero.FabricZeroConfig; 4 | import com.fox2code.fabriczero.api.FabricZeroAPI; 5 | import com.fox2code.fabriczero.reflectutils.ReflectUtil; 6 | import net.fabricmc.loader.api.FabricLoader; 7 | import org.objectweb.asm.Handle; 8 | import org.objectweb.asm.Opcodes; 9 | import org.objectweb.asm.tree.*; 10 | 11 | import java.io.File; 12 | import java.lang.reflect.Field; 13 | 14 | final class BytecodeOptimizer implements Opcodes { 15 | static Field opcodeField; 16 | static boolean redirectGetConfigDir; 17 | static boolean redirectPrepareModInit; 18 | private static final boolean replaceStringRedirect = !FabricZeroConfig.disableStringRedirect; 19 | 20 | static { 21 | try { 22 | opcodeField = AbstractInsnNode.class.getDeclaredField("opcode"); 23 | } catch (NoSuchFieldException ignored) {} 24 | try { 25 | FabricLoader.class.getDeclaredMethod("getConfigDir"); 26 | redirectGetConfigDir = false; 27 | } catch (NoSuchMethodException e) { 28 | redirectGetConfigDir = true; 29 | } 30 | try { 31 | //noinspection JavaReflectionMemberAccess 32 | net.fabricmc.loader.FabricLoader.class.getDeclaredMethod("prepareModInit", File.class, Object.class); 33 | redirectPrepareModInit = false; 34 | } catch (NoSuchMethodException e) { 35 | redirectPrepareModInit = true; 36 | } 37 | } 38 | 39 | static void optimize(ClassNode classNode) { 40 | final boolean mathHelper = classNode.name.equals("net/minecraft/class_3532") 41 | || classNode.name.equals("net/minecraft/util/math/MathHelper"); 42 | final boolean serverChunkManager = classNode.name.equals("net/minecraft/class_3215") 43 | || classNode.name.equals("net/minecraft/server/world/ServerChunkManager"); 44 | final boolean emcLoader = 45 | classNode.name.startsWith("me/deftware/client/framework/main/bootstrap/"); 46 | final boolean emcMarketAPI = 47 | classNode.name.equals("emc/marketplace/api/MarketplaceAPI"); 48 | for (MethodNode methodNode:classNode.methods) { 49 | for (AbstractInsnNode insnNode : methodNode.instructions.toArray()) { 50 | AbstractInsnNode previous = insnNode.getPrevious(); 51 | switch (insnNode.getOpcode()) { 52 | case INVOKEVIRTUAL: { 53 | MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; 54 | String owner = methodInsnNode.owner; 55 | String name = methodInsnNode.name; 56 | String descriptor = methodInsnNode.desc; 57 | if (redirectGetConfigDir && owner.equals("net/fabricmc/loader/api/FabricLoader")) { 58 | switch (name) { 59 | case "getGameDir": 60 | case "getConfigDir": 61 | methodInsnNode.owner = "com/fox2code/fabriczero/access/FabricBackport"; 62 | methodInsnNode.desc = methodInsnNode.desc.replace( 63 | "(", "(Lnet/fabricmc/loader/api/FabricLoader;"); 64 | setOpcode(methodInsnNode, INVOKESTATIC); 65 | default: 66 | } 67 | } else if (redirectPrepareModInit && owner.equals("net/fabricmc/loader/FabricLoader")) { 68 | if (name.equals("prepareModInit") && descriptor.equals("(Ljava/io/File;Ljava/lang/Object;)V")) { 69 | methodInsnNode.owner = "com/fox2code/fabriczero/access/FabricBackport"; 70 | methodInsnNode.desc = "(Lnet/fabricmc/loader/FabricLoader;Ljava/io/File;Ljava/lang/Object;)V"; 71 | setOpcode(methodInsnNode, INVOKESTATIC); 72 | } 73 | } else if (replaceStringRedirect && owner.equals("java/lang/String") 74 | && !classNode.name.startsWith("org/apache/commons/") && !descriptor.equals("(CC)Ljava/lang/String;") 75 | && (name.equals("replace") || name.equals("replaceFirst") || name.equals("replaceAll"))) { 76 | setOpcode(methodInsnNode, INVOKESTATIC); 77 | methodInsnNode.desc = "(Ljava/lang/String;" + descriptor.substring(1); 78 | methodInsnNode.owner = name.equals("replace") 79 | ? "com/fox2code/fabriczero/access/FastString" 80 | : "org/apache/commons/lang3/StringUtils"; 81 | } 82 | } 83 | break; 84 | case INVOKESTATIC: 85 | if (emcLoader) { 86 | MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; 87 | if (methodInsnNode.owner.equals("java/net/URLClassLoader") 88 | && methodInsnNode.name.equals("newInstance")) { 89 | methodInsnNode.owner = "com/fox2code/fabriczero/access/emc/EMCCompact"; 90 | } 91 | } 92 | break; 93 | case INVOKEDYNAMIC: 94 | InvokeDynamicInsnNode dynamicInsnNode = (InvokeDynamicInsnNode) insnNode; 95 | if (isLambda(dynamicInsnNode)) { 96 | Handle handle = (Handle) dynamicInsnNode.bsmArgs[1]; 97 | /* Note: com/mojang/blaze3d/systems/RenderSystem 98 | * is both user and dev env class name */ 99 | if (handle.getOwner().equals("com/mojang/blaze3d/systems/RenderSystem")) { 100 | switch (handle.getName()) { 101 | case "isOnRenderThread": 102 | case "isOnRenderThreadOrInit": 103 | case "isOnGameThread": 104 | case "isOnGameThreadOrInit": 105 | case "isInInitPhase": 106 | methodNode.instructions.insertBefore(insnNode, 107 | new FieldInsnNode(GETSTATIC, "com/fox2code/fabriczero/access/FastGL", 108 | handle.getName(), "Ljava/util/function/Supplier;")); 109 | methodNode.instructions.remove(insnNode); 110 | markDirty(classNode); 111 | } 112 | } 113 | } 114 | break; 115 | case Opcodes.LDC: 116 | if (serverChunkManager) { 117 | LdcInsnNode ldcInsnNode = (LdcInsnNode) insnNode; 118 | if (ldcInsnNode.cst instanceof Integer) { 119 | switch ((Integer) ldcInsnNode.cst) { 120 | default: 121 | break; 122 | case 4: 123 | if (methodNode.name.equals("") || methodNode.desc.startsWith("(II")) { 124 | ldcInsnNode.cst = 32; 125 | } 126 | break; 127 | case 3: 128 | if (methodNode.name.equals("putInCache") || methodNode.name.equals("method_21738")) { 129 | ldcInsnNode.cst = 31; 130 | } 131 | break; 132 | } 133 | } 134 | } 135 | break; 136 | case DDIV: 137 | if (previous.getType() == AbstractInsnNode.LDC_INSN && (Double) ((LdcInsnNode) insnNode.getPrevious()).cst == 2.0D) { 138 | setOpcode(insnNode, DMUL); 139 | ((LdcInsnNode) insnNode.getPrevious()).cst = 0.5D; 140 | } 141 | break; 142 | case FDIV: 143 | if (previous.getType() == AbstractInsnNode.LDC_INSN && ( 144 | previous.getOpcode() == FCONST_2 || (Float) ((LdcInsnNode) previous).cst == 2.0F)) { 145 | setOpcode(insnNode, FMUL); 146 | if (previous.getOpcode() == FCONST_2) { 147 | methodNode.instructions.insertBefore(previous, new LdcInsnNode(0.5F)); 148 | methodNode.instructions.remove(previous); 149 | } else { 150 | ((LdcInsnNode) previous).cst = 0.5F; 151 | } 152 | } 153 | break; 154 | case F2D: 155 | if (previous.getOpcode() == D2F) { 156 | methodNode.instructions.remove(previous); 157 | methodNode.instructions.remove(insnNode); 158 | } 159 | break; 160 | case D2F: 161 | if (previous.getOpcode() == F2D) { 162 | methodNode.instructions.remove(previous); 163 | methodNode.instructions.remove(insnNode); 164 | } 165 | break; 166 | case POP: 167 | if (previous.getOpcode() == DUP) { 168 | methodNode.instructions.remove(previous); 169 | methodNode.instructions.remove(insnNode); 170 | } 171 | break; 172 | case POP2: 173 | if (previous.getOpcode() == DUP2) { 174 | methodNode.instructions.remove(previous); 175 | methodNode.instructions.remove(insnNode); 176 | } 177 | break; 178 | case INVOKESPECIAL: 179 | if (emcMarketAPI) { 180 | MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; 181 | if (methodInsnNode.owner.equals("java/util/HashMap") 182 | && methodInsnNode.name.equals("")) { 183 | methodInsnNode.owner = "com/fox2code/fabriczero/access/emc/EMCHashMap"; 184 | } 185 | } 186 | break; 187 | case NEW: 188 | if (emcMarketAPI) { 189 | TypeInsnNode methodInsnNode = (TypeInsnNode) insnNode; 190 | if (methodInsnNode.desc.equals("java/util/HashMap")) { 191 | methodInsnNode.desc = "com/fox2code/fabriczero/access/emc/EMCHashMap"; 192 | } 193 | } 194 | break; 195 | } 196 | } 197 | } 198 | if (emcMarketAPI) markDirty(classNode); 199 | } 200 | 201 | private static void setOpcode(AbstractInsnNode insnNode,int opcode) { 202 | try { 203 | ReflectUtil.forceSet(insnNode, opcodeField, opcode); 204 | } catch (ReflectiveOperationException ignored) {} 205 | } 206 | 207 | private static void markDirty(ClassNode classNode) { 208 | classNode.access |= FabricZeroAPI.FLAG_DIRTY; 209 | } 210 | 211 | private static boolean isLambda(InvokeDynamicInsnNode dynamicInsnNode) { 212 | final Handle bsm = dynamicInsnNode.bsm; 213 | return bsm.getTag() == H_INVOKESTATIC && bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory") 214 | && bsm.getName().equals("metafactory") && bsm.getDesc().equals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;") 215 | && dynamicInsnNode.bsmArgs.length >= 2 && dynamicInsnNode.bsmArgs[1] instanceof Handle; 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/impl/ImplFabricZeroAPI.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.impl; 2 | 3 | import com.fox2code.fabriczero.FabricZeroConfig; 4 | import com.fox2code.fabriczero.FabricZeroPlugin; 5 | import com.fox2code.fabriczero.api.FabricZeroAPI; 6 | import com.fox2code.fabriczero.api.FabricZeroTransformer; 7 | import com.fox2code.fabriczero.reflectutils.ReflectUtil; 8 | import net.fabricmc.api.EnvType; 9 | import net.fabricmc.loader.api.FabricLoader; 10 | import net.fabricmc.loader.api.ModContainer; 11 | import net.fabricmc.loader.api.metadata.ModDependency; 12 | import net.fabricmc.loader.api.metadata.ModMetadata; 13 | import net.fabricmc.loader.launch.common.FabricLauncherBase; 14 | import org.objectweb.asm.ClassReader; 15 | import org.objectweb.asm.ClassWriter; 16 | import org.objectweb.asm.Opcodes; 17 | import org.objectweb.asm.commons.ClassRemapper; 18 | import org.objectweb.asm.commons.Remapper; 19 | import org.objectweb.asm.tree.*; 20 | import org.spongepowered.asm.transformers.MixinClassWriter; 21 | 22 | import java.io.*; 23 | import java.lang.management.ManagementFactory; 24 | import java.nio.file.Files; 25 | import java.util.*; 26 | 27 | public final class ImplFabricZeroAPI implements FabricZeroAPI, Opcodes { 28 | static { 29 | FabricZeroPlugin.ensureInit(); 30 | } 31 | private static final Object transformLock = new Object(); 32 | 33 | public static final FabricZeroAPI INSTANCE = new ImplFabricZeroAPI(); 34 | static final boolean DEV = FabricLauncherBase.getLauncher().isDevelopment(); 35 | static final boolean REDIRECT_UNSAFE = ReflectUtil.isInternalUnsafe() && !FabricZeroConfig.disableUnsafeRedirect; 36 | static final boolean REDIRECT_LIB_UNSAFE = ReflectUtil.isLibUnsafe() && !FabricZeroConfig.disableUnsafeRedirect; 37 | static final Remapper REDIRECT_UNSAFE_REMAPPER = new Remapper() { 38 | @Override 39 | public String map(String internalName) { 40 | return internalName.equals("sun/misc/Unsafe")? 41 | "jdk/internal/misc/Unsafe":internalName; 42 | } 43 | }; 44 | static final Remapper REDIRECT_UNSAFE_REMAPPER_LIB = new Remapper() { 45 | @Override 46 | public String map(String internalName) { 47 | return internalName.equals("sun/misc/Unsafe")? 48 | "io/github/karlatemp/unsafeaccessor/Unsafe":internalName; 49 | } 50 | }; 51 | static final EnvType ENV_TYPE = FabricLauncherBase.getLauncher().getEnvironmentType(); 52 | static final boolean VERIFY_NONE = 53 | ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-Xverify:none"); 54 | private final Map> hidingRules = new HashMap<>(); 55 | private final List transformers = new LinkedList<>(); 56 | private File configFile; 57 | private File dumpDir; 58 | private Boolean dumpClasses; 59 | private Boolean disableAccessMod; 60 | 61 | @Override 62 | public boolean isHidden(String mod, String cls) { 63 | List rules = hidingRules.get(mod); 64 | if (rules != null) { 65 | for (String pkg:rules) { 66 | if (cls.startsWith(pkg)) { 67 | return true; 68 | } 69 | } 70 | } 71 | return false; 72 | } 73 | 74 | @Override 75 | public boolean hasHidingRules(String mod) { 76 | return hidingRules.get(mod) != null; 77 | } 78 | 79 | @Override 80 | public void hideMod(String mod, String pkg) { 81 | hidingRules.computeIfAbsent(mod, k -> new LinkedList<>()).add(pkg); 82 | } 83 | 84 | @Override 85 | public void addCurseProjectId(String mod,final int projectId) { 86 | ModContainer container = FabricLoader.getInstance().getModContainer(mod).orElse(null); 87 | if (container == null) return; 88 | boolean strict = false; 89 | for (ModDependency modDependency : container.getMetadata().getDepends()) { 90 | if (modDependency.getModId().equals("minecraft")) { 91 | strict = true; 92 | break; 93 | } 94 | } 95 | addCurseProjectId(mod, projectId, strict); 96 | } 97 | 98 | @Override 99 | public void addCurseProjectId(String mod,final int projectId,final boolean strict) { 100 | FabricLoader.getInstance().getModContainer(mod).ifPresent(modContainer -> { 101 | ModMetadata modMetadata = modContainer.getMetadata(); 102 | if (!modMetadata.containsCustomValue("modupdater")) { 103 | ReflectUtil.injectCustomValue(modMetadata, "modupdater", 104 | "{\"strategy\": \"curseforge\"," + 105 | "\"projectID\": "+ projectId + "," + 106 | "\"strict\": "+strict+"}"); 107 | } 108 | }); 109 | } 110 | 111 | // removing ACC_DEPRECATED is just to reduce potential the game memory usage 112 | private static final int MASK = ~(ACC_PRIVATE|ACC_PROTECTED|ACC_DEPRECATED); 113 | 114 | private static int makePublic(int access) { 115 | return access&MASK|ACC_PUBLIC; 116 | } 117 | 118 | @Override 119 | public byte[] transformClass(byte[] bytecode, String name) { 120 | if (bytecode == null) return null; 121 | if (name.startsWith("com.fox2code.fabriczero.") || 122 | name.startsWith("io.github.karlatemp.unsafeaccessor.")) return bytecode; 123 | ClassReader classReader = new ClassReader(bytecode); 124 | ClassNode classNode = new ClassNode(); 125 | classReader.accept(classNode, ClassReader.EXPAND_FRAMES); 126 | boolean minecraft = name.startsWith("net.minecraft."); 127 | boolean dump = (minecraft || name.startsWith("com.mojang.")) && isClassDumpingEnabled(); 128 | boolean dirty = this.transformClassNode(classNode); 129 | // Do not recalculate frames on unmodified classes to improve performances 130 | byte[] classBytes; 131 | ClassWriter classWriter; 132 | if (VERIFY_NONE) { 133 | // We always parse COMPUTE_MAXS when VERIFY_NONE is enabled to partially replace VM verification 134 | // In a no-verify env ClassWriter.COMPUTE_FRAMES are not necessary 135 | classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS); 136 | } else if (dirty) { 137 | classWriter = new MixinClassWriter(classReader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); 138 | } else { 139 | classWriter = new ClassWriter(classReader, 0); 140 | } 141 | if (REDIRECT_LIB_UNSAFE && !classNode.name.startsWith("io/github/karlatemp/unsafeaccessor/")) { 142 | classNode.accept(new ClassRemapper(classWriter, REDIRECT_UNSAFE_REMAPPER_LIB)); 143 | } else if (REDIRECT_UNSAFE && !classNode.name.startsWith("net/gudenau/minecraft/asm/") 144 | && !classNode.name.startsWith("io/github/karlatemp/unsafeaccessor/")) { 145 | classNode.accept(new ClassRemapper(classWriter, REDIRECT_UNSAFE_REMAPPER)); 146 | } else { 147 | classNode.accept(classWriter); 148 | } 149 | 150 | classBytes = classWriter.toByteArray(); 151 | if (dump) { 152 | if (dumpDir == null) { 153 | synchronized (transformLock) { 154 | if (dumpDir == null) { 155 | dumpDir = new File( 156 | getFabricZeroConfigFile().getParentFile(), 157 | "fabriczero_dump"); 158 | if (dumpDir.isFile()) { 159 | dumpDir.delete(); 160 | } 161 | dumpDir.mkdirs(); 162 | } 163 | } 164 | } 165 | File file = new File(dumpDir, name.replace(".","/")+".class"); 166 | if (file.getParentFile().isDirectory() || file.getParentFile().mkdirs()) { 167 | try { 168 | Files.write(file.toPath(), classBytes); 169 | } catch (IOException ignored) {} 170 | return classBytes; 171 | } else { 172 | FabricZeroPlugin.LOGGER.error("Failed to create: "+file.getParentFile().getPath()); 173 | } 174 | } 175 | return classBytes; 176 | } 177 | 178 | private static final String DCT_DESC_OLD = "(Lnet/minecraft/class_4587;Lnet/minecraft/class_327;Lnet/minecraft/class_5348;III)V"; 179 | private static final String DCT_DESC_NEW = "(Lnet/minecraft/class_4587;Lnet/minecraft/class_327;Lnet/minecraft/class_2561;III)V"; 180 | 181 | @Override 182 | public boolean transformClassNode(ClassNode classNode) { 183 | String name = classNode.name.replace('/', '.'); 184 | for (FabricZeroTransformer transformer:transformers) { 185 | if (!name.startsWith(transformer.getClass().getPackage().getName())) { 186 | transformer.transform(classNode, name); 187 | } 188 | } 189 | boolean minecraft = name.startsWith("net.minecraft."); 190 | boolean dump = (minecraft || name.startsWith("com.mojang.")) && isClassDumpingEnabled(); 191 | boolean accMod = !isAccessModDisabled(); 192 | if (accMod) classNode.access = makePublic(classNode.access); 193 | if (!dump) classNode.invisibleAnnotations = null; 194 | for (MethodNode methodNode: classNode.methods) { 195 | if (accMod) methodNode.access = makePublic(methodNode.access); 196 | if (!dump) methodNode.invisibleAnnotations = null; 197 | } 198 | for (FieldNode fieldNode: classNode.fields) { 199 | if (minecraft && accMod) fieldNode.access = makePublic(fieldNode.access); // Fix https://github.com/Fox2Code/FabricZero/issues/4 200 | if (!dump) fieldNode.invisibleAnnotations = null; 201 | } 202 | if (classNode.name.equals("net/minecraft/class_332")) { 203 | MethodNode drawCenteredText = null; 204 | for (MethodNode methodNode:classNode.methods) { 205 | if (methodNode.name.equals("method_27534")) { 206 | drawCenteredText = methodNode; 207 | break; 208 | } 209 | } 210 | if (drawCenteredText != null && (drawCenteredText.desc.equals(DCT_DESC_OLD) 211 | || drawCenteredText.desc.equals(DCT_DESC_NEW))) { 212 | String[] methods = new String[]{"method_27534", "method_27535"}; 213 | boolean modernize = drawCenteredText.desc.equals(DCT_DESC_OLD); 214 | for (String method : methods) { 215 | MethodNode methodNode = new MethodNode(ACC_PUBLIC | (modernize ? ACC_STATIC : 0), 216 | method, modernize ? DCT_DESC_NEW : DCT_DESC_OLD, null, null); 217 | int i = modernize ? 0 : 1; 218 | if (modernize) { 219 | methodNode.instructions.add(new FieldInsnNode(GETSTATIC, 220 | "com/fox2code/fabriczero/access/Helper", 221 | "drawableHelper", "Lnet/minecraft/class_332;")); 222 | } 223 | methodNode.instructions.add(new VarInsnNode(ALOAD, i++)); 224 | methodNode.instructions.add(new VarInsnNode(ALOAD, i++)); 225 | methodNode.instructions.add(new VarInsnNode(ALOAD, i++)); 226 | methodNode.instructions.add(new TypeInsnNode(CHECKCAST, 227 | modernize ? "net/minecraft/class_2561" : "net/minecraft/class_5348")); 228 | methodNode.instructions.add(new VarInsnNode(ILOAD, i++)); 229 | methodNode.instructions.add(new VarInsnNode(ILOAD, i++)); 230 | methodNode.instructions.add(new VarInsnNode(ILOAD, i)); 231 | methodNode.instructions.add(new MethodInsnNode(modernize ? INVOKEVIRTUAL : INVOKESTATIC, 232 | "net/minecraft/class_332", method, modernize ? DCT_DESC_OLD : DCT_DESC_NEW, false)); 233 | methodNode.instructions.add(new InsnNode(RETURN)); 234 | classNode.methods.add(methodNode); 235 | } 236 | } 237 | classNode.access |= FLAG_DIRTY; 238 | } 239 | BytecodeOptimizer.optimize(classNode); 240 | boolean dirty = (classNode.access & FLAG_DIRTY) != 0; 241 | if (dirty) classNode.access &=~ FLAG_DIRTY; 242 | return dirty; 243 | } 244 | 245 | @Override 246 | public void addTransformer(FabricZeroTransformer transformer) { 247 | transformers.add(transformer); 248 | } 249 | 250 | @Override 251 | public boolean isDev() { 252 | return DEV; 253 | } 254 | 255 | @Override 256 | public EnvType getEnvType() { 257 | return ENV_TYPE; 258 | } 259 | 260 | @SuppressWarnings("deprecation") 261 | @Override 262 | public File getFabricZeroConfigFile() { 263 | if (configFile == null) { 264 | if (BytecodeOptimizer.redirectGetConfigDir) { 265 | configFile = new File(FabricLoader.getInstance() 266 | .getConfigDirectory(), "fabriczero.cfg"); 267 | } else { 268 | configFile = FabricLoader.getInstance().getConfigDir() 269 | .resolve("fabriczero.cfg").toFile(); 270 | } 271 | } 272 | return configFile; 273 | } 274 | 275 | @Override 276 | public boolean isClassDumpingEnabled() { 277 | if (dumpClasses == null) { 278 | dumpClasses = FabricZeroConfig.dumpClasses; 279 | } 280 | return dumpClasses; 281 | } 282 | 283 | @Override 284 | public boolean isAccessModDisabled() { 285 | if (disableAccessMod == null) { 286 | disableAccessMod = FabricZeroConfig.disableAccessMod; 287 | } 288 | return disableAccessMod; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/impl/ModHideMap.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.impl; 2 | 3 | import com.fox2code.fabriczero.api.FabricZeroAPI; 4 | import com.google.common.collect.ForwardingMap; 5 | import net.fabricmc.loader.ModContainer; 6 | 7 | import java.util.Map; 8 | 9 | public class ModHideMap extends ForwardingMap { 10 | private final Map delegate; 11 | private final FabricZeroAPI fabricZeroAPI; 12 | 13 | public ModHideMap(Map delegate) { 14 | this.delegate = delegate; 15 | this.fabricZeroAPI = FabricZeroAPI.getInstance(); 16 | } 17 | 18 | @Override 19 | protected Map delegate() { 20 | return delegate; 21 | } 22 | 23 | @Override 24 | public boolean containsKey(Object key) { 25 | boolean containKey = super.containsKey(key); 26 | if (containKey && fabricZeroAPI.hasHidingRules((String) key)) { 27 | StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 28 | String cls = stackTraceElements[3].getClassName(); 29 | containKey = !fabricZeroAPI.isHidden((String) key, cls); 30 | } 31 | return containKey; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mixins/DefaultResourcePackMixin.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mixins; 2 | 3 | import com.fox2code.fabriczero.access.MCResources; 4 | import net.minecraft.resource.DefaultResourcePack; 5 | import org.jetbrains.annotations.Nullable; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Pseudo; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 11 | 12 | import java.io.ByteArrayInputStream; 13 | import java.io.InputStream; 14 | 15 | @Pseudo 16 | @Mixin(DefaultResourcePack.class) 17 | public class DefaultResourcePackMixin { 18 | 19 | @Inject(at = @At(value = "HEAD"),method = "getInputStream", cancellable = true) 20 | public void getInputStreamHook(String path, CallbackInfoReturnable<@Nullable InputStream> cir) { 21 | if (MCResources.successful) { 22 | if (path.equals("pack.mcmeta")) { 23 | cir.setReturnValue(new ByteArrayInputStream(MCResources.pack_mcmeta)); 24 | } else if (path.equals("pack.png")) { 25 | cir.setReturnValue(new ByteArrayInputStream(MCResources.pack_png)); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mixins/ModUpdaterScreenMixin_ModUpdater.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mixins; 2 | 3 | import com.fox2code.fabriczero.access.modupdater.UpdateAllButton; 4 | import com.thebrokenrail.modupdater.client.gui.ModUpdateScreen; 5 | import net.minecraft.client.gui.screen.Screen; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Pseudo; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Pseudo 13 | @Mixin(ModUpdateScreen.class) 14 | public abstract class ModUpdaterScreenMixin_ModUpdater extends Screen { 15 | protected ModUpdaterScreenMixin_ModUpdater() { 16 | super(null); 17 | } 18 | 19 | @Inject(at = @At(value = "RETURN"),method = "init") 20 | public void initHook(CallbackInfo ci) { 21 | this.addButton(new UpdateAllButton(this)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mixins/ResourcePackProfileMixin.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mixins; 2 | 3 | import net.minecraft.resource.ResourcePackCompatibility; 4 | import net.minecraft.resource.ResourcePackProfile; 5 | import net.minecraft.resource.ResourcePackSource; 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Pseudo; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | @Pseudo 15 | @Mixin(ResourcePackProfile.class) 16 | public class ResourcePackProfileMixin { 17 | @Shadow 18 | @Final 19 | private ResourcePackSource source; 20 | 21 | @Inject(at = @At(value = "HEAD"),method = "getCompatibility", cancellable = true) 22 | public void getCompatibilityHook(CallbackInfoReturnable cir) { 23 | if (this.source == ResourcePackSource.PACK_SOURCE_BUILTIN) { 24 | cir.setReturnValue(ResourcePackCompatibility.COMPATIBLE); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mod/FabricZero.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mod; 2 | 3 | import com.fox2code.fabriczero.FabricZeroPlugin; 4 | import net.fabricmc.api.ModInitializer; 5 | import net.fabricmc.loader.api.FabricLoader; 6 | import org.apache.logging.log4j.LogManager; 7 | import org.apache.logging.log4j.Logger; 8 | 9 | public class FabricZero implements ModInitializer { 10 | public static final Logger LOGGER = LogManager.getLogger("FabricZero"); 11 | 12 | static { 13 | FabricZeroPlugin.ensureInit(); 14 | } 15 | 16 | @Override 17 | public void onInitialize() { 18 | if (FabricLoader.getInstance().isDevelopmentEnvironment()) { 19 | LOGGER.warn("Do not use this mod in your dev environment if you mod doesn't depends on it!"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mod/FabricZeroClient.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mod; 2 | 3 | import com.fox2code.fabriczero.access.MCResources; 4 | import net.fabricmc.api.ClientModInitializer; 5 | import net.fabricmc.api.EnvType; 6 | import net.fabricmc.api.Environment; 7 | import net.fabricmc.loader.launch.common.FabricLauncher; 8 | import net.fabricmc.loader.launch.common.FabricLauncherBase; 9 | import net.minecraft.client.MinecraftClient; 10 | 11 | import java.io.IOException; 12 | import java.util.Enumeration; 13 | import java.util.zip.ZipEntry; 14 | import java.util.zip.ZipFile; 15 | 16 | @Environment(EnvType.CLIENT) 17 | public class FabricZeroClient implements ClientModInitializer { 18 | @Override 19 | public void onInitializeClient() { 20 | Thread.currentThread().setPriority(8); // Focus on FPS if client 21 | MinecraftClient.getInstance().send(System::gc); // Optimize Memory usage 22 | Thread asyncLoader = new Thread("Async Class PreLoader") { 23 | @Override 24 | public void run() { 25 | FabricZero.LOGGER.info("Preloading classes..."); 26 | try { 27 | Thread.sleep(1000); 28 | } catch (InterruptedException ignored) {} 29 | if (this.isInterrupted()) return; 30 | FabricLauncher fabricLauncher = FabricLauncherBase.getLauncher(); 31 | ClassLoader classLoader = fabricLauncher.getTargetClassLoader(); 32 | try (ZipFile zipFile = new ZipFile(FabricLauncherBase.minecraftJar.toFile())) { 33 | Enumeration enumeration = zipFile.entries(); 34 | int count = 0; 35 | while (enumeration.hasMoreElements()) { 36 | if (this.isInterrupted()) return; 37 | String name = enumeration.nextElement().getName(); 38 | if (name.endsWith(".class")) { 39 | name = name.substring(0, name.length()-6).replace('/', '.'); 40 | try { 41 | Class.forName(name, false, classLoader); 42 | count++; 43 | } catch (ClassNotFoundException ignored) {} 44 | } 45 | } 46 | FabricZero.LOGGER.info("Preloaded "+count+" classes!"); 47 | } catch (IOException ioe) { 48 | FabricZero.LOGGER.error("Error during class preload!", ioe); 49 | } 50 | } 51 | }; 52 | asyncLoader.setDaemon(true); 53 | asyncLoader.start(); 54 | if (!MCResources.successful) { 55 | FabricZero.LOGGER.warn("Failed to setup vanilla metadata protector!"); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mod/FabricZeroModMenu.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mod; 2 | 3 | import io.github.prospector.modmenu.api.ModMenuApi; 4 | 5 | public class FabricZeroModMenu implements ModMenuApi { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mod/FabricZeroModUpdater.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mod; 2 | 3 | import com.thebrokenrail.modupdater.api.entrypoint.ModUpdaterEntryPoint; 4 | 5 | public class FabricZeroModUpdater implements ModUpdaterEntryPoint { 6 | @Override 7 | public boolean isVersionCompatible(String s) { 8 | return true; // We are Compatible with everything 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/mod/GuiConfig.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.mod; 2 | 3 | import net.minecraft.client.gui.screen.Screen; 4 | import net.minecraft.text.LiteralText; 5 | 6 | public class GuiConfig extends Screen { 7 | protected GuiConfig() { 8 | super(new LiteralText("FabricZero - Config")); 9 | } 10 | 11 | @Override 12 | protected void init() { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/reflectutils/AutoFixer.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.reflectutils; 2 | 3 | import com.fox2code.fabriczero.FabricZeroPlugin; 4 | 5 | import java.lang.management.ManagementFactory; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * This class need to work without using ANY FabricZero classes 11 | * (Also note if FabricZero execute this class this probably mean 12 | * that you can't do setAccessible(true) in this VM) 13 | */ 14 | final class AutoFixer { 15 | private static final boolean VERIFY_NONE = 16 | ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-Xverify:none"); 17 | 18 | static void plzFixme() { 19 | if (VERIFY_NONE) { 20 | System.out.println("Your JVM is not compatible with FabricZero!"); 21 | System.exit(-3); 22 | } 23 | try { 24 | Class.forName("org.multimc.onesix.OneSixLauncher", false, AutoFixer.class.getClassLoader()); 25 | // We are not compatible with MultiMC but lets help the user anyway 26 | FabricZeroPlugin.LOGGER.error("AutoFixer is not compatible with MultiMC at the moment!"); 27 | FabricZeroPlugin.LOGGER.info("Here how to fix FabricZero manually on MultiMC"); 28 | FabricZeroPlugin.LOGGER.info("Open your launcher -> Settings -> Java"); 29 | FabricZeroPlugin.LOGGER.info("And add \"--add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED --add-opens java.base/jdk.internal.vm.annotation=ALL-UNNAMED\""); 30 | FabricZeroPlugin.LOGGER.info("into the JVM arguments"); 31 | System.exit(-1); 32 | } catch (Exception ignored) {} 33 | FabricZeroPlugin.LOGGER.warn("The current environment doesn't allow FabricZero to launch correctly!"); 34 | FabricZeroPlugin.LOGGER.warn("Restarting the game with a compatible environment!"); 35 | FabricZeroPlugin.LOGGER.warn("To avoid this use an older JVM or add \"-Xverify:none\" as JVM args."); 36 | 37 | ArrayList args = new ArrayList<>(); 38 | try { 39 | args.addAll(Arrays.asList(AutoFixer9.getCommandLine().trim().split("\\s+"))); 40 | int i = args.indexOf("-classpath"); 41 | if (i == -1) { 42 | i = args.indexOf("-cp"); 43 | } 44 | args.addAll(i, Arrays.asList( 45 | "--add-opens", "java.base/java.lang=ALL-UNNAMED", 46 | "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", 47 | "--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED", 48 | "--add-opens", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED")); 49 | } catch (Throwable t) { 50 | FabricZeroPlugin.LOGGER.error("AutoFixer couldn't do it's job!", t); 51 | System.exit(-2); 52 | } 53 | Runtime.getRuntime().addShutdownHook(new Thread("Child Executor") { 54 | @Override 55 | public void run() { 56 | try { 57 | int exitCode; 58 | System.out.println("Game exit code: "+ 59 | (exitCode = new ProcessBuilder(args).inheritIO().start().waitFor())); 60 | if (exitCode != 0) { // In this VM we can't do System.halt() because no reflection 3: 61 | System.exit(exitCode); 62 | } 63 | } catch (Exception ioe) { 64 | ioe.printStackTrace(); 65 | } 66 | } 67 | }); 68 | System.exit(0); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/reflectutils/AutoFixer9.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.reflectutils; 2 | 3 | import java.util.Objects; 4 | import java.util.Optional; 5 | 6 | public class AutoFixer9 { 7 | @SuppressWarnings("unchecked") 8 | public static String getCommandLine() throws ReflectiveOperationException { 9 | final Class ProcessHandle = Class.forName("java.lang.ProcessHandle"); 10 | final Class ProcessHandle$Info = Class.forName("java.lang.ProcessHandle$Info"); 11 | return ((Optional)ProcessHandle$Info.getDeclaredMethod("commandLine").invoke( 12 | ProcessHandle.getDeclaredMethod("info").invoke( 13 | Objects.requireNonNull(ProcessHandle.getDeclaredMethod("current").invoke(null))) 14 | )).orElseThrow(NullPointerException::new); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/reflectutils/Java9Fix.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.reflectutils; 2 | 3 | import io.github.karlatemp.unsafeaccessor.Root; 4 | import io.github.karlatemp.unsafeaccessor.Unsafe; 5 | import net.gudenau.minecraft.asm.impl.ReflectionHelper; 6 | 7 | import java.lang.invoke.MethodHandle; 8 | import java.lang.reflect.AccessibleObject; 9 | import java.lang.reflect.Field; 10 | import java.lang.reflect.Method; 11 | import java.util.Map; 12 | 13 | final class Java9Fix { 14 | private static final boolean java8 = System.getProperty("java.version").startsWith("1."); 15 | private static final boolean gudASM = false; 16 | private static final Object unsafe; 17 | private static final Method fieldOffset, fieldOffset2; 18 | private static final Method staticFieldBase; 19 | private static final Method allocateInstance; 20 | private static final Method fieldPutBool; 21 | private static final Method fieldPutInt; 22 | private static Method fieldGetObject; 23 | private static final Method fieldPutObject; 24 | private static Method getModule; 25 | private static long moduleDescOffset; 26 | private static long moduleDescOpenOffset; 27 | static boolean internalUnsafe; 28 | static boolean libUnsafe; 29 | static boolean fallBackMode; 30 | 31 | private static MethodHandle accessSetter; 32 | private static Field access; 33 | private static long accessOffset; 34 | 35 | static { 36 | if (gudASM) { 37 | try { 38 | accessSetter = ReflectionHelper.findSetter(AccessibleObject.class, "override", boolean.class); 39 | } catch (Throwable ignored) {} 40 | } 41 | try { // Try this once to see if we can do it sooner 42 | Class cl = Class.forName("jdk.internal.reflect.Reflection"); 43 | Field field = getFieldBypass(cl, "fieldFilterMap"); 44 | setAccessibleHelper(field); 45 | if (field != null) { 46 | ((Map) field.get(null)).clear(); 47 | } 48 | } catch (Throwable ignored) {} 49 | Class unsafeClass; 50 | try { 51 | try { 52 | unsafeClass = Class.forName("jdk.internal.misc.Unsafe"); 53 | internalUnsafe = true; 54 | } catch (ClassNotFoundException e) { 55 | unsafeClass = Class.forName("sun.misc.Unsafe"); 56 | } 57 | Field field = unsafeClass.getDeclaredField("theUnsafe"); 58 | Object _unsafe = null; 59 | try { 60 | try { 61 | setAccessibleHelper(field); 62 | } catch (Exception e) { 63 | try { 64 | access = AccessibleObject.class.getDeclaredField("override"); 65 | } catch (Exception e1) { 66 | access = getFieldBypass(AccessibleObject.class, "override"); 67 | } 68 | setAccessibleHelper(access); 69 | access.setBoolean(field, true); 70 | } 71 | } catch (Exception e) { 72 | try { // Avoid AutoFixer if possible 73 | _unsafe = Unsafe.getUnsafe(); 74 | unsafeClass = Unsafe.class; 75 | internalUnsafe = false; 76 | libUnsafe = true; 77 | } catch (Throwable t) { 78 | AutoFixer.plzFixme(); 79 | } 80 | } 81 | if (_unsafe == null) { 82 | _unsafe = field.get(null); 83 | } 84 | unsafe = _unsafe; 85 | fieldOffset = unsafeClass.getDeclaredMethod("objectFieldOffset", Field.class); 86 | fieldOffset2 = unsafeClass.getDeclaredMethod("staticFieldOffset", Field.class); 87 | staticFieldBase = unsafeClass.getDeclaredMethod("staticFieldBase", Field.class); 88 | allocateInstance = unsafeClass.getDeclaredMethod("allocateInstance", Class.class); 89 | fieldPutBool = unsafeClass.getDeclaredMethod("putBoolean", Object.class, long.class, boolean.class); 90 | fieldPutInt = unsafeClass.getDeclaredMethod("putInt", Object.class, long.class, int.class); 91 | fieldPutObject = unsafeClass.getDeclaredMethod("putObject", Object.class, long.class, Object.class); 92 | try { 93 | setAccessibleHelper(fieldOffset); 94 | setAccessibleHelper(fieldOffset2); 95 | setAccessibleHelper(staticFieldBase); 96 | setAccessibleHelper(allocateInstance); 97 | setAccessibleHelper(fieldPutBool); 98 | setAccessibleHelper(fieldPutInt); 99 | setAccessibleHelper(fieldPutObject); 100 | } catch (ReflectiveOperationException reflectiveOperationException) { 101 | AutoFixer.plzFixme(); 102 | } 103 | if (access != null && !access.isAccessible()) { 104 | setAccessibleHelper(access); 105 | } 106 | } catch (ReflectiveOperationException e) { 107 | throw new Error("Your JVM May be incompatible with FabricZero", e); 108 | } 109 | if (!java8) /* try */ { 110 | try { 111 | Class cl = Class.forName("jdk.internal.reflect.Reflection"); 112 | Field field = getFieldBypass(cl, "fieldFilterMap"); 113 | setAccessibleHelper(field); 114 | if (field != null) { 115 | ((Map) field.get(null)).clear(); 116 | } 117 | } catch (Exception e) { 118 | System.out.println("[Java9Fix]: Unable to disable reflections blocker"); 119 | } 120 | try { 121 | //Disable Java9+ Reflection Warnings 122 | Method putObjectVolatile = unsafeClass.getDeclaredMethod("putObjectVolatile", Object.class, long.class, Object.class); 123 | setAccessible(putObjectVolatile); 124 | Class loggerClass = Class.forName("jdk.internal.module.IllegalAccessLogger"); 125 | Field loggerField = loggerClass.getDeclaredField("logger"); 126 | Long offset = (Long) fieldOffset2.invoke(unsafe, loggerField); 127 | putObjectVolatile.invoke(unsafe, loggerClass, offset, null); 128 | } catch (ReflectiveOperationException ignored) { 129 | System.out.println("[Java9Fix]: Unable to disable invalid access logging"); 130 | } 131 | try { 132 | getModule = Class.class.getDeclaredMethod("getModule"); 133 | Class module = Class.forName("java.lang.Module"); 134 | moduleDescOffset = (Long) fieldOffset.invoke(unsafe, module.getDeclaredField("descriptor")); 135 | Class desc = Class.forName("java.lang.module.ModuleDescriptor"); 136 | moduleDescOpenOffset = (Long) fieldOffset.invoke(unsafe, desc.getDeclaredField("open")); 137 | fieldGetObject = unsafeClass.getDeclaredMethod("getObject", Object.class, long.class); 138 | openModule(Class.class); 139 | openModule(unsafeClass); 140 | } catch (ReflectiveOperationException ignored) { 141 | System.out.println("[Java9Fix]: Unable to disable reflections checks"); 142 | } 143 | } 144 | if (fallBackMode) try { 145 | fallBackMode = false; 146 | access = null; 147 | setAccessible(fieldOffset); 148 | } catch (Throwable ignored) {} 149 | } 150 | 151 | @SuppressWarnings("JavaReflectionMemberAccess") 152 | private static Field getFieldBypass(Class cls, String fieldName) throws ReflectiveOperationException { 153 | Field[] fields; 154 | try { 155 | Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class); 156 | setAccessibleHelper(getDeclaredFields0); 157 | fields = (Field[]) getDeclaredFields0.invoke(cls, false); 158 | } catch (NoSuchMethodException e) { 159 | Method getDeclaredFieldsImpl = Class.class.getDeclaredMethod("getDeclaredFieldsImpl"); 160 | setAccessibleHelper(getDeclaredFieldsImpl); 161 | fields = (Field[]) getDeclaredFieldsImpl.invoke(cls); 162 | } 163 | for (Field field:fields) { 164 | if (field.getName().equals(fieldName)) { 165 | return field; 166 | } 167 | } 168 | return null; 169 | } 170 | 171 | private static void setAccessibleHelper(AccessibleObject field) throws ReflectiveOperationException { 172 | if (access != null && access.isAccessible()) { 173 | try { 174 | access.setBoolean(field, true); 175 | } catch (Throwable ignored) {} 176 | if (field.isAccessible()) { 177 | return; 178 | } 179 | } 180 | if (accessSetter != null) { 181 | try { 182 | accessSetter.invoke(field, true); 183 | } catch (Throwable ignored) {} 184 | if (field.isAccessible()) { 185 | return; 186 | } 187 | } 188 | try { 189 | field.setAccessible(true); 190 | } catch (Exception e) { 191 | Root.setAccessible(field, true); 192 | } 193 | } 194 | 195 | public static void setAccessible(AccessibleObject field) throws ReflectiveOperationException { 196 | if (fallBackMode) { 197 | setAccessibleHelper(field); 198 | return; 199 | } 200 | if (access == null) try { 201 | access = AccessibleObject.class.getDeclaredField("override"); 202 | accessOffset = (Long) fieldOffset.invoke(unsafe, access); 203 | fieldPutBool.invoke(unsafe, access, accessOffset, true); 204 | } catch (Exception e) { 205 | fallBackMode = true; 206 | setAccessibleHelper(field); 207 | return; 208 | } 209 | if (fieldPutBool != null) { 210 | fieldPutBool.invoke(unsafe, field, accessOffset, true); 211 | } else { 212 | field.setAccessible(true); 213 | } 214 | } 215 | 216 | public static void setBoolean(Object obj, Field field, boolean value) throws ReflectiveOperationException { 217 | fieldPutBool.invoke(unsafe, obj == null ? staticFieldBase.invoke(unsafe, field) : obj, 218 | (Long) (obj == null ? fieldOffset2 : fieldOffset).invoke(unsafe, field), value); 219 | } 220 | 221 | public static void setInt(Object obj, Field field, int value) throws ReflectiveOperationException { 222 | fieldPutInt.invoke(unsafe, obj == null ? staticFieldBase.invoke(unsafe, field) : obj, 223 | (Long) (obj == null ? fieldOffset2 : fieldOffset).invoke(unsafe, field), value); 224 | } 225 | 226 | public static void setObject(Object obj, Field field, Object value) throws ReflectiveOperationException { 227 | fieldPutObject.invoke(unsafe, obj == null ? staticFieldBase.invoke(unsafe, field) : obj, 228 | (Long) (obj == null ? fieldOffset2 : fieldOffset).invoke(unsafe, field), value); 229 | } 230 | 231 | @SuppressWarnings("unchecked") 232 | public static T allocateInstance(Class cls) throws ReflectiveOperationException { 233 | return (T) allocateInstance.invoke(unsafe, cls); 234 | } 235 | 236 | public static void openModule(Class cl) throws ReflectiveOperationException { 237 | if (!java8 && fieldGetObject != null) { 238 | Object tmp = getModule.invoke(cl); 239 | if (tmp != null) { 240 | tmp = fieldGetObject.invoke(unsafe, tmp, moduleDescOffset); 241 | fieldPutBool.invoke(unsafe, tmp, moduleDescOpenOffset, true); 242 | } 243 | } 244 | } 245 | 246 | static boolean isJava8() { 247 | return java8; 248 | } 249 | 250 | static boolean isJava9() { 251 | return !java8; 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/reflectutils/ReflectUtil.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.reflectutils; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonParser; 5 | import io.github.karlatemp.unsafeaccessor.Root; 6 | import net.fabricmc.loader.api.metadata.CustomValue; 7 | import net.fabricmc.loader.api.metadata.ModMetadata; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.lang.reflect.*; 11 | import java.util.Collections; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.function.Function; 15 | 16 | public class ReflectUtil { 17 | private static final JsonParser jsonParser = new JsonParser(); 18 | private static Field enumConstantDirectory; 19 | private static final boolean ModMetadata_getCustomValues; 20 | private static Class modMetadataV1 = null; 21 | private static Class modMetadataV1$CustomValueContainer = null; 22 | 23 | static { 24 | try { 25 | enumConstantDirectory = Class.class.getDeclaredField("enumConstantDirectory"); 26 | Java9Fix.setAccessible(enumConstantDirectory); 27 | } catch (Throwable ignored) {} 28 | boolean tmp; 29 | try { 30 | ModMetadata.class.getDeclaredMethod("getCustomValues"); 31 | tmp = true; 32 | } catch (Exception e) { 33 | tmp = false; 34 | } 35 | try { 36 | modMetadataV1 = Class.forName("net.fabricmc.loader.metadata.ModMetadataV1"); 37 | } catch (ClassNotFoundException e) { 38 | try { 39 | modMetadataV1 = Class.forName("net.fabricmc.loader.metadata.V1ModMetadata"); 40 | } catch (ClassNotFoundException ignored) {} 41 | } 42 | if (modMetadataV1 != null) { 43 | try { 44 | modMetadataV1$CustomValueContainer = Class.forName(modMetadataV1.getName()+"$CustomValueContainer"); 45 | } catch (Exception ignored) {} 46 | } 47 | ModMetadata_getCustomValues = tmp; 48 | } 49 | 50 | @SuppressWarnings({"unchecked", "rawtypes"}) 51 | public static void copyEnumValue(Class> cl, String from, @Nullable String to) throws ReflectiveOperationException { 52 | Enum unify = Enum.valueOf((Class) cl, from); 53 | for (Field f:cl.getDeclaredFields()) { 54 | if (f.isEnumConstant() && f.getName().equals(to)) { 55 | Java9Fix.setObject(null, f, unify); 56 | } 57 | } 58 | if (enumConstantDirectory == null) return; 59 | Map> enumDirectory = (Map>) enumConstantDirectory.get(cl); 60 | if (enumDirectory != null) { 61 | enumDirectory.put(to, unify); 62 | } 63 | } 64 | 65 | public static void setAccessible(AccessibleObject accessibleObject) throws ReflectiveOperationException { 66 | if (accessibleObject == null) { 67 | throw new NullPointerException("accessibleObject == null"); 68 | } 69 | Java9Fix.setAccessible(accessibleObject); 70 | } 71 | 72 | public static Object forceGet(Object instance,Field field) throws ReflectiveOperationException { 73 | Java9Fix.setAccessible(field); 74 | return field.get(instance); 75 | } 76 | 77 | public static void forceSet(Object instance,Field field,Object value) throws ReflectiveOperationException { 78 | if (Modifier.isStatic(field.getModifiers()) != (instance == null)) { 79 | if (instance == null) { 80 | throw new IllegalAccessException("Can't set field on null instance!"); 81 | } else { 82 | instance = null; 83 | } 84 | } 85 | // Invalid call to this method cause crash of the VM so we better do some checks before calling it 86 | Java9Fix.setObject(instance == null ? null : 87 | field.getDeclaringClass().cast(instance), field, 88 | value == null ? null : field.getType().cast(value)); 89 | } 90 | 91 | public static void forceSet(Object instance,Field field,boolean value) throws ReflectiveOperationException { 92 | if (Modifier.isStatic(field.getModifiers()) != (instance == null)) { 93 | if (instance == null) { 94 | throw new IllegalAccessException("Can't set field on null instance!"); 95 | } else { 96 | instance = null; 97 | } 98 | } 99 | // Invalid call to this method cause crash of the VM so we better do some checks before calling it 100 | Java9Fix.setBoolean(instance == null ? null : 101 | field.getDeclaringClass().cast(instance), field, value); 102 | } 103 | 104 | public static void forceSet(Object instance,Field field,int value) throws ReflectiveOperationException { 105 | if (Modifier.isStatic(field.getModifiers()) != (instance == null)) { 106 | if (instance == null) { 107 | throw new IllegalAccessException("Can't set field on null instance!"); 108 | } else { 109 | instance = null; 110 | } 111 | } 112 | // Invalid call to this method cause crash of the VM so we better do some checks before calling it 113 | Java9Fix.setInt(instance == null ? null : 114 | field.getDeclaringClass().cast(instance), field, value); 115 | } 116 | 117 | @SuppressWarnings("unchecked") 118 | public static void forceReplace(Object instance, Field field, Function value) throws ReflectiveOperationException { 119 | forceSet(instance, field, value.apply((T) forceGet(instance, field))); 120 | } 121 | 122 | @SuppressWarnings("unchecked") 123 | public static Map getModifiable(Map map) { 124 | if (map.getClass().getName().endsWith("UnmodifiableMap")) { 125 | try { 126 | return (Map) forceGet(map, getFirstOfType(map.getClass().getDeclaredFields(), Map.class)); 127 | } catch (ReflectiveOperationException ignored) {} 128 | } 129 | return map; 130 | } 131 | 132 | private static Method CustomValueImpl_fromJsonElement = null; 133 | 134 | public static CustomValue cvFromJson(JsonElement jsonElement) { 135 | try { 136 | if (CustomValueImpl_fromJsonElement == null) { 137 | CustomValueImpl_fromJsonElement = Class.forName("net.fabricmc.loader.metadata.CustomValueImpl") 138 | .getDeclaredMethod("fromJsonElement", JsonElement.class); 139 | Java9Fix.setAccessible(CustomValueImpl_fromJsonElement); 140 | } 141 | return (CustomValue) CustomValueImpl_fromJsonElement.invoke(null, jsonElement); 142 | } catch (Exception e) { 143 | return null; 144 | } 145 | } 146 | 147 | public static CustomValue cvFromJson(String json) { 148 | return cvFromJson(jsonParser.parse(json)); 149 | } 150 | 151 | private static Field ModMetadataV1_custom = null; 152 | private static Field CustomValueContainer_customValues = null; 153 | private static Field ModMetadataV1_customValues = null; 154 | 155 | @SuppressWarnings("unchecked") 156 | public static void injectCustomValue(ModMetadata modMetadata, String key, String value) { 157 | if (ModMetadata_getCustomValues) { 158 | Map map = modMetadata.getCustomValues(); 159 | if (map == Collections.EMPTY_MAP) { 160 | try { 161 | if (ModMetadataV1_custom == null) { 162 | ModMetadataV1_custom = modMetadataV1.getDeclaredField("custom"); 163 | Java9Fix.setAccessible(ModMetadataV1_custom); 164 | } 165 | if (CustomValueContainer_customValues == null) { 166 | CustomValueContainer_customValues = 167 | modMetadataV1$CustomValueContainer.getDeclaredField("customValues"); 168 | Java9Fix.setAccessible(CustomValueContainer_customValues); 169 | } 170 | forceSet(forceGet(modMetadata, ModMetadataV1_custom), 171 | CustomValueContainer_customValues, Collections.unmodifiableMap(map = new HashMap<>())); 172 | } catch (ReflectiveOperationException ignored) { 173 | return; 174 | } 175 | } else { 176 | map = ReflectUtil.getModifiable(map); 177 | } 178 | map.put(key, ReflectUtil.cvFromJson(value)); 179 | } else try { 180 | if (ModMetadataV1_custom == null) { 181 | ModMetadataV1_custom = modMetadataV1.getDeclaredField("custom"); 182 | Java9Fix.setAccessible(ModMetadataV1_custom); 183 | } 184 | ((Map)ModMetadataV1_custom.get(modMetadata)) 185 | .put(key, jsonParser.parse(value)); 186 | } catch (ReflectiveOperationException ignored) {} 187 | } 188 | 189 | public static T allocateInstance(Class cls) throws ReflectiveOperationException { 190 | if (cls == null) { 191 | throw new NullPointerException("cls must not be null!"); 192 | } 193 | if (cls.isInterface()) { 194 | throw new IllegalArgumentException("Can't allocate interface instance!"); 195 | } 196 | try { 197 | return Java9Fix.allocateInstance(cls); 198 | } catch (ReflectiveOperationException e) { 199 | return Root.allocate(cls); 200 | } 201 | } 202 | 203 | public static boolean isInternalUnsafe() { 204 | return Java9Fix.internalUnsafe; 205 | } 206 | 207 | public static boolean isLibUnsafe() { 208 | return Java9Fix.internalUnsafe; 209 | } 210 | 211 | public static Field getFirstOfType(Field[] fields,Class type) { 212 | for (Field field:fields) { 213 | if (type.isAssignableFrom(field.getType())) { 214 | return field; 215 | } 216 | } 217 | return null; 218 | } 219 | 220 | /* private static Constructor ctx; 221 | private static final MethodType lambda = MethodType.methodType(Runnable.class, String[].class); 222 | private static final MethodType main = MethodType.methodType(void.class, String[].class); 223 | private static final MethodType ret = MethodType.methodType(void.class); 224 | 225 | public static Thread asEntryPoint(Class cls,String[] args) throws ReflectiveOperationException { 226 | if (cls == null) { 227 | throw new NullPointerException("Can't create an entry point on a null class!"); 228 | } 229 | if (ctx == null) { 230 | ctx = MethodHandles.Lookup.class. 231 | getDeclaredConstructor(Class.class,int.class); 232 | Java9Fix.setAccessible(ctx); 233 | } 234 | MethodHandles.Lookup lookup = ctx.newInstance(cls, -1); 235 | try { 236 | return new Thread((Runnable) LambdaMetafactory.metafactory( 237 | lookup, "run", lambda, ret, 238 | lookup.findStatic(cls, "main", main), ret) 239 | .getTarget().invokeWithArguments((Object) args)); 240 | }catch (ReflectiveOperationException e) { 241 | throw e; 242 | } catch (Throwable t) { 243 | t.printStackTrace(); 244 | return null; 245 | } 246 | } */ 247 | } 248 | -------------------------------------------------------------------------------- /src/main/java/com/fox2code/fabriczero/reflectutils/ReflectedClass.java: -------------------------------------------------------------------------------- 1 | package com.fox2code.fabriczero.reflectutils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | import java.lang.reflect.Constructor; 8 | import java.lang.reflect.Executable; 9 | import java.lang.reflect.Field; 10 | import java.lang.reflect.Method; 11 | import java.lang.reflect.Modifier; 12 | import java.lang.reflect.Parameter; 13 | import java.util.Arrays; 14 | import java.util.Iterator; 15 | import java.util.Objects; 16 | import java.util.function.Predicate; 17 | 18 | /** 19 | * Easier way to do reflection in java 20 | */ 21 | @SuppressWarnings("UnusedReturnValue") 22 | public final class ReflectedClass implements Iterable, Closeable { 23 | private static Field modifiersField; 24 | 25 | static { 26 | try { 27 | modifiersField = Field.class.getDeclaredField("modifiers"); 28 | Java9Fix.setAccessible(modifiersField); 29 | } catch (ReflectiveOperationException ignored) {} 30 | } 31 | 32 | public static final ReflectedClass NULL = new ReflectedClass(null); 33 | 34 | public static ReflectedClass of(Object object) { 35 | if (object == null) { 36 | return NULL; 37 | } else if (object instanceof ReflectedClass) { 38 | return (ReflectedClass) object; 39 | } else { 40 | return new ReflectedClass(object); 41 | } 42 | } 43 | 44 | public static ReflectedClass forName(String name) throws ClassNotFoundException { 45 | return new ReflectedClass(Class.forName(name)); 46 | } 47 | 48 | public static ReflectedClass forName(Class ctx, String name) throws ClassNotFoundException { 49 | if (ctx == null) { 50 | return forName(name); 51 | } 52 | return new ReflectedClass(Class.forName(name.indexOf('.') == -1 ? 53 | ctx.getPackage().getName()+"."+name : name, false, ctx.getClassLoader())); 54 | } 55 | 56 | public static ReflectedClass $(Class ctx, String exec) throws ReflectiveOperationException { 57 | int p = exec.indexOf('('); 58 | if (p == -1) { 59 | p = exec.lastIndexOf('#'); 60 | ReflectedClass current; 61 | if (p == 0) { 62 | current = of(ctx); 63 | } else { 64 | current = forName(ctx, exec.substring(0, p)); 65 | } 66 | return current.get(exec.substring(p+1)); 67 | } else { 68 | String sub = exec.substring(0, p); 69 | p = sub.lastIndexOf('.'); 70 | ReflectedClass current; 71 | if (p == 0) { 72 | current = of(ctx); 73 | } else { 74 | current = forName(ctx, sub.substring(0, p)); 75 | } 76 | return current.run(sub.substring(p+1)); 77 | } 78 | } 79 | 80 | private final Object object; 81 | 82 | private ReflectedClass(Object object) { 83 | this.object = object; 84 | } 85 | 86 | public Object getObject() { 87 | return this.isClass() ? null : this.object; 88 | } 89 | 90 | public Object getHandle() { 91 | return this.object; 92 | } 93 | 94 | @SuppressWarnings("unchecked") 95 | public T $() { 96 | return (T) this.object; 97 | } // For shorter code 98 | 99 | public ReflectedClass get(String name) throws ReflectiveOperationException { 100 | return ReflectedClass.of(get0(name)); 101 | } 102 | 103 | public ReflectedClass get(String name1, String name2) throws ReflectiveOperationException { 104 | return ReflectedClass.of(get0(name1, name2)); 105 | } 106 | 107 | public Object get0(String name) throws ReflectiveOperationException { 108 | return findField(name).get(this.getObject()); 109 | } 110 | 111 | public Object get0(String name1, String name2) throws ReflectiveOperationException { 112 | return findField2(name1, name2).get(this.getObject()); 113 | } 114 | 115 | public void set(String name, Object value) throws ReflectiveOperationException { 116 | set0(name, value instanceof ReflectedClass ? ((ReflectedClass)value).getHandle() : value); 117 | } 118 | 119 | public void set(String name1, String name2, Object value) throws ReflectiveOperationException { 120 | set0(name1, name2, value instanceof ReflectedClass ? ((ReflectedClass)value).getHandle() : value); 121 | } 122 | 123 | public void set0(String name, Object value) throws ReflectiveOperationException { 124 | Field field = findField(name); 125 | if (field.isEnumConstant()) { 126 | ReflectUtil.forceSet(this.object, field, value); 127 | return; 128 | //throw new IllegalAccessException("Can't modify enum constants!"); 129 | } 130 | if ((field.getModifiers() & Modifier.FINAL) != 0) { 131 | modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 132 | } 133 | field.set(this.getObject(), value); 134 | } 135 | 136 | public void set0(String name1, String name2, Object value) throws ReflectiveOperationException { 137 | Field field = findField2(name1, name2); 138 | if (field.isEnumConstant()) { 139 | ReflectUtil.forceSet(this.object, field, value); 140 | return; 141 | //throw new IllegalAccessException("Can't modify enum constants!"); 142 | } 143 | if ((field.getModifiers() & Modifier.FINAL) != 0) { 144 | modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 145 | } 146 | field.set(this.getObject(), value); 147 | } 148 | 149 | public ReflectedClass run(String name, Object... args) throws ReflectiveOperationException { 150 | for (int i = 0;i < args.length;i++) if (args[i] instanceof ReflectedClass) args[i] = ((ReflectedClass) args[i]).getObject(); 151 | return ReflectedClass.of(run0(name, args)); 152 | } 153 | 154 | public Object run0(String name, Object... args) throws ReflectiveOperationException { 155 | return runAccessible(findMethod(name, args), args); 156 | } 157 | 158 | 159 | public Class getObjClass() { 160 | return this.object == null ? null : this.object instanceof Class ? (Class) this.object : this.object.getClass(); 161 | } 162 | 163 | @SuppressWarnings("ConstantConditions") 164 | public String getClassName() { 165 | return this.object == null ? "null" : this.getObjClass().getName(); 166 | } 167 | 168 | public ReflectedClass newInstance(Object... args) throws ReflectiveOperationException { 169 | for (int i = 0;i < args.length;i++) if (args[i] instanceof ReflectedClass) args[i] = ((ReflectedClass) args[i]).getObject(); 170 | return ReflectedClass.of(newInstance0(args)); 171 | } 172 | 173 | public Object newInstance0(Object... args) throws ReflectiveOperationException { 174 | if (this.object instanceof Class) { 175 | if (args.length == 0) { 176 | return runAccessible(((Class) this.object).getDeclaredConstructor()); 177 | } else { 178 | return runAccessible(((Class) this.object).getDeclaredConstructors(), args); 179 | } 180 | } else throw new IllegalAccessException("Unable to create an instance on a non static context!"); 181 | } 182 | 183 | private Object runAccessible(Executable[] executables,Object... args) throws ReflectiveOperationException { 184 | System.out.println(Arrays.toString(executables)); 185 | System.out.println(Arrays.toString(args)); 186 | global: 187 | for (Executable executable : executables) if (executable.getParameterCount() == args.length) { 188 | Parameter[] parameters = executable.getParameters(); 189 | System.out.println(Arrays.toString(parameters)); 190 | for (int i = 0;i < args.length;i++) if (args[i] != null) { 191 | if (!generify(parameters[i].getType()).isAssignableFrom(args[i].getClass())) { 192 | System.out.println(parameters[i].getType() + " != " + args[i].getClass()); 193 | continue global; 194 | } 195 | } 196 | return runAccessible(executable, args); 197 | } 198 | throw new NoSuchMethodException("No compatible method found!"); 199 | } 200 | 201 | private Field findField(String name) throws ReflectiveOperationException { 202 | Class cl = this.getObjClass(); 203 | while (cl != Object.class && cl != null) { 204 | for (Field field:cl.getDeclaredFields()) if (field.getName().equals(name) && Modifier.isStatic(field.getModifiers()) == this.isClass()) { 205 | if (!field.isAccessible()) Java9Fix.setAccessible(field); 206 | return field; 207 | } 208 | cl = cl.getSuperclass(); 209 | } 210 | throw new NoSuchFieldException("No field found!"); 211 | } 212 | 213 | private Field findField2(String name1,String name2) throws ReflectiveOperationException { 214 | Class cl = this.getObjClass(); 215 | while (cl != Object.class && cl != null) { 216 | for (Field field:cl.getDeclaredFields()) if ((field.getName().equals(name1) || field.getName().equals(name2)) && Modifier.isStatic(field.getModifiers()) == this.isClass()) { 217 | if (!field.isAccessible()) Java9Fix.setAccessible(field); 218 | return field; 219 | } 220 | cl = cl.getSuperclass(); 221 | } 222 | throw new NoSuchFieldException("No field found!"); 223 | } 224 | 225 | private Method findMethod(String name,Object... args) throws ReflectiveOperationException { 226 | Class cl = this.getObjClass(); 227 | while (cl != Object.class && cl != null) { 228 | global: 229 | for (Method method : cl.getDeclaredMethods()) if (method.getParameterCount() == args.length && method.getName().equals(name)) { 230 | Parameter[] parameters = method.getParameters(); 231 | for (int i = 0; i < args.length; i++) 232 | if (args[i] != null) { 233 | if (!generify(parameters[i].getType()).isAssignableFrom(args[i].getClass())) 234 | continue global; 235 | } 236 | return method; 237 | } 238 | cl = cl.getSuperclass(); 239 | } 240 | throw new NoSuchMethodException("No compatible method found!"); 241 | } 242 | 243 | public Object runAccessible(Executable executable,Object... args) throws ReflectiveOperationException { 244 | if (!executable.isAccessible()) Java9Fix.setAccessible(executable); 245 | if (executable instanceof Constructor) { 246 | if (executable.getDeclaringClass().isEnum()) { 247 | return forceNewInstance((Constructor) executable, args); 248 | } 249 | return ((Constructor) executable).newInstance(args); 250 | } 251 | boolean isStatic; 252 | if ((isStatic = Modifier.isStatic(executable.getModifiers())) != this.isClass()) { 253 | if (isStatic) { 254 | throw new IllegalAccessException("Tried to run a static method on a non static context!"); 255 | } else { 256 | throw new IllegalAccessException("Tried to run a non static method on a static context!"); 257 | } 258 | } 259 | if (executable instanceof Method) { 260 | return ((Method) executable).invoke(this.getObject(),args); 261 | } 262 | throw new IllegalArgumentException("Invalid executable type! (Found: "+executable.getClass().getName()+")"); 263 | } 264 | 265 | private Object forceNewInstance(Constructor constructor,Object... args) throws ReflectiveOperationException { 266 | ReflectedClass reflectedConstruct = ReflectedClass.of(constructor); 267 | ReflectedClass ca = reflectedConstruct.get("constructorAccessor"); 268 | if (ca.isNull()) { 269 | reflectedConstruct.set("constructorAccessor", ca = reflectedConstruct.run("acquireConstructorAccessor")); 270 | } 271 | return ca.run0("newInstance", (Object) args); 272 | } 273 | 274 | public String asString() { 275 | if (this.object instanceof String) 276 | return (String) this.object; 277 | throw new ClassCastException("Unable to cast " + this.getClassName() + " to String"); 278 | } 279 | 280 | public int asInteger() { 281 | if (this.object instanceof Integer) 282 | return (Integer) this.object; 283 | throw new ClassCastException("Unable to cast " + this.getClassName() + " to Integer"); 284 | } 285 | 286 | public boolean asBoolean() { 287 | if (this.object instanceof Boolean) 288 | return (Boolean) this.object; 289 | throw new ClassCastException("Unable to cast " + this.getClassName() + " to Boolean"); 290 | } 291 | 292 | public Class asClass() { 293 | if (this.object instanceof Class) 294 | return (Class) this.object; 295 | throw new ClassCastException("Unable to cast " + this.getClassName() + " to Class"); 296 | } 297 | 298 | public boolean isClass() { 299 | return this.object instanceof Class; 300 | } 301 | 302 | public boolean isAbstract() { 303 | return this.object instanceof Class && (((Class) this.object).getModifiers() & Modifier.ABSTRACT) != 0; 304 | } 305 | 306 | public boolean isEnum() { 307 | return this.object instanceof Class && ((Class) this.object).isEnum(); 308 | } 309 | 310 | public boolean isNull() { 311 | return this.object == null; 312 | } 313 | 314 | private static Class generify(Class cl) { 315 | if (!cl.isPrimitive()) return cl; 316 | if (cl == byte.class) return Byte.class; 317 | if (cl == short.class) return Short.class; 318 | if (cl == int.class) return Integer.class; 319 | if (cl == long.class) return Long.class; 320 | if (cl == float.class) return Float.class; 321 | if (cl == double.class) return Double.class; 322 | if (cl == boolean.class) return Boolean.class; 323 | if (cl == char.class) return Character.class; 324 | if (cl == void.class) return Void.class; 325 | throw new IllegalArgumentException("Invalid Primitive type!"); 326 | } 327 | 328 | @Override 329 | public String toString() { 330 | return "ReflectedClass{"+ this.object + "}"; 331 | } 332 | 333 | @Override 334 | public boolean equals(Object o) { 335 | return o instanceof ReflectedClass && 336 | Objects.equals(this.object, ((ReflectedClass) o).object); 337 | } 338 | 339 | @Override 340 | public int hashCode() { 341 | return object.hashCode()^~0; 342 | } 343 | 344 | @NotNull 345 | @Override 346 | public Iterator iterator() { 347 | Object object = this.object; 348 | if (this.isClass()) { 349 | if (!this.isEnum()) { 350 | throw new ClassCastException("Can't iterate on static context"); 351 | } 352 | try { 353 | object = this.run0("values"); 354 | } catch (ReflectiveOperationException e) { 355 | throw new RuntimeException(e); 356 | } 357 | } 358 | if (object instanceof Object[]) { 359 | final Object[] array = (Object[]) object; 360 | return new Iterator() { 361 | int index = 0; 362 | 363 | @Override 364 | public boolean hasNext() { 365 | return !(index < array.length); 366 | } 367 | 368 | @Override 369 | public ReflectedClass next() { 370 | return ReflectedClass.of(array[index++]); 371 | } 372 | }; 373 | } 374 | if (!(object instanceof Iterable)) { 375 | throw new ClassCastException(this.getClassName()+" is not Iterable!"); 376 | } 377 | final Iterator iterator = ((Iterable) object).iterator(); 378 | return new Iterator() { 379 | @Override 380 | public boolean hasNext() { 381 | return iterator.hasNext(); 382 | } 383 | 384 | @Override 385 | public ReflectedClass next() { 386 | return ReflectedClass.of(iterator.next()); 387 | } 388 | 389 | @Override 390 | public void remove() { 391 | iterator.remove(); 392 | } 393 | }; 394 | } 395 | 396 | public void forEach$(ConsumerT action) throws T { 397 | Objects.requireNonNull(action); 398 | for (ReflectedClass t : this) { 399 | action.accept(t); 400 | } 401 | } 402 | 403 | public boolean removeIf(Predicate filter) { 404 | Objects.requireNonNull(filter); 405 | boolean removed = false; 406 | final Iterator each = iterator(); 407 | while (each.hasNext()) { 408 | if (filter.test(each.next())) { 409 | each.remove(); 410 | removed = true; 411 | } 412 | } 413 | return removed; 414 | } 415 | 416 | public boolean removeIf$(PredicateT filter) throws T { 417 | Objects.requireNonNull(filter); 418 | boolean removed = false; 419 | final Iterator each = iterator(); 420 | while (each.hasNext()) { 421 | if (filter.test(each.next())) { 422 | each.remove(); 423 | removed = true; 424 | } 425 | } 426 | return removed; 427 | } 428 | 429 | @Override 430 | public void close() throws IOException { 431 | if (this.object instanceof Closeable) { 432 | ((Closeable) this.object).close(); 433 | } 434 | } 435 | 436 | public interface ConsumerT { 437 | void accept(ReflectedClass t) throws T; 438 | } 439 | 440 | public interface PredicateT { 441 | boolean test(ReflectedClass t) throws T; 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /src/main/java/javax/xml/bind/DatatypeConverter.java: -------------------------------------------------------------------------------- 1 | package javax.xml.bind; 2 | 3 | import java.util.Base64; 4 | 5 | /** 6 | * Partial Implementation For Java9 support if {@code javax.xml.bind.DatatypeConverter} is missing 7 | */ 8 | @Deprecated 9 | @SuppressWarnings("DeprecatedIsStillUsed") 10 | public final class DatatypeConverter { 11 | @Deprecated 12 | public static int parseInt(String string) { 13 | return Integer.parseInt(string); 14 | } 15 | 16 | @Deprecated 17 | public static byte[] parseBase64Binary(String string) { 18 | return Base64.getDecoder().decode(string); 19 | } 20 | 21 | @Deprecated 22 | public static byte[] parseHexBinary(String string) { 23 | int len = string.length(); 24 | byte[] data = new byte[len / 2]; 25 | for (int i = 0; i < len; i += 2) { 26 | data[i / 2] = (byte) ((Character.digit(string.charAt(i), 16) << 4) 27 | + Character.digit(string.charAt(i+1), 16)); 28 | } 29 | return data; 30 | } 31 | 32 | @Deprecated 33 | public static String printInt(int i) { 34 | return Integer.toString(i); 35 | } 36 | 37 | @Deprecated 38 | public static String printBase64Binary(byte[] binary) { 39 | return Base64.getEncoder().encodeToString(binary); 40 | } 41 | 42 | @Deprecated 43 | public static String printHexBinary(byte[] binary) { 44 | StringBuilder result = new StringBuilder(binary.length * 2); 45 | for (byte bb : binary) { 46 | result.append(String.format("%02X", bb)); 47 | } 48 | return result.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/javax/xml/bind/annotation/adapters/HexBinaryAdapter.java: -------------------------------------------------------------------------------- 1 | package javax.xml.bind.annotation.adapters; 2 | 3 | import javax.xml.bind.DatatypeConverter; 4 | 5 | /** 6 | * Partial Implementation For Java9 support if 7 | * {@code javax.xml.bind.annotation.adapters.HexBinaryAdapter} is missing 8 | */ 9 | @Deprecated 10 | public class HexBinaryAdapter extends XmlAdapter { 11 | @Override 12 | @Deprecated 13 | public String unmarshal(byte[] v) throws Exception { 14 | return DatatypeConverter.printHexBinary(v); 15 | } 16 | 17 | @Override 18 | @Deprecated 19 | public byte[] marshal(String v) throws Exception { 20 | return DatatypeConverter.parseHexBinary(v); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/javax/xml/bind/annotation/adapters/XmlAdapter.java: -------------------------------------------------------------------------------- 1 | package javax.xml.bind.annotation.adapters; 2 | 3 | /** 4 | * Partial Implementation For Java9 support if 5 | * {@code javax.xml.bind.annotation.adapters.XmlAdapter} is missing 6 | */ 7 | @Deprecated 8 | @SuppressWarnings("DeprecatedIsStillUsed") 9 | public abstract class XmlAdapter { 10 | @Deprecated 11 | protected XmlAdapter() {} 12 | 13 | @Deprecated 14 | public abstract To marshal(From v) throws Exception; 15 | 16 | @Deprecated 17 | public abstract From unmarshal(To v) throws Exception; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/assets/fabriczero/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fox2Code/FabricZero/0519c12e3f56c9c10b3a1e90fb9c909ea296d3fb/src/main/resources/assets/fabriczero/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/fabriczero/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "fabriczero.updateAll": "Update all" 3 | } 4 | -------------------------------------------------------------------------------- /src/main/resources/assets/fabriczero/lang/fr_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "fabriczero.updateAll": "Tous mettre a jour" 3 | } 4 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "fabriczero", 4 | "version": "${version}", 5 | "name": "Fabric Zero", 6 | "description": "Compatibility and performance enhancement mod", 7 | "authors": [ 8 | "Fox2Code" 9 | ], 10 | "contact": { 11 | "homepage": "https://www.curseforge.com/minecraft/mc-mods/fabric-zero", 12 | "issues": "https://github.com/Fox2Code/FabricZero/issues", 13 | "sources": "https://github.com/Fox2Code/FabricZero" 14 | }, 15 | "license": "MIT", 16 | "icon": "assets/fabriczero/icon.png", 17 | "environment": "*", 18 | "entrypoints": { 19 | "client": [ 20 | "com.fox2code.fabriczero.mod.FabricZeroClient" 21 | ], 22 | "main": [ 23 | "com.fox2code.fabriczero.mod.FabricZero" 24 | ], 25 | "modmenu": [ 26 | "com.fox2code.fabriczero.mod.FabricZeroModMenu" 27 | ], 28 | "modupdater": [ 29 | "com.fox2code.fabriczero.mod.FabricZeroModUpdater" 30 | ], 31 | "gud_asm": [ 32 | "com.fox2code.fabriczero.FabricZeroTransformerASM" 33 | ] 34 | }, 35 | "mixins": [ 36 | "fabriczero.mixins.json" 37 | ], 38 | "depends": { 39 | "fabricloader": ">=0.7.0" 40 | }, 41 | "suggests": { 42 | "modupdater": "*" 43 | }, 44 | "custom": { 45 | "modupdater": { 46 | "strategy": "curseforge", 47 | "projectID": 400444, 48 | "strict": false 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/resources/fabriczero.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "com.fox2code.fabriczero.mixins", 5 | "compatibilityLevel": "JAVA_8", 6 | "plugin": "com.fox2code.fabriczero.FabricZeroPlugin", 7 | "mixins": [ 8 | "DefaultResourcePackMixin", 9 | "ResourcePackProfileMixin" 10 | ], 11 | "client": [ 12 | "ModUpdaterScreenMixin_ModUpdater" 13 | ], 14 | "injectors": { 15 | "defaultRequire": 1 16 | } 17 | } 18 | --------------------------------------------------------------------------------