From b53149ce6b4c26baabbe231ce36cc4ce21d64482 Mon Sep 17 00:00:00 2001 From: Graham Date: Wed, 5 Jan 2022 21:04:30 +0000 Subject: [PATCH] Add RuneLite plugin for collecting XTEA keys The API endpoint isn't always updated immediately, so this is useful for gathering keys semi-manually if they're needed more urgently. Signed-off-by: Graham --- gradle/libs.versions.toml | 2 + settings.gradle.kts | 2 + xtea-plugin/build.gradle.kts | 46 ++++++++++ .../java/org/openrs2/xtea/XteaConfig.java | 17 ++++ .../java/org/openrs2/xtea/XteaPlugin.java | 85 +++++++++++++++++++ .../main/java/org/pf4j/ExtensionPoint.java | 9 ++ .../java/org/openrs2/xtea/XteaPluginTest.java | 16 ++++ 7 files changed, 177 insertions(+) create mode 100644 xtea-plugin/build.gradle.kts create mode 100644 xtea-plugin/src/main/java/org/openrs2/xtea/XteaConfig.java create mode 100644 xtea-plugin/src/main/java/org/openrs2/xtea/XteaPlugin.java create mode 100644 xtea-plugin/src/main/java/org/pf4j/ExtensionPoint.java create mode 100644 xtea-plugin/src/test/java/org/openrs2/xtea/XteaPluginTest.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6f499365..6282736d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -58,7 +58,9 @@ netty-codec-http = { module = "io.netty:netty-codec-http", version.ref = "netty" netty-handler = { module = "io.netty:netty-handler", version.ref = "netty" } netty-transport = { module = "io.netty:netty-transport", version.ref = "netty" } openrs2-natives = { module = "org.openrs2:openrs2-natives-all", version = "3.2.0" } +pf4j = { module = "org.pf4j:pf4j", version = "3.6.0" } postgres = { module = "org.postgresql:postgresql", version = "42.3.1" } +runelite-client = { module = "net.runelite:client", version = "1.8.8" } thymeleaf-core = { module = "org.thymeleaf:thymeleaf", version = "3.0.14.RELEASE" } thymeleaf-java8time = { module = "org.thymeleaf.extras:thymeleaf-extras-java8time", version = "3.0.4.RELEASE" } xz = { module = "org.tukaani:xz", version = "1.9" } diff --git a/settings.gradle.kts b/settings.gradle.kts index f54aad80..46c12bbf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,6 +5,7 @@ dependencyResolutionManagement { mavenCentral() gradlePluginPortal() maven(url = "https://repo.openrs2.org/repository/openrs2") + maven(url = "https://repo.runelite.net") mavenLocal() maven(url = "https://repo.openrs2.org/repository/openrs2-snapshots") } @@ -62,5 +63,6 @@ include( "patcher", "protocol", "util", + "xtea-plugin", "yaml" ) diff --git a/xtea-plugin/build.gradle.kts b/xtea-plugin/build.gradle.kts new file mode 100644 index 00000000..190ed6f3 --- /dev/null +++ b/xtea-plugin/build.gradle.kts @@ -0,0 +1,46 @@ +plugins { + `java-library` + `maven-publish` +} + +dependencies { + annotationProcessor(libs.pf4j) + + compileOnly(libs.pf4j) + compileOnly(libs.runelite.client) + + testImplementation(libs.runelite.client) +} + +publishing { + publications.create("maven") { + from(components["java"]) + + pom { + packaging = "jar" + name.set("OpenRS2 XTEA Plugin") + description.set( + """ + A RuneLite/OpenOSRS plugin that collects XTEA keys and submits + them to the OpenRS2 Archive. + """.trimIndent() + ) + } + } +} + +tasks.jar { + manifest { + attributes["Plugin-Description"] = "Collects XTEA keys and submits them to the OpenRS2 Archive" + attributes["Plugin-Id"] = "OpenRS2 XTEA" + attributes["Plugin-License"] = "ISC" + attributes["Plugin-Provider"] = "OpenRS2" + attributes["Plugin-Version"] = project.version + } +} + +tasks.register("run") { + classpath = project.sourceSets.test.get().runtimeClasspath + mainClass.set("org.openrs2.xtea.XteaPluginTest") + jvmArgs = listOf("-ea") +} diff --git a/xtea-plugin/src/main/java/org/openrs2/xtea/XteaConfig.java b/xtea-plugin/src/main/java/org/openrs2/xtea/XteaConfig.java new file mode 100644 index 00000000..731b9870 --- /dev/null +++ b/xtea-plugin/src/main/java/org/openrs2/xtea/XteaConfig.java @@ -0,0 +1,17 @@ +package org.openrs2.xtea; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("openrs2xtea") +public interface XteaConfig extends Config { + @ConfigItem( + keyName = "endpoint", + name = "API Endpoint", + description = "The URL the XTEA keys are submitted to" + ) + default String endpoint() { + return "https://archive.openrs2.org/keys"; + } +} diff --git a/xtea-plugin/src/main/java/org/openrs2/xtea/XteaPlugin.java b/xtea-plugin/src/main/java/org/openrs2/xtea/XteaPlugin.java new file mode 100644 index 00000000..0759af2f --- /dev/null +++ b/xtea-plugin/src/main/java/org/openrs2/xtea/XteaPlugin.java @@ -0,0 +1,85 @@ +package org.openrs2.xtea; + +import java.io.IOException; +import javax.inject.Inject; + +import com.google.inject.Provides; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.events.GameStateChanged; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.internal.annotations.EverythingIsNonNull; +import org.pf4j.Extension; +import org.pf4j.ExtensionPoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Extension +@PluginDescriptor( + name = "OpenRS2 XTEA", + description = "Collects XTEA keys and submits them to the OpenRS2 Archive" +) +public final class XteaPlugin extends Plugin implements ExtensionPoint { + private static final Logger log = LoggerFactory.getLogger(XteaPlugin.class); + + @Inject + private XteaConfig config; + + @Inject + private Client client; + + @Inject + private OkHttpClient httpClient; + + @Provides + public XteaConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(XteaConfig.class); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) { + if (event.getGameState() != GameState.LOGGED_IN) { + return; + } + + int[][] keys = client.getXteaKeys(); + String url = config.endpoint(); + + log.debug("Submitting {} XTEA keys to {}", keys.length, url); + + Request request = new Request.Builder() + .post(RequestBody.create(RuneLiteAPI.JSON, RuneLiteAPI.GSON.toJson(keys))) + .url(url) + .build(); + + httpClient.newCall(request).enqueue(new Callback() { + @EverythingIsNonNull + @Override + public void onFailure(Call call, IOException ex) { + log.error("XTEA key submission failed", ex); + } + + @EverythingIsNonNull + @Override + public void onResponse(Call call, Response response) { + try (response) { + if (response.isSuccessful()) { + log.debug("XTEA key submission successful"); + } else { + log.error("XTEA key submission failed with status code {}", response.code()); + } + } + } + }); + } +} diff --git a/xtea-plugin/src/main/java/org/pf4j/ExtensionPoint.java b/xtea-plugin/src/main/java/org/pf4j/ExtensionPoint.java new file mode 100644 index 00000000..37993ddd --- /dev/null +++ b/xtea-plugin/src/main/java/org/pf4j/ExtensionPoint.java @@ -0,0 +1,9 @@ +package org.pf4j; + +/** + * Stub implementation of {@code org.pf4j.ExtensionPoint} so the plugin works + * in and builds against RuneLite, which doesn't have P4J on its classpath. + */ +public interface ExtensionPoint { + // empty +} diff --git a/xtea-plugin/src/test/java/org/openrs2/xtea/XteaPluginTest.java b/xtea-plugin/src/test/java/org/openrs2/xtea/XteaPluginTest.java new file mode 100644 index 00000000..e4b4c8d7 --- /dev/null +++ b/xtea-plugin/src/test/java/org/openrs2/xtea/XteaPluginTest.java @@ -0,0 +1,16 @@ +package org.openrs2.xtea; + +import net.runelite.client.RuneLite; +import net.runelite.client.externalplugins.ExternalPluginManager; + +public final class XteaPluginTest { + @SuppressWarnings("unchecked") + public static void main(String[] args) throws Exception { + ExternalPluginManager.loadBuiltin(XteaPlugin.class); + RuneLite.main(args); + } + + private XteaPluginTest() { + // empty + } +}