diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bb2369c886..1cd0cc9fb0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,8 +19,8 @@ jobs: - name: Setting up JDK 21 uses: actions/setup-java@v4 with: - distribution: temurin - java-version: 21 + distribution: 'graalvm' + java-version: '21' - name: Grant permissions to src-theme run: sudo chmod -R 777 src-theme @@ -50,7 +50,7 @@ jobs: cd zip zip -r liquidbounce.zip * md5sum liquidbounce.zip - curl --connect-timeout 30 -m 300 -X POST -F "artifact=@liquidbounce.zip" -H "Authorization: ${{ secrets.NIGHTLY_PASS }}" -F "gh_id=${{ github.event.head_commit.id }}" -F "gh_ref=${{ github.ref }}" -F "gh_message=${{ github.event.head_commit.message }}" -F "gh_timestamp=${{ github.event.head_commit.timestamp }}" -F "lb_version=$LB_VERSION" -F "mc_version=$MINECRAFT_VERSION" -F "subsystem=fabric" -F "jre_version=21" -F "fabric_loader_version=$LOADER_VERSION" -F "fabric_api_version=$FABRICAPI_VERSION" -F "kotlin_version=$KOTLIN_VERSION" -F "fabric_kotlin_version=$FABRIC_KOTLIN_VERSION" https://api.liquidbounce.net/api/v1/version/new + curl --connect-timeout 30 -m 300 -X POST -F "artifact=@liquidbounce.zip" -H "Authorization: ${{ secrets.NIGHTLY_PASS }}" -F "gh_id=${{ github.event.head_commit.id }}" -F "gh_ref=${{ github.ref }}" -F "gh_message=${{ github.event.head_commit.message }}" -F "gh_timestamp=${{ github.event.head_commit.timestamp }}" -F "lb_version=$LB_VERSION" -F "mc_version=$MINECRAFT_VERSION" -F "subsystem=fabric" -F "jre_version=21" -F "jre_distribution=graalvm" -F "fabric_loader_version=$LOADER_VERSION" -F "fabric_api_version=$FABRICAPI_VERSION" -F "kotlin_version=$KOTLIN_VERSION" -F "fabric_kotlin_version=$FABRIC_KOTLIN_VERSION" https://api.liquidbounce.net/api/v1/version/new verify-pr: runs-on: ubuntu-latest @@ -62,10 +62,10 @@ jobs: submodules: recursive - name: Setting up JDK 21 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: - distribution: temurin - java-version: 21 + distribution: 'graalvm' + java-version: '21' - name: Grant permissions to src-theme run: sudo chmod -R 777 src-theme diff --git a/build.gradle b/build.gradle index ca18ab711d..4a29240603 100644 --- a/build.gradle +++ b/build.gradle @@ -20,41 +20,42 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { - id 'fabric-loom' - id 'org.jetbrains.kotlin.jvm' - id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'com.gorylenko.gradle-git-properties' version '2.4.2' + id "fabric-loom" + id "org.jetbrains.kotlin.jvm" + id "com.gorylenko.gradle-git-properties" version "2.4.2" id "io.gitlab.arturbosch.detekt" version "1.23.6" id "com.github.node-gradle.node" version "7.1.0" - id 'org.jetbrains.dokka' version '1.9.10' + id "org.jetbrains.dokka" version "1.9.10" } -sourceCompatibility = JavaVersion.VERSION_21 -targetCompatibility = JavaVersion.VERSION_21 - archivesBaseName = project.archives_base_name version = project.mod_version group = project.maven_group -loom { - accessWidenerPath = file('src/main/resources/liquidbounce.accesswidener') +configurations { + includeDependency + includeModDependency + + include.extendsFrom includeModDependency + modImplementation.extendsFrom includeModDependency + modCompileOnlyApi.extendsFrom includeModDependency } repositories { mavenCentral() mavenLocal() - maven { url = 'https://maven.fabricmc.net/' } + maven { url = "https://maven.fabricmc.net/" } maven { - name = 'Jitpack' - url = 'https://jitpack.io' + name = "Jitpack" + url = "https://jitpack.io" } maven { - name = 'TerraformersMC' - url = 'https://maven.terraformersmc.com/' + name = "TerraformersMC" + url = "https://maven.terraformersmc.com/" } maven { - name = 'ViaVersion' - url = 'https://repo.viaversion.com/' + name = "ViaVersion" + url = "https://repo.viaversion.com/" } maven { name = "modrinth" @@ -70,83 +71,80 @@ repositories { } } -dependencies { - testImplementation 'org.junit.jupiter:junit-jupiter:5.11.3' +loom { + accessWidenerPath = file("src/main/resources/liquidbounce.accesswidener") +} +dependencies { // Minecraft minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - // Libraries (required mods) - + // Fabric modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc:fabric-language-kotlin:${project.fabric_kotlin_version}" - implementation "net.fabricmc:tiny-mappings-parser:0.3.0+build.17" - // Recommended mods (on IDE) modRuntimeOnly "com.terraformersmc:modmenu:${project.mod_menu_version}" modImplementation "maven.modrinth:sodium:${project.sodium_version}" - modImplementation "de.florianmichael:ViaFabricPlus:${project.viafabricplus_version}" + modCompileOnly "de.florianmichael:ViaFabricPlus:${project.viafabricplus_version}" - // Tests -// modImplementation 'com.github.superblaubeere27:tenacc:e3a7ada99a' - - // fix nullable imports - implementation 'com.google.code.findbugs:jsr305:3.0.2' - - // Client libraries - implementation("com.github.CCBlueX:mc-authlib:${project.mc_authlib_version}") { - exclude group: 'com.google.code.gson', module: 'gson' - exclude group: 'org.apache.logging.log4j', module: 'log4j-core' - exclude group: 'org.apache.logging.log4j', module: 'log4j-api' - exclude group: 'org.apache.logging.log4j', module: 'log4j-slf4j-impl' - exclude group: 'org.slf4j', module: 'slf4j-api' - exclude group: 'com.mojang', module: 'authlib' + // Minecraft Authlib + includeDependency ("com.github.CCBlueX:mc-authlib:${project.mc_authlib_version}") { + exclude group: "com.google.code.gson", module: "gson" + exclude group: "org.apache.logging.log4j", module: "log4j-core" + exclude group: "org.apache.logging.log4j", module: "log4j-api" + exclude group: "org.apache.logging.log4j", module: "log4j-slf4j-impl" + exclude group: "org.slf4j", module: "slf4j-api" + exclude group: "com.mojang", module: "authlib" } - implementation "com.github.CCBlueX:mcef:916f8c5f73" - implementation 'com.github.CCBlueX:netty-httpserver:2.1.0' - implementation "com.github.CCBlueX:DiscordIPC:-SNAPSHOT" - implementation 'org.graalvm.sdk:graal-sdk:23.0.5' - implementation 'org.graalvm.truffle:truffle-api:23.0.5' - implementation 'org.graalvm.js:js:23.0.5' + // JCEF Support + includeModDependency "com.github.CCBlueX:mcef:1.1.5-1.21.1" + includeDependency "org.apache.commons:commons-exec:1.3" + includeDependency ("com.github.CCBlueX:netty-httpserver:2.1.0") { + exclude group: "io.netty", module: "netty-all" + } - runtimeOnly 'org.graalvm.tools:profiler:23.0.5' - runtimeOnly 'org.graalvm.tools:chromeinspector:23.0.5' + // Discord RPC Support + includeDependency "com.github.CCBlueX:DiscordIPC:4.0.0" - // https://mvnrepository.com/artifact/io.netty/netty-codec - implementation 'io.netty:netty-codec:4.1.82.Final' - // https://mvnrepository.com/artifact/io.netty/netty-codec-http - implementation 'io.netty:netty-codec-http:4.1.82.Final' - // https://mvnrepository.com/artifact/io.netty/netty-handler-proxy - implementation 'io.netty:netty-handler-proxy:4.1.82.Final' - // https://mvnrepository.com/artifact/io.netty/netty-codec-socks - implementation 'io.netty:netty-codec-socks:4.1.82.Final' + // ScriptAPI + includeDependency "net.fabricmc:tiny-mappings-parser:0.3.0+build.17" + includeDependency "org.graalvm.polyglot:polyglot:24.0.2" + includeDependency "org.graalvm.polyglot:js-community:24.0.2" - implementation 'com.vdurmont:semver4j:3.1.0' - implementation 'org.apache.tika:tika-core:3.0.0' + // SOCKS5 Proxy Support (to stay compatible with ViaFabricPlus) + includeDependency "io.netty:netty-handler-proxy:4.1.114.Final" - implementation 'org.apache.commons:commons-exec:1.3' + // Update Checker + includeDependency "com.vdurmont:semver4j:3.1.0" // Test libraries + testImplementation "org.junit.jupiter:junit-jupiter:5.11.3" + testRuntimeOnly "org.junit.platform:junit-platform-launcher" - testImplementation 'org.junit.jupiter:junit-jupiter:5.11.3' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + afterEvaluate { + configurations.includeDependency.incoming.resolutionResult.allDependencies.each { + dependencies.include(dependencies.implementation(dependencies.compileOnlyApi(it.requested.toString()) { + transitive = false + })) + } + } } processResources { - inputs.property 'version', project.version + inputs.property "version", project.version - inputs.property 'minecraft_version', minecraft_version - inputs.property 'fabric_version', fabric_version - inputs.property 'loader_version', loader_version - inputs.property 'min_loader_version', min_loader_version - inputs.property 'fabric_kotlin_version', fabric_kotlin_version - inputs.property 'viafabricplus_version', viafabricplus_version + inputs.property "minecraft_version", minecraft_version + inputs.property "fabric_version", fabric_version + inputs.property "loader_version", loader_version + inputs.property "min_loader_version", min_loader_version + inputs.property "fabric_kotlin_version", fabric_kotlin_version + inputs.property "viafabricplus_version", viafabricplus_version - filesMatching('fabric.mod.json') { + filesMatching("fabric.mod.json") { expand([ version : project.version, minecraft_version : minecraft_version, @@ -161,60 +159,60 @@ processResources { // The following code will include the theme into the build -tasks.register('npmInstallTheme', NpmTask) { - workingDir = file('src-theme') - args = ['i'] +tasks.register("npmInstallTheme", NpmTask) { + workingDir = file("src-theme") + args = ["i"] doLast { - println 'Successfully installed dependencies for theme' + println "Successfully installed dependencies for theme" } - inputs.files('src-theme/package.json', 'src-theme/package-lock.json') + inputs.files("src-theme/package.json", "src-theme/package-lock.json") outputs.dir("src-theme/node_modules") } -tasks.register('buildTheme', NpmTask) { - dependsOn 'npmInstallTheme' - workingDir = file('src-theme') - args = ['run', 'build'] +tasks.register("buildTheme", NpmTask) { + dependsOn "npmInstallTheme" + workingDir = file("src-theme") + args = ["run", "build"] doLast { - println 'Successfully build theme' + println "Successfully build theme" } inputs.files( - 'src-theme/package.json', - 'src-theme/package-lock.json', - 'src-theme/bundle.cjs', - 'src-theme/rollup.config.js' + "src-theme/package.json", + "src-theme/package-lock.json", + "src-theme/bundle.cjs", + "src-theme/rollup.config.js" ) inputs.dir("src-theme/src") - outputs.dir('src-theme/dist') + outputs.dir("src-theme/dist") } -tasks.register('bundleTheme', NodeTask) { - dependsOn 'buildTheme' - workingDir = file('src-theme') - script = file('src-theme/bundle.cjs') +tasks.register("bundleTheme", NodeTask) { + dependsOn "buildTheme" + workingDir = file("src-theme") + script = file("src-theme/bundle.cjs") doLast { - println 'Successfully attached theme to build' + println "Successfully attached theme to build" } // Incremental stuff inputs.files( - 'src-theme/package.json', - 'src-theme/package-lock.json', - 'src-theme/bundle.cjs', - 'src-theme/rollup.config.js' + "src-theme/package.json", + "src-theme/package-lock.json", + "src-theme/bundle.cjs", + "src-theme/rollup.config.js" ) inputs.dir("src-theme/src") inputs.dir("src-theme/public") inputs.dir("src-theme/dist") - outputs.files('src-theme/resources/assets/liquidbounce/default_theme.zip') + outputs.files("src-theme/resources/assets/liquidbounce/default_theme.zip") } sourceSets { main { resources { - srcDirs 'src-theme/resources' + srcDirs "src-theme/resources" } } } @@ -229,7 +227,7 @@ tasks.withType(JavaCompile).configureEach { // this fixes some edge cases with special characters not displaying correctly // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html // If Javadoc is generated, this must be specified in that task too. - it.options.encoding = 'UTF-8' + it.options.encoding = "UTF-8" // Minecraft 1.20.5 upwards uses Java 17. it.options.release = 21 @@ -237,6 +235,7 @@ tasks.withType(JavaCompile).configureEach { tasks.withType(Test).configureEach { useJUnitPlatform() + dependsOn(tasks.named("genSources")) } detekt { @@ -264,6 +263,9 @@ java { // if it is present. // If you remove this line, sources will not be generated. withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } compileKotlin { @@ -273,49 +275,22 @@ compileKotlin { } } -shadowJar { - archiveClassifier.set('shadow') +jar { + // Rename the project"s license file to LICENSE_ to avoid conflicts + from("LICENSE") { + rename { + "${it}_${project.archives_base_name}" + } + } - // Natives are going to be downloaded from our cloud - exclude 'native-binaries/*' - - // META-INF/versions/20 - exclude "META-INF/versions/20/**" - - dependencies { - include(dependency('com.github.CCBlueX:mcef')) - include(dependency('com.github.CCBlueX:netty-httpserver')) - include(dependency('com.github.CCBlueX:mc-authlib')) - include(dependency('com.github.CCBlueX:DiscordIPC')) - include(dependency('com.thealtening.api:api')) - include(dependency('net.fabricmc:tiny-mappings-parser')) - include(dependency('org.graalvm.sdk:graal-sdk')) - include(dependency('org.graalvm.truffle:truffle-api')) - include(dependency('org.graalvm.js:js')) - include(dependency('io.netty:netty-codec')) - include(dependency('io.netty:netty-codec-http')) - include(dependency('io.netty:netty-handler-proxy')) - include(dependency('io.netty:netty-codec-socks')) - include(dependency('org.apache.commons:commons-exec')) - include(dependency('org.apache.tika:tika-core')) - include(dependency('com.vdurmont:semver4j')) - include(dependency('com.kohlschutter.junixsocket:junixsocket-common')) - include(dependency('com.kohlschutter.junixsocket:junixsocket-native-common')) - include(dependency('net.lenni0451:Reflect')) + from(configurations.mappings.collect { zipTree(it) }) { + include "mappings/mappings.tiny" } } -jar { - from 'LICENSE' -} - -remapJar { - inputFile = shadowJar.archiveFile -} - -tasks.register('copyZipInclude', Copy) { - from 'zip_include/' - into 'build/libs/zip' +tasks.register("copyZipInclude", Copy) { + from "zip_include/" + into "build/libs/zip" } sourcesJar.dependsOn bundleTheme diff --git a/gradle.properties b/gradle.properties index dbe5ac778d..848f4c5e25 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,13 +22,13 @@ org.gradle.jvmargs=-Xms1024m -Xmx4096m # Check these on https://fabricmc.net/versions.html minecraft_version=1.21.1 yarn_mappings=1.21.1+build.3 -loader_version=0.16.3 +loader_version=0.16.9 min_loader_version=0.15.10 # Fabric API -fabric_version=0.102.1+1.21.1 +fabric_version=0.107.0+1.21.1 # Loom -loom_version=1.7-SNAPSHOT +loom_version=1.8-SNAPSHOT # Mod Properties mod_version=0.17.1 maven_group=net.ccbluex diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c9..9355b41557 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle index 4a30d9e82f..4285e5c2fe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -19,7 +19,6 @@ pluginManagement { repositories { - jcenter() maven { name = 'Fabric' url = 'https://maven.fabricmc.net/' @@ -33,5 +32,3 @@ pluginManagement { } } - -//include('mcef') diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostClassDesc.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostClassDesc.java deleted file mode 100644 index 11927952a8..0000000000 --- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostClassDesc.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) - * - * Copyright (c) 2015 - 2024 CCBlueX - * - * LiquidBounce is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LiquidBounce is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LiquidBounce. If not, see . - */ - -package net.ccbluex.liquidbounce.injection.mixins.graaljs; - -import net.ccbluex.liquidbounce.utils.mappings.Remapper; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -/** - * Remaps class method and field names to their obfuscated counterparts. - * - * Initial code by lit - */ -@Mixin(targets = "com/oracle/truffle/host/HostClassDesc") -public abstract class MixinHostClassDesc { - - @Shadow - public abstract Class getType(); - - @ModifyVariable(method = "lookupField(Ljava/lang/String;)Lcom/oracle/truffle/host/HostFieldDesc;", - at = @At("HEAD"), argsOnly = true, index = 1, remap = false) - private String remapFieldName(String name) { - return Remapper.INSTANCE.remapField(getType(), name, true); - } - - @ModifyVariable(method = "lookupStaticField", at = @At("HEAD"), argsOnly = true, index = 1, remap = false) - private String remapStaticFieldName(String name) { - return Remapper.INSTANCE.remapField(getType(), name, true); - } - - @ModifyVariable(method = "lookupMethod(Ljava/lang/String;)Lcom/oracle/truffle/host/HostMethodDesc;", - at = @At("HEAD"), argsOnly = true, index = 1, remap = false) - private String remapMethodName(String name) { - return Remapper.INSTANCE.remapMethod(getType(), name, true); - } - - @ModifyVariable(method = "lookupStaticMethod", at = @At("HEAD"), argsOnly = true, index = 1, remap = false) - private String remapStaticMethodName(String name) { - return Remapper.INSTANCE.remapMethod(getType(), name, true); - } - -} diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinTruffleLanguage.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinTruffleLanguage.java deleted file mode 100644 index 4e63d880ba..0000000000 --- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinTruffleLanguage.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.ccbluex.liquidbounce.injection.mixins.graaljs; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -@Mixin(targets = "com/oracle/truffle/api/TruffleLanguage") -public class MixinTruffleLanguage { - - /** - * @author Senk Ju - * @reason Prevent GraalVM from blocking multi threaded access to resources - */ - @Overwrite(remap = false) - protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) { - return true; - } -} diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostClassDesc.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostClassDesc.java new file mode 100644 index 0000000000..1335a55b9f --- /dev/null +++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostClassDesc.java @@ -0,0 +1,140 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2024 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ + +package net.ccbluex.liquidbounce.injection.mixins.truffle; + +import net.ccbluex.liquidbounce.interfaces.MemberRetriever; +import net.ccbluex.liquidbounce.utils.client.ClientUtilsKt; +import net.ccbluex.liquidbounce.utils.mappings.EnvironmentRemapper; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +@Pseudo +@Mixin(targets = "com/oracle/truffle/host/HostClassDesc$Members") +public abstract class MixinHostClassDesc { + + @Shadow(remap = false) + @Final + Map methods; + + @Shadow(remap = false) + @Final + Map fields; + + @Shadow(remap = false) + @Final + Map staticFields; + + @Shadow(remap = false) + @Final + Map staticMethods; + + @Inject(method = "", at = @At("RETURN"), remap = false) + private void remapClassDesc(CallbackInfo ci) { + remapEntries(methods, this::getMethod); + remapEntries(fields, this::getField); + remapEntries(staticFields, this::getField); + remapEntries(staticMethods, this::getMethod); + } + + @Unique + private void remapEntries(Map map, MemberRetriever retriever) { + var entries = new HashMap<>(map).entrySet(); + + for (var entry : entries) { + String key = entry.getKey(); + Object value = entry.getValue(); + String remapped; + + try { + Member member = retriever.getMember(value); + remapped = remapDescriptor(member); + } catch (ReflectiveOperationException e) { + ClientUtilsKt.getLogger().error("Failed to remap: {}", key, e); + continue; + } + + if (remapped != null) { + map.remove(key); + map.put(remapped, value); + } + } + } + + @Unique + private Member getMethod(Object o) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + try { + // If this works, it is likely a SingleMethod instance + Method descMethod = o.getClass().getDeclaredMethod("getReflectionMethod"); + + descMethod.setAccessible(true); + return (Member) descMethod.invoke(o); + } catch (NoSuchMethodException ignored) { + try { + var getOverloads = o.getClass().getDeclaredMethod("getOverloads"); + var overloads = (Object[]) getOverloads.invoke(o); + + return getMethod(overloads[0]); + } catch (NoSuchMethodException ignored2) { + ClientUtilsKt.getLogger().error("Unsupported method type: {}", o.getClass().getName()); + } + + return null; + } + } + + @Unique + private Member getField(Object o) throws IllegalAccessException, NoSuchFieldException { + var descField = o.getClass().getDeclaredField("field"); + descField.setAccessible(true); + return (Member) descField.get(o); + } + + @Unique + private static String remapDescriptor(Member member) { + var name = member.getName(); + + String remapped; + if (member instanceof java.lang.reflect.Method) { + remapped = EnvironmentRemapper.INSTANCE.remapMethod(member.getDeclaringClass(), name); + } else if (member instanceof java.lang.reflect.Field) { + remapped = EnvironmentRemapper.INSTANCE.remapField(member.getDeclaringClass(), name); + } else { + ClientUtilsKt.getLogger().error("Unknown member type: {}", member.getClass().getName()); + return null; + } + + // If the name is the same, return the original field + if (name.equals(remapped)) { + return null; + } + +// ClientUtilsKt.getLogger().debug("Remapped descriptor: {} in {} to {}", name, member.getDeclaringClass().getName(), remapped); + return remapped; + } + +} diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostClassLoader.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostClassLoader.java similarity index 77% rename from src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostClassLoader.java rename to src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostClassLoader.java index e8e5cb77f6..55485c199f 100644 --- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostClassLoader.java +++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostClassLoader.java @@ -17,24 +17,21 @@ * along with LiquidBounce. If not, see . */ -package net.ccbluex.liquidbounce.injection.mixins.graaljs; +package net.ccbluex.liquidbounce.injection.mixins.truffle; -import net.ccbluex.liquidbounce.utils.mappings.Remapper; +import net.ccbluex.liquidbounce.utils.mappings.EnvironmentRemapper; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyVariable; -/** - * Remaps class names to their obfuscated counterparts. - * - * Initial code by lit - */ -@Mixin(targets = "com/oracle/truffle/host/HostClassLoader") +@Pseudo +@Mixin(targets = "com/oracle/truffle/host/HostClassLoader", remap = false) public class MixinHostClassLoader { @ModifyVariable(method = "findClass", at = @At("HEAD"), argsOnly = true, remap = false) private String remapClassName(String value) { - return Remapper.INSTANCE.remapClassName(value); + return EnvironmentRemapper.INSTANCE.remapClassName(value); } } diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostContext.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostContext.java similarity index 77% rename from src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostContext.java rename to src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostContext.java index 658bfa2cb9..b40d16bdf1 100644 --- a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/graaljs/MixinHostContext.java +++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinHostContext.java @@ -19,19 +19,21 @@ * */ -package net.ccbluex.liquidbounce.injection.mixins.graaljs; +package net.ccbluex.liquidbounce.injection.mixins.truffle; -import net.ccbluex.liquidbounce.utils.mappings.Remapper; +import net.ccbluex.liquidbounce.utils.mappings.EnvironmentRemapper; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyVariable; -@Mixin(targets = "com/oracle/truffle/host/HostContext") +@Pseudo +@Mixin(targets = "com/oracle/truffle/host/HostContext", remap = false) public class MixinHostContext { @ModifyVariable(method = "findClassImpl", at = @At("HEAD"), argsOnly = true, remap = false) private String remapClassName(String value) { - return Remapper.INSTANCE.remapClassName(value); + return EnvironmentRemapper.INSTANCE.remapClassName(value); } } diff --git a/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinTruffleLanguage.java b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinTruffleLanguage.java new file mode 100644 index 0000000000..2c95951e74 --- /dev/null +++ b/src/main/java/net/ccbluex/liquidbounce/injection/mixins/truffle/MixinTruffleLanguage.java @@ -0,0 +1,38 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2024 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ + +package net.ccbluex.liquidbounce.injection.mixins.truffle; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Pseudo; + +@Pseudo +@Mixin(targets = "com/oracle/truffle/api/TruffleLanguage", remap = false) +public class MixinTruffleLanguage { + + /** + * @author Senk Ju + * @reason Prevent GraalVM from blocking multithreaded access to resources + */ + @Overwrite(remap = false) + protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) { + return true; + } +} diff --git a/src/main/java/net/ccbluex/liquidbounce/interfaces/MemberRetriever.java b/src/main/java/net/ccbluex/liquidbounce/interfaces/MemberRetriever.java new file mode 100644 index 0000000000..ed1b48974c --- /dev/null +++ b/src/main/java/net/ccbluex/liquidbounce/interfaces/MemberRetriever.java @@ -0,0 +1,27 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2024 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ + +package net.ccbluex.liquidbounce.interfaces; + +import java.lang.reflect.Member; + +@FunctionalInterface +public interface MemberRetriever { + Member getMember(Object o) throws ReflectiveOperationException; +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt b/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt index d5a09c13fe..3d362d7f84 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt @@ -62,7 +62,7 @@ import net.ccbluex.liquidbounce.utils.combat.CombatManager import net.ccbluex.liquidbounce.utils.combat.combatTargetsConfigurable import net.ccbluex.liquidbounce.utils.input.InputTracker import net.ccbluex.liquidbounce.utils.inventory.InventoryManager -import net.ccbluex.liquidbounce.utils.mappings.Remapper +import net.ccbluex.liquidbounce.utils.mappings.EnvironmentRemapper import net.ccbluex.liquidbounce.utils.render.WorldToScreen import net.minecraft.resource.ReloadableResourceManagerImpl import net.minecraft.resource.ResourceManager @@ -122,7 +122,7 @@ object LiquidBounce : Listenable { logger.debug("Loading from cloud: '$CLIENT_CLOUD'") // Load mappings - Remapper.load() + EnvironmentRemapper // Load translations LanguageManager.loadLanguages() diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/JsReflectionUtil.kt b/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/JsReflectionUtil.kt index 909b595402..55dddd97a5 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/JsReflectionUtil.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/script/bindings/api/JsReflectionUtil.kt @@ -18,13 +18,13 @@ */ package net.ccbluex.liquidbounce.script.bindings.api -import net.ccbluex.liquidbounce.utils.mappings.Remapper +import net.ccbluex.liquidbounce.utils.mappings.EnvironmentRemapper object JsReflectionUtil { @JvmName("classByName") fun classByName(name: String): Class<*> = Class.forName( - Remapper.remapClassName(name).replace('/', '.') + EnvironmentRemapper.remapClassName(name).replace('/', '.') ) @JvmName("classByObject") @@ -38,7 +38,7 @@ object JsReflectionUtil { @JvmName("newInstanceByName") fun newInstanceByName(name: String, vararg args: Any?): Any? = - Class.forName(Remapper.remapClassName(name).replace('/', '.')) + Class.forName(EnvironmentRemapper.remapClassName(name).replace('/', '.')) .getDeclaredConstructor(*args.map { it!!::class.java }.toTypedArray()).apply { isAccessible = true }.newInstance(*args) @@ -50,35 +50,37 @@ object JsReflectionUtil { }.newInstance(*args) @JvmName("getField") - fun getField(obj: Any, name: String): Any? = obj::class.java.getDeclaredField( - Remapper.remapField(obj::class.java, name, true) - ).apply { - isAccessible = true - }.get(obj) + fun getField(obj: Any, name: String): Any? = obj::class.java.fields + .find { field -> + field.name == EnvironmentRemapper.remapField(obj::class.java, name) + }?.apply { + isAccessible = true + }?.get(obj) - @JvmName("getStaticField") - fun getStaticField(clazz: Class<*>, name: String): Any? = clazz.getDeclaredField( - Remapper.remapField(clazz, name, true) - ).apply { - isAccessible = true - }.get(null) + @JvmName("getDeclaredField") + fun getDeclaredField(clazz: Class<*>, name: String): Any? = clazz.declaredFields + .find { field -> + field.name == EnvironmentRemapper.remapField(clazz, name) + }?.apply { + isAccessible = true + }?.get(null) @JvmName("invokeMethod") fun invokeMethod(obj: Any, name: String, vararg args: Any?): Any? = - obj::class.java.getDeclaredMethod( - Remapper.remapField(obj::class.java, name, true), - *args.map { it!!::class.java }.toTypedArray() - ).apply { + obj::class.java.methods.find { method -> + method.name == EnvironmentRemapper.remapMethod(obj::class.java, name) && + method.parameterTypes.contentEquals(args.map { it!!::class.java }.toTypedArray()) + }?.apply { isAccessible = true - }.invoke(obj, *args) + }?.invoke(obj, *args) - @JvmName("invokeStaticMethod") - fun invokeStaticMethod(clazz: Class<*>, name: String, vararg args: Any?): Any? = - clazz.getDeclaredMethod( - Remapper.remapField(clazz, name, true), - *args.map { it!!::class.java }.toTypedArray() - ).apply { + @JvmName("invokeDeclaredMethod") + fun invokeDeclaredMethod(clazz: Class<*>, name: String, vararg args: Any?): Any? = + clazz.declaredMethods.find { method -> + method.name == EnvironmentRemapper.remapMethod(clazz, name) && + method.parameterTypes.contentEquals(args.map { it!!::class.java }.toTypedArray()) + }?.apply { isAccessible = true - }.invoke(null, *args) + }?.invoke(null, *args) } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/mappings/EnvironmentRemapper.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/mappings/EnvironmentRemapper.kt new file mode 100644 index 0000000000..801a6c0553 --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/mappings/EnvironmentRemapper.kt @@ -0,0 +1,102 @@ +package net.ccbluex.liquidbounce.utils.mappings + +import net.ccbluex.liquidbounce.utils.client.logger +import net.ccbluex.liquidbounce.utils.io.resource +import net.fabricmc.mappings.model.V2MappingsProvider + +object EnvironmentRemapper { + + private var mappings = runCatching { + V2MappingsProvider.readTinyMappings(resource("/mappings/mappings.tiny").bufferedReader()) + }.onFailure { + logger.error("Unable to load mappings. Ignore this if you are using a development environment.", it) + }.getOrNull() + + private var environment = runCatching { + probeEnvironment() + }.onFailure { + logger.error("Unable to probe environment. Please make sure you are using a valid environment.", it) + }.getOrNull() + + private fun probeEnvironment(): String? { + val mappings = mappings ?: return null + + val minecraftClassEntry = mappings.classEntries?.find { entry -> + entry?.get("named") == "net/minecraft/client/MinecraftClient" + } + + if (minecraftClassEntry == null) { + logger.error("Unable to probe environment. Please make sure you are using a valid environment.") + return null + } + + logger.info("Probing environment...") + return when { + isClassPresent(minecraftClassEntry.get("intermediary")?.toDotNotation()) -> { + logger.info("Intermediary environment detected.") + "intermediary" + } + else -> { + logger.error("No matching environment detected. Please make sure you are using a valid environment.") + null + } + } + } + + private fun isClassPresent(className: String?): Boolean { + return try { + Class.forName(className) + true + } catch (_: ClassNotFoundException) { + false + } + } + + fun remapClassName(clazz: String): String { + environment ?: return clazz + + val className = clazz.toSlashNotation() + return mappings?.classEntries?.find { + it?.get("named") == className + }?.get(environment)?.toDotNotation() ?: clazz + } + + fun remapField(clazz: Class<*>, name: String): String { + environment ?: return name + + val clazzNames = getClassHierarchyNames(clazz) + + return mappings?.fieldEntries?.find { entry -> + val intern = entry.get(environment) + clazzNames.contains(intern.owner) && intern.name == name + }?.get("named")?.name ?: name + } + + fun remapMethod(clazz: Class<*>, name: String): String { + environment ?: return name + + val clazzNames = getClassHierarchyNames(clazz) + + return mappings?.methodEntries?.find { entry -> + val intern = entry.get(environment) + clazzNames.contains(intern.owner) && intern.name == name + }?.get("named")?.name ?: name + } + + private fun getClassHierarchyNames(clazz: Class<*>): Set { + val clazzNames = mutableSetOf(clazz.name.toSlashNotation()) + var current = clazz + + while (current.name != "java.lang.Object") { + current = current.superclass ?: break + clazzNames.add(current.name.toSlashNotation()) + } + + return clazzNames + } + + private fun String.toDotNotation(): String = replace('/', '.') + + private fun String.toSlashNotation(): String = replace('.', '/') + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/mappings/Remapper.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/mappings/Remapper.kt deleted file mode 100644 index ffb50c2ecd..0000000000 --- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/mappings/Remapper.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) - * - * Copyright (c) 2015 - 2024 CCBlueX - * - * LiquidBounce is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LiquidBounce is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LiquidBounce. If not, see . - */ -package net.ccbluex.liquidbounce.utils.mappings - -import net.ccbluex.liquidbounce.utils.client.logger -import net.ccbluex.liquidbounce.utils.io.resource -import net.fabricmc.mappings.Mappings -import net.fabricmc.mappings.model.V2MappingsProvider - -/** - * Tiny mappings - * - * These are fabric mappings which are being exported when the jar is being built. - * It allows you to remap obfuscated environments into readable names. - * - * This is going to be used for ultralight-databind and our JS script engine. - */ -object Remapper { - - var mappings: Mappings? = null - var environment: String? = null - - fun load() { - runCatching { - mappings = V2MappingsProvider.readTinyMappings(resource("/mappings/mappings.tiny").bufferedReader()) - }.onFailure { - logger.error("Unable to load mappings. Ignore this if you are using a development environment.", it) - } - - // Probe environment - runCatching { - probeEnvironment() - }.onFailure { - logger.error("Unable to probe environment. Please make sure you are using a valid environment.", it) - } - } - - private fun probeEnvironment() { - val minecraftEntry = mappings?.classEntries?.find { - it?.get("named") == "net/minecraft/client/MinecraftClient" - } - - if (minecraftEntry == null) { - logger.error("Unable to probe environment. Please make sure you are using a valid environment.") - return - } - - val officialName = minecraftEntry.get("official")?.replace('/', '.') - val intermediaryName = minecraftEntry.get("intermediary")?.replace('/', '.') - - logger.info("Probing environment... (official: $officialName, intermediary: $intermediaryName)") - - try { - Class.forName(officialName) - this.environment = "official" - logger.info("Official environment detected.") - } catch (_: ClassNotFoundException) { - try { - Class.forName(intermediaryName) - this.environment = "intermediary" - logger.info("Intermediary environment detected.") - - return - } catch (_: ClassNotFoundException) { - logger.error("No matching environment detected. Please make sure you are using a valid environment.") - return - } - } - } - - fun remapClassName(clazz: String): String { - if (environment == null) { - return clazz - } - - val className = clazz.replace('.', '/') - - return mappings?.classEntries?.find { - it?.get("named") == className - }?.get(environment)?.replace('/', '.') ?: clazz - } - - fun remapField(clazz: Class<*>, name: String, superClasses: Boolean): String { - if (environment == null) { - return name - } - - val classNames = mutableSetOf(clazz.name.replace('.', '/')) - - if (superClasses) { - var current = clazz - while (current.name != "java.lang.Object") { - current = current.superclass - classNames.add(current.name.replace('.', '/')) - } - } - - return mappings?.fieldEntries?.find { - val intern = it?.get(environment) ?: return@find false - val named = it.get("named") ?: return@find false - - classNames.contains(intern.owner) && named.name == name - }?.get(environment)?.name ?: name - } - - fun remapMethod(clazz: Class<*>, name: String, superClasses: Boolean): String { - if (environment == null) { - return name - } - - val classNames = mutableSetOf(clazz.name.replace('.', '/')) - - if (superClasses) { - var current = clazz - while (current.name != "java.lang.Object") { - current = current.superclass - classNames.add(current.name.replace('.', '/')) - } - } - - return mappings?.methodEntries?.find { - val intern = it?.get(environment) ?: return@find false - val named = it.get("named") ?: return@find false - - classNames.contains(intern.owner) && named.name == name - }?.get(environment)?.name ?: name - } - -} diff --git a/src/main/resources/liquidbounce.mixins.json b/src/main/resources/liquidbounce.mixins.json index 17c0bc4d43..87e018705d 100644 --- a/src/main/resources/liquidbounce.mixins.json +++ b/src/main/resources/liquidbounce.mixins.json @@ -6,10 +6,6 @@ "priority": 1337, "mixinPriority": 1337, "client": [ - "graaljs.MixinHostClassDesc", - "graaljs.MixinHostClassLoader", - "graaljs.MixinHostContext", - "graaljs.MixinTruffleLanguage", "minecraft.block.MixinAbstractBlock", "minecraft.block.MixinBlock", "minecraft.block.MixinBlockView", @@ -88,7 +84,6 @@ "minecraft.render.MixinPostEffectPass", "minecraft.render.MixinRenderTickCounter", "minecraft.render.MixinSignText", - "sodium.MixinSodiumBlockOcclusionCache", "minecraft.render.MixinTextRenderer", "minecraft.render.MixinWorldRenderer", "minecraft.render.entity.feature.MixinDeadmau5FeatureRenderer", @@ -96,7 +91,12 @@ "minecraft.text.MixinChatHudLineVisible", "minecraft.text.MixinTextColor", "minecraft.text.MixinTranslatableTextContent", - "sodium.MixinSodiumLightDataAccessMixin" + "sodium.MixinSodiumBlockOcclusionCache", + "sodium.MixinSodiumLightDataAccessMixin", + "truffle.MixinHostClassDesc", + "truffle.MixinHostClassLoader", + "truffle.MixinHostContext", + "truffle.MixinTruffleLanguage" ], "server": [], "injectors": {