commit f5db90a8101c49f4a3bccd72be33aef54f6a221e Author: Max Weber Date: Thu Dec 12 13:21:58 2019 -0700 Initial commit diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..d7917c6a9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: java +sudo: false +dist: xenial +cache: + directories: + - $HOME/.m2 +jdk: + - openjdk8 +install: true +script: ./travis.sh \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..4048d5d30 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +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: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* 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 HOLDER 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. \ No newline at end of file diff --git a/LICENSE.templateplugin b/LICENSE.templateplugin new file mode 100644 index 000000000..fa0eb2459 --- /dev/null +++ b/LICENSE.templateplugin @@ -0,0 +1,2 @@ +The contents of the template plugin and the output of the `create_net_plugin.py` +script are, released into the public domain unless otherwise noted. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..901899129 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +![](https://runelite.net/img/logo.png) +# plugin-hub [![Discord](https://img.shields.io/discord/301497432909414422.svg)](https://discord.gg/mePCs8U) + +This repository contains markers for [RuneLite](https://github.com/runelite/runelite) +plugins that are not supported by the RuneLite Developers. The plugins are +provided "as is"; we make no guarantees about any plugin in this repo. + + +## Creating new plugins + +Clone this repository and run the `create_new_plugin.py` script. It will ask +some questions then generate a plugin skeleton. When your plugin is ready to +release, create a new GitHub repository with it, then put the url and commit +hash you want to release in this repository's `plugins` directory and create +a PR. We will then review your plugin to ensure it isn't malicious or [breaking +jagex's rules](https://secure.runescape.com/m=news/another-message-about-unofficial-clients?oldschool=1). +__If it is difficult for us to ensure the plugin isn't against the rules we +will not merge it__. \ No newline at end of file diff --git a/build_manifest.sh b/build_manifest.sh new file mode 100755 index 000000000..d4bc2d3ff --- /dev/null +++ b/build_manifest.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +# Copyright (c) 2019 Abex +# 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. + +source repo_config.sh + +set -e -x + +[[ "${TRAVIS_PULL_REQUEST:-false}" == "false" ]] || exit 0 + +RUNELITE_VERSION="$(cat "runelite.version")" + +MANIFEST="$(mktemp /tmp/manifest.XXXXXXXX)" +trap "rm -f ""$MANIFEST*""" EXIT + +echo "[" > "$MANIFEST" + +IS_FIRST=true +for PLUGINFILE in plugins/*; do + # read in the plugin descriptor + disabled= + # shellcheck disable=SC2162 + while read LINE || [[ -n "$LINE" ]]; do + [[ $LINE =~ ^(repository|commit|disabled)=(.*)$ ]] + eval "${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\"" + done < "$PLUGINFILE" + [ -z "$disabled" ] || continue + + PLUGIN_ID=$(basename "$PLUGINFILE") + LOCATION="$REPO_ROOT/$RUNELITE_VERSION/$PLUGIN_ID/$commit" + + RET=0 + curl --fail "$LOCATION.manifest" > "$MANIFEST.sub" || RET=$? + [ $RET -ne 0 ] && continue + + if [[ "$IS_FIRST" != true ]]; then + echo "," >> "$MANIFEST" + fi + IS_FIRST= + cat "$MANIFEST.sub" >> "$MANIFEST" +done + +echo "]" >> "$MANIFEST" + +# shellcheck disable=SC2059 +openssl dgst -sha256 -sign <(set +x; printf -- "$SIGNING_KEY") -out "$MANIFEST.sig" "$MANIFEST" + +perl -e "print pack('N', -s \"$MANIFEST.sig\")" > "$MANIFEST.out" +cat "$MANIFEST.sig" >> "$MANIFEST.out" +cat "$MANIFEST" >> "$MANIFEST.out" + +curl --fail \ + --user "$REPO_CREDS" \ + --upload-file "$MANIFEST.out" "$REPO_ROOT/$RUNELITE_VERSION/manifest.js" + +echo "Build Success" \ No newline at end of file diff --git a/build_plugin.sh b/build_plugin.sh new file mode 100755 index 000000000..e6189b82f --- /dev/null +++ b/build_plugin.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +# Copyright (c) 2019 Abex +# 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. + +source repo_config.sh + +set -e -x + +PLUGINFILE="$1" +[ -s "$PLUGINFILE" ] +PLUGIN_ID=$(basename "$PLUGINFILE") + +# check valid plugin id +[[ $PLUGIN_ID =~ ^[a-z0-9-]+$ ]] + +SCRIPT_HOME="$(cd "$(dirname "$0")" ; pwd -P)" + +RUNELITE_VERSION="$(cat "$SCRIPT_HOME/runelite.version")" + +# read in the plugin descriptor +disabled= +# shellcheck disable=SC2162 +while read LINE || [[ -n "$LINE" ]]; do + [[ $LINE =~ ^(repository|commit|disabled)=(.*)$ ]] + eval "${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\"" +done < "$PLUGINFILE" +[ -z "$disabled" ] || exit 0 + +# must be a https github repo +[[ $repository =~ ^https://github.com/.*\.git$ ]] + +# we must have a full 40 char sha1sum +[[ $commit =~ ^[a-fA-F0-9]{40}+$ ]] + +BUILDDIR="$(mktemp -d /tmp/external-plugin.XXXXXXXX)" +trap "rm -rf ""$BUILDDIR""" EXIT +pushd "$BUILDDIR" + +git clone "$repository" "repo" +pushd "repo" +git checkout "$commit" + +SIGNING_KEY="" REPO_CREDS="" gradle \ + --no-build-cache \ + --parallel \ + --console=plain \ + --init-script="$SCRIPT_HOME/package.gradle" \ + -DrlpluginRuneLiteVersion="$RUNELITE_VERSION" \ + -DrlpluginOutputDirectory="$BUILDDIR" \ + -DrlpluginPluginID="$PLUGIN_ID" \ + -DrlpluginCommit="$commit" \ + rlpluginPackageJar rlpluginEmitManifest + +[ -s "$BUILDDIR/plugin.jar" ] +[ -s "$BUILDDIR/plugin.manifest" ] + +cat "$BUILDDIR/plugin.manifest" + +[[ "${TRAVIS_PULL_REQUEST:-false}" == "false" ]] || exit 0 + +LOCATION="$REPO_ROOT/$RUNELITE_VERSION/$PLUGIN_ID/$commit" + +ICON_UPLOAD=() +if [ -e "icon.png" ]; then + ICON_UPLOAD=("--upload-file" "icon.png" "$LOCATION.png") +fi + +curl --fail \ + --user "$REPO_CREDS" \ + --upload-file "$BUILDDIR/plugin.manifest" "$LOCATION.manifest" \ + --upload-file "$BUILDDIR/plugin.jar" "$LOCATION.jar" \ + "${ICON_UPLOAD[@]}" + +echo "Build Success" \ No newline at end of file diff --git a/create_new_plugin.py b/create_new_plugin.py new file mode 100755 index 000000000..a0e1f5c62 --- /dev/null +++ b/create_new_plugin.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python3 + +""" +Copyright (c) 2019 Abex +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 os +import sys +from collections import OrderedDict +import argparse +import re +from string import Template + +templatedir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templateplugin") + +def strip_plugin(str): + return re.sub(r"(?i)[ _-]*plugin$", "", str) + +def reformat(str, replacer): + if replacer != to_spaces: + str=re.sub(r"[^a-zA-Z0-9_ -]", "", str) + if re.match(r".*[ _-]", str): + return re.sub(r"(?:^|[ _.-]+)([^ _.-]+)", lambda m:replacer(m.group(1)), str).strip(" -_") + return re.sub(r"((?:^.|[A-Z0-9]+)(?:[a-z0-9]+|$))", lambda m:replacer(m.group(1)), str).strip(" -_") + +def to_spaces(seg): + return " " + seg.capitalize() + +def to_camelcase(seg): + return seg.capitalize() + +def to_dashes(seg): + return "-" + seg.lower() + +def to_lowercase(seg): + return seg.lower() + +def strfun(strfun): + if isinstance(strfun, str): + return strfun + return strfun() + +subs = OrderedDict([ + ("name", { + "ask": True, + "desc": "The name your plugin will be shown by in menus", + "value": "Foo Bazzer", + "strip_plugin": True, + }), + ("package", { + "ask": True, + "desc": "The java package your plugin will be in. Typically a reversed domain name", + "value": "com.examaple.foobazzer", + "strip_plugin": True, + }), + ("author", { + "ask": True, + "desc": "Who wrote/maintains this plugin", + "value": "John Doe", + }), + ("description", { + "ask": True, + "desc": "A short string describing the plugin", + "value": "Adds a bazzer to the foo", + }), + ("version", { + "desc": "The initial version number of the plugin", + "value": "1.0-SNAPSHOT", + }), + ("plugin_prefix", { + "desc": "The name of the your plugin's main class, without the 'Plugin' suffix", + "value": lambda: reformat(subs["name"]["value"], to_camelcase), + "strip_plugin": True + }), + ("artifact_id", { + "desc": "The name of the maven artifact", + "value": lambda: reformat(subs["name"]["value"], to_dashes), + }), + ("group_id", { + "desc": "The group of the maven artifact", + "value": lambda: subs["package"]["value"], + }), + ("plugin_config_group", { + "desc": "The prefix used to store config keys", + "value": lambda: reformat(subs["name"]["value"], to_lowercase), + "strip_plugin": True + }) +]) + +pwd = os.getcwd() +pwdIsEmpty = len(os.listdir(pwd)) == 0 +if pwdIsEmpty: + subs["name"]["value"] = strip_plugin(reformat(os.path.basename(pwd), to_spaces)) + +parser = argparse.ArgumentParser() +parser.add_argument("--noninteractive", dest = "noninteractive", action='store_true') +parser.add_argument("--output_directory", dest = "output_directory") +for key, var in subs.items(): + parser.add_argument("--" + key, dest = key, help = var["desc"]) +args = vars(parser.parse_args()) + +noninteractive = args["noninteractive"] + +if noninteractive and pwdIsEmpty: + subs["name"]["ask"] = False + +for key, var in subs.items(): + if args[key] != None: + val = args[key] + if "strip_plugin" in var and var["strip_plugin"]: + val = strip_plugin(val) + var["value"] = val + var["ask"] = False + +askAll = False +while True: + for key, var in subs.items(): + if askAll or ("ask" in var and var["ask"]): + if noninteractive: + print("\"{}\" was not specified in noninteractive mode".format(key)) + sys.exit(1) + print(var["desc"]) + print("[" + strfun(var["value"]) + "]") + val = input(key + ": ") + if val: + if "strip_plugin" in var and var["strip_plugin"]: + val = strip_plugin(val) + var["value"] = val + + askAll = True + + print("") + for key, var in subs.items(): + print("{} = \"{}\"".format(key, strfun(var["value"]))) + def input_yes(): + while True: + inp = input("Is this ok? [Yn]").lower() + if inp == "" or inp == "y": + return True + if inp == "n": + return False + if noninteractive or input_yes(): + break + +outdir = args["output_directory"] +if outdir == None: + if pwdIsEmpty: + outdir = pwd + else: + outdir = os.path.join(pwd, strfun(subs["artifact_id"]["value"])) + +mappings = {} +for key, var in subs.items(): + mappings[key] = strfun(var["value"]) +mappings["package_path"] = mappings["package"].replace(".", os.path.sep) +with open(os.path.join(templatedir, "../runelite.version"), "rt") as fi: + mappings["runelite_version"] = fi.read().strip() + +for root, dir, files in os.walk(templatedir): + for file in files: + try: + infi = os.path.join(root, file) + outfi = os.path.join(os.path.relpath(root, templatedir), file) + outfi = outfi.replace("_(", "${").replace(")_", "}") + outfi = Template(outfi).substitute(mappings) + outfi = os.path.join(outdir, outfi) + os.makedirs(os.path.dirname(outfi), exist_ok=True) + with open(infi, "rb") as ifd: # we need binary mode to not do that stupid crlf bullshit on windows + if file.endswith(".jar") or file.startswith("gradlew"): + with open(outfi, "wb") as ofd: + ofd.write(ifd.read()) + else: + contents = Template(ifd.read().decode("utf-8")).substitute(mappings) + with open(outfi, "wb") as ofd: + ofd.write(contents.encode("utf-8")) + except ValueError as ex: + raise ValueError(infi) from ex \ No newline at end of file diff --git a/package.gradle b/package.gradle new file mode 100644 index 000000000..183ecb273 --- /dev/null +++ b/package.gradle @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2019 Abex + * 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.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.google.common.hash.Hashing +import com.google.common.io.Files +import com.google.gson.Gson + +initscript { + repositories { + jcenter() + mavenCentral() + } + dependencies { + classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" + classpath "com.google.code.gson:gson:2.8.5" + classpath "com.google.guava:guava:23.2-jre" + } +} + +allprojects { + apply plugin: "java"; + apply plugin: com.github.jengelman.gradle.plugins.shadow.ShadowPlugin + + tasks.withType(AbstractArchiveTask) { + preserveFileTimestamps = false + reproducibleFileOrder = true + } + + task rlpluginPackageJar(type: ShadowJar) { + destinationDir = new File(System.properties["rlpluginOutputDirectory"]) + archiveName = "plugin.jar" + configurations = [project.configurations.runtimeClasspath] + from sourceSets.main.output + } + + task rlpluginEmitManifest { + // this doesn't have up-to-date stuff because we always do --no-build-cache + + doLast { + def manifest = new ExternalPluginManifest() + manifest.internalName = System.properties["rlpluginPluginID"] + manifest.commit = System.properties["rlpluginCommit"] + + def pluginJar = new File(System.properties["rlpluginOutputDirectory"], "plugin.jar"); + manifest.hash = Files.asByteSource(pluginJar) + .hash(Hashing.sha256()) + .toString() + manifest.size = pluginJar.length() + + def props = new Properties() + new FileInputStream(file("runelite-plugin.properties")).withCloseable { is -> + props.load(is) + } + manifest.plugins = props["plugins"].split(/[,:;]/)*.trim() + + manifest.displayName = props["displayName"] + if (!manifest.displayName) { + throw new RuntimeException("Plugin must have a display name") + } + manifest.author = props["author"] + if (!manifest.author) { + throw new RuntimeException("Plugin must have an author") + } + if (props["support"]) { + manifest.support = new URL(props["support"]) + } + manifest.description = props["description"] ?: null + manifest.tags = props["tags"]?.split() ?: null + + manifest.version = project.version + if (!(manifest.version ==~ /^[a-zA-Z0-9.-]+$/)) { + throw new RuntimeException("Plugin version \"${manifest.version}\" is invalid"); + } + + manifest.hasIcon = file("icon.png").exists(); + + new File(System.properties["rlpluginOutputDirectory"], "plugin.manifest") + .text = new Gson().toJson(manifest); + } + } + + rlpluginEmitManifest.dependsOn rlpluginPackageJar + + task configured { + def runeLiteDeps = [ + "runelite-client", + "runelite-api", + "http-api", + ] + def version = System.properties["rlpluginRuneLiteVersion"] + configurations.all { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group == "net.runelite" && details.requested.name in runeLiteDeps) { + details.useVersion version + } + } + } + } +} + +class ExternalPluginManifest { + String internalName; + String commit; + String hash; + int size; + String[] plugins; + + String displayName; + String version; + String author; + String description; + String[] tags; + URL support; + boolean hasIcon; +} \ No newline at end of file diff --git a/rebuild_all.sh b/rebuild_all.sh new file mode 100755 index 000000000..1a2d13de9 --- /dev/null +++ b/rebuild_all.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Copyright (c) 2019 Abex +# 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. + +[[ "${TRAVIS_PULL_REQUEST:-false}" == "false" ]] || exit 0 + +SECONDS=0 + +for PLUGIN in plugins/* ; do + if [ $SECONDS -gt 60 ]; then + ./build_manifest.sh + SECONDS=0 + fi + PLUGIN_ID=$(basename "$PLUGINFILE") + echo "travis_fold:start:$PLUGIN_ID]" + ./build_plugin.sh "$PLUGIN" + echo "travis_font:end:[$PLUGIN_ID]" +done + +./build_manifest.sh \ No newline at end of file diff --git a/repo_config.sh b/repo_config.sh new file mode 100755 index 000000000..cf3e57481 --- /dev/null +++ b/repo_config.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# export REPO_CREDS="user:password" +# export REPO_ROOT="https://your/webdav/server" +# export SIGNING_KEY=" +# -----BEGIN PRIVATE KEY----- +# ... +# -----END PRIVATE KEY----- +# " diff --git a/runelite.version b/runelite.version new file mode 100644 index 000000000..2c355dfb9 --- /dev/null +++ b/runelite.version @@ -0,0 +1 @@ +1.5.43-SNAPSHOT diff --git a/templateplugin/.gitignore b/templateplugin/.gitignore new file mode 100644 index 000000000..a28bff27d --- /dev/null +++ b/templateplugin/.gitignore @@ -0,0 +1,9 @@ +.gradle +build +.idea/ +.project +.settings/ +.classpath +nbactions.xml +nb-configuration.xml +nbproject/ \ No newline at end of file diff --git a/templateplugin/build.gradle b/templateplugin/build.gradle new file mode 100644 index 000000000..68612635e --- /dev/null +++ b/templateplugin/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' +} + +repositories { + mavenLocal() + maven { + url = 'http://repo.runelite.net' + } + mavenCentral() +} + +dependencies { + compileOnly 'net.runelite:client:${runelite_version}' + compileOnly 'org.slf4j:slf4j-api:1.7.25' + + compileOnly 'org.projectlombok:lombok:1.18.4' + annotationProcessor 'org.projectlombok:lombok:1.18.4' + + testImplementation 'junit:junit:4.12' + testImplementation 'org.slf4j:slf4j-simple:1.7.12' + testImplementation 'net.runelite:client:${runelite_version}' +} + +group = '${group_id}' +version = '${version}' +sourceCompatibility = '1.8' + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/templateplugin/gradle/wrapper/gradle-wrapper.jar b/templateplugin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..5c2d1cf01 Binary files /dev/null and b/templateplugin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/templateplugin/gradle/wrapper/gradle-wrapper.properties b/templateplugin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ffedc50fd --- /dev/null +++ b/templateplugin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Dec 12 13:37:44 MST 2019 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/templateplugin/gradlew b/templateplugin/gradlew new file mode 100755 index 000000000..e554bc1d8 --- /dev/null +++ b/templateplugin/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +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='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="/usr/lib/jvm/java-11-openjdk/bin/java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/templateplugin/gradlew.bat b/templateplugin/gradlew.bat new file mode 100644 index 000000000..24467a141 --- /dev/null +++ b/templateplugin/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +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="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/templateplugin/runelite-plugin.properties b/templateplugin/runelite-plugin.properties new file mode 100644 index 000000000..1dff58653 --- /dev/null +++ b/templateplugin/runelite-plugin.properties @@ -0,0 +1,6 @@ +displayName=${name} +author=${author} +support= +description=${description} +tags= +plugins=${package}.${plugin_prefix}Plugin \ No newline at end of file diff --git a/templateplugin/settings.gradle b/templateplugin/settings.gradle new file mode 100644 index 000000000..fd364a7a8 --- /dev/null +++ b/templateplugin/settings.gradle @@ -0,0 +1 @@ +rootProject.name = '${artifact_id}' diff --git a/templateplugin/src/main/java/_(package_path)_/_(plugin_prefix)_Config.java b/templateplugin/src/main/java/_(package_path)_/_(plugin_prefix)_Config.java new file mode 100644 index 000000000..3da5534e0 --- /dev/null +++ b/templateplugin/src/main/java/_(package_path)_/_(plugin_prefix)_Config.java @@ -0,0 +1,20 @@ + +package ${package}; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("${plugin_config_group}") +public interface ${plugin_prefix}Config extends Config +{ + @ConfigItem( + keyName = "greeting", + name = "Welcome Greeting", + description = "The message to show to the user when they login" + ) + default String greeting() + { + return "Hello"; + } +} diff --git a/templateplugin/src/main/java/_(package_path)_/_(plugin_prefix)_Plugin.java b/templateplugin/src/main/java/_(package_path)_/_(plugin_prefix)_Plugin.java new file mode 100644 index 000000000..5b3530b40 --- /dev/null +++ b/templateplugin/src/main/java/_(package_path)_/_(plugin_prefix)_Plugin.java @@ -0,0 +1,53 @@ +package ${package}; + +import com.google.inject.Provides; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.ChatMessageType; +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 lombok.extern.slf4j.Slf4j; + +@Slf4j +@PluginDescriptor( + name = "${name}" +) +public class ${plugin_prefix}Plugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private ${plugin_prefix}Config config; + + @Override + protected void startUp() throws Exception + { + log.info("${name} started!"); + } + + @Override + protected void shutDown() throws Exception + { + log.info("${name} stopped!"); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState() == GameState.LOGGED_IN) + { + client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "${name} says " + config.greeting(), null); + } + } + + @Provides + ${plugin_prefix}Config provideConfig(ConfigManager configManager) + { + return configManager.getConfig(${plugin_prefix}Config.class); + } +} diff --git a/templateplugin/src/test/java/_(package_path)_/_(plugin_prefix)_PluginTest.java b/templateplugin/src/test/java/_(package_path)_/_(plugin_prefix)_PluginTest.java new file mode 100644 index 000000000..9daabaf38 --- /dev/null +++ b/templateplugin/src/test/java/_(package_path)_/_(plugin_prefix)_PluginTest.java @@ -0,0 +1,13 @@ +package ${package}; + +import net.runelite.client.RuneLite; +import net.runelite.client.externalplugins.ExternalPluginManager; + +public class ${plugin_prefix}PluginTest +{ + public static void main(String[] args) throws Exception + { + ExternalPluginManager.loadBuiltin(${plugin_prefix}Plugin.class); + RuneLite.main(args); + } +} \ No newline at end of file diff --git a/travis.sh b/travis.sh new file mode 100755 index 000000000..b53a3d9ea --- /dev/null +++ b/travis.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# Copyright (c) 2019 Abex +# 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. + +set -e -x + +: ' +env: + -FORCE_BUILD: example-external-plugin +' + +if [[ "$FORCE_BUILD" == "ALL" ]]; then + ./rebuild_all + exit +elif [[ -n "${FORCE_BUILD+x}" ]]; then + for FI in "${FORCE_BUILD[@]}"; do + ./build_plugin.sh "plugins/$FORCE_BUILD" + done + exit +fi + +PLUGIN_CHANGE= +while read -r FI ; do + if [[ $FI =~ ^plugins/.*$ ]]; then + ./build_plugin.sh "$FI" + PLUGIN_CHANGE=true + elif [[ "$FI" == "runelite.version" ]]; then + ./rebuild_all.sh + fi +done < <(git diff --name-only "$TRAVIS_COMMIT_RANGE") + +if [[ "$PLUGIN_CHANGE" == true ]]; then + ./build_manifest.sh +fi \ No newline at end of file