diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fe0d820eca..28cc23d1ee 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -54,7 +54,7 @@ Before you submit your pull request consider the following guidelines: * After cloning, set a new remote [upstream](https://help.github.com/articles/configuring-a-remote-for-a-fork/) (this helps to keep your fork up to date) ```shell - git remote add upstream https://github.com/runelite-extended/runelite.git + git remote add upstream https://github.com/open-osrs/runelite.git ``` * Make your changes in a new git branch: diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000000..698e6fa1a8 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,25 @@ +version-template: '$MAJOR.$MINOR.$PATCH.0' +name-template: 'v$NEXT_PATCH_VERSION' +tag-template: 'v$NEXT_PATCH_VERSION' +exclude-labels: + - 'skip-changelog' + - 'automated-pull-request' +categories: + - title: '🚀 Features' + labels: + - 'feature' + - 'enhancement' + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - title: '🧰 Maintenance' + label: 'chore' +change-template: '* $TITLE (#$NUMBER) @$AUTHOR' +template: | + Thanks to: $CONTRIBUTORS + + ## Changes + + $CHANGES \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 691a56bcdb..0000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: OpenOSRS - CI - -on: [pull_request, push] - -jobs: - pr-lint: - name: PR title - runs-on: ubuntu-latest - - steps: - - name: PR title lint - if: github.event_name == 'pull_request' - uses: seferov/pr-lint-action@master - with: - title-regex: '^([\w-/]+): \w+' - - build: - runs-on: windows-latest - name: Build - - steps: - - uses: actions/checkout@master - - name: Set up JDK 11 - uses: actions/setup-java@master - with: - java-version: 11 - - name: Assembling - run: gradlew assemble --console=plain - - name: Building - run: gradlew build --stacktrace -x test -x checkstyleMain --console=plain - - test: - runs-on: windows-latest - name: Test - - steps: - - uses: actions/checkout@master - - name: Set up JDK 11 - uses: actions/setup-java@master - with: - java-version: 11 - - name: Assembling - run: gradlew assemble --console=plain - - name: Testing - run: gradlew test --stacktrace --console=plain - - checkstyle: - name: Checkstyle - runs-on: windows-latest - - steps: - - uses: actions/checkout@master - - name: Set up JDK 11 - uses: actions/setup-java@master - with: - java-version: 11 - - name: Assembling - run: gradlew assemble --console=plain - - name: Checking code conventions - run: gradlew checkstyleMain --console=plain - - approve: - name: Approve - needs: [build, test, checkstyle] - runs-on: ubuntu-latest - - steps: - - name: Approve pull request - if: github.event_name == 'pull_request' && github.actor == 'OpenOSRS' - uses: hmarr/auto-approve-action@master - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 619e3921c6..f16ec08572 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 - name: Make gradlew executable run: chmod +x ./gradlew - name: Update Gradle Wrapper @@ -22,23 +22,23 @@ jobs: PULL_REQUEST_TITLE: 'project: Update gradle wrapper' PULL_REQUEST_BODY: This is an auto-generated PR with an updated gradle version COMMIT_MESSAGE: 'project: Update gradle wrapper' - PULL_REQUEST_LABELS: automated pull request, gradle + PULL_REQUEST_LABELS: automated-pull-request, gradle update-dependencies: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master - - name: Make gradlew executable - run: chmod +x ./gradlew - - name: Update Gradle dependencies - run: ./gradlew useLatestVersions --console=plain - - name: Create Gradle dependencies update Pull Request - uses: Owain94/create-pull-request@master - env: - GITHUB_TOKEN: ${{ secrets.OpenOSRS }} - PULL_REQUEST_BRANCH: GRADLE-DEPENDENCY-UPDATE - PULL_REQUEST_TITLE: 'project: Update gradle dependencies' - PULL_REQUEST_BODY: This is an auto-generated PR with an updated gradle dependencies versions - COMMIT_MESSAGE: 'project: Update gradle dependencies' - PULL_REQUEST_LABELS: automated pull request, gradle + - uses: actions/checkout@v1 + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Update Gradle dependencies + run: ./gradlew useLatestVersions --console=plain + - name: Create Gradle dependencies update Pull Request + uses: Owain94/create-pull-request@master + env: + GITHUB_TOKEN: ${{ secrets.OpenOSRS }} + PULL_REQUEST_BRANCH: GRADLE-DEPENDENCY-UPDATE + PULL_REQUEST_TITLE: 'project: Update gradle dependencies' + PULL_REQUEST_BODY: This is an auto-generated PR with an updated gradle dependencies versions + COMMIT_MESSAGE: 'project: Update gradle dependencies' + PULL_REQUEST_LABELS: automated-pull-request, gradle \ No newline at end of file diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100644 index 0000000000..4c84c98b3f --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,15 @@ +name: OpenOSRS - First interaction + +on: + issues: + types: [opened] + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: 'Thank you for opening your first issue! Please make sure to join our [Discord](https://discord.gg/openosrs).' \ No newline at end of file diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml new file mode 100644 index 0000000000..f7931e242b --- /dev/null +++ b/.github/workflows/merge.yml @@ -0,0 +1,37 @@ +name: OpenOSRS - Auto merge + +on: + pull_request_review: + types: + - submitted + +jobs: + automerge: + name: Auto merge + runs-on: ubuntu-latest + + steps: + - name: automerge + uses: pascalgn/automerge-action@f84dd310ea4a19890c70a4ff11ab282a872fb94b + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MERGE_FORKS: false + LABELS: automated-pull-request + AUTOMERGE: automated-pull-request + + cleanup: + name: Cleanup + needs: automerge + runs-on: ubuntu-latest + + steps: + - name: Extract branch name + shell: bash + run: echo "##[set-output name=branch;]$(echo $(jq --raw-output .pull_request.head.ref "$GITHUB_EVENT_PATH"))" + id: extract_branch + - name: Delete PR head branch + uses: dawidd6/action-delete-branch@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ steps.extract_branch.outputs.branch }} + be_kind: true diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000000..c0752922b0 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,78 @@ +name: OpenOSRS - CI (PR) + +on: pull_request + +jobs: + pr-lint: + name: PR title + runs-on: ubuntu-latest + + steps: + - name: PR title lint + if: github.event_name == 'pull_request' + uses: seferov/pr-lint-action@master + with: + title-regex: '^([\w-/]+): \w+' + + build: + runs-on: ubuntu-latest + name: Build + + steps: + - uses: actions/checkout@v1 + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Assembling + run: ./gradlew assemble --console=plain + - name: Building + run: ./gradlew build --stacktrace -x test -x checkstyleMain --console=plain + + test: + runs-on: ubuntu-latest + name: Test + + steps: + - uses: actions/checkout@v1 + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Assembling + run: ./gradlew assemble --console=plain + - name: Testing + run: ./gradlew test --stacktrace --console=plain + + checkstyle: + name: Checkstyle + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Assembling + run: ./gradlew assemble --console=plain + - name: Checking code conventions + run: ./gradlew checkstyleMain --console=plain + + approve: + name: Approve + needs: [build, test, checkstyle] + runs-on: ubuntu-latest + + steps: + - name: Approve pull request + if: github.event_name == 'pull_request' && github.actor == 'OpenOSRS' + uses: hmarr/auto-approve-action@v2.0.0 + with: + github-token: ${{ secrets.Owain }} \ No newline at end of file diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000000..171230c2b1 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,67 @@ +name: OpenOSRS - CI (push) + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + name: Build + + steps: + - uses: actions/checkout@v1 + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Assembling + run: ./gradlew assemble --console=plain + - name: Building + run: ./gradlew build --stacktrace -x test -x checkstyleMain --console=plain + + test: + runs-on: ubuntu-latest + name: Test + + steps: + - uses: actions/checkout@v1 + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Assembling + run: ./gradlew assemble --console=plain + - name: Testing + run: ./gradlew test --stacktrace --console=plain + + checkstyle: + name: Checkstyle + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Assembling + run: ./gradlew assemble --console=plain + - name: Checking code conventions + run: ./gradlew checkstyleMain --console=plain + + update_draft_release: + name: Draft release + runs-on: ubuntu-latest + + steps: + - uses: toolmantim/release-drafter@v5.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/scraper.yml b/.github/workflows/scraper.yml index 62e7f738a2..17223979bf 100644 --- a/.github/workflows/scraper.yml +++ b/.github/workflows/scraper.yml @@ -9,9 +9,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v1 - name: Set up JDK 11 - uses: actions/setup-java@master + uses: actions/setup-java@v1 with: java-version: 11 - name: Make gradlew executable @@ -25,7 +25,7 @@ jobs: - name: Building scraper run: ./gradlew :wiki-scraper:build --console=plain - name: Downloading jagex cache - run: ./gradlew :cache-client:update --console=plain + run: ./gradlew :cache-client:download --console=plain - name: Scraping NPC stats run: ./gradlew :wiki-scraper:npcStatsScrape --console=plain - name: Create NPC stats Pull Request @@ -36,4 +36,4 @@ jobs: PULL_REQUEST_TITLE: 'Client: Update NPC stats' PULL_REQUEST_BODY: This is an auto-generated PR with changes from the OSRS wiki COMMIT_MESSAGE: 'Client: Update NPC stats' - PULL_REQUEST_LABELS: automated pull request, NPC stats + PULL_REQUEST_LABELS: automated-pull-request, NPC stats \ No newline at end of file diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f6ec51e2e4..31269fc102 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -19,4 +19,4 @@ jobs: exempt-issue-label: 'awaiting-approval' exempt-pr-label: 'awaiting-approval' days-before-stale: 60 - days-before-close: 30 + days-before-close: 30 \ No newline at end of file diff --git a/README.md b/README.md index 2d93718f4c..f287b3039c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # OpenOSRS -[![Build Status](https://github.com/open-osrs/runelite/workflows/OpenOSRS%20-%20CI/badge.svg)](https://github.com/open-osrs/runelite/actions) +[![Build Status](https://github.com/open-osrs/runelite/workflows/OpenOSRS%20-%20CI%20(push)/badge.svg)](https://github.com/open-osrs/runelite/actions?query=workflow%3A%22OpenOSRS+-+CI+%28push%29%22) [![HitCount](http://hits.dwyl.io/open-osrs/runelite.svg)](http://hits.dwyl.io/open-osrs/runelite) [OpenOSRS](https://openosrs.com) is an extended version of [RuneLite](https://github.com/runelite/runelite) that provides more functionality and less restrictions while staying more open-source. We are not affiliated with RuneLite. @@ -54,3 +54,7 @@ OpenOSRS is licensed under the BSD 2-clause license. See the license header in t ## Contribute and Develop We've set up a separate document for our [contribution guidelines](https://github.com/open-osrs/runelite/blob/master/.github/CONTRIBUTING.md). + +## Supported By + +OpenOSRS uses profiling tools provided by [![YourKit](https://www.yourkit.com/images/yklogo.png)](https://www.yourkit.com/java/profiler/) diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 535702c0a8..0000000000 --- a/build.gradle +++ /dev/null @@ -1,207 +0,0 @@ -import org.ajoberstar.grgit.Grgit - -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "org.ajoberstar.grgit:grgit-gradle:3.1.1" - } -} - -plugins { - id 'com.adarshr.test-logger' version '1.7.0' apply false - id "com.github.ben-manes.versions" version "0.22.0" - id "com.gradle.build-scan" version "2.4" - id 'se.patrikerdes.use-latest-versions' version '0.2.8' -} - -apply plugin: 'application' - -ext { - grgit = Grgit.open(dir: "${rootProject.projectDir}") - localGitCommit = grgit.head().id - localGitCommitShort = grgit.head().getAbbreviatedId(7) - localGitDirty = !grgit.status().clean - - // sets the minimum launcher version that is output for the bootstrapper - launcherVersion = '2.0.3' - - // Dependencies versions - annotations = '17.0.0' - antlr = '4.7.2' - apacheCommonsCompress = '1.19' - apacheCommonsCsv = '1.7' - apacheCommonsText = '1.8' - asm = '7.2' - commonsCli = '1.4' - discord = '1.1' - fernflower = '07082019' - findbugs = '3.0.2' - gson = '2.8.6' - guava = '28.1-jre' - guice = '4.2.2' - h2 = '1.4.200' - hamcrest = '2.2' - httpcore = '4.4.12' - httpmime = '4.5.10' - javassist = '3.26.0-GA' - javax = '1.3.2' - javaxInject = '1' - jbsdiff = '1.0' - jclCore = '2.8' - jedis = '3.1.0' - jfoenix = '9.0.9' - jna = '5.4.0' - jogamp = '2.3.2' - jopt = '5.0.4' - jooq = '3.12.1' - junit = '4.12' - jupiter = '5.5.2' - logback = '1.2.3' - lombok = '1.18.10' - mapstruct = '1.3.1.Final' - mariadbJdbc = '2.5.1' - mavenPluginAnnotations = '3.6.0' - mavenPluginApi = '3.6.2' - minio = '6.0.11' - mockito = '3.1.0' - mongodbDriverSync = '3.11.1' - mysqlConnectorJava = '8.0.18' - netty = '4.1.42.Final' - okhttp3 = '4.2.2' - orangeExtensions = '1.0' - petitparser = '2.2.0' - plexus = '3.3.0' - rxjava = '2.2.13' - rxrelay = '2.1.1' - scribejava = '6.9.0' - sisu = '0.3.3' - slf4j = '1.7.28' - springJdbc = '5.2.0.RELEASE' - springboot = '2.2.0.RELEASE' - sql2o = '1.6.0' - substance = '8.0.02' - trident = '1.5.00' -} - -allprojects { - apply plugin: 'maven' - if (this.name != 'rs-client') apply plugin: 'checkstyle' - - group = 'com.openosrs' - version = '1.5.37-SNAPSHOT' - - ext { - rsversion = 184 - cacheversion = 165 - plusVersion = '2.1.8.0' - - gitCommit = localGitCommit - gitCommitShort = localGitCommitShort - gitDirty = localGitDirty - - - rootPath = rootDir.toString().replace('\\', '/') - injectedClassesPath = rootPath + "/injector-plugin/out/injected-client/" - } -} - -subprojects { - apply plugin: 'com.adarshr.test-logger' - apply plugin: 'java-library' - apply plugin: 'maven' - apply plugin: 'fernflower' - apply plugin: 'maven-publish' - - sourceCompatibility = 1.8 - targetCompatibility = 1.8 - - tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' - } - - tasks.withType(GroovyCompile).configureEach { - options.incremental = true - } - - publishing { - repositories { - maven { - name = "runelite" - url = uri("https://maven.pkg.github.com/open-osrs/runelite") - credentials { - username = System.getProperty("gpr_user") - password = System.getProperty("gpr_key") - } - } - } - publications { - gpr(MavenPublication) { - from(components.java) - } - } - } - - repositories { - mavenLocal() - - maven { url "http://repo1.maven.org/maven2" } - maven { url "http://repo.runelite.net" } - maven { url "http://repo.maven.apache.org/maven2" } - maven { url "https://raw.githubusercontent.com/open-osrs/hosting/master" } - - if (System.getenv("NEXUS-URL") != null) { - maven { url System.getenv("NEXUS-URL") } - } - } - - checkstyle { - toolVersion = '6.4.1' - sourceSets = [sourceSets.main] - configFile = file("${rootDir}/checkstyle/checkstyle.xml") - configProperties = [ "suppressionFile" : file("${rootDir}/checkstyle/suppressions.xml")] - showViolations = true - ignoreFailures = false - maxWarnings = 0 - } - -} - - -wrapper { - gradleVersion = '5.6.2' - - doLast { - def optsEnvVar = "DEFAULT_JVM_OPTS" - scriptFile.write scriptFile.text.replace("$optsEnvVar='\"-Xmx64m\" \"-Xms64m\"'", "$optsEnvVar='\"-Xmx4g\" \"-Xms2g\" \"-Dfile.encoding=UTF-8\"'") - batchScript.write batchScript.text.replace("set $optsEnvVar=\"-Xmx64m\" \"-Xms64m\"", "set $optsEnvVar=\"-Xmx4g\" \"-Xms2g\" \"-Dfile.encoding=UTF-8\"") - } -} - -run { - classpath = childProjects.client.sourceSets.main.runtimeClasspath - mainClassName = "net.runelite.client.RuneLite" -} - -def isNonStable = { String version -> - def unstableKeyword = ['ALPHA', 'BETA', 'RC'].any { it -> version.toUpperCase().contains(it) } - - return unstableKeyword -} - -dependencyUpdates { - checkForGradleUpdate = false - - resolutionStrategy { - componentSelection { - all { - if (isNonStable(candidate.version)) { - reject() - } - } - } - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000000..756b3de89f --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2019 Owain van Brakel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask +import org.ajoberstar.grgit.Grgit + +buildscript { + repositories { + maven(url = "https://plugins.gradle.org/m2/") + maven(url = "https://raw.githubusercontent.com/open-osrs/hosting/master") + mavenLocal() + } + dependencies { + classpath(Plugins.grgitPlugin) + classpath(Plugins.versionsPlugin) + classpath(Plugins.injectorPlugin) + } +} + +plugins { + id(Plugins.testLogger.first) version Plugins.testLogger.second apply false + id(Plugins.versions.first) version Plugins.versions.second + id(Plugins.buildScan.first) version Plugins.buildScan.second + id(Plugins.latestVersion.first) version Plugins.latestVersion.second + id(Plugins.grgit.first) version Plugins.grgit.second + + application +} + +val grgit = Grgit.open(mapOf("dir" to rootProject.projectDir.absolutePath)) +val localGitCommit = grgit.head().id +val localGitCommitShort = grgit.head().getAbbreviatedId(7) + +fun isNonStable(version: String): Boolean { + return listOf("ALPHA", "BETA", "RC").any { + version.toUpperCase().contains(it) + } +} + +allprojects { + apply() + apply() + apply() + + group = "com.openosrs" + version = ProjectVersions.rlVersion + + project.extra["gitCommit"] = localGitCommit + project.extra["gitCommitShort"] = localGitCommitShort + + project.extra["rootPath"] = rootDir.toString().replace("\\", "/") +} + +subprojects { + apply(plugin = Plugins.testLogger.first) + + if (this.name != "runescape-client") { + apply(plugin = "checkstyle") + configure { + sourceSets = setOf(project.sourceSets.main.get()) + configFile = file("${rootDir}/checkstyle/checkstyle.xml") + configProperties = mapOf("suppressionFile" to file("${rootDir}/checkstyle/suppressions.xml")) + maxWarnings = 0 + toolVersion = "6.4.1" + isShowViolations = true + isIgnoreFailures = false + } + } + + repositories { + mavenLocal() + + maven(url = "http://repo1.maven.org/maven2") + maven(url = "http://repo.runelite.net") + maven(url = "http://repo.maven.apache.org/maven2") + maven(url = "https://raw.githubusercontent.com/open-osrs/hosting/master") + + if (System.getenv("NEXUS-URL") != null) { + maven(url = System.getenv("NEXUS-URL")) + } + } + + configure { + repositories { + maven { + name = "runelite" + url = uri("https://maven.pkg.github.com/open-osrs/runelite") + credentials { + username = System.getProperty("gpr_user") + password = System.getProperty("gpr_key") + } + } + } + publications { + register("gpr", MavenPublication::class) { + from(components["java"]) + } + } + } + + tasks { + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + withType { + options.encoding = "UTF-8" + } + } +} + +application { + mainClassName = "net.runelite.client.RuneLite" +} + +tasks { + named("run") { + classpath = project(":runelite-client").sourceSets.main.get().runtimeClasspath + } + + named("dependencyUpdates") { + checkForGradleUpdate = false + + resolutionStrategy { + componentSelection { + all { + if (candidate.displayName.contains("fernflower") || isNonStable(candidate.version)) { + reject("Non stable") + } + } + } + } + } +} \ No newline at end of file diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle deleted file mode 100644 index 313b14ce5c..0000000000 --- a/buildSrc/build.gradle +++ /dev/null @@ -1,7 +0,0 @@ -repositories { - maven { url "https://raw.githubusercontent.com/open-osrs/hosting/master" } -} -dependencies { - compile localGroovy() - implementation group: 'net.runelite', name: 'fernflower', version: '07082019' -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000000..00e689a37d --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Owain van Brakel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() + maven(url = "https://raw.githubusercontent.com/open-osrs/hosting/master") +} + +dependencies { + implementation(gradleApi()) + implementation(group = "net.runelite", name = "fernflower", version = "07082019") + implementation(group = "org.json", name = "json", version = "20190722") +} + +kotlinDslPluginOptions { + experimentalWarning.set(false) +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/FernflowerPlugin.groovy b/buildSrc/src/main/groovy/FernflowerPlugin.groovy deleted file mode 100644 index 062adced78..0000000000 --- a/buildSrc/src/main/groovy/FernflowerPlugin.groovy +++ /dev/null @@ -1,16 +0,0 @@ -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.StopExecutionException - -class FernflowerPlugin implements Plugin { - void apply(Project project) { - project.task('decompile', type: FernflowerTask) { - it.dependsOn(project.tasks.jar) - it.doFirst { - if (!project.tasks.jar.didWork) { - throw new StopExecutionException() - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/FernflowerTask.groovy b/buildSrc/src/main/groovy/FernflowerTask.groovy deleted file mode 100644 index 49e46b5639..0000000000 --- a/buildSrc/src/main/groovy/FernflowerTask.groovy +++ /dev/null @@ -1,32 +0,0 @@ -import org.gradle.api.DefaultTask -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction -import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler - -class FernflowerTask extends DefaultTask { - List extraArgs - String inputJar - String outputDir - - @InputFile - File getInputJar() { - project.file(inputJar ?: project.buildDir.toString() + '/libs/' + project.getName() + '-' + project.version + '.jar') - } - - @OutputDirectory - File getOutputDir() { - project.file(outputDir ?: project.buildDir.toString() + '/decompiled-sources') - } - - @TaskAction - void decompile() { - getOutputDir().mkdirs() - def args = [getInputJar().toString(), getOutputDir().toString()] - if (extraArgs) { - args.addAll(extraArgs) - } - - ConsoleDecompiler.main(args as String[]) - } -} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/BootstrapPlugin.kt b/buildSrc/src/main/kotlin/BootstrapPlugin.kt new file mode 100644 index 0000000000..ff90211c7f --- /dev/null +++ b/buildSrc/src/main/kotlin/BootstrapPlugin.kt @@ -0,0 +1,87 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.register +import java.io.File + +class BootstrapPlugin : Plugin { + override fun apply(project: Project) { + project.tasks.register("bootstrapStaging") { + dependsOn("jar") + dependsOn("shadowJar") + + type = "staging" + clientJar = project.tasks["jar"].outputs.files.singleFile + + dependsOn(project.parent!!.project(":runelite-api").tasks["jar"]) + dependsOn(project.parent!!.project(":runescape-api").tasks["jar"]) + dependsOn(project.parent!!.project(":http-api").tasks["jar"]) + dependsOn(project.parent!!.project(":injected-client").tasks["jar"]) + + doLast { + + project.copy { + from(project.tasks["jar"]) + from(project.parent!!.project(":runelite-api").tasks["jar"]) + from(project.parent!!.project(":runescape-api").tasks["jar"]) + from(project.parent!!.project(":http-api").tasks["jar"]) + from(project.parent!!.project(":injected-client").tasks["jar"]) + + into("${project.buildDir}/bootstrap/${type}/") + } + } + } + + project.tasks.register("bootstrapStable") { + dependsOn("jar") + dependsOn("shadowJar") + + type = "stable" + clientJar = project.tasks["jar"].outputs.files.singleFile + + dependsOn(project.parent!!.project(":runelite-api").tasks["jar"]) + dependsOn(project.parent!!.project(":runescape-api").tasks["jar"]) + dependsOn(project.parent!!.project(":http-api").tasks["jar"]) + dependsOn(project.parent!!.project(":injected-client").tasks["jar"]) + + doLast { + + project.copy { + from(project.tasks["jar"]) + from(project.parent!!.project(":runelite-api").tasks["jar"]) + from(project.parent!!.project(":runescape-api").tasks["jar"]) + from(project.parent!!.project(":http-api").tasks["jar"]) + from(project.parent!!.project(":injected-client").tasks["jar"]) + + into("${project.buildDir}/bootstrap/${type}/") + } + } + } + + project.tasks.register("bootstrapNightly") { + dependsOn("jar") + dependsOn("shadowJar") + + type = "nightly" + clientJar = project.tasks["jar"].outputs.files.singleFile + + dependsOn(project.parent!!.project(":runelite-api").tasks["jar"]) + dependsOn(project.parent!!.project(":runescape-api").tasks["jar"]) + dependsOn(project.parent!!.project(":http-api").tasks["jar"]) + dependsOn(project.parent!!.project(":injected-client").tasks["jar"]) + + doLast { + + project.copy { + from(project.tasks["jar"]) + from(project.parent!!.project(":runelite-api").tasks["jar"]) + from(project.parent!!.project(":runescape-api").tasks["jar"]) + from(project.parent!!.project(":http-api").tasks["jar"]) + from(project.parent!!.project(":injected-client").tasks["jar"]) + + into("${project.buildDir}/bootstrap/${type}/") + } + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/BootstrapTask.kt b/buildSrc/src/main/kotlin/BootstrapTask.kt new file mode 100644 index 0000000000..a6e0652cea --- /dev/null +++ b/buildSrc/src/main/kotlin/BootstrapTask.kt @@ -0,0 +1,106 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.extra +import org.gradle.kotlin.dsl.get +import java.io.File +import java.security.MessageDigest + +open class BootstrapTask : DefaultTask() { + + @Input + @Optional + var type: String? = "stable" + + @InputFile + @PathSensitive(PathSensitivity.ABSOLUTE) + var clientJar: File? = null + + @Input + val launcherJvm11Arguments = arrayOf("-XX:+DisableAttachMechanism", "-Drunelite.launcher.nojvm=true", "-Xmx512m", "-Xss2m", "-XX:CompileThreshold=1500", "-Djna.nosys=true") + + @Input + val launcherArguments = arrayOf("-XX:+DisableAttachMechanism", "-Drunelite.launcher.nojvm=true", "-Xmx512m", "-Xss2m", "-XX:CompileThreshold=1500", "-Xincgc", "-XX:+UseConcMarkSweepGC", "-XX:+UseParNewGC", "-Djna.nosys=true") + + @Input + val clientJvmArguments = arrayOf("-XX:+DisableAttachMechanism", "-Xmx512m", "-Xss2m", "-XX:CompileThreshold=1500", "-Xincgc", "-XX:+UseConcMarkSweepGC", "-XX:+UseParNewGC", "-Djna.nosys=true") + + @Input + val clientJvm9Arguments = arrayOf("-XX:+DisableAttachMechanism", "-Xmx512m", "-Xss2m", "-XX:CompileThreshold=1500", "-Djna.nosys=true") + + private fun hash(file: ByteArray): String { + return MessageDigest.getInstance("SHA-256").digest(file).fold("", { str, it -> str + "%02x".format(it) }) + } + + private fun getArtifacts(): Array { + val artifacts = ArrayList() + + project.configurations["runtimeClasspath"].resolvedConfiguration.resolvedArtifacts.forEach { + val module = it.moduleVersion.id.toString() + + val name = module.split(":")[1] + val group = module.split(":")[0] + val version = module.split(":")[2] + var path = "" + + if (it.file.name.contains(ProjectVersions.rlVersion)) { + path = "https://github.com/open-osrs/hosting/raw/master/${type}/${it.file.name}" + } else if (!group.contains("runelite")) { + path = "https://repo.maven.apache.org/maven2/" + group.replace(".", "/") + "/${name}/$version/${name}-$version" + if (it.classifier != null && it.classifier != "no_aop") { + path += "-${it.classifier}" + } + path += ".jar" + } else if (it.file.name.contains("trident") || it.file.name.contains("discord") || it.file.name.contains("substance")) { + path = "https://repo.runelite.net/net/runelite/" + if (!it.file.name.contains("discord")) { + path += "pushingpixels/" + } + path += "${name}/$version/${name}-$version.jar" + } + + val artifactFile = File(it.file.absolutePath) + + artifacts.add(JsonBuilder( + "name" to it.file.name, + "path" to path, + "size" to artifactFile.length(), + "hash" to hash(artifactFile.readBytes()) + )) + } + + artifacts.add(JsonBuilder( + "name" to clientJar!!.name, + "path" to "https://github.com/open-osrs/hosting/raw/master/${type}/${clientJar!!.name}", + "size" to clientJar!!.length(), + "hash" to hash(clientJar!!.readBytes()) + )) + + return artifacts.toTypedArray() + } + + @TaskAction + fun boostrap() { + val json = JsonBuilder( + "projectVersion" to ProjectVersions.openosrsVersion, + "minimumLauncherVersion" to ProjectVersions.launcherVersion, + "launcherJvm11Arguments" to launcherJvm11Arguments, + "launcherArguments" to launcherArguments, + "clientJvmArguments" to clientJvmArguments, + "clientJvm9Arguments" to clientJvm9Arguments, + "buildCommit" to project.extra["gitCommit"], + "artifacts" to getArtifacts() + ).toString() + + val bootstrapDir = File("${project.buildDir}/bootstrap") + bootstrapDir.mkdirs() + + File(bootstrapDir, "bootstrap-${type}.json").printWriter().use { out -> + out.println(json) + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt new file mode 100644 index 0000000000..9dc9cc341a --- /dev/null +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2019 Owain van Brakel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +const val kotlinVersion = "1.3.50" + +object ProjectVersions { + const val launcherVersion = "2.0.4" + const val rlVersion = "1.5.39-SNAPSHOT" + + const val openosrsVersion = "2.1.9.1" + + const val rsversion = 185 + const val cacheversion = 165 +} + +object Plugins { + val grgitPlugin = "org.ajoberstar:grgit:2.3.0" + val versionsPlugin = "com.github.ben-manes:gradle-versions-plugin:0.27.0" + val injectorPlugin = "com.openosrs:injector-plugin:1.0.2" + val testLogger = Pair("com.adarshr.test-logger", "2.0.0") + val versions = Pair("com.github.ben-manes.versions", "0.27.0") + val buildScan = Pair("com.gradle.build-scan", "3.0") + val latestVersion = Pair("se.patrikerdes.use-latest-versions", "0.2.12") + val grgit = Pair("org.ajoberstar.grgit", "4.0.0-rc.1") + val jarTest = Pair("com.github.hauner.jarTest", "1.0.1") + val shadow = Pair("com.github.johnrengelman.shadow", "5.1.0") +} + +object Libraries { + private object Versions { + const val annotations = "17.0.0" + const val antlr = "4.7.2" + const val apacheCommonsCompress = "1.19" + const val apacheCommonsCsv = "1.7" + const val apacheCommonsText = "1.8" + const val asm = "7.2" + const val commonsCli = "1.4" + const val discord = "1.1" + const val fernflower = "07082019" + const val findbugs = "3.0.2" + const val gson = "2.8.6" + const val guava = "28.1-jre" + const val guice = "4.2.2" + const val h2 = "1.4.200" + const val hamcrest = "2.2" + const val httpcore = "4.4.12" + const val httpmime = "4.5.10" + const val javassist = "3.26.0-GA" + const val javax = "1.3.2" + const val javaxInject = "1" + const val jbsdiff = "1.0" + const val jclCore = "2.8" + const val jedis = "3.1.0" + const val jna = "5.4.0" + const val jogamp = "2.3.2" + const val jopt = "5.0.4" + const val jooq = "3.12.2" + const val junit = "4.12" + const val jupiter = "5.6.0-M1" + const val logback = "1.2.3" + const val lombok = "1.18.10" + const val mapstruct = "1.3.1.Final" + const val mariadbJdbc = "2.5.1" + const val mavenPluginAnnotations = "3.6.0" + const val mavenPluginApi = "3.6.2" + const val minio = "6.0.11" + const val mockito = "3.1.0" + const val mongodbDriverSync = "3.11.1" + const val mysqlConnectorJava = "8.0.18" + const val naturalMouse = "2.0.2" + const val netty = "4.1.42.Final" + const val okhttp3 = "4.2.2" + const val orangeExtensions = "1.0" + const val petitparser = "2.2.0" + const val plexus = "3.3.0" + const val rxjava = "2.2.13" + const val rxrelay = "2.1.1" + const val scribejava = "6.9.0" + const val sisu = "0.3.3" + const val slf4j = "1.7.28" + const val springJdbc = "5.2.0.RELEASE" + const val springboot = "2.2.0.RELEASE" + const val sql2o = "1.6.0" + const val substance = "8.0.02" + const val trident = "1.5.00" + } + + const val annotations = "org.jetbrains:annotations:${Versions.annotations}" + const val antlr = "org.antlr:antlr4-runtime:${Versions.antlr}" + const val apacheCommonsCompress = "org.apache.commons:commons-compress:${Versions.apacheCommonsCompress}" + const val apacheCommonsCsv = "org.apache.commons:commons-csv:${Versions.apacheCommonsCsv}" + const val apacheCommonsText = "org.apache.commons:commons-text:${Versions.apacheCommonsText}" + const val asmAll = "org.ow2.asm:asm:${Versions.asm}" + const val asmUtil = "org.ow2.asm:asm-util:${Versions.asm}" + const val asmTree = "org.ow2.asm:asm-tree:${Versions.asm}" + const val commonsCli = "commons-cli:commons-cli:${Versions.commonsCli}" + const val discord = "net.runelite:discord:${Versions.discord}" + const val fernflower = "net.runelite:fernflower:${Versions.fernflower}" + const val findbugs = "com.google.code.findbugs:jsr305:${Versions.findbugs}" + const val gson = "com.google.code.gson:gson:${Versions.gson}" + const val guava = "com.google.guava:guava:${Versions.guava}" + const val guice = "com.google.inject:guice:${Versions.guice}:no_aop" + const val guiceGrapher = "com.google.inject.extensions:guice-grapher:${Versions.guice}" + const val guiceTestlib = "com.google.inject.extensions:guice-testlib:${Versions.guice}" + const val h2 = "com.h2database:h2:${Versions.h2}" + const val hamcrest = "org.hamcrest:hamcrest-library:${Versions.hamcrest}" + const val httpcore = "org.apache.httpcomponents:httpcore:${Versions.httpcore}" + const val httpmime = "org.apache.httpcomponents:httpmime:${Versions.httpmime}" + const val javassist = "org.javassist:javassist:${Versions.javassist}" + const val javax = "javax.annotation:javax.annotation-api:${Versions.javax}" + const val javaxInject = "javax.inject:javax.inject:${Versions.javaxInject}" + const val jbsdiff = "io.sigpipe:jbsdiff:${Versions.jbsdiff}" + const val jclCore = "org.xeustechnologies:jcl-core:${Versions.jclCore}" + const val jedis = "redis.clients:jedis:${Versions.jedis}" + const val jna = "net.java.dev.jna:jna:${Versions.jna}" + const val jnaPlatform = "net.java.dev.jna:jna-platform:${Versions.jna}" + const val jogampJogl = "org.jogamp.jogl:jogl-all:${Versions.jogamp}" + const val jogampGluegen = "org.jogamp.gluegen:gluegen-rt:${Versions.jogamp}" + const val jogampGluegenLinuxAmd64 = "org.jogamp.gluegen:gluegen-rt:${Versions.jogamp}:natives-linux-amd64" + const val jogampGluegenLinuxI586 = "org.jogamp.gluegen:gluegen-rt:${Versions.jogamp}:natives-linux-i586" + const val jogampGluegenWindowsAmd64 = "org.jogamp.gluegen:gluegen-rt:${Versions.jogamp}:natives-windows-amd64" + const val jogampGluegenWindowsI586 = "org.jogamp.gluegen:gluegen-rt:${Versions.jogamp}:natives-windows-i586" + const val jogampJoglLinuxAmd64 = "org.jogamp.jogl:jogl-all:${Versions.jogamp}:natives-linux-amd64" + const val jogampJoglLinuxI586 = "org.jogamp.jogl:jogl-all:${Versions.jogamp}:natives-linux-i586" + const val jogampJoglWindowsAmd64 = "org.jogamp.jogl:jogl-all:${Versions.jogamp}:natives-windows-amd64" + const val jogampJoglWindowsI586 = "org.jogamp.jogl:jogl-all:${Versions.jogamp}:natives-windows-i586" + const val jopt = "net.sf.jopt-simple:jopt-simple:${Versions.jopt}" + const val jooq = "org.jooq:jooq:${Versions.jooq}" + const val jooqCodegen = "org.jooq:jooq-codegen:${Versions.jooq}" + const val jooqMeta = "org.jooq:jooq-meta:${Versions.jooq}" + const val junit = "junit:junit:${Versions.junit}" + const val jupiter = "org.junit.jupiter:junit-jupiter-api:${Versions.jupiter}" + const val logback = "ch.qos.logback:logback-classic:${Versions.logback}" + const val lombok = "org.projectlombok:lombok:${Versions.lombok}" + const val mapstruct = "org.mapstruct:mapstruct-jdk8:${Versions.mapstruct}" + const val mapstructProcessor = "org.mapstruct:mapstruct-processor:${Versions.mapstruct}" + const val mariadbJdbc = "org.mariadb.jdbc:mariadb-java-client:${Versions.mariadbJdbc}" + const val mavenPluginAnnotations = "org.apache.maven.plugin-tools:maven-plugin-annotations:${Versions.mavenPluginAnnotations}" + const val mavenPluginApi = "org.apache.maven:maven-plugin-api:${Versions.mavenPluginApi}" + const val minio = "io.minio:minio:${Versions.minio}" + const val mockitoCore = "org.mockito:mockito-core:${Versions.mockito}" + const val mockitoInline = "org.mockito:mockito-inline:${Versions.mockito}" + const val mongodbDriverSync = "org.mongodb:mongodb-driver-sync:${Versions.mongodbDriverSync}" + const val mysqlConnectorJava = "mysql:mysql-connector-java:${Versions.mysqlConnectorJava}" + const val naturalMouse = "com.github.joonasvali.naturalmouse:naturalmouse:${Versions.naturalMouse}" + const val nettyAll = "io.netty:netty-all:${Versions.netty}" + const val nettyBuffer = "io.netty:netty-buffer:${Versions.netty}" + const val okhttp3 = "com.squareup.okhttp3:okhttp:${Versions.okhttp3}" + const val okhttp3Webserver = "com.squareup.okhttp3:mockwebserver:${Versions.okhttp3}" + const val orangeExtensions = "net.runelite:orange-extensions:${Versions.orangeExtensions}" + const val petitparser = "com.github.petitparser:java-petitparser:${Versions.petitparser}" + const val plexus = "org.codehaus.plexus:plexus-utils:${Versions.plexus}" + const val rxjava = "io.reactivex.rxjava2:rxjava:${Versions.rxjava}" + const val rxrelay = "com.jakewharton.rxrelay2:rxrelay:${Versions.rxrelay}" + const val scribejava = "com.github.scribejava:scribejava-apis:${Versions.scribejava}" + const val sisu = "org.eclipse.sisu:org.eclipse.sisu.inject:${Versions.sisu}" + const val slf4jApi = "org.slf4j:slf4j-api:${Versions.slf4j}" + const val slf4jNop = "org.slf4j:slf4j-nop:${Versions.slf4j}" + const val slf4jSimple = "org.slf4j:slf4j-simple:${Versions.slf4j}" + const val springbootDevtools = "org.springframework.boot:spring-boot-devtools:${Versions.springboot}" + const val springbootStarter = "org.springframework.boot:spring-boot-starter:${Versions.springboot}" + const val springbootStarterWeb = "org.springframework.boot:spring-boot-starter-web:${Versions.springboot}" + const val springbootStarterJdbc = "org.springframework.boot:spring-boot-starter-jdbc:${Versions.springboot}" + const val springbootStarterTest = "org.springframework.boot:spring-boot-starter-test:${Versions.springboot}" + const val springbootStarterTomcat = "org.springframework.boot:spring-boot-starter-tomcat:${Versions.springboot}" + const val springbootJdbc = "org.springframework:spring-jdbc:${Versions.springJdbc}" + const val sql2o = "org.sql2o:sql2o:${Versions.sql2o}" + const val substance = "net.runelite.pushingpixels:substance:${Versions.substance}" + const val trident = "net.runelite.pushingpixels:trident:${Versions.trident}" + const val vanilla = "net.runelite.rs:vanilla:${ProjectVersions.rsversion}" +} diff --git a/buildSrc/src/main/kotlin/FernflowerPlugin.kt b/buildSrc/src/main/kotlin/FernflowerPlugin.kt new file mode 100644 index 0000000000..d1cf9ebb94 --- /dev/null +++ b/buildSrc/src/main/kotlin/FernflowerPlugin.kt @@ -0,0 +1,19 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.StopExecutionException +import org.gradle.api.tasks.diagnostics.DependencyReportTask +import org.gradle.kotlin.dsl.register + +class FernflowerPlugin : Plugin { + override fun apply(project: Project) { + project.tasks.register("decompile") { + dependsOn(project.tasks.getByName("jar")) + + doFirst { + if (!project.tasks.getByName("jar").didWork) { + throw StopExecutionException() + } + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/FernflowerTask.kt b/buildSrc/src/main/kotlin/FernflowerTask.kt new file mode 100644 index 0000000000..cdf76679c8 --- /dev/null +++ b/buildSrc/src/main/kotlin/FernflowerTask.kt @@ -0,0 +1,45 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity +import org.gradle.api.tasks.TaskAction +import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler + +@CacheableTask +open class FernflowerTask: DefaultTask() { + + @Input + @Optional + var extraArgs: List? = null + + @Input + @Optional + var inputJar: String? = null + + @Input + @Optional + var outputDir: String? = null + + @InputFile + @PathSensitive(PathSensitivity.ABSOLUTE) + var getInputJar = project.file(inputJar ?: "${project.buildDir}/libs/${project.name}-${project.version}.jar") + + @OutputDirectory + var getOutputDir = project.file(outputDir ?: "${project.buildDir}/decompiled-sources") + + + @TaskAction + fun decompile() { + getOutputDir.mkdirs() + val args = mutableListOf(getInputJar.toString(), getOutputDir.toString()) + if (extraArgs != null) { + args.addAll(extraArgs!!) + } + + ConsoleDecompiler.main(args.toTypedArray()) + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/JsonBuilder.kt b/buildSrc/src/main/kotlin/JsonBuilder.kt new file mode 100644 index 0000000000..51a90ade36 --- /dev/null +++ b/buildSrc/src/main/kotlin/JsonBuilder.kt @@ -0,0 +1,55 @@ +import org.json.JSONArray +import org.json.JSONObject + +class JsonBuilder() { + private var json = JSONObject() + + constructor(vararg pairs: Pair) : this() { + add(*pairs) + } + + fun add(vararg pairs: Pair) { + for ((key, value) in pairs) { + when (value) { + is Boolean -> json.put(key, value) + is Number -> add(key, value) + is String -> json.put(key, value) + is JsonBuilder -> json.put(key, value.json) + is Array<*> -> add(key, value) + is JSONObject -> json.put(key, value) + is JSONArray -> json.put(key, value) + } + } + } + + fun add(key: String, value: Number): JsonBuilder { + when (value) { + is Int -> json.put(key, value) + is Long -> json.put(key, value) + is Float -> json.put(key, value) + is Double -> json.put(key, value) + else -> {} + } + + return this + } + + fun add(key: String, items: Array): JsonBuilder { + val jsonArray = JSONArray() + items.forEach { + when (it) { + is String,is Long,is Int, is Boolean -> jsonArray.put(it) + is JsonBuilder -> jsonArray.put(it.json) + else -> try {jsonArray.put(it)} catch (ignored:Exception) { + + } + } + } + + json.put(key, jsonArray) + + return this + } + + override fun toString() = json.toString() +} \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/fernflower.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/fernflower.properties deleted file mode 100644 index 3d922df9d7..0000000000 --- a/buildSrc/src/main/resources/META-INF/gradle-plugins/fernflower.properties +++ /dev/null @@ -1 +0,0 @@ -implementation-class=FernflowerPlugin \ No newline at end of file diff --git a/cache-client/build.gradle b/cache-client/build.gradle deleted file mode 100644 index feed79e98e..0000000000 --- a/cache-client/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -description = 'Cache Client' - -dependencies { - api project(':cache') - api project(':protocol') - - implementation group: 'com.google.guava', name: 'guava', version: guava - implementation group: 'io.netty', name: 'netty-all', version: netty - implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j - - testImplementation group: 'junit', name: 'junit', version: junit - testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: slf4j - testImplementation project(path: ':cache', configuration: 'testArchives') -} - -task update { - dependsOn ":cache-client:build" - - doLast { - def path = sourceSets.main.runtimeClasspath - def loader = new URLClassLoader(path.collect { f -> f.toURI().toURL() } as URL[]) - def cacheClient = loader.loadClass('net.runelite.cache.client.CacheClient') - - cacheClient.getCache(rsversion); - - loader.close() - } -} diff --git a/injected-client/build.gradle b/cache-client/cache-client.gradle.kts similarity index 65% rename from injected-client/build.gradle rename to cache-client/cache-client.gradle.kts index e0810e7bad..794a19ab8e 100644 --- a/injected-client/build.gradle +++ b/cache-client/cache-client.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 ThatGamerBlue + * Copyright (c) 2019 Owain van Brakel * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,28 +22,28 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -description = 'Injected Client' -compileJava { - dependsOn ':injector-plugin:assemble' +description = "Cache Client" + +dependencies { + api(project(":cache")) + api(project(":protocol")) + + implementation(Libraries.guava) + implementation(Libraries.nettyAll) + implementation(Libraries.slf4jApi) + + testImplementation(Libraries.junit) + testImplementation(Libraries.slf4jSimple) + testImplementation(project(path = ":cache", configuration = "testArchives")) } -compileJava.outputs.upToDateWhen { false } +tasks { + register("download") { + dependsOn(":cache-client:build") -compileJava.doLast() { - copy { - File f = file("build/classes/java/main") - f.deleteDir() - f.mkdirs() - from ("${injectedClassesPath}") - into ("build/classes/java/main") + classpath = project.sourceSets.main.get().runtimeClasspath + main = "net.runelite.cache.client.CacheClient" + args(listOf(ProjectVersions.rsversion)) } } - -classes.doLast() { - File f = file("build/classes/java/main/Placeholder.class") - f.delete() -} - -// tasks.build.dependsOn(tasks.decompile) -// this is just here to show how this could be used \ No newline at end of file diff --git a/cache-client/src/main/java/net/runelite/cache/client/CacheClient.java b/cache-client/src/main/java/net/runelite/cache/client/CacheClient.java index a8afe8b82d..956905f539 100644 --- a/cache-client/src/main/java/net/runelite/cache/client/CacheClient.java +++ b/cache-client/src/main/java/net/runelite/cache/client/CacheClient.java @@ -85,7 +85,7 @@ public class CacheClient implements AutoCloseable private CompletableFuture handshakeFuture; private final Queue requests = new ArrayDeque<>(); - public static void getCache(int clientRevision) + public static void main(String[] args) { Path path = Paths.get(System.getProperty("user.home"), "jagexcache" + File.separator + "oldschool" + File.separator + "LIVE"); final File jagexcache = new File(String.valueOf(path)); @@ -95,7 +95,7 @@ public class CacheClient implements AutoCloseable try (Store store = new Store(jagexcache)) { store.load(); - CacheClient c = new CacheClient(store, clientRevision); + CacheClient c = new CacheClient(store, Integer.parseInt(args[0])); c.connect(); CompletableFuture handshake = c.handshake(); handshake.get(); diff --git a/cache-updater/build.gradle b/cache-updater/build.gradle deleted file mode 100644 index ec821898e7..0000000000 --- a/cache-updater/build.gradle +++ /dev/null @@ -1,15 +0,0 @@ -description = 'Cache Updater' - -dependencies { - annotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok - - compileOnly group: 'org.projectlombok', name: 'lombok', version: lombok - - implementation group: 'io.minio', name: 'minio', version: minio - implementation group: 'mysql', name: 'mysql-connector-java', version: mysqlConnectorJava - implementation group: 'org.springframework.boot', name: 'spring-boot-devtools', version: springboot - implementation group: 'org.springframework.boot', name: 'spring-boot-starter', version: springboot - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc', version: springboot - implementation group: 'org.sql2o', name: 'sql2o', version: sql2o - implementation project(':cache-client') -} diff --git a/cache-updater/cache-updater.gradle.kts b/cache-updater/cache-updater.gradle.kts new file mode 100644 index 0000000000..2007258401 --- /dev/null +++ b/cache-updater/cache-updater.gradle.kts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Owain van Brakel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +description = "Cache Updater" + +dependencies { + annotationProcessor(Libraries.lombok) + + compileOnly(Libraries.lombok) + + implementation(Libraries.minio) + implementation(Libraries.mysqlConnectorJava) + implementation(Libraries.springbootDevtools) + implementation(Libraries.springbootStarter) + implementation(Libraries.springbootStarterJdbc) + implementation(Libraries.sql2o) + implementation(project(":cache-client")) +} diff --git a/cache/build.gradle b/cache/build.gradle deleted file mode 100644 index 3221972040..0000000000 --- a/cache/build.gradle +++ /dev/null @@ -1,36 +0,0 @@ -import org.apache.tools.ant.filters.ReplaceTokens - -plugins { - id "com.github.hauner.jarTest" version "1.0.1" -} - -description = 'Cache' - -dependencies { - annotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok - - api project(':http-api') - - compileOnly group: 'org.projectlombok', name: 'lombok', version: lombok - - implementation group: 'com.google.code.gson', name: 'gson', version: gson - implementation group: 'com.google.guava', name: 'guava', version: guava - implementation group: 'commons-cli', name: 'commons-cli', version: commonsCli - implementation group: 'io.netty', name: 'netty-buffer', version: netty - implementation group: 'org.antlr', name: 'antlr4-runtime', version: antlr - implementation group: 'org.apache.commons', name: 'commons-compress', version: apacheCommonsCompress - implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j - - testImplementation group: 'junit', name: 'junit', version: junit - testImplementation group: 'net.runelite.rs', name: 'cache', version: cacheversion - testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: slf4j -} - -processTestResources { - from file("src/test/resources/cache.properties"), { - filter(ReplaceTokens, tokens: [ - "rs.version": rsversion.toString(), - "cache.version": cacheversion.toString() - ]) - } -} diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassAnnotationVisitor.java b/cache/cache.gradle.kts similarity index 51% rename from deobfuscator/src/main/java/net/runelite/asm/visitors/ClassAnnotationVisitor.java rename to cache/cache.gradle.kts index f9f62fc82a..e85a59a7d8 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassAnnotationVisitor.java +++ b/cache/cache.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Adam + * Copyright (c) 2019 Owain van Brakel * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,46 +23,47 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.asm.visitors; +import org.apache.tools.ant.filters.ReplaceTokens -import net.runelite.asm.ClassFile; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.annotation.Element; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Opcodes; - -public class ClassAnnotationVisitor extends AnnotationVisitor -{ - private final ClassFile classFile; - private final Type type; - private final Annotation annotation; - - public ClassAnnotationVisitor(ClassFile classFile, Type type) - { - super(Opcodes.ASM5); - - this.classFile = classFile; - this.type = type; - - annotation = new Annotation(classFile.getAnnotations()); - annotation.setType(type); - } - - @Override - public void visit(String name, Object value) - { - Element element = new Element(annotation); - - element.setName(name); - element.setValue(value); - - annotation.addElement(element); - } - - @Override - public void visitEnd() - { - classFile.getAnnotations().addAnnotation(annotation); - } +plugins { + id(Plugins.jarTest.first) version Plugins.jarTest.second +} + +description = "Cache" + +dependencies { + annotationProcessor(Libraries.lombok) + + api(project(":http-api")) + + compileOnly(Libraries.lombok) + + implementation(Libraries.gson) + implementation(Libraries.guava) + implementation(Libraries.commonsCli) + implementation(Libraries.nettyBuffer) + implementation(Libraries.antlr) + implementation(Libraries.apacheCommonsCompress) + implementation(Libraries.slf4jApi) + + testImplementation(Libraries.junit) + testImplementation(group = "net.runelite.rs", name = "cache", version = "${ProjectVersions.cacheversion}") + testImplementation(Libraries.slf4jSimple) +} + +tasks { + "processTestResources"(ProcessResources::class) { + val tokens = mapOf( + "rs.version" to ProjectVersions.rsversion.toString(), + "cache.version" to ProjectVersions.cacheversion.toString() + ) + + inputs.properties(tokens) + + from("src/test/resources") { + include("cache.properties") + + filter("tokens" to tokens) + } + } } diff --git a/cache/src/main/java/net/runelite/cache/definitions/NpcDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/NpcDefinition.java index 8ba160c97a..ddfabfe367 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/NpcDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/NpcDefinition.java @@ -31,38 +31,37 @@ import lombok.Data; @Data public class NpcDefinition { - public final int id; - public short[] recolorToFind; - public int rotation = 32; public String name = "null"; - public short[] recolorToReplace; + public int size = 1; public int[] models; - public int[] models_2; - public int stanceAnimation = -1; - public int anInt2165 = -1; - public int tileSpacesOccupied = 1; - public int walkAnimation = -1; - public short[] retextureToReplace; - public int rotate90RightAnimation = -1; - public boolean aBool2170 = true; - public int resizeX = 128; - public int contrast = 0; + public int[] chatheadModels; + public int standingAnimation = -1; + public int rotateLeftAnimation = -1; + public int rotateRightAnimation = -1; + public int walkingAnimation = -1; public int rotate180Animation = -1; - public int varbitIndex = -1; - public String[] options = new String[5]; - public boolean renderOnMinimap = true; - public int combatLevel = -1; + public int rotate90RightAnimation = -1; public int rotate90LeftAnimation = -1; - public int resizeY = 128; - public boolean hasRenderPriority = false; - public int ambient = 0; - public int headIcon = -1; - public int[] configs; + public short[] recolorToFind; + public short[] recolorToReplace; public short[] retextureToFind; + public short[] retextureToReplace; + public String[] actions = new String[5]; + public boolean isMinimapVisible = true; + public int combatLevel = -1; + public int widthScale = 128; + public int heightScale = 128; + public boolean hasRenderPriority; + public int ambient; + public int contrast; + public int headIcon = -1; + public int rotationSpeed = 32; + public int[] configs; + public int varbitId = -1; public int varpIndex = -1; - public boolean isClickable = true; - public int anInt2189 = -1; - public boolean aBool2190 = false; - public Map params = null; + public boolean isInteractable = true; + public boolean rotationFlag = true; + public boolean isPet; + public Map params; } diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/NpcLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/NpcLoader.java index 478ef2660a..0ce81f864b 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/NpcLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/NpcLoader.java @@ -24,13 +24,12 @@ */ package net.runelite.cache.definitions.loaders; +import java.util.HashMap; import net.runelite.cache.definitions.NpcDefinition; import net.runelite.cache.io.InputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; - public class NpcLoader { private static final Logger logger = LoggerFactory.getLogger(NpcLoader.class); @@ -67,7 +66,6 @@ public class NpcLoader { def.models[index] = stream.readUnsignedShort(); } - } else if (opcode == 2) { @@ -75,37 +73,37 @@ public class NpcLoader } else if (opcode == 12) { - def.tileSpacesOccupied = stream.readUnsignedByte(); + def.size = stream.readUnsignedByte(); } else if (opcode == 13) { - def.stanceAnimation = stream.readUnsignedShort(); + def.standingAnimation = stream.readUnsignedShort(); } else if (opcode == 14) { - def.walkAnimation = stream.readUnsignedShort(); + def.walkingAnimation = stream.readUnsignedShort(); } else if (opcode == 15) { - def.anInt2165 = stream.readUnsignedShort(); + def.rotateLeftAnimation = stream.readUnsignedShort(); } else if (opcode == 16) { - def.anInt2189 = stream.readUnsignedShort(); + def.rotateRightAnimation = stream.readUnsignedShort(); } else if (opcode == 17) { - def.walkAnimation = stream.readUnsignedShort(); + def.walkingAnimation = stream.readUnsignedShort(); def.rotate180Animation = stream.readUnsignedShort(); def.rotate90RightAnimation = stream.readUnsignedShort(); def.rotate90LeftAnimation = stream.readUnsignedShort(); } else if (opcode >= 30 && opcode < 35) { - def.options[opcode - 30] = stream.readString(); - if (def.options[opcode - 30].equalsIgnoreCase("Hidden")) + def.actions[opcode - 30] = stream.readString(); + if (def.actions[opcode - 30].equalsIgnoreCase("Hidden")) { - def.options[opcode - 30] = null; + def.actions[opcode - 30] = null; } } else if (opcode == 40) @@ -137,17 +135,17 @@ public class NpcLoader else if (opcode == 60) { length = stream.readUnsignedByte(); - def.models_2 = new int[length]; + def.chatheadModels = new int[length]; for (index = 0; index < length; ++index) { - def.models_2[index] = stream.readUnsignedShort(); + def.chatheadModels[index] = stream.readUnsignedShort(); } } else if (opcode == 93) { - def.renderOnMinimap = false; + def.isMinimapVisible = false; } else if (opcode == 95) { @@ -155,11 +153,11 @@ public class NpcLoader } else if (opcode == 97) { - def.resizeX = stream.readUnsignedShort(); + def.widthScale = stream.readUnsignedShort(); } else if (opcode == 98) { - def.resizeY = stream.readUnsignedShort(); + def.heightScale = stream.readUnsignedShort(); } else if (opcode == 99) { @@ -179,18 +177,18 @@ public class NpcLoader } else if (opcode == 103) { - def.rotation = stream.readUnsignedShort(); + def.rotationSpeed = stream.readUnsignedShort(); } else if (opcode == 106) { - def.varbitIndex = stream.readUnsignedShort(); - if ('\uffff' == def.varbitIndex) + def.varbitId = stream.readUnsignedShort(); + if (def.varbitId == 65535) { - def.varbitIndex = -1; + def.varbitId = -1; } def.varpIndex = stream.readUnsignedShort(); - if ('\uffff' == def.varpIndex) + if (def.varpIndex == 65535) { def.varpIndex = -1; } @@ -212,26 +210,26 @@ public class NpcLoader } else if (opcode == 107) { - def.isClickable = false; + def.isInteractable = false; } else if (opcode == 109) { - def.aBool2170 = false; + def.rotationFlag = false; } else if (opcode == 111) { - def.aBool2190 = true; + def.isPet = true; } else if (opcode == 118) { - def.varbitIndex = stream.readUnsignedShort(); - if ('\uffff' == def.varbitIndex) + def.varbitId = stream.readUnsignedShort(); + if (def.varbitId == 65535) { - def.varbitIndex = -1; + def.varbitId = -1; } def.varpIndex = stream.readUnsignedShort(); - if ('\uffff' == def.varpIndex) + if (def.varpIndex == 65535) { def.varpIndex = -1; } diff --git a/cache/src/main/java/net/runelite/cache/definitions/savers/NpcSaver.java b/cache/src/main/java/net/runelite/cache/definitions/savers/NpcSaver.java index 55d4b966e9..577681cf80 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/savers/NpcSaver.java +++ b/cache/src/main/java/net/runelite/cache/definitions/savers/NpcSaver.java @@ -47,45 +47,45 @@ public class NpcSaver out.writeByte(2); out.writeString(npc.name); } - if (npc.tileSpacesOccupied != 1) + if (npc.size != 1) { out.writeByte(12); - out.writeByte(npc.tileSpacesOccupied); + out.writeByte(npc.size); } - if (npc.stanceAnimation != -1) + if (npc.standingAnimation != -1) { out.writeByte(13); - out.writeShort(npc.stanceAnimation); + out.writeShort(npc.standingAnimation); } - if (npc.walkAnimation != -1) + if (npc.walkingAnimation != -1) { out.writeByte(14); - out.writeShort(npc.walkAnimation); + out.writeShort(npc.walkingAnimation); } - if (npc.anInt2165 != -1) + if (npc.rotateLeftAnimation != -1) { out.writeByte(15); - out.writeShort(npc.anInt2165); + out.writeShort(npc.rotateLeftAnimation); } - if (npc.anInt2189 != -1) + if (npc.rotateRightAnimation != -1) { out.writeByte(16); - out.writeShort(npc.anInt2189); + out.writeShort(npc.rotateRightAnimation); } if (npc.rotate180Animation != -1 || npc.rotate90LeftAnimation != -1 || npc.rotate90RightAnimation != -1) { out.writeByte(17); - out.writeShort(npc.walkAnimation); + out.writeShort(npc.walkingAnimation); out.writeShort(npc.rotate180Animation); out.writeShort(npc.rotate90RightAnimation); out.writeShort(npc.rotate90LeftAnimation); } for (int i = 0; i < 5; ++i) { - if (npc.options[i] != null) + if (npc.actions[i] != null) { out.writeByte(30 + i); - out.writeString(npc.options[i]); + out.writeString(npc.actions[i]); } } if (npc.recolorToFind != null && npc.recolorToReplace != null) @@ -108,16 +108,16 @@ public class NpcSaver out.writeShort(npc.retextureToReplace[i]); } } - if (npc.models_2 != null) + if (npc.chatheadModels != null) { out.writeByte(60); - out.writeByte(npc.models_2.length); - for (int modelId : npc.models_2) + out.writeByte(npc.chatheadModels.length); + for (int modelId : npc.chatheadModels) { out.writeShort(modelId); } } - if (!npc.renderOnMinimap) + if (!npc.isMinimapVisible) { out.writeByte(93); } @@ -127,9 +127,9 @@ public class NpcSaver out.writeShort(npc.combatLevel); } out.writeByte(97); - out.writeShort(npc.resizeX); + out.writeShort(npc.widthScale); out.writeByte(98); - out.writeShort(npc.resizeY); + out.writeShort(npc.heightScale); if (npc.hasRenderPriority) { out.writeByte(99); @@ -144,23 +144,23 @@ public class NpcSaver out.writeShort(npc.headIcon); } out.writeByte(103); - out.writeShort(npc.rotation); - if (!npc.isClickable) + out.writeShort(npc.rotationSpeed); + if (!npc.isInteractable) { out.writeByte(107); } - if (!npc.aBool2170) + if (!npc.rotationFlag) { out.writeByte(109); } - if (npc.aBool2190) + if (npc.isPet) { out.writeByte(111); } if (npc.configs != null) { out.writeByte(118); - out.writeShort(npc.varbitIndex); + out.writeShort(npc.varbitId); out.writeShort(npc.varpIndex); int[] c = npc.configs; diff --git a/deobfuscator/build.gradle b/deobfuscator/build.gradle deleted file mode 100644 index 0d61c904d6..0000000000 --- a/deobfuscator/build.gradle +++ /dev/null @@ -1,117 +0,0 @@ -import org.apache.tools.ant.filters.ReplaceTokens -import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -import java.nio.file.Files -import java.nio.file.Paths -import java.util.zip.ZipFile - -plugins { - id "com.github.hauner.jarTest" version "1.0.1" -} - -description = 'Deobfuscator' - -def deobfuscatedJar = "${rootPath}/runescape-client/build/libs/rs-client-${project.version}.jar" - -def unzipFile(String file, String dest) -{ - def zipFile = new ZipFile(file) - - zipFile.entries().each { it -> - def path = Paths.get(dest + File.separator + it.name) - if (it.directory) - { - Files.createDirectories(path) - } - else - { - def parentDir = path.getParent() - if (!Files.exists(parentDir)) - { - Files.createDirectories(parentDir) - } - Files.copy(zipFile.getInputStream(it), path) - } - } -} - -configurations { - deobjars -} - -dependencies { - deobjars group: 'net.runelite.rs', name: 'vanilla', version: rsversion - deobjars project(':rs-client') - - implementation group: 'com.google.code.gson', name: 'gson', version: gson - implementation group: 'com.google.guava', name: 'guava', version: guava - implementation group: 'net.runelite', name: 'fernflower', version: fernflower - implementation group: 'org.ow2.asm', name: 'asm', version: asm - implementation group: 'org.ow2.asm', name: 'asm-util', version: asm - implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j - implementation project(':runelite-api') - implementation project(':runescape-api') - - runtime group: 'org.slf4j', name: 'slf4j-simple', version: slf4j - - testImplementation configurations.deobjars.dependencies - testImplementation group: 'junit', name: 'junit', version: junit - testImplementation group: 'org.mockito', name: 'mockito-core', version: mockito -} - -processResources { - from file("src/main/resources/deob.properties"), { - filter(ReplaceTokens, tokens: [ - "rs.version": rsversion.toString(), - "vanilla.jar": configurations.deobjars.find {it.name.startsWith("vanilla")}.toString().replace('\\', "/"), - "rs.client": configurations.deobjars.find {it.name.startsWith("rs-client")}.toString().replace('\\', "/") - ]) - } -} -processTestResources { - from file("src/test/resources/deob-test.properties"), { - filter(ReplaceTokens, tokens: [ - "rs.client": configurations.deobjars.find {it.name.startsWith("rs-client")}.toString().replace('\\', "/"), - "rs.version": rsversion.toString(), - "vanilla.jar": configurations.deobjars.find {it.name.startsWith("vanilla")}.toString().replace('\\', "/") - ]) - } -} - -task gamepackUpdate { - dependsOn ":deobfuscator:build" - dependsOn ":rs-client:build" - - doLast { - def path = sourceSets.main.runtimeClasspath - def loader = new URLClassLoader(path.collect { f -> f.toURI().toURL() } as URL[]) - def downloader = loader.loadClass('net.runelite.gamepack.Downloader') - def clientVersion = loader.loadClass('net.runelite.deob.clientver.ClientVersionMain') - def deob = loader.loadClass('net.runelite.deob.Deob') - def mappings = loader.loadClass('net.runelite.deob.updater.UpdateMappings') - - String gamepack = downloader.gamepack() - int version = clientVersion.version(gamepack) - - String gamepackVersion = gamepack.replace("gamepack.jar", "gamepack-" + version + ".jar") - String gamepackDeob = gamepack.replace("gamepack.jar", "gamepack-" + version + "-deob.jar") - String gamepackMappings = gamepack.replace("gamepack.jar", "gamepack-" + version + "-updated-mappings.jar") - String gamepackMappingsDecomp = gamepackMappings.replace(".jar", "-decomp") - String gamepackMappingsFern = gamepackMappingsDecomp + File.separator + gamepackMappings.split("/gamepack/")[1] - - if (version == -1 || version == rsversion) - { - return - } - - deob.main(gamepackVersion, gamepackDeob) - mappings.main(deobfuscatedJar, gamepackDeob, gamepackMappings) - - new File(gamepackMappingsDecomp).mkdirs() - ConsoleDecompiler.main(gamepackMappings, gamepackMappingsDecomp) - - unzipFile(gamepackMappingsFern, gamepackMappingsDecomp) - new File(gamepackMappingsFern).delete() - - loader.close() - } -} diff --git a/deobfuscator/deobfuscator.gradle.kts b/deobfuscator/deobfuscator.gradle.kts new file mode 100644 index 0000000000..a307aa9b04 --- /dev/null +++ b/deobfuscator/deobfuscator.gradle.kts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019 Owain van Brakel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.apache.tools.ant.filters.ReplaceTokens + +plugins { + id(Plugins.jarTest.first) version Plugins.jarTest.second +} + +val deobjars = configurations.create("deobjars") + +dependencies { + deobjars(group = "net.runelite.rs", name = "vanilla", version = ProjectVersions.rsversion.toString()) + deobjars(project(":runescape-client")) + + implementation(Libraries.annotations) + implementation(Libraries.asmAll) + implementation(Libraries.asmUtil) + implementation(Libraries.fernflower) + implementation(Libraries.gson) + implementation(Libraries.guava) + implementation(Libraries.slf4jApi) + implementation(project(":runelite-api")) + implementation(project(":runescape-api")) + + runtime(Libraries.slf4jSimple) + + testImplementation(deobjars) + testImplementation(Libraries.junit) + testImplementation(Libraries.mockitoCore) +} + +tasks { + val tokens = mapOf( + "rs.version" to ProjectVersions.rsversion.toString(), + "vanilla.jar" to deobjars.find { it.name.startsWith("vanilla") }.toString().replace("\\", "/"), + "rs.client" to deobjars.find { it.name.startsWith("runescape-client") }.toString().replace("\\", "/") + ) + + "processResources"(ProcessResources::class) { + inputs.properties(tokens) + + from("src/main/resources") { + include("deob.properties") + + filter("tokens" to tokens) + } + } + + "processTestResources"(ProcessResources::class) { + inputs.properties(tokens) + + from("src/test/resources") { + include("deob-test.properties") + + filter("tokens" to tokens) + } + } +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/Annotated.java b/deobfuscator/src/main/java/net/runelite/asm/Annotated.java new file mode 100644 index 0000000000..4645fa23a2 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/Annotated.java @@ -0,0 +1,17 @@ +package net.runelite.asm; + +import java.util.Iterator; +import net.runelite.asm.attributes.Annotations; +import net.runelite.asm.attributes.annotation.Annotation; +import org.jetbrains.annotations.NotNull; + +public interface Annotated extends Iterable +{ + Annotations getAnnotations(); + + @NotNull + default Iterator iterator() + { + return getAnnotations().iterator(); + } +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java b/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java index a5f3a6ecb6..fd2ba5a40a 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java +++ b/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java @@ -31,13 +31,12 @@ import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.pool.Class; import net.runelite.asm.signature.Signature; import static net.runelite.deob.DeobAnnotations.*; -import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -public class ClassFile +public class ClassFile implements Annotated, Named { private ClassGroup group; @@ -100,10 +99,9 @@ public class ClassFile visitor.visit(version, access, name.getName(), null, super_class.getName(), ints); visitor.visitSource(source, null); - for (Annotation annotation : annotations.getAnnotations()) + for (Annotation annotation : annotations) { - AnnotationVisitor av = visitor.visitAnnotation(annotation.getType().toString(), true); - annotation.accept(av); + annotation.accept(visitor.visitAnnotation(annotation.getType().toString(), true)); } for (Field field : fields) diff --git a/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java b/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java index 33ab161acc..fabde88742 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java +++ b/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java @@ -27,13 +27,16 @@ package net.runelite.asm; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import net.runelite.asm.attributes.Code; import net.runelite.asm.signature.Signature; import static net.runelite.deob.DeobAnnotations.*; +import org.jetbrains.annotations.NotNull; -public class ClassGroup +public class ClassGroup implements Iterable { private final List classes = new ArrayList<>(); // to keep order private final Map classMap = new HashMap<>(); @@ -156,4 +159,17 @@ public class ClassGroup return findClass(name); } + + @NotNull + @Override + public Iterator iterator() + { + return this.classes.iterator(); + } + + @Override + public void forEach(Consumer action) + { + this.classes.forEach(action); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/Field.java b/deobfuscator/src/main/java/net/runelite/asm/Field.java index 39590b021c..1a9fd7a776 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Field.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Field.java @@ -27,15 +27,13 @@ package net.runelite.asm; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.deob.DeobAnnotations; -import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Opcodes; - import static org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.objectweb.asm.Opcodes.ACC_PROTECTED; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -public class Field +public class Field implements Annotated, Named { public static final int ACCESS_MODIFIERS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED; @@ -53,15 +51,14 @@ public class Field this.name = name; this.type = type; - annotations = new Annotations(); + this.annotations = new Annotations(); } public void accept(FieldVisitor visitor) { for (Annotation annotation : annotations.getAnnotations()) { - AnnotationVisitor av = visitor.visitAnnotation(annotation.getType().toString(), true); - annotation.accept(av); + annotation.accept(visitor.visitAnnotation(annotation.getType().toString(), true)); } visitor.visitEnd(); diff --git a/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java b/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java index f5994ad1d3..9bc15d5100 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java @@ -25,12 +25,14 @@ package net.runelite.asm; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; import net.runelite.asm.pool.Class; import net.runelite.deob.DeobAnnotations; +import org.jetbrains.annotations.NotNull; -public class Interfaces +public class Interfaces implements Iterable { private final ClassFile classFile; @@ -107,4 +109,10 @@ public class Interfaces return names; } + + @NotNull + public Iterator iterator() + { + return this.interfaces.iterator(); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/Method.java b/deobfuscator/src/main/java/net/runelite/asm/Method.java index ad7394c7be..b13e98aa3f 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Method.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Method.java @@ -36,7 +36,6 @@ import net.runelite.asm.attributes.code.Parameter; import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; import net.runelite.asm.signature.Signature; import net.runelite.deob.DeobAnnotations; -import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import static org.objectweb.asm.Opcodes.ACC_FINAL; @@ -47,7 +46,7 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED; -public class Method +public class Method implements Annotated, Named { public static final int ACCESS_MODIFIERS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED; @@ -92,8 +91,7 @@ public class Method for (Annotation annotation : annotations.getAnnotations()) { - AnnotationVisitor av = visitor.visitAnnotation(annotation.getType().toString(), true); - annotation.accept(av); + annotation.accept(visitor.visitAnnotation(annotation.getType().toString(), true)); } if (code != null) diff --git a/deobfuscator/src/main/java/net/runelite/asm/Named.java b/deobfuscator/src/main/java/net/runelite/asm/Named.java new file mode 100644 index 0000000000..ec2bc0b6a9 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/Named.java @@ -0,0 +1,6 @@ +package net.runelite.asm; + +public interface Named +{ + String getName(); +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java index b14d761c28..7c1a6ba535 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java @@ -26,13 +26,16 @@ package net.runelite.asm.attributes; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import net.runelite.asm.Type; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; +import org.jetbrains.annotations.NotNull; -public class Annotations +public class Annotations implements Iterable { private final List annotations = new ArrayList<>(); @@ -40,7 +43,7 @@ public class Annotations { return annotations; } - + public void addAnnotation(Annotation annotation) { annotations.add(annotation); @@ -55,7 +58,7 @@ public class Annotations { annotations.clear(); } - + public Annotation find(Type type) { for (Annotation a : annotations) @@ -68,18 +71,22 @@ public class Annotations { return annotations.size(); } - + public Annotation addAnnotation(Type type, String name, Object value) { - Annotation annotation = new Annotation(this); - annotation.setType(type); + Annotation annotation = new Annotation(type); addAnnotation(annotation); - - Element element = new Element(annotation); - element.setName(name); - element.setValue(value); + + Element element = new SimpleElement(name, value); annotation.addElement(element); return annotation; } + + @NotNull + @Override + public Iterator iterator() + { + return this.annotations.iterator(); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java index b20c183fea..58c759844a 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java @@ -41,11 +41,11 @@ public class Code private int maxStack; private Instructions instructions; private final Exceptions exceptions; - + public Code(Method method) { this.method = method; - + exceptions = new Exceptions(this); instructions = new Instructions(this); } @@ -59,12 +59,12 @@ public class Code { return maxStack; } - + public void setMaxStack(int maxStack) { this.maxStack = maxStack; } - + private int getMaxLocalsFromSig() { Method m = getMethod(); @@ -77,12 +77,11 @@ public class Code /** * calculates the size of the lvt required for this method - * @return */ public int getMaxLocals() { int max = -1; - + for (Instruction ins : instructions.getInstructions()) { if (ins instanceof LVTInstruction) @@ -96,19 +95,19 @@ public class Code } } } - + int fromSig = getMaxLocalsFromSig(); if (fromSig > max) max = fromSig; - + return max; } - + public Exceptions getExceptions() { return exceptions; } - + public Instructions getInstructions() { return instructions; diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java index 7c727eb788..6f3a459eb3 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java @@ -26,30 +26,26 @@ package net.runelite.asm.attributes.annotation; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; - import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; +import org.jetbrains.annotations.NotNull; import org.objectweb.asm.AnnotationVisitor; -public class Annotation +public class Annotation extends Element> implements Iterable { - private final Annotations annotations; - private Type type; - private final List elements = new ArrayList<>(); + private final Type type; - public Annotation(Annotations annotations) + public Annotation(Type type) { - this.annotations = annotations; + this.value = new ArrayList<>(); + this.type = type; } - public Annotations getAnnotations() - { - return annotations; - } - - public void setType(Type type) + public Annotation(String name, Type type) { + this.value = new ArrayList<>(); + this.name = name; this.type = type; } @@ -60,23 +56,44 @@ public class Annotation public List getElements() { - return elements; + return value; } - + public Element getElement() { - return elements.get(0); + return value.get(0); } - + public void addElement(Element element) { - elements.add(element); + value.add(element); } - + + @Override + public final void setValue(List value) + { + throw new UnsupportedOperationException(); + } + public void accept(AnnotationVisitor visitor) { - for (Element element : elements) - visitor.visit(element.getName(), element.getValue()); + if (visitor == null) + { + return; + } + + for (Element element : this) + { + accept(visitor, element.name, element.value); + } + visitor.visitEnd(); } + + @NotNull + @Override + public Iterator iterator() + { + return this.value.iterator(); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/ArrayElement.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/ArrayElement.java new file mode 100644 index 0000000000..b7e2b7ef84 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/ArrayElement.java @@ -0,0 +1,42 @@ +package net.runelite.asm.attributes.annotation; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; + +public class ArrayElement extends Element implements Iterable +{ + public ArrayElement(String name) + { + this.name = name; + this.value = new ArrayList<>(); + } + + @SuppressWarnings("unchecked") + public void addValue(Object value) + { + this.value.add(value); + } + + @Override + public final void setValue(List value) + { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + @SuppressWarnings("unchecked") + public Iterator iterator() + { + return this.value.iterator(); + } + + @SuppressWarnings("unchecked") + public Stream stream() + { + return this.value.stream(); + } +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java index 18fdfa33f4..10b59b5b27 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java @@ -25,21 +25,14 @@ package net.runelite.asm.attributes.annotation; -public class Element -{ - private final Annotation annotation; - private String name; - private Object value; - - public Element(Annotation annotation) - { - this.annotation = annotation; - } +import java.util.List; +import org.objectweb.asm.AnnotationVisitor; - public Annotation getAnnotation() - { - return annotation; - } +public abstract class Element +{ + String name = "value"; + + T value; public String getName() { @@ -51,18 +44,48 @@ public class Element this.name = name; } - public Object getValue() + public T getValue() { return value; } - public void setValue(Object value) + public void setValue(T value) { this.value = value; } - + public String getString() { return value.toString(); } + + public static void accept(AnnotationVisitor visitor, final String name, final Object value) + { + if (visitor == null) + { + return; + } + + if (value instanceof Annotation) + { + Annotation annotation = (Annotation) value; + annotation.accept(visitor.visitAnnotation(name, annotation.getType().toString())); + } + else if (value instanceof List) + { + AnnotationVisitor arr = visitor.visitArray(name); + List arrayValue = (List) value; + + for (Object o : arrayValue) + { + accept(arr, null, o); + } + + arr.visitEnd(); + } + else + { + visitor.visit(name, value); + } + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/SimpleElement.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/SimpleElement.java new file mode 100644 index 0000000000..52e25e295c --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/SimpleElement.java @@ -0,0 +1,15 @@ +package net.runelite.asm.attributes.annotation; + +public class SimpleElement extends Element +{ + public SimpleElement(Object value) + { + this.value = value; + } + + public SimpleElement(String name, Object value) + { + this.name = name; + this.value = value; + } +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java index a528950d0a..212c168998 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java @@ -26,11 +26,14 @@ package net.runelite.asm.attributes.code; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; import net.runelite.asm.attributes.Code; +import org.jetbrains.annotations.NotNull; -public class Instructions +public class Instructions implements Iterable { private final Code code; private final List instructions = new ArrayList<>(); @@ -186,4 +189,25 @@ public class Instructions return i; } + + public int size() + { + return this.instructions.size(); + } + + @NotNull + public Iterator iterator() + { + return this.instructions.iterator(); + } + + public ListIterator listIterator() + { + return this.instructions.listIterator(); + } + + public ListIterator listIterator(int i) + { + return this.instructions.listIterator(i); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java index 266cd7f1b1..7acb82c1e5 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/ArrayStore.java @@ -52,8 +52,7 @@ public abstract class ArrayStore extends Instruction implements ArrayStoreInstru if (r.getInstruction() instanceof GetFieldInstruction) { GetFieldInstruction gf = (GetFieldInstruction) r.getInstruction(); - Field f = gf.getMyField(); - return f; + return gf.getMyField(); } return null; @@ -89,7 +88,7 @@ public abstract class ArrayStore extends Instruction implements ArrayStoreInstru Field f1 = gf1.getMyField(), f2 = gf2.getMyField(); - + assert MappingExecutorUtil.isMaybeEqual(f1, f2); if (f1 != null && f2 != null) diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java index f992fb6621..7d01d0d38c 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/instructions/InvokeStatic.java @@ -24,7 +24,6 @@ */ package net.runelite.asm.attributes.code.instructions; -import java.util.Arrays; import java.util.Collections; import java.util.List; import net.runelite.asm.ClassFile; @@ -86,7 +85,7 @@ public class InvokeStatic extends Instruction implements InvokeInstruction @SuppressWarnings("unchecked") public List getMethods() { - return myMethod != null ? Arrays.asList(myMethod) : Collections.EMPTY_LIST; + return myMethod != null ? Collections.singletonList(myMethod) : Collections.EMPTY_LIST; } @Override diff --git a/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java b/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java index e55d5e6aeb..4615200f72 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java +++ b/deobfuscator/src/main/java/net/runelite/asm/execution/MethodContext.java @@ -70,10 +70,9 @@ public class MethodContext return contexts.get(i); } - @SuppressWarnings("unchecked") public Collection getInstructionContexts() { - return (Collection) contexts.values(); + return contexts.values(); } public void reset() diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/MethodAnnotationVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/AnnotationElementVisitor.java similarity index 62% rename from deobfuscator/src/main/java/net/runelite/asm/visitors/MethodAnnotationVisitor.java rename to deobfuscator/src/main/java/net/runelite/asm/visitors/AnnotationElementVisitor.java index bcce61aedd..7bd5811813 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/MethodAnnotationVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/AnnotationElementVisitor.java @@ -25,44 +25,59 @@ package net.runelite.asm.visitors; -import net.runelite.asm.Method; import net.runelite.asm.Type; import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.ArrayElement; +import net.runelite.asm.attributes.annotation.SimpleElement; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Opcodes; -public class MethodAnnotationVisitor extends AnnotationVisitor +public class AnnotationElementVisitor extends AnnotationVisitor { - private final Method method; - private final Type type; private final Annotation annotation; - - public MethodAnnotationVisitor(Method method, Type type) + + AnnotationElementVisitor(Annotation annotation) { super(Opcodes.ASM5); - - this.method = method; - this.type = type; - - annotation = new Annotation(method.getAnnotations()); - annotation.setType(type); + + this.annotation = annotation; } - + @Override public void visit(String name, Object value) { - Element element = new Element(annotation); - - element.setName(name); - element.setValue(value); - + SimpleElement element = new SimpleElement(name, value); annotation.addElement(element); } - + @Override - public void visitEnd() + public AnnotationVisitor visitArray(String name) { - method.getAnnotations().addAnnotation(annotation); + ArrayElement element = new ArrayElement(name); + this.annotation.addElement(element); + return new AnnotationVisitor(Opcodes.ASM5) + { + @Override + public void visit(String name, Object value) + { + element.addValue(value); + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String descriptor) + { + Annotation annotation = new Annotation(name, new Type(descriptor)); + element.addValue(annotation); + return new AnnotationElementVisitor(annotation); + } + }; + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String descriptor) + { + Annotation annotation = new Annotation(name, new Type(descriptor)); + this.annotation.addElement(annotation); + return new AnnotationElementVisitor(annotation); } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java index 37478d26e3..c9012b162c 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java @@ -22,12 +22,12 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package net.runelite.asm.visitors; import net.runelite.asm.ClassFile; import net.runelite.asm.Field; import net.runelite.asm.Type; +import net.runelite.asm.attributes.annotation.Annotation; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; @@ -35,25 +35,25 @@ import org.objectweb.asm.Opcodes; public class ClassFieldVisitor extends FieldVisitor { - private final ClassFile classFile; private final Field field; - public ClassFieldVisitor(ClassFile cf, int access, String name, Type desc, Object value) + ClassFieldVisitor(ClassFile cf, int access, String name, Type desc, Object value) { super(Opcodes.ASM5); - this.classFile = cf; + this.field = new Field(cf, name, desc); + this.field.setAccessFlags(access); + this.field.setValue(value); - field = new Field(cf, name, desc); - field.setAccessFlags(access); - field.setValue(value); + cf.addField(field); } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - Type type = new Type(desc); - return new FieldAnnotationVisitor(field, type); + Annotation element = new Annotation(new Type(desc)); + this.field.getAnnotations().addAnnotation(element); + return new AnnotationElementVisitor(element); } @Override @@ -61,10 +61,4 @@ public class ClassFieldVisitor extends FieldVisitor { System.out.println(attr); } - - @Override - public void visitEnd() - { - classFile.addField(field); - } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java index abaf4e919d..d96ec550b1 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java @@ -27,6 +27,7 @@ package net.runelite.asm.visitors; import net.runelite.asm.ClassFile; import net.runelite.asm.Type; +import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.signature.Signature; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; @@ -55,7 +56,7 @@ public class ClassFileVisitor extends ClassVisitor classFile.setSuperName(superName); classFile.setVersion(version); classFile.setAccess(access); - + for (String inter : interfaces) classFile.getInterfaces().addInterface(new net.runelite.asm.pool.Class(inter)); } @@ -69,8 +70,10 @@ public class ClassFileVisitor extends ClassVisitor @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - Type type = new Type(desc); - return new ClassAnnotationVisitor(classFile, type); + Annotation annotation = new Annotation(new Type(desc)); + classFile.getAnnotations().addAnnotation(annotation); + + return new AnnotationElementVisitor(annotation); } @Override diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java index d01873b83b..7746cd7a7a 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java @@ -32,6 +32,7 @@ import net.runelite.asm.ClassFile; import net.runelite.asm.Method; import net.runelite.asm.Type; import net.runelite.asm.attributes.Code; +import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.code.Exceptions; import net.runelite.asm.attributes.code.Instruction; import net.runelite.asm.attributes.code.InstructionType; @@ -72,18 +73,14 @@ import static org.objectweb.asm.Opcodes.ICONST_5; import static org.objectweb.asm.Opcodes.ICONST_M1; import static org.objectweb.asm.Opcodes.LCONST_0; import static org.objectweb.asm.Opcodes.LCONST_1; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class CodeVisitor extends MethodVisitor { - private static final Logger logger = LoggerFactory.getLogger(CodeVisitor.class); - private final ClassFile classFile; private final Method method; private Code code; - public CodeVisitor(ClassFile classFile, int access, String name, Signature signature, String[] sexceptions) + CodeVisitor(ClassFile classFile, int access, String name, Signature signature, String[] sexceptions) { super(Opcodes.ASM5); @@ -111,8 +108,9 @@ public class CodeVisitor extends MethodVisitor @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - Type type = new Type(desc); - return new MethodAnnotationVisitor(method, type); + Annotation element = new Annotation(new Type(desc)); + this.method.getAnnotations().addAnnotation(element); + return new AnnotationElementVisitor(element); } @Override @@ -333,7 +331,7 @@ public class CodeVisitor extends MethodVisitor if (cst instanceof org.objectweb.asm.Type) { org.objectweb.asm.Type t = (org.objectweb.asm.Type) cst; - entry = new net.runelite.asm.pool.Class((String) t.getClassName()); + entry = new net.runelite.asm.pool.Class(t.getClassName()); } LDC ldc = new LDC(code.getInstructions(), entry); diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/FieldAnnotationVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/FieldAnnotationVisitor.java deleted file mode 100644 index 962328f272..0000000000 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/FieldAnnotationVisitor.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.runelite.asm.visitors; - -import net.runelite.asm.Field; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.annotation.Element; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Opcodes; - -public class FieldAnnotationVisitor extends AnnotationVisitor -{ - private final Field field; - private final Type type; - private final Annotation annotation; - - public FieldAnnotationVisitor(Field field, Type type) - { - super(Opcodes.ASM5); - - this.field = field; - this.type = type; - - annotation = new Annotation(field.getAnnotations()); - annotation.setType(type); - } - - @Override - public void visit(String name, Object value) - { - Element element = new Element(annotation); - - element.setName(name); - element.setValue(value); - - annotation.addElement(element); - } - - @Override - public void visitEnd() - { - field.getAnnotations().addAnnotation(annotation); - } -} diff --git a/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java b/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java index 2881148caa..6294574e74 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java +++ b/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java @@ -95,7 +95,7 @@ public class DeobAnnotations { return null; } - + return (Number) an.getElement().getValue(); } diff --git a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java index 418802ef5a..588b840918 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java +++ b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java @@ -193,6 +193,7 @@ public class Renamer implements Deobfuscator } @Override + @SuppressWarnings("unchecked") public void run(ClassGroup group) { group.buildClassGraph(); diff --git a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java index 0970a9b3e1..b2a0c369b3 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java +++ b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java @@ -37,6 +37,7 @@ import net.runelite.asm.Method; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; import net.runelite.asm.attributes.code.Instruction; import net.runelite.asm.attributes.code.InstructionType; import net.runelite.asm.attributes.code.Instructions; @@ -113,7 +114,6 @@ public class ConstantParameter implements Deobfuscator List pops = invokeCtx.getPops(); - outer: // object is popped first, then param 1, 2, 3, etc. double and long take two slots. for (int lvtOffset = offset, parameterIndex = 0; parameterIndex < method.getDescriptor().size(); @@ -451,9 +451,7 @@ public class ConstantParameter implements Deobfuscator } // Add garbage value - Element element = new Element(obfuscatedSignature); - element.setName("garbageValue"); - element.setValue(value.toString()); + Element element = new SimpleElement("garbageValue", value.toString()); obfuscatedSignature.addElement(element); } } @@ -464,12 +462,12 @@ public class ConstantParameter implements Deobfuscator public void run(ClassGroup group) { Execution execution = new Execution(group); - execution.addExecutionVisitor(i -> findParameters(i)); + execution.addExecutionVisitor(this::findParameters); execution.populateInitialMethods(); execution.run(); execution = new Execution(group); - execution.addMethodContextVisitor(mc -> findDeadParameters(mc)); + execution.addMethodContextVisitor(this::findDeadParameters); execution.populateInitialMethods(); execution.run(); diff --git a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java index 87e01ac4ae..bd60ec165e 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java +++ b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java @@ -32,6 +32,7 @@ import net.runelite.asm.Method; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; import net.runelite.deob.DeobAnnotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +40,7 @@ import org.slf4j.LoggerFactory; public class AnnotationMapper { private static final Logger logger = LoggerFactory.getLogger(AnnotationMapper.class); - + private final ClassGroup source, target; private final ParallelExecutorMapping mapping; @@ -119,20 +120,17 @@ public class AnnotationMapper if (from.getAnnotations() == null) return count; - + for (Annotation a : from.getAnnotations()) { if (isCopyable(a)) { - Annotation annotation = new Annotation(to); - annotation.setType(a.getType()); + Annotation annotation = new Annotation(a.getType()); to.addAnnotation(annotation); for (Element e : a.getElements()) { - Element element = new Element(annotation); - element.setName(e.getName()); - element.setValue(e.getValue()); + Element element = new SimpleElement(e.getName(), e.getValue()); annotation.addElement(element); } @@ -155,7 +153,6 @@ public class AnnotationMapper private boolean isCopyable(Annotation a) { return a.getType().equals(DeobAnnotations.EXPORT) - || a.getType().equals(DeobAnnotations.IMPLEMENTS) - || a.getType().equals(DeobAnnotations.HOOK); + || a.getType().equals(DeobAnnotations.IMPLEMENTS); } } diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java index a01628d863..d2c3d62034 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java @@ -8,6 +8,7 @@ import net.runelite.asm.Method; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; import net.runelite.deob.Deob; import net.runelite.deob.DeobAnnotations; import org.slf4j.Logger; @@ -23,6 +24,7 @@ public class AnnotationAdder private final ClassGroup group; private final Logger log = LoggerFactory.getLogger(AnnotationAdder.class); + @SuppressWarnings("unchecked") public void run() { int impl = 0; @@ -50,12 +52,9 @@ public class AnnotationAdder { Annotations an = c.getAnnotations(); - Annotation implAn = new Annotation(an); - implAn.setType(DeobAnnotations.IMPLEMENTS); + Annotation implAn = new Annotation(DeobAnnotations.IMPLEMENTS); - Element value = new Element(implAn); - value.setValue(c.getClassName()); - value.setName("value"); + Element value = new SimpleElement(c.getClassName()); implAn.addElement(value); an.addAnnotation(implAn); @@ -81,12 +80,9 @@ public class AnnotationAdder Annotation a = an.find(DeobAnnotations.EXPORT); if (a == null) { - a = new Annotation(an); - a.setType(DeobAnnotations.EXPORT); + a = new Annotation(DeobAnnotations.EXPORT); - Element value = new Element(a); - value.setValue(fieldName); - value.setName("value"); + Element value = new SimpleElement(fieldName); a.addElement(value); an.addAnnotation(a); @@ -114,12 +110,9 @@ public class AnnotationAdder Annotation a = an.find(DeobAnnotations.EXPORT); if (a == null) { - a = new Annotation(an); - a.setType(DeobAnnotations.EXPORT); + a = new Annotation(DeobAnnotations.EXPORT); - Element value = new Element(a); - value.setValue(methodName); - value.setName("value"); + Element value = new SimpleElement(methodName); a.addElement(value); an.addAnnotation(a); diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java index 0c594cfe19..5d495b9029 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java @@ -34,6 +34,7 @@ import net.runelite.asm.Type; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; public class AnnotationCopier { @@ -97,15 +98,12 @@ public class AnnotationCopier { if (!isType(a.getType())) continue; - - Annotation a2 = new Annotation(an2); - a2.setType(a.getType()); + + Annotation a2 = new Annotation(a.getType()); for (Element element : a.getElements()) { - Element element2 = new Element(a2); - element2.setName(element.getName()); - element2.setValue(element.getValue()); + Element element2 = new SimpleElement(element.getName(), element.getValue()); a2.addElement(element2); } diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java index 7d0f2f03d2..da920899bc 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java @@ -34,13 +34,9 @@ import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.deob.DeobAnnotations; import net.runelite.deob.deobfuscators.Renamer; import net.runelite.deob.util.NameMappings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class AnnotationRenamer { - private static final Logger logger = LoggerFactory.getLogger(AnnotationRenamer.class); - private ClassGroup group; public AnnotationRenamer(ClassGroup group) diff --git a/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java b/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java index 1b0435d3d0..67364468c0 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java +++ b/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java @@ -25,9 +25,11 @@ package net.runelite.deob.util; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -79,6 +81,41 @@ public class JarUtil return group; } + public static ClassFile loadClass(byte[] bytes) + { + ClassReader reader = new ClassReader(bytes); + ClassFileVisitor cv = new ClassFileVisitor(); + reader.accept(cv, ClassReader.SKIP_FRAMES); + return cv.getClassFile(); + } + + public static ClassGroup loadClasses(Collection files) throws IOException + { + final ClassGroup group = new ClassGroup(); + + for (File file : files) + { + if (!file.getName().endsWith(".class")) + { + continue; + } + + try (InputStream is = new FileInputStream(file)) + { + ClassReader reader = new ClassReader(is); + ClassFileVisitor cv = new ClassFileVisitor(); + + reader.accept(cv, ClassReader.SKIP_FRAMES); + + group.addClass(cv.getClassFile()); + } + } + + group.initialize(); + + return group; + } + public static void saveJar(ClassGroup group, File jarfile) throws IOException { try (JarOutputStream jout = new JarOutputStream(new FileOutputStream(jarfile), new Manifest())) diff --git a/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java b/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java index bf8e2bed2b..dbb17bfe55 100644 --- a/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java +++ b/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java @@ -276,8 +276,7 @@ public class HookImporter { for (Element e : a.getElements()) { - String str = (String) e.getValue(); - return str; + return (String) e.getValue(); } } } @@ -288,7 +287,7 @@ public class HookImporter private Signature getObfuscatedMethodSignature(Method method) { String sig = getAnnotation(method.getAnnotations(), OBFUSCATED_SIGNATURE); - if (sig.isEmpty() == false) + if (!sig.isEmpty()) { return toObSignature(new Signature(sig)); // if it is annoted, use that } diff --git a/gradle.properties b/gradle.properties index 3f7769ea7e..dbf57649ed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.warning.mode=all org.gradle.parallel=true org.gradle.console=rich org.gradle.configureondemand=true -org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ca9d62814a..0ebb3108e2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a016f754cd..83f2acfdc3 100755 --- a/gradlew +++ b/gradlew @@ -44,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx4g" "-Xms2g" "-Dfile.encoding=UTF-8"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e79b159744..24467a141f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -30,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx4g" "-Xms2g" "-Dfile.encoding=UTF-8" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/http-api/build.gradle b/http-api/build.gradle deleted file mode 100644 index a191f21f61..0000000000 --- a/http-api/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -import org.apache.tools.ant.filters.ReplaceTokens - -description = 'Web API' - -dependencies { - annotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok - - compileOnly group: 'javax.inject', name: 'javax.inject', version: javaxInject - compileOnly group: 'org.projectlombok', name: 'lombok', version: lombok - - implementation group: 'com.google.code.gson', name: 'gson', version: gson - implementation group: 'com.google.guava', name: 'guava', version: guava - implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp3 - implementation group: 'io.reactivex.rxjava2', name: 'rxjava', version: rxjava - implementation group: 'org.apache.commons', name: 'commons-csv', version: apacheCommonsCsv - implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j - implementation project(':runelite-api') - - testImplementation group: 'com.squareup.okhttp3', name: 'mockwebserver', version: okhttp3 - testImplementation group: 'junit', name: 'junit', version: junit - testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: slf4j -} - -processResources { - from file("src/main/resources/runelite.properties"), { - filter(ReplaceTokens, tokens: [ - "projectver": project.version, - "rsver": rsversion.toString(), - "gitcommit": gitCommitShort, - "gitdirty": gitDirty.toString() - ]) - } -} diff --git a/injector-plugin/src/test/java/net/runelite/injector/InjectConstructTest.java b/http-api/http-api.gradle.kts similarity index 53% rename from injector-plugin/src/test/java/net/runelite/injector/InjectConstructTest.java rename to http-api/http-api.gradle.kts index dbde5e10bd..9f5dfac4af 100644 --- a/injector-plugin/src/test/java/net/runelite/injector/InjectConstructTest.java +++ b/http-api/http-api.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Adam + * Copyright (c) 2019 Owain van Brakel * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,42 +22,44 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.injector; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Method; -import net.runelite.asm.signature.Signature; -import static org.junit.Assert.assertNotNull; -import org.junit.Test; -import org.mockito.Matchers; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.apache.tools.ant.filters.ReplaceTokens -public class InjectConstructTest -{ - @Test - public void testInjectConstruct() throws Exception - { - ClassFile targetClass = new ClassFile(); - targetClass.setName("test"); +description = "Web API" - ClassFile vanillaClass = new ClassFile(); - vanillaClass.setName("ab"); - Method constructor = new Method(vanillaClass, "", new Signature("()V")); - vanillaClass.addMethod(constructor); +dependencies { + annotationProcessor(Libraries.lombok) - Inject inject = mock(Inject.class); - when(inject.findVanillaForInterface(Matchers.any(Class.class))) - .thenReturn(vanillaClass); - InjectConstruct injectConstruct = new InjectConstruct(inject); - injectConstruct.injectConstruct(targetClass, APIClass.class.getDeclaredMethod("create")); + compileOnly(Libraries.javaxInject) + compileOnly(Libraries.lombok) - assertNotNull(targetClass.findMethod("create")); - } - - interface APIClass - { - APIClass create(); - } + implementation(Libraries.gson) + implementation(Libraries.guava) + implementation(Libraries.okhttp3) + implementation(Libraries.rxjava) + implementation(Libraries.apacheCommonsCsv) + implementation(Libraries.slf4jApi) + implementation(project(":runelite-api")) + testImplementation(Libraries.okhttp3Webserver) + testImplementation(Libraries.junit) + testImplementation(Libraries.slf4jSimple) +} + +tasks { + "processResources"(ProcessResources::class) { + val tokens = mapOf( + "projectver" to ProjectVersions.rlVersion, + "rsver" to ProjectVersions.rsversion.toString(), + "gitcommit" to project.extra["gitCommit"] + ) + + inputs.properties(tokens) + + from("src/main/resources") { + include("runelite.properties") + + filter("tokens" to tokens) + } + } } diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java index dbcceda631..7e035757ca 100644 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java @@ -25,13 +25,9 @@ package net.runelite.http.api; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import net.runelite.http.api.item.ItemEquipmentStats; -import net.runelite.http.api.item.ItemPrice; -import net.runelite.http.api.item.ItemStats; -import net.runelite.http.api.util.TypeAdapters; import okhttp3.HttpUrl; import okhttp3.Interceptor; +import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -60,12 +56,9 @@ public class RuneLiteAPI public static final String RUNELITE_AUTH = "RUNELITE-AUTH"; public static final OkHttpClient CLIENT; - public static final Gson GSON = new GsonBuilder() - .setPrettyPrinting() - .registerTypeAdapter(ItemStats.class, TypeAdapters.ITEMSTATS) - .registerTypeAdapter(ItemEquipmentStats.class, TypeAdapters.EQUIPMENTSTATS) - .registerTypeAdapter(ItemPrice.class, TypeAdapters.ITEMPRICE) - .create(); + public static final Gson GSON = new Gson(); + public static final MediaType JSON = MediaType.parse("application/json"); + public static String userAgent; private static final String BASE = "https://api.runelite.net"; private static final String WSBASE = "https://api.runelite.net/ws"; @@ -76,8 +69,6 @@ public class RuneLiteAPI private static final String MAVEN_METADATA = "http://repo.runelite.net/net/runelite/runelite-parent/maven-metadata.xml"; private static final Properties properties = new Properties(); - private static String userAgent; - private static String version; private static String upstreamVersion; private static int rsVersion; diff --git a/http-api/src/main/java/net/runelite/http/api/discord/DiscordEmbed.java b/http-api/src/main/java/net/runelite/http/api/discord/DiscordEmbed.java index 9de5f42331..d702a0d82d 100644 --- a/http-api/src/main/java/net/runelite/http/api/discord/DiscordEmbed.java +++ b/http-api/src/main/java/net/runelite/http/api/discord/DiscordEmbed.java @@ -61,49 +61,20 @@ public class DiscordEmbed VideoEmbed video; ProviderEmbed provider; AuthorEmbed author; - @Builder.Default - List fields = new ArrayList<>(); + final List fields = new ArrayList<>(); - public DiscordEmbed() + public DiscordEmbed(AuthorEmbed author, ThumbnailEmbed thumb, String description, FooterEmbed footer, String color, List fields) { - + this.author = author; + this.thumbnail = thumb; + this.description = description; + this.footer = footer; + this.color = color; + this.fields.addAll(fields); } - public DiscordEmbed(String title, String description) + public DiscordMessage toDiscordMessage(String username, String content, String avatarUrl) { - this(title, description, null); - } - - public DiscordEmbed(String title, String description, String url) - { - setTitle(title); - setDescription(description); - setUrl(url); - } - - public static DiscordMessage toDiscordMessage(DiscordEmbed embed, String username, String avatarURL) - { - return DiscordMessage.builder() - .username(username) - .avatarUrl(avatarURL) - .content("") - .embed(embed) - .build(); - } - - public DiscordMessage toDiscordMessage(String username, String avatarUrl) - { - return DiscordEmbed.toDiscordMessage(this, username, avatarUrl); - } - - public static class DiscordEmbedBuilder - { - List fields = new ArrayList<>(); - - public DiscordEmbedBuilder field(FieldEmbed field) - { - fields.add(field); - return this; - } + return new DiscordMessage(username, content, avatarUrl, this); } } diff --git a/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java b/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java index 061568da9d..cea482d203 100644 --- a/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java +++ b/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java @@ -29,16 +29,12 @@ package net.runelite.http.api.discord; import com.google.gson.annotations.SerializedName; import java.util.ArrayList; import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter -@Builder -@AllArgsConstructor @ToString public class DiscordMessage { @@ -48,24 +44,14 @@ public class DiscordMessage String avatarUrl; @SerializedName("tts") boolean textToSpeech; - List embeds = new ArrayList<>(); + final List embeds = new ArrayList<>(); - public DiscordMessage() + DiscordMessage(String username, String content, String avatar_url, DiscordEmbed embed) { - - } - - public DiscordMessage(String username, String content, String avatar_url) - { - this(username, content, avatar_url, false); - } - - public DiscordMessage(String username, String content, String avatar_url, boolean tts) - { - setUsername(username); - setContent(content); - setAvatarUrl(avatar_url); - setTextToSpeech(tts); + this.username = username; + this.content = content; + this.avatarUrl = avatar_url; + this.embeds.add(embed); } public void setUsername(String username) @@ -79,15 +65,4 @@ public class DiscordMessage this.username = null; } } - - public static class DiscordMessageBuilder - { - List embeds = new ArrayList<>(); - - public DiscordMessageBuilder embed(DiscordEmbed embed) - { - embeds.add(embed); - return this; - } - } } diff --git a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java index f016468e92..71ea20b533 100644 --- a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java +++ b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java @@ -30,10 +30,10 @@ import java.util.UUID; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; +import static net.runelite.http.api.RuneLiteAPI.JSON; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; -import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; @@ -42,7 +42,6 @@ import okhttp3.Response; @AllArgsConstructor public class GrandExchangeClient { - private static final MediaType JSON = MediaType.parse("application/json"); private static final Gson GSON = RuneLiteAPI.GSON; private final UUID uuid; diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java index c6a52ea419..51b9329018 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java @@ -36,10 +36,10 @@ import java.util.UUID; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; +import static net.runelite.http.api.RuneLiteAPI.JSON; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; -import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; @@ -48,7 +48,6 @@ import okhttp3.Response; @AllArgsConstructor public class LootTrackerClient { - private static final MediaType JSON = MediaType.parse("application/json"); private static final Gson GSON = RuneLiteAPI.GSON; private final UUID uuid; diff --git a/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java b/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java index 5176307511..5c6789ee4b 100644 --- a/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java +++ b/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java @@ -31,10 +31,10 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; import net.runelite.http.api.RuneLiteAPI; +import static net.runelite.http.api.RuneLiteAPI.JSON; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; -import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; @@ -43,8 +43,6 @@ import org.slf4j.LoggerFactory; public class XteaClient { - private static final MediaType JSON = MediaType.parse("application/json"); - private static final Logger logger = LoggerFactory.getLogger(XteaClient.class); public void submit(XteaRequest xteaRequest) diff --git a/http-api/src/main/resources/runelite.properties b/http-api/src/main/resources/runelite.properties index 7eb618db7a..9464b52906 100644 --- a/http-api/src/main/resources/runelite.properties +++ b/http-api/src/main/resources/runelite.properties @@ -1,4 +1,3 @@ runelite.version=@projectver@ rs.version=@rsver@ -runelite.commit=@gitcommit@ -runelite.dirty=@gitdirty@ \ No newline at end of file +runelite.commit=@gitcommit@ \ No newline at end of file diff --git a/http-service-openosrs/build.gradle b/http-service-openosrs/build.gradle deleted file mode 100644 index 1aee171338..0000000000 --- a/http-service-openosrs/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -apply plugin: 'war' - -description = 'Web Service OpenOSRS' - -dependencies { - annotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok - - api project(':cache') - api project(':http-api') - api project(':http-service') - - implementation group: 'com.google.code.gson', name: 'gson', version: gson - implementation group: 'com.google.guava', name: 'guava', version: guava - implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp3 - implementation group: 'org.springframework', name: 'spring-jdbc', version: springJdbc - implementation group: 'org.springframework.boot', name: 'spring-boot-devtools', version: springboot - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springboot - implementation group: 'org.sql2o', name: 'sql2o', version: sql2o - implementation(group: 'redis.clients', name: 'jedis', version: jedis) { - exclude(module: 'commons-pool2') - } - - providedCompile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: mariadbJdbc - providedCompile group: 'org.projectlombok', name: 'lombok', version: lombok - providedCompile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: springboot -} diff --git a/http-service-openosrs/http-service-openosrs.gradle.kts b/http-service-openosrs/http-service-openosrs.gradle.kts new file mode 100644 index 0000000000..6bf4f040ac --- /dev/null +++ b/http-service-openosrs/http-service-openosrs.gradle.kts @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 Owain van Brakel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +plugins { + war +} + +description = "Web Service OpenOSRS" + +dependencies { + annotationProcessor(Libraries.lombok) + + api(project(":cache")) + api(project(":http-api")) + api(project(":http-service")) + + implementation(Libraries.gson) + implementation(Libraries.guava) + implementation(Libraries.okhttp3) + implementation(Libraries.springbootJdbc) + implementation(Libraries.springbootDevtools) + implementation(Libraries.springbootStarterWeb) + implementation(Libraries.sql2o) + implementation(Libraries.jedis) { + exclude(module = "commons-pool2") + } + + providedCompile(Libraries.mariadbJdbc) + providedCompile(Libraries.lombok) + providedCompile(Libraries.springbootStarterTomcat) +} diff --git a/http-service/build.gradle b/http-service/build.gradle deleted file mode 100644 index 831fb94d45..0000000000 --- a/http-service/build.gradle +++ /dev/null @@ -1,37 +0,0 @@ -apply plugin: 'war' - -description = 'Web Service' - -dependencies { - annotationProcessor group: 'org.mapstruct', name: 'mapstruct-processor', version: mapstruct - annotationProcessor group: 'org.projectlombok', name: 'lombok', version: lombok - - api project(':cache') - api project(':http-api') - api project(':runelite-api') - - implementation group: 'com.github.scribejava', name: 'scribejava-apis', version: scribejava - implementation group: 'com.google.code.gson', name: 'gson', version: gson - implementation group: 'com.google.guava', name: 'guava', version: guava - implementation group: 'io.minio', name: 'minio', version: minio - implementation group: 'org.mapstruct', name: 'mapstruct-jdk8', version: mapstruct - implementation group: 'org.mongodb', name: 'mongodb-driver-sync', version: mongodbDriverSync - implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j - implementation group: 'org.springframework', name: 'spring-jdbc', version: springJdbc - implementation group: 'org.springframework.boot', name: 'spring-boot-devtools', version: springboot - implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springboot - implementation group: 'org.sql2o', name: 'sql2o', version: sql2o - implementation(group: 'redis.clients', name: 'jedis', version: jedis) { - exclude(module: 'commons-pool2') - } - - providedCompile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: mariadbJdbc - providedCompile group: 'org.projectlombok', name: 'lombok', version: lombok - providedCompile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: springboot - - testImplementation group: 'com.h2database', name: 'h2', version: '1.4.200' - testImplementation group: 'com.squareup.okhttp3', name: 'mockwebserver', version: okhttp3 - testImplementation(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: springboot) { - exclude(module: 'commons-logging') - } -} diff --git a/injector-plugin/src/test/java/net/runelite/injector/InjectTest.java b/http-service/http-service.gradle.kts similarity index 52% rename from injector-plugin/src/test/java/net/runelite/injector/InjectTest.java rename to http-service/http-service.gradle.kts index 109550d5b9..6eaf8c53a3 100644 --- a/injector-plugin/src/test/java/net/runelite/injector/InjectTest.java +++ b/http-service/http-service.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Adam + * Copyright (c) 2019 Owain van Brakel * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,53 +22,43 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.injector; - -import java.io.File; -import java.io.IOException; -import net.runelite.asm.ClassGroup; -import net.runelite.deob.DeobTestProperties; -import net.runelite.deob.TemporyFolderLocation; -import net.runelite.deob.util.JarUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class InjectTest -{ - @Rule - public DeobTestProperties properties = new DeobTestProperties(); - - @Rule - public TemporaryFolder folder = TemporyFolderLocation.getTemporaryFolder(); - - private ClassGroup deob, vanilla; - - @Before - public void before() throws IOException - { - deob = JarUtil.loadJar(new File(properties.getRsClient())); - vanilla = JarUtil.loadJar(new File(properties.getVanillaClient())); - } - - @After - public void after() throws IOException - { - JarUtil.saveJar(vanilla, folder.newFile()); - } - - @Test - @Ignore - public void testRun() throws InjectionException - { - Inject instance = new Inject(deob, vanilla); - instance.run(); - - InjectorValidator iv = new InjectorValidator(vanilla); - iv.validate(); - } +plugins { + war +} + +description = "Web Service" + +dependencies { + annotationProcessor(Libraries.mapstructProcessor) + annotationProcessor(Libraries.lombok) + + api(project(":cache")) + api(project(":http-api")) + api(project(":runelite-api")) + + implementation(Libraries.scribejava) + implementation(Libraries.gson) + implementation(Libraries.guava) + implementation(Libraries.minio) + implementation(Libraries.mapstruct) + implementation(Libraries.mongodbDriverSync) + implementation(Libraries.slf4jApi) + implementation(Libraries.springbootJdbc) + implementation(Libraries.springbootDevtools) + implementation(Libraries.springbootStarterWeb) + implementation(Libraries.sql2o) + implementation(Libraries.jedis) { + exclude(module = "commons-pool2") + } + + providedCompile(Libraries.mariadbJdbc) + providedCompile(Libraries.lombok) + providedCompile(Libraries.springbootStarterTomcat) + + testImplementation(Libraries.h2) + testImplementation(Libraries.okhttp3Webserver) + testImplementation(Libraries.springbootStarterTest) { + exclude(module = "commons-logging") + } } diff --git a/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java b/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java index bbe8557d88..727620570f 100644 --- a/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java +++ b/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java @@ -51,6 +51,7 @@ import net.runelite.http.api.config.ConfigEntry; import net.runelite.http.api.config.Configuration; import org.bson.Document; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service @@ -66,11 +67,12 @@ public class ConfigService @Autowired public ConfigService( - MongoClient mongoClient + MongoClient mongoClient, + @Value("${mongo.database}") String databaseName ) { - MongoDatabase database = mongoClient.getDatabase("config"); + MongoDatabase database = mongoClient.getDatabase(databaseName); MongoCollection collection = database.getCollection("config"); this.mongoCollection = collection; diff --git a/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java b/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java index 797d7e76e2..49e9e4a636 100644 --- a/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java +++ b/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java @@ -98,6 +98,11 @@ public class OSBGrandExchangeService Integer itemId = entry.getKey(); OsbuddySummaryItem item = entry.getValue(); + if (item.getBuy_average() <= 0 || item.getSell_average() <= 0 || item.getOverall_average() <= 0) + { + continue; + } + query .addParameter("itemId", itemId) .addParameter("buyAverage", item.getBuy_average()) diff --git a/http-service/src/main/resources/application.yaml b/http-service/src/main/resources/application.yaml index 3c6fc451fe..f5e1a799d9 100644 --- a/http-service/src/main/resources/application.yaml +++ b/http-service/src/main/resources/application.yaml @@ -32,10 +32,11 @@ redis: mongo: jndiName: java:comp/env/mongodb/runelite + database: runelite # Twitter client for feed runelite: twitter: consumerkey: secretkey: - listid: 968949795153948673 \ No newline at end of file + listid: 1185897074786742273 \ No newline at end of file diff --git a/injected-client/injected-client.gradle.kts b/injected-client/injected-client.gradle.kts new file mode 100644 index 0000000000..3d15bb3cbb --- /dev/null +++ b/injected-client/injected-client.gradle.kts @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 ThatGamerBlue + * Copyright (c) 2019 Owain van Brakel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +apply() + +description = "Injected Client" + +plugins { + id("com.openosrs.injector") +} + +configurations { + create("vanilla") + create("injected-client") +} + +dependencies { + "vanilla"(Libraries.vanilla) +} + +injector { + mixins.set(tasks.getByPath(":runelite-mixins:jar").outputs.files.singleFile) + rsapi.set(tasks.getByPath(":runescape-api:jar").outputs.files.singleFile) + rsclient.set(tasks.getByPath(":runescape-client:jar").outputs.files.singleFile) + vanilla.set(project.file(configurations["vanilla"].asPath)) +} + +artifacts { + add("runtime", tasks.inject.get().output) { + builtBy(tasks.inject) + } +} + +// keep the sourcesets etc but remove useless tasks +tasks { + classes { + enabled = false + } + compileJava { + enabled = false + } + jar { + enabled = false + } + processResources { + enabled = false + } +} \ No newline at end of file diff --git a/injector-plugin/build.gradle b/injector-plugin/build.gradle deleted file mode 100644 index 13e3f2555e..0000000000 --- a/injector-plugin/build.gradle +++ /dev/null @@ -1,63 +0,0 @@ -group = 'us.runelitepl.rs' -description = 'Injector' - -def buildPath = buildDir.toString().replace('\\', '/') // this doesnt work in an ext block for some reason -def deobfuscatedJar = "${rootPath}/runescape-client/build/libs/rs-client-${project.version}.jar" -def vanillaJar = "${buildPath}/vanilla-${rsversion}.jar" - -configurations { - vanilla -} - -dependencies { - annotationProcessor group: 'org.eclipse.sisu', name: 'org.eclipse.sisu.inject', version: sisu - - compileOnly group: 'org.apache.maven.plugin-tools', name: 'maven-plugin-annotations', version: mavenPluginAnnotations - - implementation group: 'com.google.guava', name: 'guava', version: guava - implementation group: 'org.apache.maven', name: 'maven-plugin-api', version: mavenPluginApi - implementation group: 'org.ow2.asm', name: 'asm', version: asm - implementation group: 'org.ow2.asm', name: 'asm-util', version: asm - implementation project(':deobfuscator') - implementation project(':mixins') - implementation project(':runelite-api') - implementation project(':runescape-api') - - testImplementation group: 'junit', name: 'junit', version: junit - testImplementation group: 'org.mockito', name: 'mockito-core', version: mockito - testImplementation project(':deobfuscator') - testImplementation project(path: ':deobfuscator', configuration: 'testArchives') - - vanilla "net.runelite.rs:vanilla:${rsversion}" -} - -compileJava { - dependsOn ":rs-client:build" - - inputs.dir("${project.rootDir}/runescape-client/") - inputs.dir("${project.rootDir}/runescape-api/") - inputs.dir("${project.rootDir}/runelite-mixins/") -} - -compileJava.doLast() { - copy { - from configurations.vanilla - into "$buildDir" - } - def path = sourceSets.main.runtimeClasspath - def loader - try { - loader = new URLClassLoader(path.collect { f -> f.toURI().toURL() } as URL[]) - def inject = loader.loadClass('net.runelite.injector.Injector') - String[] jarPaths = [ - deobfuscatedJar.toString(), - vanillaJar.toString(), - injectedClassesPath.toString() - ] - inject.main(jarPaths) - } finally { - if (loader) { - loader.close() - } - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/Inject.java b/injector-plugin/src/main/java/net/runelite/injector/Inject.java deleted file mode 100644 index 9d9b372f07..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/Inject.java +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.HashMap; -import java.util.Map; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Field; -import net.runelite.asm.Interfaces; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.DLoad; -import net.runelite.asm.attributes.code.instructions.FLoad; -import net.runelite.asm.attributes.code.instructions.ILoad; -import net.runelite.asm.attributes.code.instructions.LLoad; -import net.runelite.asm.pool.Class; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import net.runelite.deob.deobfuscators.arithmetic.DMath; -import static net.runelite.injector.InjectUtil.getFieldType; -import net.runelite.injector.raw.ClearColorBuffer; -import net.runelite.injector.raw.DrawAfterWidgets; -import net.runelite.injector.raw.Occluder; -import net.runelite.injector.raw.RasterizerHook; -import net.runelite.injector.raw.RenderDraw; -import net.runelite.injector.raw.ScriptVM; -import net.runelite.mapping.Import; -import net.runelite.rs.api.RSClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import net.runelite.injector.raw.HidePlayerAttacks; - -// import net.runelite.injector.raw.DrawMenu; - -public class Inject -{ - public static final java.lang.Class CLIENT_CLASS = RSClient.class; - public static final String API_PACKAGE_BASE = "net.runelite.rs.api.RS"; - public static final String RL_API_PACKAGE_BASE = "net.runelite.api."; - private static final Logger logger = LoggerFactory.getLogger(Inject.class); - private final InjectHookMethod hookMethod = new InjectHookMethod(this); - - private final InjectGetter getters = new InjectGetter(this); - private final InjectSetter setters = new InjectSetter(this); - private final InjectInvoker invokes = new InjectInvoker(this); - private final InjectConstruct construct = new InjectConstruct(this); - - private final MixinInjector mixinInjector = new MixinInjector(this); - - // deobfuscated contains exports etc to apply to vanilla - private final ClassGroup deobfuscated, vanilla; - - public Inject(ClassGroup deobfuscated, ClassGroup vanilla) - { - this.deobfuscated = deobfuscated; - this.vanilla = vanilla; - } - - /** - * Convert a java.lang.Class to a Type - * - * @param c - * @return - */ - public static Type classToType(java.lang.Class c) - { - int dimms = 0; - while (c.isArray()) - { - c = c.getComponentType(); - ++dimms; - } - - if (c.isPrimitive()) - { - String s; - - switch (c.getName()) - { - case "int": - s = "I"; - break; - case "long": - s = "J"; - break; - case "boolean": - s = "Z"; - break; - case "char": - s = "C"; - break; - case "short": - s = "S"; - break; - case "float": - s = "F"; - break; - case "double": - s = "D"; - break; - case "byte": - s = "B"; - break; - case "void": - s = "V"; - break; - default: - throw new RuntimeException("unknown primitive type " + c.getName()); - } - - return Type.getType(s, dimms); - } - - return Type.getType("L" + c.getName().replace('.', '/') + ";", dimms); - } - - public Signature getMethodSignature(Method m) - { - Signature signature = m.getDescriptor(); - - Annotation obfSignature = m.getAnnotations().find(DeobAnnotations.OBFUSCATED_SIGNATURE); - if (obfSignature != null) - { - //Annotation exists. Signature was updated by us during deobfuscation - signature = DeobAnnotations.getObfuscatedSignature(m); - } - - return signature; - } - - /** - * Build a Signature from a java method - * - * @param method - * @return - */ - public Signature javaMethodToSignature(java.lang.reflect.Method method) - { - Signature.Builder builder = new Signature.Builder() - .setReturnType(classToType(method.getReturnType())); - for (java.lang.Class clazz : method.getParameterTypes()) - { - builder.addArgument(classToType(clazz)); - } - return builder.build(); - } - - public void run() throws InjectionException - { - Map implemented = new HashMap<>(); - - // inject interfaces first, so the validateTypeIsConvertibleTo - // check below works - for (ClassFile cf : deobfuscated.getClasses()) - { - Annotations an = cf.getAnnotations(); - - if (an == null || an.size() == 0) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(an); - if (obfuscatedName == null) - { - obfuscatedName = cf.getName(); - } - - ClassFile other = vanilla.findClass(obfuscatedName); - assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName; - - java.lang.Class implementingClass = injectInterface(cf, other); - // it can not implement an interface but still have exported static fields, which are - // moved to client - - implemented.put(cf, implementingClass); - } - - // Has to be done before mixins - // well, can be done after really - // but why do that when you can do it before - new RasterizerHook(this).inject(); - - // requires interfaces to be injected - mixinInjector.inject(); - construct.inject(implemented); - - for (ClassFile cf : deobfuscated.getClasses()) - { - java.lang.Class implementingClass = implemented.get(cf); - Annotations an = cf.getAnnotations(); - - if (an == null || an.size() == 0) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(an); - if (obfuscatedName == null) - { - obfuscatedName = cf.getName(); - } - - ClassFile other = vanilla.findClass(obfuscatedName); - assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName; - - for (Field f : cf.getFields()) - { - an = f.getAnnotations(); - - if (an == null || an.find(DeobAnnotations.EXPORT) == null) - { - continue; // not an exported field - } - - Annotation exportAnnotation = an.find(DeobAnnotations.EXPORT); - String exportedName = exportAnnotation.getElement().getString(); - - obfuscatedName = DeobAnnotations.getObfuscatedName(an); - - Annotation getterAnnotation = an.find(DeobAnnotations.OBFUSCATED_GETTER); - Number getter = null; - if (getterAnnotation != null) - { - getter = (Number) getterAnnotation.getElement().getValue(); - } - // the ob jar is the same as the vanilla so this field must exist in this class. - - Type obType = getFieldType(f); - Field otherf = other.findField(obfuscatedName, obType); - assert otherf != null; - - assert f.isStatic() == otherf.isStatic(); - - ClassFile targetClass = f.isStatic() ? vanilla.findClass("client") : other; // target class for getter - java.lang.Class targetApiClass = f.isStatic() ? CLIENT_CLASS : implementingClass; // target api class for getter - if (targetApiClass == null) - { - assert !f.isStatic(); - - // non static field exported on non exported interface - // logger.debug("Non static exported field {} on non exported interface", exportedName); - continue; - } - - java.lang.reflect.Method apiMethod = findImportMethodOnApi(targetApiClass, exportedName, true); - if (apiMethod != null) - { - Number setter = null; - if (getter != null) - { - setter = DMath.modInverse(getter); // inverse getter to get the setter - } - - setters.injectSetter(targetClass, targetApiClass, otherf, exportedName, setter); - } - - apiMethod = findImportMethodOnApi(targetApiClass, exportedName, false); - if (apiMethod == null) - { - //logger.debug("Unable to find import method on api class {} with imported name {}, not injecting getter", targetApiClass, exportedName); - continue; - } - - // check that otherf is converable to apiMethod's - // return type - Type fieldType = otherf.getType(); - Type returnType = classToType(apiMethod.getReturnType()); - if (!validateTypeIsConvertibleTo(fieldType, returnType)) - { - throw new InjectionException("Type " + fieldType + " is not convertable to " + returnType + " for getter " + apiMethod); - } - - getters.injectGetter(targetClass, apiMethod, otherf, getter); - } - - for (Method m : cf.getMethods()) - { - hookMethod.process(m); - invokes.process(m, other, implementingClass); - } - } - - logger.info("Injected {} getters, {} setters, {} invokers", - getters.getInjectedGetters(), - setters.getInjectedSetters(), invokes.getInjectedInvokers()); - - new DrawAfterWidgets(this).inject(); - new ScriptVM(this).inject(); - new ClearColorBuffer(this).inject(); - new RenderDraw(this).inject(); - // new DrawMenu(this).inject(); - new Occluder(this).inject(); - new HidePlayerAttacks(this).inject(); - } - - private java.lang.Class injectInterface(ClassFile cf, ClassFile other) - { - Annotations an = cf.getAnnotations(); - if (an == null) - { - return null; - } - - Annotation a = an.find(DeobAnnotations.IMPLEMENTS); - if (a == null) - { - return null; - } - - String ifaceName = API_PACKAGE_BASE + a.getElement().getString(); - java.lang.Class apiClass; - - try - { - apiClass = java.lang.Class.forName(ifaceName); - } - catch (ClassNotFoundException ex) - { - logger.trace("Class {} implements nonexistent interface {}, skipping interface injection", - cf.getName(), - ifaceName); - return null; - } - - String ifaceNameInternal = ifaceName.replace('.', '/'); // to internal name - Class clazz = new Class(ifaceNameInternal); - - Interfaces interfaces = other.getInterfaces(); - interfaces.addInterface(clazz); - - return apiClass; - } - - public java.lang.reflect.Method findImportMethodOnApi(java.lang.Class clazz, String name, Boolean setter) - { - for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) - { - if (method.isSynthetic()) - { - /* - * If you override an interface method in another interface - * with a return type that is a child of the overriden methods - * return type, both methods end up in the interface, and both - * are *annotated*. But the base one is synthetic. - */ - continue; - } - - Import i = method.getAnnotation(Import.class); - - if (i == null || !name.equals(i.value()) || (setter != null && (method.getParameterCount() > 0) != setter)) - { - continue; - } - - return method; - } - - return null; - } - - /** - * create a load instruction for a variable of type from a given index - * - * @param instructions - * @param type - * @param index - * @return - */ - public Instruction createLoadForTypeIndex(Instructions instructions, Type type, int index) - { - if (type.getDimensions() > 0 || !type.isPrimitive()) - { - return new ALoad(instructions, index); - } - - switch (type.toString()) - { - case "B": - case "C": - case "I": - case "S": - case "Z": - return new ILoad(instructions, index); - case "D": - return new DLoad(instructions, index); - case "F": - return new FLoad(instructions, index); - case "J": - return new LLoad(instructions, index); - default: - throw new RuntimeException("Unknown type"); - } - } - - ClassFile toDeobClass(ClassFile obClass) - { - for (ClassFile cf : deobfuscated.getClasses()) - { - String obfuscatedName = DeobAnnotations.getObfuscatedName(cf.getAnnotations()); - - if (obClass.getName().equalsIgnoreCase(obfuscatedName)) - { - return cf; - } - } - - return null; - } - - Type deobfuscatedTypeToApiType(Type type) throws InjectionException - { - if (type.isPrimitive()) - { - return type; - } - - ClassFile cf = deobfuscated.findClass(type.getInternalName()); - if (cf == null) - { - return type; // not my type - } - - java.lang.Class rsApiType; - try - { - rsApiType = java.lang.Class.forName(API_PACKAGE_BASE + cf.getName().replace("/", ".")); - } - catch (ClassNotFoundException ex) - { - throw new InjectionException("Deobfuscated type " + type.getInternalName() + " has no API type", ex); - } - - java.lang.Class rlApiType = null; - - for (java.lang.Class inter : rsApiType.getInterfaces()) - { - if (inter.getName().startsWith(RL_API_PACKAGE_BASE)) - { - rlApiType = inter; - } - } - - // if (rlApiType == null) - // { - // throw new InjectionException("RS API type " + rsApiType + " does not extend RL API interface"); - // } - - final java.lang.Class finalType = rlApiType == null ? rsApiType : rlApiType; - - return Type.getType("L" + finalType.getName().replace('.', '/') + ";", type.getDimensions()); - } - - Type apiTypeToDeobfuscatedType(Type type) - { - if (type.isPrimitive()) - { - return type; - } - - String internalName = type.getInternalName().replace('/', '.'); - if (!internalName.startsWith(API_PACKAGE_BASE)) - { - return type; // not an rs api type - } - - return Type.getType("L" + type.getInternalName().substring(API_PACKAGE_BASE.length()) + ";", type.getDimensions()); - } - - ClassFile findVanillaForInterface(java.lang.Class clazz) - { - String className = clazz.getName().replace('.', '/'); - for (ClassFile cf : getVanilla().getClasses()) - { - for (net.runelite.asm.pool.Class cl : cf.getInterfaces().getInterfaces()) - { - if (cl.getName().equals(className)) - { - return cf; - } - } - } - return null; - } - - private boolean validateTypeIsConvertibleTo(Type from, Type to) throws InjectionException - { - if (from.getDimensions() != to.getDimensions()) - { - throw new InjectionException("Array dimension mismatch"); - } - - if (from.isPrimitive()) - { - return true; - } - - ClassFile vanillaClass = vanilla.findClass(from.getInternalName()); - if (vanillaClass == null) - { - return true; - } - - boolean okay = false; - for (Class inter : vanillaClass.getInterfaces().getInterfaces()) - { - java.lang.Class c; - - try - { - c = java.lang.Class.forName(inter.getName().replace('/', '.')); - } - catch (ClassNotFoundException ex) - { - continue; - } - - okay |= check(c, to); - } - - return okay; - } - - private boolean check(java.lang.Class c, Type type) - { - String s = type.getInternalName() - .replace('/', '.'); - - if (c.getName().equals(s)) - { - return true; - } - - for (java.lang.Class c2 : c.getInterfaces()) - { - if (check(c2, type)) - { - return true; - } - } - return false; - } - - public final ClassGroup getDeobfuscated() - { - return deobfuscated; - } - - public final ClassGroup getVanilla() - { - return vanilla; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectConstruct.java b/injector-plugin/src/main/java/net/runelite/injector/InjectConstruct.java deleted file mode 100644 index 8a87451da6..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectConstruct.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.Dup; -import net.runelite.asm.attributes.code.instructions.InvokeSpecial; -import net.runelite.asm.attributes.code.instructions.New; -import net.runelite.asm.attributes.code.instructions.Return; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import net.runelite.mapping.Construct; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class InjectConstruct -{ - private static final Logger logger = LoggerFactory.getLogger(InjectConstruct.class); - - private final Inject inject; - - InjectConstruct(Inject inject) - { - this.inject = inject; - } - - public void inject(Map implemented) throws InjectionException - { - for (Entry entry : implemented.entrySet()) - { - Class clazz = entry.getValue(); - ClassFile cf = entry.getKey(); - - if (clazz == null) - { - continue; - } - - for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) - { - if (method.isSynthetic()) - { - continue; - } - - Construct construct = method.getAnnotation(Construct.class); - if (construct == null) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(cf.getAnnotations()); - if (obfuscatedName == null) - { - obfuscatedName = cf.getName(); - } - - ClassGroup vanilla = inject.getVanilla(); - ClassFile other = vanilla.findClass(obfuscatedName); - assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName; - - injectConstruct(other, method); - } - } - } - - void injectConstruct(ClassFile targetClass, java.lang.reflect.Method apiMethod) throws InjectionException - { - logger.info("Injecting construct for {}", apiMethod); - - assert targetClass.findMethod(apiMethod.getName()) == null; - - Class typeToConstruct = apiMethod.getReturnType(); - ClassFile vanillaClass = inject.findVanillaForInterface(typeToConstruct); - if (vanillaClass == null) - { - throw new InjectionException("Unable to find vanilla class which implements interface " + typeToConstruct); - } - - Signature sig = inject.javaMethodToSignature(apiMethod); - - Signature constructorSig = new Signature.Builder() - .addArguments(Stream.of(apiMethod.getParameterTypes()) - .map(arg -> - { - ClassFile vanilla = inject.findVanillaForInterface(arg); - if (vanilla != null) - { - return new Type("L" + vanilla.getName() + ";"); - } - return Inject.classToType(arg); - }) - .collect(Collectors.toList())) - .setReturnType(Type.VOID) - .build(); - Method vanillaConstructor = vanillaClass.findMethod("", constructorSig); - if (vanillaConstructor == null) - { - throw new InjectionException("Unable to find constructor for " + vanillaClass.getName() + "." + constructorSig); - } - - Method setterMethod = new Method(targetClass, apiMethod.getName(), sig); - setterMethod.setAccessFlags(ACC_PUBLIC); - targetClass.addMethod(setterMethod); - - Code code = new Code(setterMethod); - setterMethod.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - ins.add(new New(instructions, vanillaClass.getPoolClass())); - ins.add(new Dup(instructions)); - int idx = 1; - int parameter = 0; - for (Type type : vanillaConstructor.getDescriptor().getArguments()) - { - Instruction load = inject.createLoadForTypeIndex(instructions, type, idx); - idx += type.getSize(); - ins.add(load); - - Type paramType = sig.getTypeOfArg(parameter); - if (!type.equals(paramType)) - { - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(type); - ins.add(checkCast); - } - - ++parameter; - } - ins.add(new InvokeSpecial(instructions, vanillaConstructor.getPoolMethod())); - ins.add(new Return(instructions)); - - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectGetter.java b/injector-plugin/src/main/java/net/runelite/injector/InjectGetter.java deleted file mode 100644 index cd94ee80d8..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectGetter.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.GetField; -import net.runelite.asm.attributes.code.instructions.GetStatic; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LMul; -import net.runelite.asm.attributes.code.instructions.Return; -import net.runelite.asm.signature.Signature; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectGetter -{ - private static final Logger logger = LoggerFactory.getLogger(InjectGetter.class); - - private final Inject inject; - - private int injectedGetters; - - InjectGetter(Inject inject) - { - this.inject = inject; - } - - void injectGetter(ClassFile clazz, java.lang.reflect.Method method, Field field, Number getter) - { - // clazz = class file we're injecting the method into. - // method = api method (java reflect) that we're overriding - // field = field we're getting. might not be in this class if static. - // getter = encryption getter - - assert clazz.findMethod(method.getName()) == null; - assert field.isStatic() || field.getClassFile() == clazz; - - Signature sig = new Signature.Builder() - .setReturnType(Inject.classToType(method.getReturnType())) - .build(); - Method getterMethod = new Method(clazz, method.getName(), sig); - getterMethod.setAccessFlags(ACC_PUBLIC); - - // create code - Code code = new Code(getterMethod); - getterMethod.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - if (field.isStatic()) - { - code.setMaxStack(1); - - ins.add(new GetStatic(instructions, field.getPoolField())); - } - else - { - code.setMaxStack(2); - - ins.add(new ALoad(instructions, 0)); - ins.add(new GetField(instructions, field.getPoolField())); - } - - if (getter != null) - { - code.setMaxStack(2); - - assert getter instanceof Integer || getter instanceof Long; - - if (getter instanceof Integer) - { - ins.add(new LDC(instructions, (int) getter)); - ins.add(new IMul(instructions)); - } - else - { - ins.add(new LDC(instructions, (long) getter)); - ins.add(new LMul(instructions)); - } - } - - InstructionType returnType; - if (field.getType().isPrimitive() && field.getType().getDimensions() == 0) - { - switch (field.getType().toString()) - { - case "B": - case "C": - case "I": - case "S": - case "Z": - returnType = InstructionType.IRETURN; - break; - case "D": - returnType = InstructionType.DRETURN; - break; - case "F": - returnType = InstructionType.FRETURN; - break; - case "J": - returnType = InstructionType.LRETURN; - break; - default: - throw new RuntimeException("Unknown type"); - } - } - else - { - returnType = InstructionType.ARETURN; - } - - ins.add(new Return(instructions, returnType)); - - clazz.addMethod(getterMethod); - ++injectedGetters; - } - - int getInjectedGetters() - { - return injectedGetters; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectHook.java b/injector-plugin/src/main/java/net/runelite/injector/InjectHook.java deleted file mode 100644 index 19ae3a3df6..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectHook.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import com.google.common.collect.Lists; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.DupInstruction; -import net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction; -import net.runelite.asm.attributes.code.instructions.ArrayStore; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.Dup; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.InvokeVirtual; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LMul; -import net.runelite.asm.attributes.code.instructions.PutField; -import net.runelite.asm.attributes.code.instructions.Swap; -import net.runelite.asm.execution.Execution; -import net.runelite.asm.execution.InstructionContext; -import net.runelite.asm.execution.StackContext; -import net.runelite.asm.signature.Signature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectHook -{ - private static final Logger logger = LoggerFactory.getLogger(InjectHook.class); - private static final String HOOK_METHOD_SIGNATURE = "(I)V"; - private static final String CLINIT = ""; - private final Inject inject; - private final Map hooked = new HashMap<>(); - private int injectedHooks; - - InjectHook(Inject inject) - { - this.inject = inject; - } - - void hook(Field field, HookInfo hookInfo) - { - hooked.put(field, hookInfo); - } - - void run() - { - Execution e = new Execution(inject.getVanilla()); - e.populateInitialMethods(); - - Set done = new HashSet<>(); - Set doneIh = new HashSet<>(); - - e.addExecutionVisitor((InstructionContext ic) -> - { - Instruction i = ic.getInstruction(); - Instructions ins = i.getInstructions(); - Code code = ins.getCode(); - Method method = code.getMethod(); - - if (method.getName().equals(CLINIT)) - { - return; - } - - if (!(i instanceof SetFieldInstruction)) - { - return; - } - - if (!done.add(i)) - { - return; - } - - SetFieldInstruction sfi = (SetFieldInstruction) i; - Field fieldBeingSet = sfi.getMyField(); - - if (fieldBeingSet == null) - { - return; - } - - HookInfo hookInfo = hooked.get(fieldBeingSet); - if (hookInfo == null) - { - return; - } - - String hookName = hookInfo.fieldName; - assert hookName != null; - - logger.trace("Found injection location for hook {} at instruction {}", hookName, sfi); - ++injectedHooks; - - StackContext value = ic.getPops().get(0); - - StackContext objectStackContext = null; - if (sfi instanceof PutField) - { - objectStackContext = ic.getPops().get(1); - } - - int idx = ins.getInstructions().indexOf(sfi); - assert idx != -1; - - try - { - if (hookInfo.before) - { - injectCallbackBefore(ins, idx, hookInfo, null, objectStackContext, value); - } - else - { - // idx + 1 to insert after the set - injectCallback(ins, idx + 1, hookInfo, null, objectStackContext); - } - } - catch (InjectionException ex) - { - throw new RuntimeException(ex); - } - }); - - // these look like: - // getfield - // iload_0 - // iconst_0 - // iastore - e.addExecutionVisitor((InstructionContext ic) -> - { - Instruction i = ic.getInstruction(); - Instructions ins = i.getInstructions(); - Code code = ins.getCode(); - Method method = code.getMethod(); - - if (method.getName().equals(CLINIT)) - { - return; - } - - if (!(i instanceof ArrayStore)) - { - return; - } - - if (!doneIh.add(i)) - { - return; - } - - ArrayStore as = (ArrayStore) i; - - Field fieldBeingSet = as.getMyField(ic); - if (fieldBeingSet == null) - { - return; - } - - HookInfo hookInfo = hooked.get(fieldBeingSet); - if (hookInfo == null) - { - return; - } - - String hookName = hookInfo.fieldName; - - StackContext value = ic.getPops().get(0); - StackContext index = ic.getPops().get(1); - - StackContext arrayReference = ic.getPops().get(2); - InstructionContext arrayReferencePushed = arrayReference.getPushed(); - - StackContext objectStackContext = null; - if (arrayReferencePushed.getInstruction().getType() == InstructionType.GETFIELD) - { - objectStackContext = arrayReferencePushed.getPops().get(0); - } - - // inject hook after 'i' - logger.info("Found array injection location for hook {} at instruction {}", hookName, i); - ++injectedHooks; - - int idx = ins.getInstructions().indexOf(i); - assert idx != -1; - - try - { - if (hookInfo.before) - { - injectCallbackBefore(ins, idx, hookInfo, index, objectStackContext, value); - } - else - { - injectCallback(ins, idx + 1, hookInfo, index, objectStackContext); - } - } - catch (InjectionException ex) - { - throw new RuntimeException(ex); - } - }); - - e.run(); - } - - private void injectCallbackBefore(Instructions ins, int idx, HookInfo hookInfo, StackContext index, StackContext object, StackContext value) throws InjectionException - { - Signature signature = hookInfo.method.getDescriptor(); - Type methodArgumentType = signature.getTypeOfArg(0); - - if (!hookInfo.method.isStatic()) - { - if (object == null) - { - throw new InjectionException("null object"); - } - - ins.getInstructions().add(idx++, new Dup(ins)); // dup value - idx = recursivelyPush(ins, idx, object); - ins.getInstructions().add(idx++, new Swap(ins)); - if (hookInfo.getter != null) - { - assert hookInfo.getter instanceof Integer || hookInfo.getter instanceof Long; - - if (hookInfo.getter instanceof Integer) - { - ins.getInstructions().add(idx++, new LDC(ins, (int) hookInfo.getter)); - ins.getInstructions().add(idx++, new IMul(ins)); - } - else - { - ins.getInstructions().add(idx++, new LDC(ins, (long) hookInfo.getter)); - ins.getInstructions().add(idx++, new LMul(ins)); - } - } - if (!value.type.equals(methodArgumentType)) - { - CheckCast checkCast = new CheckCast(ins); - checkCast.setType(methodArgumentType); - ins.getInstructions().add(idx++, checkCast); - } - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - - InvokeVirtual invoke = new InvokeVirtual(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - signature - ) - ); - ins.getInstructions().add(idx++, invoke); - } - else - { - ins.getInstructions().add(idx++, new Dup(ins)); // dup value - if (!value.type.equals(methodArgumentType)) - { - CheckCast checkCast = new CheckCast(ins); - checkCast.setType(methodArgumentType); - ins.getInstructions().add(idx++, checkCast); - } - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - - InvokeStatic invoke = new InvokeStatic(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - signature - ) - ); - ins.getInstructions().add(idx++, invoke); - } - } - - private int recursivelyPush(Instructions ins, int idx, StackContext sctx) - { - InstructionContext ctx = sctx.getPushed(); - if (ctx.getInstruction() instanceof DupInstruction) - { - DupInstruction dupInstruction = (DupInstruction) ctx.getInstruction(); - sctx = dupInstruction.getOriginal(sctx); - ctx = sctx.getPushed(); - } - - for (StackContext s : Lists.reverse(ctx.getPops())) - { - idx = recursivelyPush(ins, idx, s); - } - - ins.getInstructions().add(idx++, ctx.getInstruction().clone()); - return idx; - } - - private void injectCallback(Instructions ins, int idx, HookInfo hookInfo, StackContext index, StackContext objectPusher) throws InjectionException - { - if (!hookInfo.method.isStatic()) - { - if (objectPusher == null) - { - throw new InjectionException("Null object pusher"); - } - - idx = recursivelyPush(ins, idx, objectPusher); - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - else - { - ins.getInstructions().add(idx++, new LDC(ins, -1)); - } - - InvokeVirtual invoke = new InvokeVirtual(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - new Signature(HOOK_METHOD_SIGNATURE) - ) - ); - ins.getInstructions().add(idx++, invoke); - - } - else - { - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - else - { - ins.getInstructions().add(idx++, new LDC(ins, -1)); - } - - InvokeStatic invoke = new InvokeStatic(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - new Signature(HOOK_METHOD_SIGNATURE) - ) - ); - ins.getInstructions().add(idx++, invoke); - } - } - - int getInjectedHooks() - { - return injectedHooks; - } - - static class HookInfo - { - String fieldName; - String clazz; - Method method; - boolean before; - Number getter; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectHookMethod.java b/injector-plugin/src/main/java/net/runelite/injector/InjectHookMethod.java deleted file mode 100644 index 3c304807be..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectHookMethod.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction; -import net.runelite.asm.attributes.code.instruction.types.ReturnInstruction; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.InvokeVirtual; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class InjectHookMethod -{ - public static final String HOOKS = "net/runelite/client/callback/Hooks"; - private static final Logger logger = LoggerFactory.getLogger(InjectHookMethod.class); - private final Inject inject; - - InjectHookMethod(Inject inject) - { - this.inject = inject; - } - - void process(Method method) throws InjectionException - { - Annotations an = method.getAnnotations(); - if (an == null) - { - return; - } - - Annotation a = an.find(DeobAnnotations.HOOK); - if (a == null) - { - return; - } - - String hookName = a.getElement().getString(); - boolean end = a.getElements().size() == 2 && a.getElements().get(1).getValue().equals(true); - - inject(null, method, hookName, end, true); - } - - public void inject(Method hookMethod, Method method, String name, boolean end, boolean useHooks) throws InjectionException - { - Annotations an = method.getAnnotations(); - - // Method is hooked - // Find equivalent method in vanilla, and insert callback at the beginning - ClassFile cf = method.getClassFile(); - String obfuscatedMethodName = DeobAnnotations.getObfuscatedName(an), - obfuscatedClassName = DeobAnnotations.getObfuscatedName(cf.getAnnotations()); - - // might be a constructor - if (obfuscatedMethodName == null) - { - obfuscatedMethodName = method.getName(); - } - - assert obfuscatedClassName != null : "hook on method in class with no obfuscated name"; - assert obfuscatedMethodName != null : "hook on method with no obfuscated name"; - - Signature obfuscatedSignature = inject.getMethodSignature(method); - - ClassGroup vanilla = inject.getVanilla(); - ClassFile vanillaClass = vanilla.findClass(obfuscatedClassName); - Method vanillaMethod = vanillaClass.findMethod(obfuscatedMethodName, obfuscatedSignature); - assert method.isStatic() == vanillaMethod.isStatic(); - - // Insert instructions at beginning of method - injectHookMethod(hookMethod, name, end, method, vanillaMethod, useHooks); - } - - private void injectHookMethod(Method hookMethod, String hookName, boolean end, Method deobMethod, Method vanillaMethod, boolean useHooks) throws InjectionException - { - Code code = vanillaMethod.getCode(); - if (code == null) - { - logger.warn(vanillaMethod + " code is null"); - } - Instructions instructions = code.getInstructions(); - - Signature.Builder builder = new Signature.Builder() - .setReturnType(Type.VOID); // Hooks always return void - - for (Type type : deobMethod.getDescriptor().getArguments()) - { - builder.addArgument(inject.deobfuscatedTypeToApiType(type)); - } - - assert deobMethod.isStatic() == vanillaMethod.isStatic(); - - boolean modifiedSignature = false; - if (!deobMethod.isStatic() && useHooks) - { - // Add variable to signature - builder.addArgument(0, inject.deobfuscatedTypeToApiType(new Type(deobMethod.getClassFile().getName()))); - modifiedSignature = true; - } - - Signature signature = builder.build(); - - List insertIndexes = findHookLocations(hookName, end, vanillaMethod); - insertIndexes.sort((a, b) -> Integer.compare(b, a)); - - for (int insertPos : insertIndexes) - { - if (!deobMethod.isStatic()) - { - instructions.addInstruction(insertPos++, new ALoad(instructions, 0)); - } - - int signatureStart = modifiedSignature ? 1 : 0; - int index = deobMethod.isStatic() ? 0 : 1; // current variable index - - for (int i = signatureStart; i < signature.size(); ++i) - { - Type type = signature.getTypeOfArg(i); - - Instruction load = inject.createLoadForTypeIndex(instructions, type, index); - instructions.addInstruction(insertPos++, load); - - index += type.getSize(); - } - - InvokeInstruction invoke; - - // use old Hooks callback - if (useHooks) - { - // Invoke callback - invoke = new InvokeStatic(instructions, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(HOOKS), - hookName, - signature - ) - ); - } - else - { - // Invoke methodhook - assert hookMethod != null; - - if (vanillaMethod.isStatic()) - { - invoke = new InvokeStatic(instructions, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class("client"), // Static methods are in client - hookMethod.getName(), - signature - ) - ); - } - else - { - // otherwise invoke member function - //instructions.addInstruction(insertPos++, new ALoad(instructions, 0)); - invoke = new InvokeVirtual(instructions, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(vanillaMethod.getClassFile().getName()), - hookMethod.getName(), - hookMethod.getDescriptor() - ) - ); - } - } - - instructions.addInstruction(insertPos++, (Instruction) invoke); - } - - logger.info("Injected method hook {} in {} with {} args: {}", - hookName, vanillaMethod, signature.size(), - signature.getArguments()); - } - - private List findHookLocations(String hookName, boolean end, Method vanillaMethod) throws InjectionException - { - Instructions instructions = vanillaMethod.getCode().getInstructions(); - - if (end) - { - // find return - List returns = instructions.getInstructions().stream() - .filter(i -> i instanceof ReturnInstruction) - .collect(Collectors.toList()); - List indexes = new ArrayList<>(); - - for (Instruction ret : returns) - { - int idx = instructions.getInstructions().indexOf(ret); - assert idx != -1; - indexes.add(idx); - } - - return indexes; - } - - if (!vanillaMethod.getName().equals("")) - { - return Arrays.asList(0); - } - - // Find index after invokespecial - for (int i = 0; i < instructions.getInstructions().size(); ++i) - { - Instruction in = instructions.getInstructions().get(i); - - if (in.getType() == InstructionType.INVOKESPECIAL) - { - return Arrays.asList(i + 1); // one after - } - } - - throw new IllegalStateException("constructor with no invokespecial"); - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectInvoker.java b/injector-plugin/src/main/java/net/runelite/injector/InjectInvoker.java deleted file mode 100644 index 3367b26c7a..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectInvoker.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.BiPush; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.DLoad; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.InvokeVirtual; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LLoad; -import net.runelite.asm.attributes.code.instructions.Return; -import net.runelite.asm.attributes.code.instructions.SiPush; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import static net.runelite.deob.DeobAnnotations.EXPORT; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectInvoker -{ - private static final Logger logger = LoggerFactory.getLogger(InjectInvoker.class); - - private final Inject inject; - - private int injectedInvokers; - - InjectInvoker(Inject inject) - { - this.inject = inject; - } - - /** - * Inject an invoker for a method - * - * @param m Method in the deobfuscated client to inject an invoker for - * @param other Class in the vanilla client of the same class m is a - * member of - * @param implementingClass Java class for the API interface the class - * will implement - */ - void process(Method m, ClassFile other, java.lang.Class implementingClass) - { - Annotations an = m.getAnnotations(); - - if (an == null || an.find(EXPORT) == null) - { - return; // not an exported method - } - - String exportedName = DeobAnnotations.getExportedName(an); - String obfuscatedName = DeobAnnotations.getObfuscatedName(an); - - if (obfuscatedName == null) - { - obfuscatedName = m.getName(); - } - - String garbage = DeobAnnotations.getDecoder(m); - Method otherm = other.findMethod(obfuscatedName, inject.getMethodSignature(m)); - - assert otherm != null; - assert m.isStatic() == otherm.isStatic(); - - ClassGroup vanilla = inject.getVanilla(); - - ClassFile targetClass = m.isStatic() ? vanilla.findClass("client") : other; - - // Place into implementing class, unless the method is static - java.lang.Class targetClassJava = m.isStatic() ? Inject.CLIENT_CLASS : implementingClass; - - if (targetClassJava == null) - { - assert !m.isStatic(); - - // non static exported method on non exported interface, weird. - // logger.debug("Non static exported method {} on non exported interface", exportedName); - return; - } - - java.lang.reflect.Method apiMethod = inject.findImportMethodOnApi(targetClassJava, exportedName, null); // api method to invoke 'otherm' - if (apiMethod == null) - { - // logger.debug("Unable to find api method on {} with imported name {}, not injecting invoker", targetClassJava, exportedName); - return; - } - - injectInvoker(targetClass, apiMethod, m, otherm, garbage); - ++injectedInvokers; - } - - private void injectInvoker(ClassFile clazz, java.lang.reflect.Method method, Method deobfuscatedMethod, Method invokeMethod, String garbage) - { - // clazz = clazz to add invoker to - // method = api method to override - // deobfuscatedMethod = deobfuscated method, used to get the deobfuscated signature - // invokeMethod = method to invoke, obfuscated - - if (clazz.findMethod(method.getName(), deobfuscatedMethod.getDescriptor()) != null) - { - logger.warn("Not injecting method {} because it already exists!", method); - return; // this can happen from exporting a field and method with the same name - } - - assert invokeMethod.isStatic() == deobfuscatedMethod.isStatic(); - assert invokeMethod.isStatic() || invokeMethod.getClassFile() == clazz; - - Type lastGarbageArgumentType = null; - - if (deobfuscatedMethod.getDescriptor().getArguments().size() != invokeMethod.getDescriptor().getArguments().size()) - { - // allow for obfuscated method to have a single bogus signature at the end - assert deobfuscatedMethod.getDescriptor().size() + 1 == invokeMethod.getDescriptor().size(); - - List arguments = invokeMethod.getDescriptor().getArguments(); - lastGarbageArgumentType = arguments.get(arguments.size() - 1); - } - - // Injected method signature is always the same as the API - Signature apiSignature = inject.javaMethodToSignature(method); - Method invokerMethodSignature = new Method(clazz, method.getName(), apiSignature); - invokerMethodSignature.setAccessFlags(ACC_PUBLIC); - - // create code attribute - Code code = new Code(invokerMethodSignature); - invokerMethodSignature.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - code.setMaxStack(1 + invokeMethod.getDescriptor().size()); // this + arguments - - // load function arguments onto the stack. - int index = 0; - if (!invokeMethod.isStatic()) - { - ins.add(new ALoad(instructions, index++)); // this - } - else - { - ++index; // this method is always non static - } - for (int i = 0; i < deobfuscatedMethod.getDescriptor().size(); ++i) - { - Type type = deobfuscatedMethod.getDescriptor().getTypeOfArg(i); - - Instruction loadInstruction = inject.createLoadForTypeIndex(instructions, type, index); - ins.add(loadInstruction); - - Signature invokeDesc = invokeMethod.getDescriptor(); - Type obType = invokeDesc.getTypeOfArg(i); - if (!type.equals(obType)) - { - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(obType); - ins.add(checkCast); - } - - if (loadInstruction instanceof DLoad || loadInstruction instanceof LLoad) - { - index += 2; - } - else - { - index += 1; - } - } - - if (lastGarbageArgumentType != null) - { - // function requires garbage value - - // if garbage is null here it might just be an unused parameter, not part of the obfuscation - if (garbage == null) - { - garbage = "0"; - } - - switch (lastGarbageArgumentType.toString()) - { - case "Z": - case "B": - case "C": - ins.add(new BiPush(instructions, Byte.parseByte(garbage))); - break; - case "S": - ins.add(new SiPush(instructions, Short.parseShort(garbage))); - break; - case "I": - ins.add(new LDC(instructions, Integer.parseInt(garbage))); - break; - case "D": - ins.add(new LDC(instructions, Double.parseDouble(garbage))); - break; - case "F": - ins.add(new LDC(instructions, Float.parseFloat(garbage))); - break; - case "J": - ins.add(new LDC(instructions, Long.parseLong(garbage))); - break; - default: - throw new RuntimeException("Unknown type"); - } - } - - if (invokeMethod.isStatic()) - { - ins.add(new InvokeStatic(instructions, invokeMethod.getPoolMethod())); - } - else - { - ins.add(new InvokeVirtual(instructions, invokeMethod.getPoolMethod())); - } - - Type returnValue = invokeMethod.getDescriptor().getReturnValue(); - InstructionType returnType; - - if (returnValue.isPrimitive() && returnValue.getDimensions() == 0) - { - switch (returnValue.toString()) - { - case "Z": - case "I": - returnType = InstructionType.IRETURN; - break; - case "J": - returnType = InstructionType.LRETURN; - break; - case "F": - returnType = InstructionType.FRETURN; - break; - case "D": - returnType = InstructionType.DRETURN; - break; - case "V": - returnType = InstructionType.RETURN; - break; - default: - assert false; - return; - } - } - else - { - returnType = InstructionType.ARETURN; - } - - ins.add(new Return(instructions, returnType)); - - clazz.addMethod(invokerMethodSignature); - } - - int getInjectedInvokers() - { - return injectedInvokers; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectMojo.java b/injector-plugin/src/main/java/net/runelite/injector/InjectMojo.java deleted file mode 100644 index b7c22194fe..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectMojo.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.deob.clientver.ClientVersion; -import net.runelite.deob.util.JarUtil; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugin.logging.Log; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; - -@Mojo( - name = "runelite-injector", - defaultPhase = LifecyclePhase.GENERATE_RESOURCES -) -public class InjectMojo extends AbstractMojo -{ - private final Log log = getLog(); - @Parameter(defaultValue = "${project.build.outputDirectory}") - private File outputDirectory; - @Parameter(defaultValue = "./runescape-client/target/rs-client-${project.version}.jar", readonly = true, required = true) - private String rsClientPath; - @Parameter(defaultValue = "${net.runelite.rs:vanilla:jar}", readonly = true, required = true) - private String vanillaPath; - - @Override - public void execute() throws MojoExecutionException, MojoFailureException - { - ClientVersion ver = new ClientVersion(new File(vanillaPath)); - int version; - try - { - version = ver.getVersion(); - } - catch (IOException ex) - { - throw new MojoExecutionException("Unable to read vanilla client version", ex); - } - - log.info("Vanilla client version " + version); - - ClassGroup rs; - ClassGroup vanilla; - - try - { - rs = JarUtil.loadJar(new File(rsClientPath)); - vanilla = JarUtil.loadJar(new File(vanillaPath)); - } - catch (IOException ex) - { - throw new MojoExecutionException("Unable to load dependency jars", ex); - } - - Injector injector = new Injector(rs, vanilla); - try - { - injector.inject(); - } - catch (InjectionException ex) - { - throw new MojoExecutionException("Error injecting client", ex); - } - - InjectorValidator iv = new InjectorValidator(vanilla); - iv.validate(); - - if (iv.getError() > 0) - { - throw new MojoExecutionException("Error building injected jar"); - } - - if (iv.getMissing() > 0) - { - throw new MojoExecutionException("Unable to inject all methods"); - } - - try - { - writeClasses(vanilla, outputDirectory); - } - catch (IOException ex) - { - throw new MojoExecutionException("Unable to write classes", ex); - } - - log.info("Injector wrote " + vanilla.getClasses().size() + " classes, " + iv.getOkay() + " injected methods"); - } - - private void writeClasses(ClassGroup group, File outputDirectory) throws IOException - { - for (ClassFile cf : group.getClasses()) - { - File classFile = getClassFile(outputDirectory, cf); - byte[] classData = JarUtil.writeClass(group, cf); - - try (FileOutputStream fout = new FileOutputStream(classFile, false)) - { - fout.write(classData); - } - } - } - - private File getClassFile(File base, ClassFile cf) - { - File f = base; - - String[] parts = cf.getName().split("/"); - for (int i = 0; i < parts.length - 1; ++i) - { - String part = parts[i]; - - f = new File(f, part); - } - - f.mkdirs(); - f = new File(f, parts[parts.length - 1] + ".class"); - - return f; - } - -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectSetter.java b/injector-plugin/src/main/java/net/runelite/injector/InjectSetter.java deleted file mode 100644 index 58c225fa87..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectSetter.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LMul; -import net.runelite.asm.attributes.code.instructions.PutField; -import net.runelite.asm.attributes.code.instructions.PutStatic; -import net.runelite.asm.attributes.code.instructions.VReturn; -import net.runelite.asm.signature.Signature; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectSetter -{ - private static final Logger logger = LoggerFactory.getLogger(InjectSetter.class); - - private final Inject inject; - - private int injectedSetters; - - InjectSetter(Inject inject) - { - this.inject = inject; - } - - /** - * inject a setter into the vanilla classgroup - * - * @param targetClass Class where to inject the setter (field's class, - * or client) - * @param targetApiClass API targetClass implements, which may have the - * setter declared - * @param field Field of vanilla that will be set - * @param exportedName exported name of field - */ - void injectSetter(ClassFile targetClass, Class targetApiClass, Field field, String exportedName, Number setter) - { - java.lang.reflect.Method method = inject.findImportMethodOnApi(targetApiClass, exportedName, true); - if (method == null) - { - logger.warn("Setter injection for field {} but an API method was not found on {}", exportedName, targetApiClass); - return; - } - - if (method.getParameterCount() != 1) - { - logger.warn("Setter {} with not parameter count != 1?", exportedName); - return; - } - - logger.info("Injecting setter for {} on {}", exportedName, targetApiClass); - - assert targetClass.findMethod(method.getName()) == null; - assert field.isStatic() || field.getClassFile() == targetClass; - - Signature sig = new Signature.Builder() - .setReturnType(Type.VOID) - .addArgument(Inject.classToType(method.getParameterTypes()[0])) - .build(); - - Method setterMethod = new Method(targetClass, method.getName(), sig); - setterMethod.setAccessFlags(ACC_PUBLIC); - targetClass.addMethod(setterMethod); - ++injectedSetters; - - Code code = new Code(setterMethod); - setterMethod.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - // load this - if (!field.isStatic()) - { - ins.add(new ALoad(instructions, 0)); - } - - // load argument - Type argumentType = sig.getTypeOfArg(0); - ins.add(inject.createLoadForTypeIndex(instructions, argumentType, 1)); - - // cast argument to field type - Type fieldType = field.getType(); - if (!argumentType.equals(fieldType)) - { - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(fieldType); - ins.add(checkCast); - } - - if (setter != null) - { - assert setter instanceof Integer || setter instanceof Long; - - if (setter instanceof Integer) - { - ins.add(new LDC(instructions, (int) setter)); - ins.add(new IMul(instructions)); - } - else - { - ins.add(new LDC(instructions, (long) setter)); - ins.add(new LMul(instructions)); - } - } - - if (field.isStatic()) - { - ins.add(new PutStatic(instructions, field)); - } - else - { - ins.add(new PutField(instructions, field)); - } - - ins.add(new VReturn(instructions)); - } - - int getInjectedSetters() - { - return injectedSetters; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectUtil.java b/injector-plugin/src/main/java/net/runelite/injector/InjectUtil.java deleted file mode 100644 index 2292b349ab..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectUtil.java +++ /dev/null @@ -1,281 +0,0 @@ -package net.runelite.injector; - -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; - -public class InjectUtil -{ - public static ClassFile toObClass(final ClassGroup vanilla, final ClassFile deobCf) throws InjectionException - { - final String obfuscatedName = DeobAnnotations.getObfuscatedName(deobCf.getAnnotations()); - final ClassFile obCf = vanilla.findClass(obfuscatedName); - - if (obCf == null) - { - throw new InjectionException(String.format("ClassFile \"%s\" could not be found.", obfuscatedName)); - } - - return obCf; - } - - public static Field toObField(final ClassGroup vanilla, final Field field) throws InjectionException - { - String obfuscatedClassName = DeobAnnotations.getObfuscatedName(field.getClassFile().getAnnotations()); - String obfuscatedFieldName = DeobAnnotations.getObfuscatedName(field.getAnnotations()); // obfuscated name of field - Type type = getFieldType(field); - - ClassFile obfuscatedClass = vanilla.findClass(obfuscatedClassName); - if (obfuscatedClass == null) - { - throw new InjectionException(String.format("ClassFile \"%s\" could not be found.", obfuscatedClassName)); - } - - Field obfuscatedField = obfuscatedClass.findFieldDeep(obfuscatedFieldName, type); - if (obfuscatedField == null) - { - throw new InjectionException(String.format("Field \"%s\" could not be found.", obfuscatedFieldName)); - } - - return obfuscatedField; - } - - public static ClassFile toDeobClass(final ClassFile obCf, final ClassGroup deob) throws InjectionException - { - final ClassFile wowThatWasQuick = deob.findObfuscatedName(obCf.getName()); - if (wowThatWasQuick == null) - { - throw new InjectionException("It wasn't obfscated enough, or a bit too much. Whatever it was it, wasn't in deob"); - } - return wowThatWasQuick; - } - - public static Type getFieldType(final Field f) - { - Type type = f.getType(); - - Annotation obfSignature = f.getAnnotations().find(DeobAnnotations.OBFUSCATED_SIGNATURE); - if (obfSignature != null) - { - //Annotation exists. Type was updated by us during deobfuscation - type = DeobAnnotations.getObfuscatedType(f); - } - - return type; - } - - /** - * Find a static method in ClassGroup group. Check the class with name hint first. - * (useful for static methods which are in the class they belong to) - */ - public static Method findStaticMethod(final ClassGroup group, final String name, final String hint) throws InjectionException - { - final ClassFile cf = group.findClass(hint); - - if (cf == null) - { - throw new InjectionException(String.format("ClassFile \"%s\" could not be found.", hint)); - } - - Method m = cf.findStaticMethod(name); - - if (m == null) - { - m = group.findStaticMethod(name); - } - - return m; - } - - /** - * Find a static method in ClassGroup group. Throws exception if not found. - */ - public static Method findStaticMethod(final ClassGroup group, final String name) throws InjectionException - { - Method m = group.findStaticMethod(name); - - if (m == null) - { - throw new InjectionException(String.format("Static method \"%s\" could not be found.", name)); - } - - return m; - } - - /** - * Find a static method in ClassGroup group. Throws exception if not found. - */ - public static Method findStaticMethod(final ClassGroup group, final String name, Signature sig) throws InjectionException - { - Method m = group.findStaticMethod(name, sig); - - if (m == null) - { - throw new InjectionException(String.format("Static method \"%s\" could not be found.", name)); - } - - return m; - } - - public static Method findMethod(Inject inject, String name) throws InjectionException - { - return findMethod(inject, name, null); - } - - public static Method findMethod(Inject inject, String name, String hint) throws InjectionException - { - if (hint != null) - { - ClassFile c = inject.getDeobfuscated().findClass(hint); - - if (c == null) - { - throw new InjectionException("Class " + hint + " doesn't exist. (check capitalization)"); - } - - Method deob = c.findMethod(name); - - if (deob != null) - { - String obfuscatedName = DeobAnnotations.getObfuscatedName(deob.getAnnotations()); - Signature obfuscatedSignature = DeobAnnotations.getObfuscatedSignature(deob); - - ClassFile ob = toObClass(inject.getVanilla(), c); - - return ob.findMethod(obfuscatedName, (obfuscatedSignature != null) ? obfuscatedSignature : deob.getDescriptor()); - } - } - - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Method m : c.getMethods()) - { - if (!m.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations()); - Signature obfuscatedSignature = DeobAnnotations.getObfuscatedSignature(m); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - - return c2.findMethod(obfuscatedName, (obfuscatedSignature != null) ? obfuscatedSignature : m.getDescriptor()); - } - } - - throw new InjectionException("Couldn't find method " + name); - } - - public static Method findStaticMethod(Inject inject, String name) throws InjectionException - { - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Method m : c.getMethods()) - { - if (!m.isStatic() || !m.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations()); - Signature obfuscatedSignature = DeobAnnotations.getObfuscatedSignature(m); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - - return c2.findMethod(obfuscatedName, (obfuscatedSignature != null) ? obfuscatedSignature : m.getDescriptor()); - } - } - - throw new InjectionException("Couldn't find static method " + name); - } - - - public static Field findObField(Inject inject, String name) throws InjectionException - { - for (ClassFile c : inject.getVanilla().getClasses()) - { - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - return f; - } - } - - throw new InjectionException(String.format("Field \"%s\" could not be found.", name)); - } - - public static Field findDeobField(Inject inject, String name) throws InjectionException - { - return findDeobField(inject, name, null); - } - - public static Field findDeobField(Inject inject, String name, String hint) throws InjectionException - { - if (hint != null) - { - ClassFile c = inject.getDeobfuscated().findClass(hint); - if (c == null) - { - throw new InjectionException("Class " + hint + " doesn't exist. (check capitalization)"); - } - - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations()); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - return c2.findField(obfuscatedName); - } - } - - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations()); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - return c2.findField(obfuscatedName); - } - } - - throw new InjectionException(String.format("Mapped field \"%s\" could not be found.", name)); - } - - public static Field findDeobFieldButUseless(Inject inject, String name) throws InjectionException - { - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - - return f; - } - } - - throw new InjectionException(String.format("Mapped field \"%s\" could not be found.", name)); - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectorValidator.java b/injector-plugin/src/main/java/net/runelite/injector/InjectorValidator.java deleted file mode 100644 index a49df63a3a..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectorValidator.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.signature.Signature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Verifies the injected jar is valid - * - * @author Adam - */ -class InjectorValidator -{ - private static final Logger logger = LoggerFactory.getLogger(InjectorValidator.class); - - private static final String API_PACKAGE_BASE = "net/runelite/rs/api/"; - - private final ClassGroup group; - - private int error, missing, okay; - - InjectorValidator(ClassGroup group) - { - this.group = group; - } - - void validate() - { - for (ClassFile cf : group.getClasses()) - { - validate(cf); - } - - logger.info("{} overridden methods, {} missing", okay, missing); - } - - private void validate(ClassFile cf) - { - // find methods of the interface not implemented in the class - for (net.runelite.asm.pool.Class clazz : cf.getInterfaces().getInterfaces()) - { - if (!clazz.getName().startsWith(API_PACKAGE_BASE)) - { - continue; - } - - Class c; - try - { - c = Class.forName(clazz.getName().replace('/', '.')); - } - catch (ClassNotFoundException ex) - { - logger.warn(null, ex); - continue; - } - - if (cf.isAbstract()) - { - // Abstract classes don't have to implement anything - continue; - } - - for (Method method : c.getMethods()) - { - if (method.isSynthetic() || method.isDefault()) - { - continue; - } - - // could check method signature here too but it is - // annoying to deal with both runelite api and java - // reflection api - if (cf.findMethodDeep(method.getName()) == null) - { - logger.warn("Class {} implements interface {} but not does implement method {}", - cf.getName(), c.getSimpleName(), method); - ++missing; - } - else - { - ++okay; - } - } - } - - Set signatures = new HashSet<>(); - - for (net.runelite.asm.Method method : cf.getMethods()) - { - NameAndSignature nas = new NameAndSignature(method.getName(), method.getDescriptor()); - - if (signatures.contains(nas)) - { - logger.error("Class {} has duplicate method with same name and signature {} {}", - cf.getName(), method.getName(), method.getDescriptor()); - ++error; - } - - signatures.add(nas); - } - } - - int getError() - { - return error; - } - - int getMissing() - { - return missing; - } - - int getOkay() - { - return okay; - } - - static final class NameAndSignature - { - String name; - Signature signature; - - NameAndSignature(String name, Signature signature) - { - this.name = name; - this.signature = signature; - } - - @Override - public int hashCode() - { - int hash = 3; - hash = 67 * hash + Objects.hashCode(this.name); - hash = 67 * hash + Objects.hashCode(this.signature); - return hash; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - final NameAndSignature other = (NameAndSignature) obj; - if (!Objects.equals(this.name, other.name)) - { - return false; - } - if (!Objects.equals(this.signature, other.signature)) - { - return false; - } - return true; - } - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/MixinInjector.java b/injector-plugin/src/main/java/net/runelite/injector/MixinInjector.java deleted file mode 100644 index bf4627c785..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/MixinInjector.java +++ /dev/null @@ -1,998 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import com.google.common.reflect.ClassPath; -import com.google.common.reflect.ClassPath.ClassInfo; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import net.runelite.api.mixins.Mixin; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.FieldInstruction; -import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction; -import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; -import net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction; -import net.runelite.asm.attributes.code.instruction.types.ReturnInstruction; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.ANewArray; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.GetField; -import net.runelite.asm.attributes.code.instructions.ILoad; -import net.runelite.asm.attributes.code.instructions.InvokeDynamic; -import net.runelite.asm.attributes.code.instructions.InvokeSpecial; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.Pop; -import net.runelite.asm.attributes.code.instructions.PutField; -import net.runelite.asm.signature.Signature; -import net.runelite.asm.visitors.ClassFileVisitor; -import net.runelite.deob.DeobAnnotations; -import static net.runelite.injector.InjectUtil.findStaticMethod; -import static net.runelite.injector.InjectUtil.toDeobClass; -import static net.runelite.injector.InjectUtil.toObClass; -import static net.runelite.injector.InjectUtil.toObField; -import org.objectweb.asm.ClassReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MixinInjector -{ - private static final Logger logger = LoggerFactory.getLogger(MixinInjector.class); - - private static final Type INJECT = new Type("Lnet/runelite/api/mixins/Inject;"); - private static final Type SHADOW = new Type("Lnet/runelite/api/mixins/Shadow;"); - private static final Type COPY = new Type("Lnet/runelite/api/mixins/Copy;"); - private static final Type REPLACE = new Type("Lnet/runelite/api/mixins/Replace;"); - private static final Type FIELDHOOK = new Type("Lnet/runelite/api/mixins/FieldHook;"); - private static final Type METHODHOOK = new Type("Lnet/runelite/api/mixins/MethodHook;"); - private static final Type JAVAX_INJECT = new Type("Ljavax/inject/Inject;"); - private static final Type NAMED = new Type("Ljavax/inject/Named;"); - - private static final String MIXIN_BASE = "net.runelite.mixins"; - private static final String ASSERTION_FIELD = "$assertionsDisabled"; - - private final Inject inject; - - // field name -> Field of injected fields - private final Map injectedFields = new HashMap<>(); - // Use net.runelite.asm.pool.Field instead of Field because the pool version has hashcode implemented - private final Map shadowFields = new HashMap<>(); - - MixinInjector(Inject inject) - { - this.inject = inject; - } - - public void inject() throws InjectionException - { - ClassPath classPath; - - try - { - classPath = ClassPath.from(this.getClass().getClassLoader()); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - // key: mixin class - // value: mixin targets - Map, List> mixinClasses = new HashMap<>(); - - // Find mixins and populate mixinClasses - for (ClassInfo classInfo : classPath.getTopLevelClasses(MIXIN_BASE)) - { - Class mixinClass = classInfo.load(); - List mixinTargets = new ArrayList<>(); - - for (Mixin mixin : mixinClass.getAnnotationsByType(Mixin.class)) - { - Class implementInto = mixin.value(); - - ClassFile targetCf = inject.findVanillaForInterface(implementInto); - - if (targetCf == null) - { - throw new InjectionException("No class implements " + implementInto + " for mixin " + mixinClass); - } - - mixinTargets.add(targetCf); - } - - mixinClasses.put(mixinClass, mixinTargets); - } - - inject(mixinClasses); - } - - public void inject(Map, List> mixinClasses) throws InjectionException - { - injectFields(mixinClasses); - findShadowFields(mixinClasses); - - for (Class mixinClass : mixinClasses.keySet()) - { - try - { - for (ClassFile cf : mixinClasses.get(mixinClass)) - { - // Make a new mixin ClassFile copy every time, - // so they don't share Code references - ClassFile mixinCf = loadClass(mixinClass); - - injectMethods(mixinCf, cf, shadowFields); - } - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - } - - injectFieldHooks(mixinClasses); - injectMethodHooks(mixinClasses); - } - - /** - * Finds fields that are marked @Inject and inject them into the target - */ - private void injectFields(Map, List> mixinClasses) throws InjectionException - { - // Inject fields, and put them in injectedFields if they can be used by other mixins - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - List targetCfs = mixinClasses.get(mixinClass); - - for (ClassFile cf : targetCfs) - { - for (Field field : mixinCf.getFields()) - { - // Always inject $assertionsEnabled if its missing. - if (ASSERTION_FIELD.equals(field.getName())) - { - if (cf.findField(ASSERTION_FIELD, Type.BOOLEAN) != null) - { - continue; - } - } - else - { - Annotation inject = field.getAnnotations().find(INJECT); - - if (inject == null) - { - continue; - } - } - - Field copy = new Field(cf, field.getName(), field.getType()); - copy.setAccessFlags(field.getAccessFlags()); - copy.setPublic(); - copy.setValue(field.getValue()); - - Annotation jInject = field.getAnnotations().find(JAVAX_INJECT); - if (jInject != null) - { - copy.getAnnotations().addAnnotation(jInject); - logger.info("Added javax inject to {}.{}", cf.getClassName(), copy.getName()); - - Annotation named = field.getAnnotations().find(NAMED); - if (named != null) - { - copy.getAnnotations().addAnnotation(named); - logger.info("Added javax named to {}.{}", cf.getClassName(), copy.getName()); - } - } - - cf.addField(copy); - - if (injectedFields.containsKey(field.getName()) && !field.getName().equals(ASSERTION_FIELD)) - { - java.util.logging.Logger.getAnonymousLogger().severe("Duplicate field : " + field.getName()); - throw new InjectionException("Injected field names must be globally unique"); - } - - injectedFields.put(field.getName(), copy); - } - } - - } - } - - /** - * Find fields which are marked @Shadow, and what they shadow - */ - private void findShadowFields(Map, List> mixinClasses) throws InjectionException - { - // Find shadow fields - // Injected static fields take precedence when looking up shadowed fields - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - for (Field field : mixinCf.getFields()) - { - Annotation shadow = field.getAnnotations().find(SHADOW); - if (shadow != null) - { - if (!field.isStatic()) - { - throw new InjectionException("Can only shadow static fields"); - } - - String shadowName = shadow.getElement().getString(); // shadow this field - - Field injectedField = injectedFields.get(shadowName); - if (injectedField != null) - { - // Shadow a field injected by a mixin - shadowFields.put(field.getPoolField(), injectedField); - } - else - { - // Shadow a field already in the gamepack - Field shadowField = InjectUtil.findDeobFieldButUseless(inject, shadowName); - - if (shadowField == null) - { - throw new InjectionException("Shadow of nonexistent field " + shadowName); - } - - Field obShadow = toObField(inject.getVanilla(), shadowField); - assert obShadow != null; - shadowFields.put(field.getPoolField(), obShadow); - } - } - } - } - } - - private ClassFile loadClass(Class clazz) throws IOException - { - try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".class")) - { - ClassReader reader = new ClassReader(is); - ClassFileVisitor cv = new ClassFileVisitor(); - - reader.accept(cv, 0); - - return cv.getClassFile(); - } - } - - private void injectMethods(ClassFile mixinCf, ClassFile cf, Map shadowFields) - throws InjectionException - { - // Keeps mappings between methods annotated with @Copy -> the copied method within the vanilla pack - Map copiedMethods = new HashMap<>(); - - // Handle the copy mixins first, so all other mixins know of the copies - for (Method method : mixinCf.getMethods()) - { - Annotation copyAnnotation = method.getAnnotations().find(COPY); - - if (copyAnnotation == null) - { - continue; - } - - String deobMethodName = (String) copyAnnotation.getElement().getValue(); - Method deobMethod; - if (method.isStatic()) - { - deobMethod = findStaticMethod(inject.getDeobfuscated(), deobMethodName, method.getDescriptor().rsApiToRsClient()); - } - else - { - ClassFile deobCf = toDeobClass(cf, inject.getDeobfuscated()); - deobMethod = deobCf.findMethod(deobMethodName, method.getDescriptor().rsApiToRsClient()); - } - - - if (deobMethod == null) - { - throw new InjectionException("Failed to find the deob method " + deobMethodName + " for mixin " + mixinCf); - } - - if (method.isStatic() != deobMethod.isStatic()) - { - throw new InjectionException("Mixin method " + method + " should be " + (deobMethod.isStatic() ? "static" : "non-static")); - } - - // Find the vanilla class where the method to copy is in - String obClassName = DeobAnnotations.getObfuscatedName(deobMethod.getClassFile().getAnnotations()); - ClassFile obCf = inject.getVanilla().findClass(obClassName); - assert obCf != null : "unable to find vanilla class from obfuscated name " + obClassName; - - String obMethodName = DeobAnnotations.getObfuscatedName(deobMethod.getAnnotations()); - Signature obMethodSignature = DeobAnnotations.getObfuscatedSignature(deobMethod); - - if (obMethodName == null) - { - obMethodName = deobMethod.getName(); - } - if (obMethodSignature == null) - { - obMethodSignature = deobMethod.getDescriptor(); - } - - Method obMethod = obCf.findMethod(obMethodName, obMethodSignature); - if (obMethod == null) - { - throw new InjectionException("Failed to find the ob method " + obMethodName + " for mixin " + mixinCf); - } - - if (method.getDescriptor().size() > obMethod.getDescriptor().size()) - { - throw new InjectionException("Mixin methods cannot have more parameters than their corresponding ob method"); - } - - Method copy = new Method(cf, "copy$" + deobMethodName, obMethodSignature); - moveCode(copy, obMethod.getCode()); - copy.setAccessFlags(obMethod.getAccessFlags()); - copy.setPublic(); - copy.getExceptions().getExceptions().addAll(obMethod.getExceptions().getExceptions()); - copy.getAnnotations().getAnnotations().addAll(obMethod.getAnnotations().getAnnotations()); - cf.addMethod(copy); - - /* - If the desc for the mixin method and the desc for the ob method - are the same in length, assume that the mixin method is taking - care of the garbage parameter itself. - */ - boolean hasGarbageValue = method.getDescriptor().size() != obMethod.getDescriptor().size() - && deobMethod.getDescriptor().size() < obMethodSignature.size(); - copiedMethods.put(method.getPoolMethod(), new CopiedMethod(copy, hasGarbageValue)); - - logger.debug("Injected copy of {} to {}", obMethod, copy); - } - - // Handle the rest of the mixin types - for (Method method : mixinCf.getMethods()) - { - boolean isClinit = "".equals(method.getName()); - boolean isInit = "".equals(method.getName()); - boolean hasInject = method.getAnnotations().find(INJECT) != null; - - // You can't annotate clinit, so its always injected - if ((hasInject && isInit) || isClinit) - { - if (!"()V".equals(method.getDescriptor().toString())) - { - throw new InjectionException("Injected constructors cannot have arguments"); - } - - Method[] originalMethods = cf.getMethods().stream() - .filter(n -> n.getName().equals(method.getName())) - .toArray(Method[]::new); - // If there isn't a already just inject ours, otherwise rename it - // This is always true for - String name = method.getName(); - if (originalMethods.length > 0) - { - name = "rl$$" + (isInit ? "init" : "clinit"); - } - String numberlessName = name; - for (int i = 1; cf.findMethod(name, method.getDescriptor()) != null; i++) - { - name = numberlessName + i; - } - - Method copy = new Method(cf, name, method.getDescriptor()); - moveCode(copy, method.getCode()); - copy.setAccessFlags(method.getAccessFlags()); - copy.setPrivate(); - assert method.getExceptions().getExceptions().isEmpty(); - - // Remove the call to the superclass's ctor - if (isInit) - { - Instructions instructions = copy.getCode().getInstructions(); - ListIterator listIter = instructions.getInstructions().listIterator(); - for (; listIter.hasNext(); ) - { - Instruction instr = listIter.next(); - if (instr instanceof InvokeSpecial) - { - InvokeSpecial invoke = (InvokeSpecial) instr; - assert invoke.getMethod().getName().equals(""); - listIter.remove(); - int pops = invoke.getMethod().getType().getArguments().size() + 1; - for (int i = 0; i < pops; i++) - { - listIter.add(new Pop(instructions)); - } - break; - } - } - } - - setOwnersToTargetClass(mixinCf, cf, copy, shadowFields, copiedMethods); - cf.addMethod(copy); - - // Call our method at the return point of the matching method(s) - for (Method om : originalMethods) - { - Instructions instructions = om.getCode().getInstructions(); - ListIterator listIter = instructions.getInstructions().listIterator(); - for (; listIter.hasNext(); ) - { - Instruction instr = listIter.next(); - if (instr instanceof ReturnInstruction) - { - listIter.previous(); - if (isInit) - { - listIter.add(new ALoad(instructions, 0)); - listIter.add(new InvokeSpecial(instructions, copy.getPoolMethod())); - } - else if (isClinit) - { - listIter.add(new InvokeStatic(instructions, copy.getPoolMethod())); - } - listIter.next(); - } - } - } - - logger.debug("Injected mixin method {} to {}", copy, cf); - } - else if (hasInject) - { - // Make sure the method doesn't invoke copied methods - for (Instruction i : method.getCode().getInstructions().getInstructions()) - { - if (i instanceof InvokeInstruction) - { - InvokeInstruction ii = (InvokeInstruction) i; - - if (copiedMethods.containsKey(ii.getMethod())) - { - throw new InjectionException("Injected methods cannot invoke copied methods"); - } - } - } - - Method copy = new Method(cf, method.getName(), method.getDescriptor()); - moveCode(copy, method.getCode()); - copy.setAccessFlags(method.getAccessFlags()); - copy.setPublic(); - assert method.getExceptions().getExceptions().isEmpty(); - - setOwnersToTargetClass(mixinCf, cf, copy, shadowFields, copiedMethods); - - cf.addMethod(copy); - - logger.debug("Injected mixin method {} to {}", copy, cf); - } - else if (method.getAnnotations().find(REPLACE) != null) - { - Annotation replaceAnnotation = method.getAnnotations().find(REPLACE); - String deobMethodName = (String) replaceAnnotation.getElement().getValue(); - - ClassFile deobCf = inject.toDeobClass(cf); - Method deobMethod = findDeobMethod(deobCf, deobMethodName, method.getDescriptor()); - - if (deobMethod == null) - { - throw new InjectionException("Failed to find the deob method " + deobMethodName + " for mixin " + mixinCf); - } - - if (method.isStatic() != deobMethod.isStatic()) - { - throw new InjectionException("Mixin method " + method + " should be " - + (deobMethod.isStatic() ? "static" : "non-static")); - } - - String obMethodName = DeobAnnotations.getObfuscatedName(deobMethod.getAnnotations()); - Signature obMethodSignature = DeobAnnotations.getObfuscatedSignature(deobMethod); - - // Deob signature is the same as ob signature - if (obMethodName == null) - { - obMethodName = deobMethod.getName(); - } - if (obMethodSignature == null) - { - obMethodSignature = deobMethod.getDescriptor(); - } - - // Find the vanilla class where the method to copy is in - String obClassName = DeobAnnotations.getObfuscatedName(deobMethod.getClassFile().getAnnotations()); - ClassFile obCf = inject.getVanilla().findClass(obClassName); - - Method obMethod = obCf.findMethod(obMethodName, obMethodSignature); - assert obMethod != null : "obfuscated method " + obMethodName + obMethodSignature + " does not exist"; - - if (method.getDescriptor().size() > obMethod.getDescriptor().size()) - { - throw new InjectionException("Mixin methods cannot have more parameters than their corresponding ob method"); - } - - Type returnType = method.getDescriptor().getReturnValue(); - Type deobReturnType = inject.apiTypeToDeobfuscatedType(returnType); - if (!returnType.equals(deobReturnType)) - { - ClassFile deobReturnTypeClassFile = inject.getDeobfuscated() - .findClass(deobReturnType.getInternalName()); - if (deobReturnTypeClassFile != null) - { - ClassFile obReturnTypeClass = toObClass(inject.getVanilla(), deobReturnTypeClassFile); - - Instructions instructions = method.getCode().getInstructions(); - ListIterator listIter = instructions.getInstructions().listIterator(); - for (; listIter.hasNext(); ) - { - Instruction instr = listIter.next(); - if (instr instanceof ReturnInstruction) - { - listIter.previous(); - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(new Type(obReturnTypeClass.getName())); - listIter.add(checkCast); - listIter.next(); - } - } - } - } - - moveCode(obMethod, method.getCode()); - - boolean hasGarbageValue = method.getDescriptor().size() != obMethod.getDescriptor().size() - && deobMethod.getDescriptor().size() < obMethodSignature.size(); - - if (hasGarbageValue) - { - int garbageIndex = obMethod.isStatic() - ? obMethod.getDescriptor().size() - 1 - : obMethod.getDescriptor().size(); - - /* - If the mixin method doesn't have the garbage parameter, - the compiler will have produced code that uses the garbage - parameter's local variable index for other things, - so we'll have to add 1 to all loads/stores to indices - that are >= garbageIndex. - */ - shiftLocalIndices(obMethod.getCode().getInstructions(), garbageIndex); - } - - setOwnersToTargetClass(mixinCf, cf, obMethod, shadowFields, copiedMethods); - - logger.debug("Replaced method {} with mixin method {}", obMethod, method); - } - } - } - - private void moveCode(Method method, Code code) - { - Code newCode = new Code(method); - newCode.setMaxStack(code.getMaxStack()); - newCode.getInstructions().getInstructions().addAll(code.getInstructions().getInstructions()); - // Update instructions for each instruction - for (Instruction i : newCode.getInstructions().getInstructions()) - { - i.setInstructions(newCode.getInstructions()); - } - newCode.getExceptions().getExceptions().addAll(code.getExceptions().getExceptions()); - for (net.runelite.asm.attributes.code.Exception e : newCode.getExceptions().getExceptions()) - { - e.setExceptions(newCode.getExceptions()); - } - method.setCode(newCode); - } - - private void setOwnersToTargetClass(ClassFile mixinCf, ClassFile cf, Method method, - Map shadowFields, - Map copiedMethods) - throws InjectionException - { - ListIterator iterator = method.getCode().getInstructions().getInstructions().listIterator(); - - while (iterator.hasNext()) - { - Instruction i = iterator.next(); - - if (i instanceof ANewArray) - { - Type type = ((ANewArray) i).getType_(); - ClassFile deobCf = inject.getDeobfuscated().findClass(type.toString().replace("Lnet/runelite/rs/api/RS", "").replace(";", "")); - - if (deobCf != null) - { - ClassFile obReturnTypeClass = toObClass(inject.getVanilla(), deobCf); - Type newType = new Type("L" + obReturnTypeClass.getName() + ";"); - - ((ANewArray) i).setType(newType); - logger.info("Replaced {} type {} with type {}", i, type, newType); - } - } - - if (i instanceof InvokeInstruction) - { - InvokeInstruction ii = (InvokeInstruction) i; - - CopiedMethod copiedMethod = copiedMethods.get(ii.getMethod()); - if (copiedMethod != null) - { - ii.setMethod(copiedMethod.obMethod.getPoolMethod()); - - // Pass through garbage value if the method has one - if (copiedMethod.hasGarbageValue) - { - int garbageIndex = copiedMethod.obMethod.isStatic() - ? copiedMethod.obMethod.getDescriptor().size() - 1 - : copiedMethod.obMethod.getDescriptor().size(); - - iterator.previous(); - iterator.add(new ILoad(method.getCode().getInstructions(), garbageIndex)); - iterator.next(); - } - } - else if (ii.getMethod().getClazz().getName().equals(mixinCf.getName())) - { - ii.setMethod(new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(cf.getName()), - ii.getMethod().getName(), - ii.getMethod().getType() - )); - } - } - else if (i instanceof FieldInstruction) - { - FieldInstruction fi = (FieldInstruction) i; - - Field shadowed = shadowFields.get(fi.getField()); - if (shadowed != null) - { - fi.setField(shadowed.getPoolField()); - } - else if (fi.getField().getClazz().getName().equals(mixinCf.getName())) - { - fi.setField(new net.runelite.asm.pool.Field( - new net.runelite.asm.pool.Class(cf.getName()), - fi.getField().getName(), - fi.getField().getType() - )); - } - } - else if (i instanceof PushConstantInstruction) - { - PushConstantInstruction pi = (PushConstantInstruction) i; - if (mixinCf.getPoolClass().equals(pi.getConstant())) - { - pi.setConstant(cf.getPoolClass()); - } - } - - verify(mixinCf, i); - } - } - - private void shiftLocalIndices(Instructions instructions, int startIdx) - { - for (Instruction i : instructions.getInstructions()) - { - if (i instanceof LVTInstruction) - { - LVTInstruction lvti = (LVTInstruction) i; - - if (lvti.getVariableIndex() >= startIdx) - { - lvti.setVariableIndex(lvti.getVariableIndex() + 1); - } - } - } - } - - private Method findDeobMethod(ClassFile deobCf, String deobMethodName, Signature descriptor) - throws InjectionException - { - List matchingMethods = new ArrayList<>(); - - for (Method m : deobCf.getMethods()) - { - if (!deobMethodName.equals(m.getName())) - { - continue; - } - - Type returnType = inject.apiTypeToDeobfuscatedType(descriptor.getReturnValue()); - Type returnType2 = m.getDescriptor().getReturnValue(); - - if (!returnType.equals(returnType2)) - { - continue; - } - - List args = descriptor.getArguments(); - List args2 = m.getDescriptor().getArguments(); - - if (args.size() > args2.size()) - { - continue; - } - - boolean matchingArgs = true; - - for (int i = 0; i < args.size(); i++) - { - Type type = inject.apiTypeToDeobfuscatedType(args.get(i)); - Type type2 = args2.get(i); - - if (!type.equals(type2)) - { - matchingArgs = false; - break; - } - } - - if (!matchingArgs) - { - continue; - } - - matchingMethods.add(m); - } - - if (matchingMethods.size() > 1) - { - // this happens when it has found several deob methods for some mixin method, - // to get rid of the error, refine your search by making your mixin method have more parameters - throw new InjectionException("There are several matching methods when there should only be one"); - } - else if (matchingMethods.size() == 1) - { - return matchingMethods.get(0); - } - - Method method = deobCf.findMethod(deobMethodName); - - if (method == null) - { - // Look for static methods if an instance method couldn't be found - for (ClassFile deobCf2 : inject.getDeobfuscated().getClasses()) - { - if (deobCf2 != deobCf) - { - method = deobCf2.findMethod(deobMethodName); - - if (method != null) - { - break; - } - } - } - } - - return method; - } - - private void verify(ClassFile mixinCf, Instruction i) throws InjectionException - { - if (i instanceof FieldInstruction) - { - FieldInstruction fi = (FieldInstruction) i; - - if (fi.getField().getClazz().getName().equals(mixinCf.getName())) - { - if (i instanceof PutField || i instanceof GetField) - { - throw new InjectionException("Access to non static member field of mixin"); - } - - Field field = fi.getMyField(); - if (field != null && !field.isPublic()) - { - throw new InjectionException("Static access to non public field " + field); - } - } - } - else if (i instanceof InvokeStatic) - { - InvokeStatic is = (InvokeStatic) i; - - if (is.getMethod().getClazz() != mixinCf.getPoolClass() - && is.getMethod().getClazz().getName().startsWith(MIXIN_BASE.replace(".", "/"))) - { - throw new InjectionException("Invoking static methods of other mixins is not supported"); - } - } - else if (i instanceof InvokeDynamic) - { - // RS classes don't verify under java 7+ due to the - // super() invokespecial being inside of a try{} - throw new InjectionException("Injected bytecode must be Java 6 compatible"); - } - } - - private void injectFieldHooks(Map, List> mixinClasses) throws InjectionException - { - InjectHook injectHook = new InjectHook(inject); - - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - List targetCfs = mixinClasses.get(mixinClass); - - for (ClassFile cf : targetCfs) - { - for (Method method : mixinCf.getMethods()) - { - Annotation fieldHook = method.getAnnotations().find(FIELDHOOK); - if (fieldHook != null) - { - String hookName = fieldHook.getElement().getString(); - boolean before = fieldHook.getElements().size() == 2 && fieldHook.getElements().get(1).getValue().equals(true); - ClassFile deobCf = inject.toDeobClass(cf); - Field targetField = deobCf.findField(hookName); - if (targetField == null) - { - // first try non static fields, then static - targetField = InjectUtil.findDeobFieldButUseless(inject, hookName); - } - - if (targetField == null) - { - throw new InjectionException("Field hook for nonexistent field " + hookName + " on " + method); - } - - Annotation an = targetField.getAnnotations().find(DeobAnnotations.OBFUSCATED_GETTER); - Number getter = null; - if (an != null) - { - getter = (Number) an.getElement().getValue(); - } - - Field obField = toObField(inject.getVanilla(), targetField); - - if (method.isStatic() != targetField.isStatic()) - { - throw new InjectionException("Field hook method static flag must match target field"); - } - - // cf is the target class to invoke - InjectHook.HookInfo hookInfo = new InjectHook.HookInfo(); - hookInfo.clazz = cf.getName(); - hookInfo.fieldName = hookName; - hookInfo.method = method; - hookInfo.before = before; - hookInfo.getter = getter; - injectHook.hook(obField, hookInfo); - } - } - } - } - - injectHook.run(); - - logger.info("Injected {} field hooks", injectHook.getInjectedHooks()); - } - - private void injectMethodHooks(Map, List> mixinClasses) throws InjectionException - { - InjectHookMethod injectHookMethod = new InjectHookMethod(inject); - - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - List targetCfs = mixinClasses.get(mixinClass); - - for (ClassFile cf : targetCfs) - { - for (Method method : mixinCf.getMethods()) - { - Annotation methodHook = method.getAnnotations().find(METHODHOOK); - - if (methodHook == null) - { - continue; - } - - String hookName = methodHook.getElement().getString(); - boolean end = methodHook.getElements().size() == 2 && methodHook.getElements().get(1).getValue().equals(true); - ClassFile deobCf = inject.toDeobClass(cf); - Method targetMethod = findDeobMethod(deobCf, hookName, method.getDescriptor()); - - if (targetMethod == null) - { - throw new InjectionException("Method hook for nonexistent method " + hookName + " on " + method); - } - - if (method.isStatic() != targetMethod.isStatic()) - { - throw new InjectionException("Method hook static flag must match target - " + hookName); - } - - injectHookMethod.inject(method, targetMethod, hookName, end, false); - } - } - } - } - - private static class CopiedMethod - { - private Method obMethod; - private boolean hasGarbageValue; - - private CopiedMethod(Method obMethod, boolean hasGarbageValue) - { - this.obMethod = obMethod; - this.hasGarbageValue = hasGarbageValue; - } - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/raw/ClearColorBuffer.java b/injector-plugin/src/main/java/net/runelite/injector/raw/ClearColorBuffer.java deleted file mode 100644 index f4de5d056e..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/raw/ClearColorBuffer.java +++ /dev/null @@ -1,124 +0,0 @@ -package net.runelite.injector.raw; - -import java.util.ListIterator; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ILoad; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.pool.Class; -import net.runelite.asm.signature.Signature; -import net.runelite.injector.Inject; -import net.runelite.injector.InjectUtil; -import net.runelite.injector.InjectionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ClearColorBuffer -{ - private static final Logger log = LoggerFactory.getLogger(ClearColorBuffer.class); - private static final net.runelite.asm.pool.Method clearBuffer = new net.runelite.asm.pool.Method( - new Class("net.runelite.client.callback.Hooks"), - "clearColorBuffer", - new Signature("(IIIII)V") - ); - private final Inject inject; - - public ClearColorBuffer(Inject inject) - { - this.inject = inject; - } - - public void inject() throws InjectionException - { - injectColorBufferHooks(); - } - - private void injectColorBufferHooks() throws InjectionException - { - net.runelite.asm.pool.Method fillRectangle = InjectUtil.findStaticMethod(inject, "Rasterizer2D_fillRectangle").getPoolMethod(); - - int count = 0; - int replaced = 0; - - for (ClassFile cf : inject.getVanilla().getClasses()) - { - for (Method m : cf.getMethods()) - { - if (!m.isStatic()) - { - continue; - } - - Code c = m.getCode(); - if (c == null) - { - continue; - } - - Instructions ins = c.getInstructions(); - ListIterator it = ins.getInstructions().listIterator(); - - for (; it.hasNext(); ) - { - Instruction i = it.next(); - if (!(i instanceof InvokeStatic)) - { - continue; - } - - if (!((InvokeStatic) i).getMethod().equals(fillRectangle)) - { - continue; - } - - int indexToReturnTo = it.nextIndex(); - count++; - it.previous(); - Instruction current = it.previous(); - if (current instanceof LDC && ((LDC) current).getConstantAsInt() == 0) - { - int varIdx = 0; - for (; ; ) - { - current = it.previous(); - if (current instanceof ILoad && ((ILoad) current).getVariableIndex() == 3 - varIdx) - { - varIdx++; - log.debug(varIdx + " we can count yay"); - continue; - } - - break; - } - - if (varIdx == 4) - { - for (; !(current instanceof InvokeStatic); ) - { - current = it.next(); - } - assert it.nextIndex() == indexToReturnTo; - - it.set(new InvokeStatic(ins, clearBuffer)); - replaced++; - log.debug("Found drawRectangle at {}. Found: {}, replaced {}", m.getName(), count, replaced); - } - else - { - log.debug("Welp, guess this wasn't it chief " + m); - } - } - - while (it.nextIndex() != indexToReturnTo) - { - it.next(); - } - } - } - } - } -} \ No newline at end of file diff --git a/injector-plugin/src/main/java/net/runelite/injector/raw/DrawAfterWidgets.java b/injector-plugin/src/main/java/net/runelite/injector/raw/DrawAfterWidgets.java deleted file mode 100644 index 5b6f6fbd50..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/raw/DrawAfterWidgets.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector.raw; - -import java.util.HashSet; -import java.util.ListIterator; -import java.util.Set; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.Label; -import net.runelite.asm.attributes.code.instruction.types.JumpingInstruction; -import net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction; -import net.runelite.asm.attributes.code.instructions.GetStatic; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.signature.Signature; -import net.runelite.injector.Inject; -import static net.runelite.injector.InjectHookMethod.HOOKS; -import static net.runelite.injector.InjectUtil.findStaticMethod; -import net.runelite.injector.InjectionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DrawAfterWidgets -{ - private static final Logger logger = LoggerFactory.getLogger(DrawAfterWidgets.class); - - private final Inject inject; - - public DrawAfterWidgets(Inject inject) - { - this.inject = inject; - } - - public void inject() throws InjectionException - { - injectDrawAfterWidgets(); - } - - private void injectDrawAfterWidgets() throws InjectionException - { - /* - This call has to be injected using raw injection because the - drawWidgets method gets inlined in some revisions. If it wouldn't be, - mixins would be used to add the call to the end of drawWidgets. - - --> This hook depends on the positions of "if (535573958 * kl != -1)" and "jz.db();". - - - Revision 180 - client.gs(): - ______________________________________________________ - - @Export("drawLoggedIn") - final void drawLoggedIn() { - if(rootInterface != -1) { - ClientPreferences.method1809(rootInterface); - } - - int var1; - for(var1 = 0; var1 < rootWidgetCount; ++var1) { - if(__client_od[var1]) { - __client_ot[var1] = true; - } - - __client_oq[var1] = __client_od[var1]; - __client_od[var1] = false; - } - - __client_oo = cycle; - __client_lq = -1; - __client_ln = -1; - UserComparator6.__fg_jh = null; - if(rootInterface != -1) { - rootWidgetCount = 0; - Interpreter.method1977(rootInterface, 0, 0, SoundCache.canvasWidth, Huffman.canvasHeight, 0, 0, -1); - } - - < -- here appearantly - - Rasterizer2D.Rasterizer2D_resetClip(); - ______________________________________________________ - */ - - boolean injected = false; - - Method noClip = findStaticMethod(inject, "Rasterizer2D_resetClip"); // !!!!! - - if (noClip == null) - { - throw new InjectionException("Mapped method \"Rasterizer2D_resetClip\" could not be found."); - } - - net.runelite.asm.pool.Method poolNoClip = noClip.getPoolMethod(); - - for (ClassFile c : inject.getVanilla().getClasses()) - { - for (Method m : c.getMethods()) - { - if (m.getCode() == null) - { - continue; - } - - Instructions instructions = m.getCode().getInstructions(); - - Set