From 3403c0a2d119708d63328742e390c69c869b1070 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Fri, 26 May 2017 00:51:51 +0100 Subject: [PATCH 001/209] First draft of KotlinPluginEnvironment --- game/build.gradle | 25 +++++ .../plugin/kotlin/KotlinPluginCompiler.kt | 64 +++++++++++ .../game/plugin/kotlin/KotlinPluginScript.kt | 45 ++++++++ .../game/plugin/KotlinPluginEnvironment.java | 101 ++++++++++++++++++ .../org/apollo/game/plugin/PluginManager.java | 2 +- 5 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt create mode 100644 game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt create mode 100644 game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java diff --git a/game/build.gradle b/game/build.gradle index a96d17a99..15e9fbb84 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -1,7 +1,32 @@ description = 'Apollo Game' +buildscript { + ext.kotlinVersion = '1.1.2-4' + + repositories { + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + } +} + +apply plugin: 'kotlin' + dependencies { compile project(':cache') compile project(':net') compile project(':util') + + compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: $kotlinVersion + compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: $kotlinVersion +} + +sourceSets { + main.kotlin.srcDirs += 'src/kotlin' +} + +repositories { + mavenCentral() } diff --git a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt b/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt new file mode 100644 index 000000000..e87dbe5d6 --- /dev/null +++ b/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt @@ -0,0 +1,64 @@ +package org.apollo.game.plugin.kotlin + +import com.intellij.openapi.util.Disposer +import org.apollo.Server +import org.apollo.game.model.World +import org.apollo.game.plugin.PluginContext +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot +import org.jetbrains.kotlin.codegen.CompilationException +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.addKotlinSourceRoot +import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate +import java.io.File + +class KotlinPluginCompiler(val classpath: List, val messageCollector: MessageCollector) { + + private fun createCompilerConfiguration(inputPath: String): CompilerConfiguration { + val configuration = CompilerConfiguration() + val scriptDefinition = KotlinScriptDefinitionFromAnnotatedTemplate(KotlinPluginScript::class) + + configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.map { JvmClasspathRoot(it) }) + configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) + configuration.put(CommonConfigurationKeys.MODULE_NAME, inputPath) + configuration.addKotlinSourceRoot(inputPath) + + return configuration + } + + @Throws(KotlinPluginCompilerException::class) + fun compile(inputPath: String): Class { + val rootDisposable = Disposer.newDisposable() + val configuration = createCompilerConfiguration(inputPath) + + val configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES + val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, configFiles) + + try { + val clazz = KotlinToJVMBytecodeCompiler.compileScript(environment, Server::class.java.classLoader) + + if (clazz?.getConstructor(World::class.java, PluginContext::class.java) == null) { + throw KotlinPluginCompilerException("Unable to compile $inputPath, no plugin constructor found") + } + + return clazz as Class + } catch (e: CompilationException) { + throw KotlinPluginCompilerException("Compilation failed", e) + } finally { + Disposer.dispose(rootDisposable) + } + } + +} + +class KotlinPluginCompilerException(message: String, cause: Throwable? = null) : Exception(message, cause) { + +} \ No newline at end of file diff --git a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt new file mode 100644 index 000000000..29a84213c --- /dev/null +++ b/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -0,0 +1,45 @@ +package org.apollo.game.plugin.kotlin + +import org.apollo.game.message.handler.MessageHandler +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.PluginContext +import org.apollo.net.message.Message +import kotlin.reflect.KClass +import kotlin.script.templates.ScriptTemplateDefinition + +@ScriptTemplateDefinition( + scriptFilePattern = ".*\\.plugin\\.kts" +) +abstract class KotlinPluginScript(val world: World, val context: PluginContext) { + + protected fun on(type: () -> KClass): KotlinMessageHandler { + return KotlinMessageHandler(world, context, type.invoke()) + } + +} + + +class KotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : MessageHandler(world) { + + override fun handle(player: Player, message: T) { + if (message.predicate()) { + message.function(player) + } + } + + var function: T.(Player) -> Unit = { _ -> } + + var predicate: T.() -> Boolean = { true } + + fun where(predicate: T.() -> Boolean): KotlinMessageHandler { + this.predicate = predicate + return this + } + + fun then(function: T.(Player) -> Unit) { + this.function = function + this.context.addMessageHandler(type.java, this) + } + +} diff --git a/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java new file mode 100644 index 000000000..0dfe06cd6 --- /dev/null +++ b/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -0,0 +1,101 @@ +package org.apollo.game.plugin; + +import org.apollo.game.model.World; +import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; +import org.apollo.game.plugin.kotlin.KotlinPluginScript; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; +import org.jetbrains.kotlin.cli.common.messages.MessageCollector; + +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class KotlinPluginEnvironment implements PluginEnvironment, MessageCollector { + + private static final Logger logger = Logger.getLogger(KotlinPluginEnvironment.class.getName()); + + private final World world; + private final KotlinPluginCompiler pluginCompiler; + + private PluginContext context; + + public KotlinPluginEnvironment(World world) { + this.world = world; + this.pluginCompiler = new KotlinPluginCompiler(resolveClasspath(), this); + } + + /** + * Resolve the classpath of the current running {@link Thread}. + * + * @return A {@link List} of {@link File}s pointing to classpath entries. + */ + private static List resolveClasspath() { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + if (!(classLoader instanceof URLClassLoader)) { + throw new RuntimeException("Unable to resolve classpath for current ClassLoader"); + } + + URLClassLoader urlClassLoader = (URLClassLoader) classLoader; + URL[] classpathUrls = urlClassLoader.getURLs(); + List classpath = new ArrayList<>(); + + for (URL classpathUrl : classpathUrls) { + try { + classpath.add(new File(classpathUrl.toURI())); + } catch (URISyntaxException e) { + throw new RuntimeException("URL returned by ClassLoader is invalid"); + } + } + + return classpath; + } + + @Override + public void parse(InputStream is, String name) { + //@todo - wait until all plugin classes are loading until running constructors? + try { + Class pluginClass = pluginCompiler.compile(name); + Constructor pluginConstructor = pluginClass.getConstructor(World.class, + PluginContext.class); + + pluginConstructor.newInstance(world, context); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void setContext(PluginContext context) { + this.context = context; + } + + @Override + public void clear() { + + } + + @Override + public void report(@NotNull CompilerMessageSeverity severity, @NotNull String message, + @NotNull CompilerMessageLocation location) { + if (severity.isError()) { + logger.log(Level.SEVERE, String.format("%s:%s-%s: %s", location.getPath(), location.getLine(), + location.getColumn(), message)); + } + } + + @Override + public boolean hasErrors() { + return false; + } + +} diff --git a/game/src/main/org/apollo/game/plugin/PluginManager.java b/game/src/main/org/apollo/game/plugin/PluginManager.java index acf980d0c..2e4987858 100644 --- a/game/src/main/org/apollo/game/plugin/PluginManager.java +++ b/game/src/main/org/apollo/game/plugin/PluginManager.java @@ -146,7 +146,7 @@ public void start() throws IOException, SAXException, DependencyException { Map plugins = createMap(findPlugins()); Set started = new HashSet<>(); - PluginEnvironment env = new RubyPluginEnvironment(world); // TODO isolate plugins if possible in the future! + PluginEnvironment env = new KotlinPluginEnvironment(world); // TODO isolate plugins if possible in the future! env.setContext(context); for (PluginMetaData plugin : plugins.values()) { From 79f79cd15cd58388cca3513b4d423d579abfb0c7 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 27 May 2017 18:33:17 +0100 Subject: [PATCH 002/209] Add a 'plugins' source set to the game module Creates a new sourceset for server plugins to support IDE integration with plugin code. Additionally moves plugins to game/data/plugins and contains some gradle related fixes (remove java plugin from root project and fix exec task dependency). --- build.gradle | 12 ++- game/build.gradle | 23 +++--- game/data/plugins/bank/bank.plugin.kts | 75 +++++++++++++++++++ game/data/plugins/bank/plugin.xml | 14 ++++ .../data/plugins/dialogue/dialogue.plugin.kts | 0 game/data/plugins/dialogue/plugin.xml | 0 game/data/plugins/stub.kt | 20 +++++ .../org/apollo/game/plugin/PluginManager.java | 2 +- 8 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 game/data/plugins/bank/bank.plugin.kts create mode 100644 game/data/plugins/bank/plugin.xml create mode 100644 game/data/plugins/dialogue/dialogue.plugin.kts create mode 100644 game/data/plugins/dialogue/plugin.xml create mode 100644 game/data/plugins/stub.kt diff --git a/build.gradle b/build.gradle index bdaa13e15..a9cb46d6b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,15 @@ allprojects { group = 'apollo' version = '0.0.1' - apply plugin: 'java' +} + +ext { + kotlinVersion = '1.1.2-4' } subprojects { + apply plugin: 'java' + sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -41,8 +46,9 @@ subprojects { } } -task(run, dependsOn: classes, type: JavaExec) { - def gameSubproject = project(':game') +def gameSubproject = project(':game') + +task(run, dependsOn: gameSubproject.tasks['classes'], type: JavaExec) { def gameClasspath = gameSubproject.sourceSets.main.runtimeClasspath main = 'org.apollo.Server' diff --git a/game/build.gradle b/game/build.gradle index 15e9fbb84..c380c06a1 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -1,8 +1,6 @@ description = 'Apollo Game' buildscript { - ext.kotlinVersion = '1.1.2-4' - repositories { mavenCentral() } @@ -14,19 +12,22 @@ buildscript { apply plugin: 'kotlin' +sourceSets { + main.kotlin.srcDirs += 'src/kotlin' + + plugins { + kotlin.srcDirs += 'data/plugins' + } +} + dependencies { compile project(':cache') compile project(':net') compile project(':util') - compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: $kotlinVersion - compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: $kotlinVersion -} - -sourceSets { - main.kotlin.srcDirs += 'src/kotlin' -} + pluginsCompile(configurations.compile) + pluginsCompile(sourceSets.main.output) -repositories { - mavenCentral() + compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlinVersion" + compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" } diff --git a/game/data/plugins/bank/bank.plugin.kts b/game/data/plugins/bank/bank.plugin.kts new file mode 100644 index 000000000..929ffacda --- /dev/null +++ b/game/data/plugins/bank/bank.plugin.kts @@ -0,0 +1,75 @@ +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.NpcActionMessage +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.Player +import org.apollo.game.model.inter.bank.BankUtils +import org.apollo.net.message.Message + +val BANK_BOOTH_ID = 2213 + +/** + * Hook into the [ObjectActionMessage] and listen for when a bank booth's second action ("Open Bank") is selected. + */ +on { ObjectActionMessage::class } + .where { option == 2 && id == BANK_BOOTH_ID } + .then { BankAction.start(this, it, position) } + +/** + * Hook into the [NpcActionMessage] and listen for when a banker's second action ("Open Bank") is selected. + */ +on { NpcActionMessage::class } + .where { option == 2 } + .then { + val npc: Npc = Any() as Npc // TODO world.npcRepository.get(index) + + if (npc.id in BANKER_NPCS) { + BankAction.start(this, it, npc.position) + } + } + +/** + * The ids of all banker [Npcs][Npc]. + */ +val BANKER_NPCS = setOf(166, 494, 495, 496, 497, 498, 499, 1036, 1360, 1702, 2163, 2164, 2354, 2355, 2568, 2569, 2570) + +/** + * A [DistancedAction] that opens a [Player]'s bank when they get close enough to a booth or banker. + * + * @property position The [Position] of the booth/[Npc]. + */ +class BankAction(player: Player, position: Position) : DistancedAction(0, true, player, position, DISTANCE) { + + companion object { + + /** + * The distance threshold that must be reached before the bank interface is opened. + */ + const val DISTANCE = 1 + + /** + * Starts a [BankAction] for the specified [Player], terminating the [Message] that triggered. + */ + fun start(message: Message, player: Player, position: Position) { + player.startAction(BankAction(player, position)) + message.terminate() + } + + } + + override fun executeAction() { + mob.turnTo(position) + BankUtils.openBank(mob) + stop() + } + + override fun equals(other: Any?): Boolean { + return other is BankAction && position == other.position + } + + override fun hashCode(): Int { + return position.hashCode() + } + +} diff --git a/game/data/plugins/bank/plugin.xml b/game/data/plugins/bank/plugin.xml new file mode 100644 index 000000000..4402e5f09 --- /dev/null +++ b/game/data/plugins/bank/plugin.xml @@ -0,0 +1,14 @@ + + + bank + 1 + Bank + Opens the bank interface when players select 'use-quickly' on a bank booth. + + Major + + + + + + diff --git a/game/data/plugins/dialogue/dialogue.plugin.kts b/game/data/plugins/dialogue/dialogue.plugin.kts new file mode 100644 index 000000000..e69de29bb diff --git a/game/data/plugins/dialogue/plugin.xml b/game/data/plugins/dialogue/plugin.xml new file mode 100644 index 000000000..e69de29bb diff --git a/game/data/plugins/stub.kt b/game/data/plugins/stub.kt new file mode 100644 index 000000000..4e6fe63f2 --- /dev/null +++ b/game/data/plugins/stub.kt @@ -0,0 +1,20 @@ +/** + * NOTE: This file is a stub, intended only for use within an IDE. It should be updated + * each time [org.apollo.game.plugin.kotlin.KotlinPluginScript] has a new method added to it. + * + * Until IntelliJ IDEA starts to support ScriptTemplateDefinitions this is + * required to resolve references within plugin code. + */ + +import org.apollo.game.model.World +import org.apollo.game.plugin.PluginContext +import org.apollo.game.plugin.kotlin.KotlinMessageHandler +import org.apollo.net.message.Message +import kotlin.reflect.KClass + +val world: World = null!! +var context: PluginContext = null!! + +fun on(type: () -> KClass): KotlinMessageHandler { + null!! +} \ No newline at end of file diff --git a/game/src/main/org/apollo/game/plugin/PluginManager.java b/game/src/main/org/apollo/game/plugin/PluginManager.java index 2e4987858..d816a7339 100644 --- a/game/src/main/org/apollo/game/plugin/PluginManager.java +++ b/game/src/main/org/apollo/game/plugin/PluginManager.java @@ -72,7 +72,7 @@ private static Map createMap(Collection * @throws SAXException If a SAX error occurs. */ private Collection findPlugins() throws IOException, SAXException { - return findPlugins(new File("./data/plugins")); + return findPlugins(new File("./game/data/plugins")); } /** From 7ffef28117fe50fbe173390e433d3a2e89ad1c8f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 28 May 2017 01:38:58 +0100 Subject: [PATCH 003/209] Compile plugins at build-time instead of runtime Adds gradle tasks to build all plugin scripts under data/plugins with the KotlinPluginCompiler implementation previously used for runtime code generation. In addition to .plugin.kts files, scripts can also declare API code in .kt files which will also be included on the classpath and made available to other plugins. --- build.gradle | 2 +- game/build.gradle | 37 ++++- .../plugin/kotlin/KotlinPluginCompiler.kt | 146 +++++++++++++++--- .../game/plugin/KotlinPluginEnvironment.java | 77 +++++++-- .../apollo/game/plugin/PluginEnvironment.java | 9 +- .../org/apollo/game/plugin/PluginManager.java | 38 +---- .../game/plugin/RubyPluginEnvironment.java | 61 -------- 7 files changed, 227 insertions(+), 143 deletions(-) delete mode 100644 game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java diff --git a/build.gradle b/build.gradle index a9cb46d6b..a4bdcb9a8 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ subprojects { def gameSubproject = project(':game') -task(run, dependsOn: gameSubproject.tasks['classes'], type: JavaExec) { +task(run, dependsOn: gameSubproject.tasks['assemble'], type: JavaExec) { def gameClasspath = gameSubproject.sourceSets.main.runtimeClasspath main = 'org.apollo.Server' diff --git a/game/build.gradle b/game/build.gradle index c380c06a1..92df95e84 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -14,9 +14,15 @@ apply plugin: 'kotlin' sourceSets { main.kotlin.srcDirs += 'src/kotlin' + main.kotlin.excludes += 'stub.kt' + main.kotlin.excludes += '**/*.kts' plugins { - kotlin.srcDirs += 'data/plugins' + kotlin { + srcDir 'data/plugins' + exclude 'stub.kt' + exclude '**/*.kts' + } } } @@ -28,6 +34,33 @@ dependencies { pluginsCompile(configurations.compile) pluginsCompile(sourceSets.main.output) - compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" + compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlinVersion" + + runtime files("$buildDir/plugins") + runtime sourceSets.plugins.output +} + + +task('compilePluginScripts', dependsOn: [classes, pluginsClasses], type: JavaExec) { + def compilerClasspath = [ + configurations.compile.asPath, + configurations.runtime.asPath, + sourceSets.main.compileClasspath.asPath, + sourceSets.main.runtimeClasspath.asPath + ] + + def inputDir = "$projectDir/data/plugins" + def outputDir = "$buildDir/plugins" + def manifestPath = "$buildDir/plugins/manifest.txt" + + inputs.source inputDir + outputs.dir outputDir + + println compilerClasspath.join(':') + classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath + main = 'org.apollo.game.plugin.kotlin.KotlinPluginCompiler' + args = [inputDir, outputDir, manifestPath, compilerClasspath.join(':')] } + +assemble.dependsOn(compilePluginScripts) \ No newline at end of file diff --git a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt b/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt index e87dbe5d6..71bfb4cff 100644 --- a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt +++ b/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt @@ -1,41 +1,132 @@ package org.apollo.game.plugin.kotlin +import com.google.common.base.CaseFormat import com.intellij.openapi.util.Disposer -import org.apollo.Server -import org.apollo.game.model.World -import org.apollo.game.plugin.PluginContext import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler +import org.jetbrains.kotlin.cli.common.messages.* +import org.jetbrains.kotlin.cli.jvm.compiler.* import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot import org.jetbrains.kotlin.codegen.CompilationException -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.addKotlinSourceRoot +import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate import java.io.File +import java.lang.management.ManagementFactory +import java.net.URISyntaxException +import java.net.URLClassLoader +import java.nio.file.* +import java.nio.file.StandardOpenOption.* +import java.nio.file.attribute.BasicFileAttributes +import java.util.* +import java.util.function.BiPredicate + +class KotlinMessageCollector : MessageCollector { + + override fun clear() { + } + + override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { + if (severity.isError) { + println("${location.path}:${location.line}-${location.column}: $message") + println(">>> ${location.lineContent}") + } + } + + override fun hasErrors(): Boolean { + return false + } + +} + +data class KotlinCompilerResult(val fqName: String, val outputPath: Path) class KotlinPluginCompiler(val classpath: List, val messageCollector: MessageCollector) { - private fun createCompilerConfiguration(inputPath: String): CompilerConfiguration { + companion object { + + private val maxSearchDepth = 1024; + + fun currentClasspath(): List { + val classLoader = Thread.currentThread().contextClassLoader as? URLClassLoader ?: + throw RuntimeException("Unable to resolve classpath for current ClassLoader") + + val classpathUrls = classLoader.urLs + val classpath = ArrayList() + + for (classpathUrl in classpathUrls) { + try { + classpath.add(File(classpathUrl.toURI())) + } catch (e: URISyntaxException) { + throw RuntimeException("URL returned by ClassLoader is invalid") + } + + } + + return classpath + } + + @JvmStatic + fun main(args: Array) { + if (args.size < 4) throw RuntimeException("Usage: ") + + val inputDir = Paths.get(args[0]) + val outputDir = Paths.get(args[1]) + val manifestPath = Paths.get(args[2]) + val classpathEntries = args[3].split(':') + val classpath = mutableListOf() + + val runtimeBean = ManagementFactory.getRuntimeMXBean() + if (!runtimeBean.isBootClassPathSupported) { + println("Warning! Boot class path is not supported, must be supplied on the command line") + } else { + val bootClasspath = runtimeBean.bootClassPath + classpath.addAll(bootClasspath.split(':').map { File(it) }) + } + + /** + * Classpath entries on the command line contain the kotlin runtime + * and plugin API code. We use our current classpath to provide + * Kotlin with access to the JRE and apollo modules. + */ + classpath.addAll(currentClasspath()) + classpath.addAll(classpathEntries.map { File(it) }) + + val inputScriptsMatcher = { path: Path, _: BasicFileAttributes -> path.toString().endsWith(".plugin.kts") } + val inputScripts = Files.find(inputDir, maxSearchDepth, BiPredicate(inputScriptsMatcher)) + + val compiler = KotlinPluginCompiler(classpath, MessageCollector.NONE) + val compiledScriptClasses = mutableListOf() + + try { + Files.createDirectory(outputDir) + + inputScripts.forEach { + compiledScriptClasses.add(compiler.compile(it, outputDir).fqName) + } + + Files.write(manifestPath, compiledScriptClasses, CREATE, TRUNCATE_EXISTING) + } catch (t: Throwable) { + t.printStackTrace() + System.exit(1) + } + } + } + + private fun createCompilerConfiguration(inputPath: Path): CompilerConfiguration { val configuration = CompilerConfiguration() val scriptDefinition = KotlinScriptDefinitionFromAnnotatedTemplate(KotlinPluginScript::class) configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.map { JvmClasspathRoot(it) }) configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) - configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) - configuration.put(CommonConfigurationKeys.MODULE_NAME, inputPath) - configuration.addKotlinSourceRoot(inputPath) + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, KotlinMessageCollector()) + configuration.put(CommonConfigurationKeys.MODULE_NAME, inputPath.toString()) + configuration.addKotlinSourceRoot(inputPath.toAbsolutePath().toString()) return configuration } @Throws(KotlinPluginCompilerException::class) - fun compile(inputPath: String): Class { + fun compile(inputPath: Path, outputPath: Path): KotlinCompilerResult { val rootDisposable = Disposer.newDisposable() val configuration = createCompilerConfiguration(inputPath) @@ -43,13 +134,26 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, configFiles) try { - val clazz = KotlinToJVMBytecodeCompiler.compileScript(environment, Server::class.java.classLoader) + val generationState = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(environment) + if (generationState == null) { + throw KotlinPluginCompilerException("Failed to generate bytecode for kotlin script") + } + + val sourceFiles = environment.getSourceFiles() + val script = sourceFiles[0].script ?: throw KotlinPluginCompilerException("Main script file isnt a script") - if (clazz?.getConstructor(World::class.java, PluginContext::class.java) == null) { - throw KotlinPluginCompilerException("Unable to compile $inputPath, no plugin constructor found") + val scriptFilePath = script.fqName.asString().replace('.', '/') + ".class" + val scriptFileClass = generationState.factory.get(scriptFilePath) + + if (scriptFileClass == null) { + throw KotlinPluginCompilerException("Unable to find compiled plugin class file $scriptFilePath") + } + + generationState.factory.asList().forEach { + Files.write(outputPath.resolve(it.relativePath), it.asByteArray(), CREATE, WRITE, TRUNCATE_EXISTING) } - return clazz as Class + return KotlinCompilerResult(script.fqName.asString(), outputPath.resolve(scriptFileClass.relativePath)) } catch (e: CompilationException) { throw KotlinPluginCompilerException("Compilation failed", e) } finally { @@ -61,4 +165,4 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess class KotlinPluginCompilerException(message: String, cause: Throwable? = null) : Exception(message, cause) { -} \ No newline at end of file +} diff --git a/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java index 0dfe06cd6..dce8bb602 100644 --- a/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ b/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -1,23 +1,27 @@ package org.apollo.game.plugin; -import org.apollo.game.model.World; -import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; -import org.apollo.game.plugin.kotlin.KotlinPluginScript; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.kotlin.cli.common.messages.MessageCollector; - +import java.io.BufferedReader; import java.io.File; import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; +import org.apollo.game.model.World; +import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; +import org.apollo.game.plugin.kotlin.KotlinPluginScript; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; +import org.jetbrains.kotlin.cli.common.messages.MessageCollector; public class KotlinPluginEnvironment implements PluginEnvironment, MessageCollector { @@ -61,17 +65,56 @@ private static List resolveClasspath() { } @Override - public void parse(InputStream is, String name) { - //@todo - wait until all plugin classes are loading until running constructors? - try { - Class pluginClass = pluginCompiler.compile(name); - Constructor pluginConstructor = pluginClass.getConstructor(World.class, - PluginContext.class); - - pluginConstructor.newInstance(world, context); + public void load(Collection plugins) { + try (InputStream resource = KotlinPluginEnvironment.class.getResourceAsStream("/manifest.txt")) { + BufferedReader reader = new BufferedReader(new InputStreamReader(resource)); + List pluginClassNames = reader.lines().collect(Collectors.toList()); + + for (String pluginClassName : pluginClassNames) { + Class pluginClass = + (Class) Class.forName(pluginClassName); + + Constructor pluginConstructor = + pluginClass.getConstructor(World.class, PluginContext.class); + + KotlinPluginScript plugin = pluginConstructor.newInstance(world, context); + } } catch (Exception e) { throw new RuntimeException(e); } + + List> pluginClasses = new ArrayList<>(); + List sourceRoots = new ArrayList<>(); + + for (PluginMetaData plugin : plugins) { + List pluginSourceRoots = Arrays.stream(plugin.getScripts()) + .map(script -> plugin.getBase() + "/" + script) + .collect(Collectors.toList()); + + sourceRoots.addAll(pluginSourceRoots); + } + + for (String scriptSource : sourceRoots) { +// try { + List dependencySourceRoots = new ArrayList<>(sourceRoots); + dependencySourceRoots.remove(scriptSource); + +// pluginClasses.add(pluginCompiler.compile(scriptSource)); +// } catch (KotlinPluginCompilerException e) { +// throw new RuntimeException(e); +// } + } + + for (Class pluginClass : pluginClasses) { + try { + Constructor constructor = pluginClass + .getConstructor(World.class, PluginContext.class); + + KotlinPluginScript script = constructor.newInstance(world, context); + } catch (Exception e) { + throw new RuntimeException(e); + } + } } @Override @@ -89,7 +132,7 @@ public void report(@NotNull CompilerMessageSeverity severity, @NotNull String me @NotNull CompilerMessageLocation location) { if (severity.isError()) { logger.log(Level.SEVERE, String.format("%s:%s-%s: %s", location.getPath(), location.getLine(), - location.getColumn(), message)); + location.getColumn(), message)); } } diff --git a/game/src/main/org/apollo/game/plugin/PluginEnvironment.java b/game/src/main/org/apollo/game/plugin/PluginEnvironment.java index f049f9748..505d8473e 100644 --- a/game/src/main/org/apollo/game/plugin/PluginEnvironment.java +++ b/game/src/main/org/apollo/game/plugin/PluginEnvironment.java @@ -1,6 +1,8 @@ package org.apollo.game.plugin; import java.io.InputStream; +import java.util.Collection; +import java.util.Set; /** * Represents some sort of environment that plugins could be executed in, e.g. {@code javax.script} or Jython. @@ -10,12 +12,11 @@ public interface PluginEnvironment { /** - * Parses the input stream. + * Load all of the plugins defined in the given {@link Set} of {@link PluginMetaData}. * - * @param is The input stream. - * @param name The name of the file. + * @param plugins The plugins to be loaded. */ - public void parse(InputStream is, String name); + void load(Collection plugins); /** * Sets the context for this environment. diff --git a/game/src/main/org/apollo/game/plugin/PluginManager.java b/game/src/main/org/apollo/game/plugin/PluginManager.java index d816a7339..db1b45dde 100644 --- a/game/src/main/org/apollo/game/plugin/PluginManager.java +++ b/game/src/main/org/apollo/game/plugin/PluginManager.java @@ -149,43 +149,7 @@ public void start() throws IOException, SAXException, DependencyException { PluginEnvironment env = new KotlinPluginEnvironment(world); // TODO isolate plugins if possible in the future! env.setContext(context); - for (PluginMetaData plugin : plugins.values()) { - start(env, plugin, plugins, started); - } - } - - /** - * Starts a specific plugin. - * - * @param env The environment. - * @param plugin The plugin. - * @param plugins The plugin map. - * @param started A set of started plugins. - * @throws DependencyException If a dependency error occurs. - * @throws IOException If an I/O error occurs. - */ - private void start(PluginEnvironment env, PluginMetaData plugin, Map plugins, Set started) throws DependencyException, IOException { - // TODO check for cyclic dependencies! this way just won't cut it, we need an exception - if (started.contains(plugin)) { - return; - } - started.add(plugin); - - for (String dependencyId : plugin.getDependencies()) { - PluginMetaData dependency = plugins.get(dependencyId); - if (dependency == null) { - throw new DependencyException("Unresolved dependency: " + dependencyId + "."); - } - start(env, dependency, plugins, started); - } - - String[] scripts = plugin.getScripts(); - - for (String script : scripts) { - File scriptFile = new File(plugin.getBase(), script); - InputStream is = new FileInputStream(scriptFile); - env.parse(is, scriptFile.getAbsolutePath()); - } + env.load(plugins.values()); } } \ No newline at end of file diff --git a/game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java b/game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java deleted file mode 100644 index 9ac48c67c..000000000 --- a/game/src/main/org/apollo/game/plugin/RubyPluginEnvironment.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.apollo.game.plugin; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.apollo.game.model.World; -import org.jruby.embed.ScriptingContainer; - -/** - * A {@link PluginEnvironment} which uses Ruby. - * - * @author Graham - */ -public final class RubyPluginEnvironment implements PluginEnvironment { - - /** - * The scripting container. - */ - private final ScriptingContainer container = new ScriptingContainer(); - - /** - * Creates and bootstraps the Ruby plugin environment. - * - * @param world The {@link World} this RubyPluginEnvironment is for. - * @throws IOException If an I/O error occurs during bootstrapping. - */ - public RubyPluginEnvironment(World world) throws IOException { - container.put("$world", world); - parseBootstrapper(); - } - - @Override - public void parse(InputStream is, String name) { - try { - container.runScriptlet(is, name); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Error parsing scriptlet " + name + ".", e); - } - } - - /** - * Parses the bootstrapper. - * - * @throws IOException If an I/O error occurs. - */ - private void parseBootstrapper() throws IOException { - File bootstrap = new File("./data/plugins/bootstrap.rb"); - try (InputStream is = new FileInputStream(bootstrap)) { - parse(is, bootstrap.getAbsolutePath()); - } - } - - @Override - public void setContext(PluginContext context) { - container.put("$ctx", context); - } - -} \ No newline at end of file From 05e20d9d51af5e27c952a7f79d79b9371f5ac691 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 28 May 2017 22:04:34 +0100 Subject: [PATCH 004/209] Reorganize project sources from src/main to src/main/java --- build.gradle | 4 +- .../org/apollo/cache/FileDescriptor.java | 0 .../org/apollo/cache/FileSystemConstants.java | 0 .../{ => java}/org/apollo/cache/Index.java | 0 .../org/apollo/cache/IndexedFileSystem.java | 0 .../org/apollo/cache/archive/Archive.java | 0 .../apollo/cache/archive/ArchiveEntry.java | 0 .../apollo/cache/archive/package-info.java | 0 .../cache/decoder/ItemDefinitionDecoder.java | 0 .../cache/decoder/NpcDefinitionDecoder.java | 0 .../decoder/ObjectDefinitionDecoder.java | 0 .../apollo/cache/decoder/package-info.java | 0 .../apollo/cache/def/EquipmentDefinition.java | 0 .../org/apollo/cache/def/ItemDefinition.java | 0 .../org/apollo/cache/def/NpcDefinition.java | 0 .../apollo/cache/def/ObjectDefinition.java | 0 .../org/apollo/cache/def/package-info.java | 0 .../org/apollo/cache/map/MapConstants.java | 0 .../org/apollo/cache/map/MapFile.java | 0 .../org/apollo/cache/map/MapFileDecoder.java | 0 .../org/apollo/cache/map/MapIndex.java | 0 .../org/apollo/cache/map/MapIndexDecoder.java | 0 .../org/apollo/cache/map/MapObject.java | 0 .../apollo/cache/map/MapObjectsDecoder.java | 0 .../org/apollo/cache/map/MapPlane.java | 0 .../{ => java}/org/apollo/cache/map/Tile.java | 0 .../org/apollo/cache/map/TileUtils.java | 0 .../org/apollo/cache/package-info.java | 0 .../apollo/cache/tools/EquipmentUpdater.java | 0 .../org/apollo/cache/tools/package-info.java | 0 game/build.gradle | 21 ++- .../data/plugins/dialogue/dialogue.plugin.kts | 0 game/data/plugins/dialogue/plugin.xml | 0 .../main/{ => java}/org/apollo/Server.java | 0 .../{ => java}/org/apollo/ServerContext.java | 0 .../main/{ => java}/org/apollo/Service.java | 0 .../{ => java}/org/apollo/ServiceManager.java | 0 .../org/apollo/game/GameConstants.java | 0 .../org/apollo/game/GamePulseHandler.java | 0 .../org/apollo/game/action/Action.java | 0 .../apollo/game/action/DistancedAction.java | 0 .../org/apollo/game/action/package-info.java | 0 .../org/apollo/game/command/Command.java | 0 .../game/command/CommandDispatcher.java | 0 .../apollo/game/command/CommandListener.java | 0 .../game/command/CreditsCommandListener.java | 0 .../org/apollo/game/command/package-info.java | 0 .../game/fs/decoder/SynchronousDecoder.java | 0 .../decoder/SynchronousDecoderException.java | 0 .../game/fs/decoder/WorldMapDecoder.java | 0 .../game/fs/decoder/WorldObjectsDecoder.java | 0 .../apollo/game/fs/decoder/package-info.java | 0 .../game/io/EquipmentDefinitionParser.java | 0 .../game/io/MessageHandlerChainSetParser.java | 0 .../apollo/game/io/PluginMetaDataParser.java | 0 .../org/apollo/game/io/package-info.java | 0 .../io/player/BinaryPlayerSerializer.java | 0 .../game/io/player/DummyPlayerSerializer.java | 0 .../game/io/player/JdbcPlayerSerializer.java | 0 .../game/io/player/PlayerLoaderResponse.java | 0 .../game/io/player/PlayerSerializer.java | 0 .../apollo/game/io/player/package-info.java | 0 .../apollo/game/login/PlayerLoaderWorker.java | 0 .../apollo/game/login/PlayerSaverWorker.java | 0 .../org/apollo/game/login/package-info.java | 0 .../handler/BankButtonMessageHandler.java | 0 .../message/handler/BankMessageHandler.java | 0 .../ClosedInterfaceMessageHandler.java | 0 .../handler/CommandMessageHandler.java | 0 .../handler/DialogueButtonHandler.java | 0 .../DialogueContinueMessageHandler.java | 0 .../handler/EnteredAmountMessageHandler.java | 0 .../message/handler/EquipItemHandler.java | 0 .../ItemOnItemVerificationHandler.java | 0 .../ItemOnObjectVerificationHandler.java | 0 .../handler/ItemVerificationHandler.java | 0 .../game/message/handler/MessageHandler.java | 0 .../message/handler/MessageHandlerChain.java | 0 .../handler/MessageHandlerChainSet.java | 0 .../handler/NpcActionVerificationHandler.java | 0 .../ObjectActionVerificationHandler.java | 0 .../PlayerActionVerificationHandler.java | 0 .../handler/PlayerDesignMessageHandler.java | 0 .../PlayerDesignVerificationHandler.java | 0 .../handler/PublicChatMessageHandler.java | 0 .../PublicChatVerificationHandler.java | 0 .../handler/RemoveEquippedItemHandler.java | 0 .../handler/SwitchItemMessageHandler.java | 0 .../message/handler/WalkMessageHandler.java | 0 .../game/message/handler/package-info.java | 0 .../game/message/impl/AddFriendMessage.java | 0 .../game/message/impl/AddIgnoreMessage.java | 0 .../game/message/impl/ArrowKeyMessage.java | 0 .../game/message/impl/ButtonMessage.java | 0 .../apollo/game/message/impl/ChatMessage.java | 0 .../game/message/impl/ClearRegionMessage.java | 0 .../message/impl/CloseInterfaceMessage.java | 0 .../message/impl/ClosedInterfaceMessage.java | 0 .../game/message/impl/CommandMessage.java | 0 .../game/message/impl/ConfigMessage.java | 0 .../message/impl/DialogueContinueMessage.java | 0 .../impl/DisplayCrossbonesMessage.java | 0 .../impl/DisplayTabInterfaceMessage.java | 0 .../game/message/impl/EnterAmountMessage.java | 0 .../message/impl/EnteredAmountMessage.java | 0 .../impl/FlaggedMouseEventMessage.java | 0 .../impl/FlashTabInterfaceMessage.java | 0 .../impl/FlashingTabClickedMessage.java | 0 .../game/message/impl/FocusUpdateMessage.java | 0 .../impl/ForwardPrivateChatMessage.java | 0 .../impl/FriendServerStatusMessage.java | 0 .../impl/GroupedRegionUpdateMessage.java | 0 .../game/message/impl/HintIconMessage.java | 0 .../message/impl/IdAssignmentMessage.java | 0 .../game/message/impl/IgnoreListMessage.java | 0 .../message/impl/InventoryItemMessage.java | 0 .../game/message/impl/ItemActionMessage.java | 0 .../game/message/impl/ItemOnItemMessage.java | 0 .../game/message/impl/ItemOnNpcMessage.java | 0 .../message/impl/ItemOnObjectMessage.java | 0 .../game/message/impl/ItemOptionMessage.java | 0 .../game/message/impl/KeepAliveMessage.java | 0 .../game/message/impl/LogoutMessage.java | 0 .../game/message/impl/MagicOnItemMessage.java | 0 .../game/message/impl/MagicOnMobMessage.java | 0 .../game/message/impl/MagicOnNpcMessage.java | 0 .../message/impl/MagicOnPlayerMessage.java | 0 .../impl/MobAnimationResetMessage.java | 0 .../game/message/impl/MobHintIconMessage.java | 0 .../message/impl/MouseClickedMessage.java | 0 .../game/message/impl/NpcActionMessage.java | 0 .../impl/NpcSynchronizationMessage.java | 0 .../message/impl/ObjectActionMessage.java | 0 .../impl/OpenDialogueInterfaceMessage.java | 0 .../impl/OpenDialogueOverlayMessage.java | 0 .../message/impl/OpenInterfaceMessage.java | 0 .../impl/OpenInterfaceSidebarMessage.java | 0 .../game/message/impl/OpenOverlayMessage.java | 0 .../game/message/impl/OpenSidebarMessage.java | 0 .../message/impl/PlayerActionMessage.java | 0 .../message/impl/PlayerDesignMessage.java | 0 .../impl/PlayerSynchronizationMessage.java | 0 .../message/impl/PositionHintIconMessage.java | 0 .../message/impl/PrivacyOptionMessage.java | 0 .../game/message/impl/PrivateChatMessage.java | 0 .../game/message/impl/PublicChatMessage.java | 0 .../message/impl/RegionChangeMessage.java | 0 .../message/impl/RegionUpdateMessage.java | 0 .../message/impl/RemoveFriendMessage.java | 0 .../message/impl/RemoveIgnoreMessage.java | 0 .../message/impl/RemoveObjectMessage.java | 0 .../message/impl/RemoveTileItemMessage.java | 0 .../game/message/impl/ReportAbuseMessage.java | 0 .../game/message/impl/SendFriendMessage.java | 0 .../game/message/impl/SendObjectMessage.java | 0 .../message/impl/SendProjectileMessage.java | 0 .../impl/SendPublicTileItemMessage.java | 0 .../message/impl/SendTileItemMessage.java | 0 .../game/message/impl/ServerChatMessage.java | 0 .../message/impl/SetPlayerActionMessage.java | 0 .../message/impl/SetUpdatedRegionMessage.java | 0 .../impl/SetWidgetItemModelMessage.java | 0 .../impl/SetWidgetModelAnimationMessage.java | 0 .../message/impl/SetWidgetModelMessage.java | 0 .../impl/SetWidgetNpcModelMessage.java | 0 .../impl/SetWidgetPlayerModelMessage.java | 0 .../message/impl/SetWidgetTextMessage.java | 0 .../impl/SetWidgetVisibilityMessage.java | 0 .../game/message/impl/SpamPacketMessage.java | 0 .../game/message/impl/SwitchItemMessage.java | 0 .../impl/SwitchTabInterfaceMessage.java | 0 .../message/impl/TakeTileItemMessage.java | 0 .../game/message/impl/UpdateItemsMessage.java | 0 .../message/impl/UpdateRunEnergyMessage.java | 0 .../game/message/impl/UpdateSkillMessage.java | 0 .../impl/UpdateSlottedItemsMessage.java | 0 .../message/impl/UpdateTileItemMessage.java | 0 .../message/impl/UpdateWeightMessage.java | 0 .../apollo/game/message/impl/WalkMessage.java | 0 .../game/message/impl/package-info.java | 0 .../org/apollo/game/model/Animation.java | 0 .../org/apollo/game/model/Appearance.java | 0 .../org/apollo/game/model/Direction.java | 0 .../org/apollo/game/model/Graphic.java | 0 .../org/apollo/game/model/Item.java | 0 .../org/apollo/game/model/Position.java | 0 .../org/apollo/game/model/World.java | 0 .../org/apollo/game/model/WorldConstants.java | 0 .../game/model/area/EntityUpdateType.java | 0 .../org/apollo/game/model/area/Region.java | 0 .../game/model/area/RegionCoordinates.java | 0 .../game/model/area/RegionListener.java | 0 .../game/model/area/RegionRepository.java | 0 .../model/area/collision/CollisionFlag.java | 0 .../area/collision/CollisionManager.java | 0 .../model/area/collision/CollisionMatrix.java | 0 .../model/area/collision/CollisionUpdate.java | 0 .../collision/CollisionUpdateListener.java | 0 .../area/collision/CollisionUpdateType.java | 0 .../model/area/collision/package-info.java | 0 .../apollo/game/model/area/package-info.java | 0 .../model/area/update/GroupableEntity.java | 0 .../area/update/ItemUpdateOperation.java | 0 .../area/update/ObjectUpdateOperation.java | 0 .../update/ProjectileUpdateOperation.java | 0 .../model/area/update/UpdateOperation.java | 0 .../game/model/area/update/package-info.java | 0 .../org/apollo/game/model/entity/Entity.java | 0 .../apollo/game/model/entity/EntityType.java | 0 .../game/model/entity/EquipmentConstants.java | 0 .../apollo/game/model/entity/GroundItem.java | 0 .../org/apollo/game/model/entity/Mob.java | 0 .../game/model/entity/MobRepository.java | 0 .../org/apollo/game/model/entity/Npc.java | 0 .../org/apollo/game/model/entity/Player.java | 0 .../apollo/game/model/entity/Projectile.java | 0 .../org/apollo/game/model/entity/Skill.java | 0 .../apollo/game/model/entity/SkillSet.java | 0 .../game/model/entity/WalkingQueue.java | 0 .../game/model/entity/attr/Attribute.java | 0 .../entity/attr/AttributeDefinition.java | 0 .../game/model/entity/attr/AttributeMap.java | 0 .../entity/attr/AttributePersistence.java | 0 .../game/model/entity/attr/AttributeType.java | 0 .../model/entity/attr/BooleanAttribute.java | 0 .../model/entity/attr/NumericalAttribute.java | 0 .../model/entity/attr/StringAttribute.java | 0 .../game/model/entity/attr/package-info.java | 0 .../model/entity/obj/DynamicGameObject.java | 0 .../game/model/entity/obj/GameObject.java | 0 .../game/model/entity/obj/ObjectGroup.java | 0 .../game/model/entity/obj/ObjectType.java | 0 .../model/entity/obj/StaticGameObject.java | 0 .../game/model/entity/obj/package-info.java | 0 .../game/model/entity/package-info.java | 0 .../path/AStarPathfindingAlgorithm.java | 0 .../model/entity/path/ChebyshevHeuristic.java | 0 .../model/entity/path/EuclideanHeuristic.java | 0 .../game/model/entity/path/Heuristic.java | 0 .../model/entity/path/ManhattanHeuristic.java | 0 .../apollo/game/model/entity/path/Node.java | 0 .../entity/path/PathfindingAlgorithm.java | 0 .../path/SimplePathfindingAlgorithm.java | 0 .../game/model/entity/path/package-info.java | 0 .../game/model/entity/setting/Gender.java | 0 .../entity/setting/MembershipStatus.java | 0 .../model/entity/setting/PrivacyState.java | 0 .../model/entity/setting/PrivilegeLevel.java | 0 .../entity/setting/ScreenBrightness.java | 0 .../model/entity/setting/ServerStatus.java | 0 .../model/entity/setting/package-info.java | 0 .../org/apollo/game/model/event/Event.java | 0 .../game/model/event/EventListener.java | 0 .../game/model/event/EventListenerChain.java | 0 .../model/event/EventListenerChainSet.java | 0 .../apollo/game/model/event/PlayerEvent.java | 0 .../apollo/game/model/event/ProxyEvent.java | 0 .../game/model/event/ProxyEventListener.java | 0 .../event/impl/CloseInterfacesEvent.java | 0 .../game/model/event/impl/LoginEvent.java | 0 .../game/model/event/impl/LogoutEvent.java | 0 .../event/impl/MobPositionUpdateEvent.java | 0 .../game/model/event/impl/package-info.java | 0 .../apollo/game/model/event/package-info.java | 0 .../game/model/inter/EnterAmountListener.java | 0 .../game/model/inter/InterfaceConstants.java | 0 .../game/model/inter/InterfaceListener.java | 0 .../apollo/game/model/inter/InterfaceSet.java | 0 .../game/model/inter/InterfaceType.java | 0 .../game/model/inter/bank/BankConstants.java | 0 .../bank/BankDepositEnterAmountListener.java | 0 .../inter/bank/BankInterfaceListener.java | 0 .../game/model/inter/bank/BankUtils.java | 0 .../bank/BankWithdrawEnterAmountListener.java | 0 .../game/model/inter/bank/package-info.java | 0 .../model/inter/dialogue/DialogueAdapter.java | 0 .../inter/dialogue/DialogueListener.java | 0 .../model/inter/dialogue/package-info.java | 0 .../apollo/game/model/inter/package-info.java | 0 .../inv/AppearanceInventoryListener.java | 0 .../game/model/inv/FullInventoryListener.java | 0 .../org/apollo/game/model/inv/Inventory.java | 0 .../game/model/inv/InventoryAdapter.java | 0 .../game/model/inv/InventoryConstants.java | 0 .../game/model/inv/InventoryListener.java | 0 .../apollo/game/model/inv/SlottedItem.java | 0 .../inv/SynchronizationInventoryListener.java | 0 .../apollo/game/model/inv/package-info.java | 0 .../org/apollo/game/model/package-info.java | 0 .../model/skill/LevelUpSkillListener.java | 0 .../apollo/game/model/skill/SkillAdapter.java | 0 .../game/model/skill/SkillListener.java | 0 .../skill/SynchronizationSkillListener.java | 0 .../apollo/game/model/skill/package-info.java | 0 .../org/apollo/game/package-info.java | 0 .../game/plugin/DependencyException.java | 0 .../game/plugin/KotlinPluginCompilerStub.java | 9 ++ .../game/plugin/KotlinPluginEnvironment.java | 66 ++++++++ .../org/apollo/game/plugin/PluginContext.java | 0 .../apollo/game/plugin/PluginEnvironment.java | 0 .../org/apollo/game/plugin/PluginManager.java | 13 +- .../apollo/game/plugin/PluginMetaData.java | 0 .../org/apollo/game/plugin/package-info.java | 0 .../release/r317/AddFriendMessageDecoder.java | 0 .../r317/AddGlobalTileItemMessageEncoder.java | 0 .../release/r317/AddIgnoreMessageDecoder.java | 0 .../r317/AddTileItemMessageEncoder.java | 0 .../release/r317/ArrowKeyMessageDecoder.java | 0 .../release/r317/ButtonMessageDecoder.java | 0 .../r317/ClearRegionMessageEncoder.java | 0 .../r317/CloseInterfaceMessageEncoder.java | 0 .../r317/ClosedInterfaceMessageDecoder.java | 0 .../release/r317/CommandMessageDecoder.java | 0 .../release/r317/ConfigMessageEncoder.java | 0 .../r317/DialogueContinueMessageDecoder.java | 0 .../r317/DisplayCrossbonesMessageEncoder.java | 0 .../DisplayTabInterfaceMessageEncoder.java | 0 .../r317/EnterAmountMessageEncoder.java | 0 .../r317/EnteredAmountMessageDecoder.java | 0 .../r317/FifthItemActionMessageDecoder.java | 0 .../r317/FifthItemOptionMessageDecoder.java | 0 .../r317/FifthNpcActionMessageDecoder.java | 0 .../r317/FifthPlayerActionMessageDecoder.java | 0 .../r317/FirstItemActionMessageDecoder.java | 0 .../r317/FirstItemOptionMessageDecoder.java | 0 .../r317/FirstNpcActionMessageDecoder.java | 0 .../r317/FirstObjectActionMessageDecoder.java | 0 .../r317/FirstPlayerActionMessageDecoder.java | 0 .../r317/FlaggedMouseEventMessageDecoder.java | 0 .../r317/FlashTabInterfaceMessageEncoder.java | 0 .../FlashingTabClickedMessageDecoder.java | 0 .../r317/FocusUpdateMessageDecoder.java | 0 .../ForwardPrivateChatMessageEncoder.java | 0 .../r317/FourthItemActionMessageDecoder.java | 0 .../r317/FourthItemOptionMessageDecoder.java | 0 .../r317/FourthNpcActionMessageDecoder.java | 0 .../FourthPlayerActionMessageDecoder.java | 0 .../FriendServerStatusMessageEncoder.java | 0 .../GroupedRegionUpdateMessageEncoder.java | 0 .../r317/IdAssignmentMessageEncoder.java | 0 .../r317/IgnoreListMessageEncoder.java | 0 .../r317/ItemOnItemMessageDecoder.java | 0 .../release/r317/ItemOnNpcMessageDecoder.java | 0 .../r317/ItemOnObjectMessageDecoder.java | 0 .../release/r317/KeepAliveMessageDecoder.java | 0 .../release/r317/LogoutMessageEncoder.java | 0 .../r317/MagicOnItemMessageDecoder.java | 0 .../r317/MagicOnNpcMessageDecoder.java | 0 .../r317/MagicOnPlayerMessageDecoder.java | 0 .../r317/MobAnimationResetMessageEncoder.java | 0 .../r317/MobHintIconMessageEncoder.java | 0 .../r317/MouseClickedMessageDecoder.java | 0 .../NpcSynchronizationMessageEncoder.java | 0 .../OpenDialogueInterfaceMessageEncoder.java | 0 .../OpenDialogueOverlayMessageEncoder.java | 0 .../r317/OpenInterfaceMessageEncoder.java | 0 .../OpenInterfaceSidebarMessageEncoder.java | 0 .../r317/OpenOverlayMessageEncoder.java | 0 .../r317/OpenSidebarMessageEncoder.java | 0 .../r317/PlayerDesignMessageDecoder.java | 0 .../PlayerSynchronizationMessageEncoder.java | 0 .../r317/PositionHintIconMessageEncoder.java | 0 .../r317/PrivacyOptionMessageDecoder.java | 0 .../r317/PrivacyOptionMessageEncoder.java | 0 .../r317/PrivateChatMessageDecoder.java | 0 .../r317/PublicChatMessageDecoder.java | 0 .../r317/RegionChangeMessageEncoder.java | 0 .../apollo/game/release/r317/Release317.java | 0 .../r317/RemoveFriendMessageDecoder.java | 0 .../r317/RemoveIgnoreMessageDecoder.java | 0 .../r317/RemoveObjectMessageEncoder.java | 0 .../r317/RemoveTileItemMessageEncoder.java | 0 .../r317/ReportAbuseMessageDecoder.java | 0 .../r317/SecondItemActionMessageDecoder.java | 0 .../r317/SecondItemOptionMessageDecoder.java | 0 .../r317/SecondNpcActionMessageDecoder.java | 0 .../SecondObjectActionMessageDecoder.java | 0 .../SecondPlayerActionMessageDecoder.java | 0 .../r317/SendFriendMessageEncoder.java | 0 .../r317/SendObjectMessageEncoder.java | 0 .../r317/ServerMessageMessageEncoder.java | 0 .../r317/SetPlayerActionMessageEncoder.java | 0 .../r317/SetUpdatedRegionMessageEncoder.java | 0 .../SetWidgetItemModelMessageEncoder.java | 0 ...SetWidgetModelAnimationMessageEncoder.java | 0 .../r317/SetWidgetModelMessageEncoder.java | 0 .../r317/SetWidgetNpcModelMessageEncoder.java | 0 .../SetWidgetPlayerModelMessageEncoder.java | 0 .../r317/SetWidgetTextMessageEncoder.java | 0 .../SetWidgetVisibilityMessageEncoder.java | 0 .../r317/SpamPacketMessageDecoder.java | 0 .../r317/SwitchItemMessageDecoder.java | 0 .../SwitchTabInterfaceMessageEncoder.java | 0 .../r317/TakeTileItemMessageDecoder.java | 0 .../r317/ThirdItemActionMessageDecoder.java | 0 .../r317/ThirdItemOptionMessageDecoder.java | 0 .../r317/ThirdNpcActionMessageDecoder.java | 0 .../r317/ThirdObjectActionMessageDecoder.java | 0 .../r317/ThirdPlayerActionMessageDecoder.java | 0 .../r317/UpdateItemsMessageEncoder.java | 0 .../r317/UpdateRunEnergyMessageEncoder.java | 0 .../r317/UpdateSkillMessageEncoder.java | 0 .../UpdateSlottedItemsMessageEncoder.java | 0 .../r317/UpdateTileItemMessageEncoder.java | 0 .../r317/UpdateWeightMessageEncoder.java | 0 .../game/release/r317/WalkMessageDecoder.java | 0 .../game/release/r317/package-info.java | 0 .../release/r377/AddFriendMessageDecoder.java | 0 .../r377/AddGlobalTileItemMessageEncoder.java | 0 .../release/r377/AddIgnoreMessageDecoder.java | 0 .../r377/AddTileItemMessageEncoder.java | 0 .../release/r377/ArrowKeyMessageDecoder.java | 0 .../release/r377/ButtonMessageDecoder.java | 0 .../r377/ClearRegionMessageEncoder.java | 0 .../r377/CloseInterfaceMessageEncoder.java | 0 .../r377/ClosedInterfaceMessageDecoder.java | 0 .../release/r377/CommandMessageDecoder.java | 0 .../release/r377/ConfigMessageEncoder.java | 0 .../r377/DialogueContinueMessageDecoder.java | 0 .../r377/DisplayCrossbonesMessageEncoder.java | 0 .../DisplayTabInterfaceMessageEncoder.java | 0 .../r377/EnterAmountMessageEncoder.java | 0 .../r377/EnteredAmountMessageDecoder.java | 0 .../r377/FifthItemActionMessageDecoder.java | 0 .../r377/FifthItemOptionMessageDecoder.java | 0 .../r377/FifthNpcActionMessageDecoder.java | 0 .../r377/FifthPlayerActionMessageDecoder.java | 0 .../r377/FirstItemActionMessageDecoder.java | 0 .../r377/FirstItemOptionMessageDecoder.java | 0 .../r377/FirstNpcActionMessageDecoder.java | 0 .../r377/FirstObjectActionMessageDecoder.java | 0 .../r377/FirstPlayerActionMessageDecoder.java | 0 .../r377/FlaggedMouseEventMessageDecoder.java | 0 .../r377/FlashTabInterfaceMessageEncoder.java | 0 .../FlashingTabClickedMessageDecoder.java | 0 .../r377/FocusUpdateMessageDecoder.java | 0 .../ForwardPrivateChatMessageEncoder.java | 0 .../r377/FourthItemActionMessageDecoder.java | 0 .../r377/FourthItemOptionMessageDecoder.java | 0 .../r377/FourthNpcActionMessageDecoder.java | 0 .../FourthPlayerActionMessageDecoder.java | 0 .../FriendServerStatusMessageEncoder.java | 0 .../GroupedRegionUpdateMessageEncoder.java | 0 .../r377/IdAssignmentMessageEncoder.java | 0 .../r377/IgnoreListMessageEncoder.java | 0 .../r377/ItemOnItemMessageDecoder.java | 0 .../release/r377/ItemOnNpcMessageDecoder.java | 0 .../r377/ItemOnObjectMessageDecoder.java | 0 .../release/r377/KeepAliveMessageDecoder.java | 0 .../release/r377/LogoutMessageEncoder.java | 0 .../r377/MagicOnItemMessageDecoder.java | 0 .../r377/MagicOnNpcMessageDecoder.java | 0 .../r377/MagicOnPlayerMessageDecoder.java | 0 .../r377/MobAnimationResetMessageEncoder.java | 0 .../r377/MobHintIconMessageEncoder.java | 0 .../r377/MouseClickedMessageDecoder.java | 0 .../NpcSynchronizationMessageEncoder.java | 0 .../OpenDialogueInterfaceMessageEncoder.java | 0 .../OpenDialogueOverlayMessageEncoder.java | 0 .../r377/OpenInterfaceMessageEncoder.java | 0 .../OpenInterfaceSidebarMessageEncoder.java | 0 .../r377/OpenOverlayMessageEncoder.java | 0 .../r377/OpenSidebarMessageEncoder.java | 0 .../r377/PlayerDesignMessageDecoder.java | 0 .../PlayerSynchronizationMessageEncoder.java | 0 .../r377/PositionHintIconMessageEncoder.java | 0 .../r377/PrivacyOptionMessageDecoder.java | 0 .../r377/PrivacyOptionMessageEncoder.java | 0 .../r377/PrivateChatMessageDecoder.java | 0 .../r377/PublicChatMessageDecoder.java | 0 .../r377/RegionChangeMessageEncoder.java | 0 .../apollo/game/release/r377/Release377.java | 0 .../r377/RemoveFriendMessageDecoder.java | 0 .../r377/RemoveIgnoreMessageDecoder.java | 0 .../r377/RemoveObjectMessageEncoder.java | 0 .../r377/RemoveTileItemMessageEncoder.java | 0 .../r377/ReportAbuseMessageDecoder.java | 0 .../r377/SecondItemActionMessageDecoder.java | 0 .../r377/SecondItemOptionMessageDecoder.java | 0 .../r377/SecondNpcActionMessageDecoder.java | 0 .../SecondObjectActionMessageDecoder.java | 0 .../SecondPlayerActionMessageDecoder.java | 0 .../r377/SendFriendMessageEncoder.java | 0 .../r377/SendObjectMessageEncoder.java | 0 .../r377/SendProjectileMessageEncoder.java | 0 .../r377/ServerMessageMessageEncoder.java | 0 .../r377/SetPlayerActionMessageEncoder.java | 0 .../r377/SetUpdatedRegionMessageEncoder.java | 0 .../SetWidgetItemModelMessageEncoder.java | 0 ...SetWidgetModelAnimationMessageEncoder.java | 0 .../r377/SetWidgetModelMessageEncoder.java | 0 .../r377/SetWidgetNpcModelMessageEncoder.java | 0 .../SetWidgetPlayerModelMessageEncoder.java | 0 .../r377/SetWidgetTextMessageEncoder.java | 0 .../SetWidgetVisibilityMessageEncoder.java | 0 .../r377/SpamPacketMessageDecoder.java | 0 .../r377/SwitchItemMessageDecoder.java | 0 .../SwitchTabInterfaceMessageEncoder.java | 0 .../r377/TakeTileItemMessageDecoder.java | 0 .../r377/ThirdItemActionMessageDecoder.java | 0 .../r377/ThirdItemOptionMessageDecoder.java | 0 .../r377/ThirdNpcActionMessageDecoder.java | 0 .../r377/ThirdObjectActionMessageDecoder.java | 0 .../r377/ThirdPlayerActionMessageDecoder.java | 0 .../r377/UpdateItemsMessageEncoder.java | 0 .../r377/UpdateRunEnergyMessageEncoder.java | 0 .../r377/UpdateSkillMessageEncoder.java | 0 .../UpdateSlottedItemsMessageEncoder.java | 0 .../r377/UpdateTileItemMessageEncoder.java | 0 .../r377/UpdateWeightMessageEncoder.java | 0 .../game/release/r377/WalkMessageDecoder.java | 0 .../game/release/r377/package-info.java | 0 .../apollo/game/scheduling/ScheduledTask.java | 0 .../org/apollo/game/scheduling/Scheduler.java | 0 .../game/scheduling/impl/NpcMovementTask.java | 0 .../impl/SkillNormalizationTask.java | 0 .../game/scheduling/impl/package-info.java | 0 .../apollo/game/scheduling/package-info.java | 0 .../org/apollo/game/service/GameService.java | 0 .../org/apollo/game/service/LoginService.java | 0 .../apollo/game/service/UpdateService.java | 0 .../org/apollo/game/service/package-info.java | 0 .../apollo/game/session/ApolloHandler.java | 0 .../org/apollo/game/session/GameSession.java | 0 .../org/apollo/game/session/LoginSession.java | 0 .../org/apollo/game/session/Session.java | 0 .../apollo/game/session/UpdateSession.java | 0 .../org/apollo/game/session/package-info.java | 0 .../apollo/game/sync/ClientSynchronizer.java | 0 .../game/sync/ParallelClientSynchronizer.java | 0 .../sync/SequentialClientSynchronizer.java | 0 .../game/sync/block/AnimationBlock.java | 0 .../game/sync/block/AppearanceBlock.java | 0 .../org/apollo/game/sync/block/ChatBlock.java | 0 .../game/sync/block/ForceChatBlock.java | 0 .../game/sync/block/ForceMovementBlock.java | 0 .../apollo/game/sync/block/GraphicBlock.java | 0 .../game/sync/block/HitUpdateBlock.java | 0 .../game/sync/block/InteractingMobBlock.java | 0 .../sync/block/SecondaryHitUpdateBlock.java | 0 .../game/sync/block/SynchronizationBlock.java | 0 .../sync/block/SynchronizationBlockSet.java | 0 .../game/sync/block/TransformBlock.java | 0 .../game/sync/block/TurnToPositionBlock.java | 0 .../apollo/game/sync/block/package-info.java | 0 .../org/apollo/game/sync/package-info.java | 0 .../apollo/game/sync/seg/AddNpcSegment.java | 0 .../game/sync/seg/AddPlayerSegment.java | 0 .../apollo/game/sync/seg/MovementSegment.java | 0 .../game/sync/seg/RemoveMobSegment.java | 0 .../org/apollo/game/sync/seg/SegmentType.java | 0 .../game/sync/seg/SynchronizationSegment.java | 0 .../apollo/game/sync/seg/TeleportSegment.java | 0 .../apollo/game/sync/seg/package-info.java | 0 .../sync/task/NpcSynchronizationTask.java | 0 .../sync/task/PhasedSynchronizationTask.java | 0 .../sync/task/PlayerSynchronizationTask.java | 0 .../sync/task/PostNpcSynchronizationTask.java | 0 .../task/PostPlayerSynchronizationTask.java | 0 .../sync/task/PreNpcSynchronizationTask.java | 0 .../task/PrePlayerSynchronizationTask.java | 0 .../game/sync/task/SynchronizationTask.java | 0 .../apollo/game/sync/task/package-info.java | 0 .../{ => java}/org/apollo/package-info.java | 0 .../plugin/kotlin/KotlinPluginCompiler.kt | 6 +- .../game/plugin/kotlin/KotlinPluginScript.kt | 18 +++ .../game/plugin/KotlinPluginEnvironment.java | 144 ------------------ .../plugins/bank/bank.plugin.kts | 3 +- game/{data => src}/plugins/bank/plugin.xml | 0 .../chat/private-messaging/friends.plugin.kts | 23 +++ .../chat/private-messaging/ignores.plugin.kts | 8 + game/src/plugins/entity/spawn/spawn.kt | 15 ++ .../src/plugins/entity/spawn/spawn.plugin.kts | 27 ++++ .../locations/lumbridge/lumbridge-npcs.kts | 10 ++ game/{data => src}/plugins/stub.kt | 12 +- game/src/plugins/util/lookup/lookup.kt | 17 +++ .../ItemOnItemVerificationHandlerTests.java | 0 .../ItemOnObjectVerificationHandlerTests.java | 0 .../ObjectActionVerificationHandlerTests.java | 0 .../PublicChatMessageHandlerTests.java | 0 .../org/apollo/game/model/PositionTests.java | 0 .../area/collision/CollisionManagerTests.java | 0 .../game/model/entity/MobRepositoryTests.java | 0 .../game/model/entity/SkillSetTests.java | 0 .../model/entity/attr/AttributeTests.java | 0 .../apollo/net/HttpChannelInitializer.java | 0 .../apollo/net/JagGrabChannelInitializer.java | 0 .../org/apollo/net/NetworkConstants.java | 0 .../apollo/net/ServiceChannelInitializer.java | 0 .../org/apollo/net/codec/game/AccessMode.java | 0 .../apollo/net/codec/game/DataConstants.java | 0 .../org/apollo/net/codec/game/DataOrder.java | 0 .../net/codec/game/DataTransformation.java | 0 .../org/apollo/net/codec/game/DataType.java | 0 .../net/codec/game/GameDecoderState.java | 0 .../net/codec/game/GameMessageDecoder.java | 0 .../net/codec/game/GameMessageEncoder.java | 0 .../org/apollo/net/codec/game/GamePacket.java | 0 .../net/codec/game/GamePacketBuilder.java | 0 .../net/codec/game/GamePacketDecoder.java | 0 .../net/codec/game/GamePacketEncoder.java | 0 .../net/codec/game/GamePacketReader.java | 0 .../apollo/net/codec/game/package-info.java | 0 .../codec/handshake/HandshakeConstants.java | 0 .../net/codec/handshake/HandshakeDecoder.java | 0 .../net/codec/handshake/HandshakeMessage.java | 0 .../net/codec/handshake/package-info.java | 0 .../net/codec/jaggrab/JagGrabRequest.java | 0 .../codec/jaggrab/JagGrabRequestDecoder.java | 0 .../net/codec/jaggrab/JagGrabResponse.java | 0 .../codec/jaggrab/JagGrabResponseEncoder.java | 0 .../net/codec/jaggrab/package-info.java | 0 .../net/codec/login/LoginConstants.java | 0 .../apollo/net/codec/login/LoginDecoder.java | 0 .../net/codec/login/LoginDecoderState.java | 0 .../apollo/net/codec/login/LoginEncoder.java | 0 .../apollo/net/codec/login/LoginRequest.java | 0 .../apollo/net/codec/login/LoginResponse.java | 0 .../apollo/net/codec/login/package-info.java | 0 .../net/codec/update/OnDemandRequest.java | 0 .../net/codec/update/OnDemandResponse.java | 0 .../net/codec/update/UpdateDecoder.java | 0 .../net/codec/update/UpdateEncoder.java | 0 .../apollo/net/codec/update/package-info.java | 0 .../org/apollo/net/message/Message.java | 0 .../org/apollo/net/message/package-info.java | 0 .../org/apollo/net/meta/PacketMetaData.java | 0 .../apollo/net/meta/PacketMetaDataGroup.java | 0 .../org/apollo/net/meta/PacketType.java | 0 .../org/apollo/net/meta/package-info.java | 0 .../org/apollo/net/package-info.java | 0 .../apollo/net/release/MessageDecoder.java | 0 .../apollo/net/release/MessageEncoder.java | 0 .../org/apollo/net/release/Release.java | 0 .../org/apollo/net/release/package-info.java | 0 .../org/apollo/net/update/ChannelRequest.java | 0 .../net/update/ComparableChannelRequest.java | 0 .../apollo/net/update/HttpRequestWorker.java | 0 .../net/update/JagGrabRequestWorker.java | 0 .../net/update/OnDemandRequestWorker.java | 0 .../org/apollo/net/update/RequestWorker.java | 0 .../apollo/net/update/UpdateConstants.java | 0 .../apollo/net/update/UpdateDispatcher.java | 0 .../org/apollo/net/update/package-info.java | 0 .../resource/CombinedResourceProvider.java | 0 .../resource/HypertextResourceProvider.java | 0 .../net/update/resource/ResourceProvider.java | 0 .../resource/VirtualResourceProvider.java | 0 .../net/update/resource/package-info.java | 0 .../codec/game/GamePacketEncoderTests.java | 0 .../org/apollo/util/BufferUtil.java | 0 .../org/apollo/util/CollectionUtil.java | 0 .../org/apollo/util/CompressionUtil.java | 0 .../org/apollo/util/LanguageUtil.java | 0 .../{ => java}/org/apollo/util/NameUtil.java | 0 .../{ => java}/org/apollo/util/Point.java | 0 .../org/apollo/util/StatefulFrameDecoder.java | 0 .../org/apollo/util/StreamUtil.java | 0 .../{ => java}/org/apollo/util/TextUtil.java | 0 .../org/apollo/util/ThreadUtil.java | 0 .../org/apollo/util/package-info.java | 0 .../org/apollo/util/security/IsaacRandom.java | 0 .../apollo/util/security/IsaacRandomPair.java | 0 .../util/security/PlayerCredentials.java | 0 .../apollo/util/security/package-info.java | 0 .../apollo/util/tools/EquipmentConstants.java | 0 .../apollo/util/tools/RsaKeyGenerator.java | 0 .../org/apollo/util/tools/package-info.java | 0 .../org/apollo/util/xml/XmlNode.java | 0 .../org/apollo/util/xml/XmlParser.java | 0 .../org/apollo/util/xml/package-info.java | 0 .../org/apollo/util/BufferUtilTests.java | 0 .../org/apollo/util/CollectionUtilTests.java | 0 .../org/apollo/util/CompressionUtilTests.java | 0 .../org/apollo/util/LanguageUtilTests.java | 0 .../org/apollo/util/NameUtilTests.java | 0 .../org/apollo/util/StreamUtilTests.java | 0 .../org/apollo/util/TextUtilTests.java | 0 .../org/apollo/util/ThreadUtilTests.java | 0 .../org/apollo/util/xml/XmlParserTests.java | 0 680 files changed, 225 insertions(+), 171 deletions(-) rename cache/src/main/{ => java}/org/apollo/cache/FileDescriptor.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/FileSystemConstants.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/Index.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/IndexedFileSystem.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/archive/Archive.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/archive/ArchiveEntry.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/archive/package-info.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/decoder/ItemDefinitionDecoder.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/decoder/NpcDefinitionDecoder.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/decoder/ObjectDefinitionDecoder.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/decoder/package-info.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/def/EquipmentDefinition.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/def/ItemDefinition.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/def/NpcDefinition.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/def/ObjectDefinition.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/def/package-info.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapConstants.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapFile.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapFileDecoder.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapIndex.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapIndexDecoder.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapObject.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapObjectsDecoder.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/MapPlane.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/Tile.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/map/TileUtils.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/package-info.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/tools/EquipmentUpdater.java (100%) rename cache/src/main/{ => java}/org/apollo/cache/tools/package-info.java (100%) delete mode 100644 game/data/plugins/dialogue/dialogue.plugin.kts delete mode 100644 game/data/plugins/dialogue/plugin.xml rename game/src/main/{ => java}/org/apollo/Server.java (100%) rename game/src/main/{ => java}/org/apollo/ServerContext.java (100%) rename game/src/main/{ => java}/org/apollo/Service.java (100%) rename game/src/main/{ => java}/org/apollo/ServiceManager.java (100%) rename game/src/main/{ => java}/org/apollo/game/GameConstants.java (100%) rename game/src/main/{ => java}/org/apollo/game/GamePulseHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/action/Action.java (100%) rename game/src/main/{ => java}/org/apollo/game/action/DistancedAction.java (100%) rename game/src/main/{ => java}/org/apollo/game/action/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/command/Command.java (100%) rename game/src/main/{ => java}/org/apollo/game/command/CommandDispatcher.java (100%) rename game/src/main/{ => java}/org/apollo/game/command/CommandListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/command/CreditsCommandListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/command/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/fs/decoder/SynchronousDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/fs/decoder/SynchronousDecoderException.java (100%) rename game/src/main/{ => java}/org/apollo/game/fs/decoder/WorldMapDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/fs/decoder/WorldObjectsDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/fs/decoder/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/EquipmentDefinitionParser.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/MessageHandlerChainSetParser.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/PluginMetaDataParser.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/player/BinaryPlayerSerializer.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/player/DummyPlayerSerializer.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/player/JdbcPlayerSerializer.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/player/PlayerLoaderResponse.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/player/PlayerSerializer.java (100%) rename game/src/main/{ => java}/org/apollo/game/io/player/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/login/PlayerLoaderWorker.java (100%) rename game/src/main/{ => java}/org/apollo/game/login/PlayerSaverWorker.java (100%) rename game/src/main/{ => java}/org/apollo/game/login/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/BankButtonMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/BankMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/ClosedInterfaceMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/CommandMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/DialogueButtonHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/DialogueContinueMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/EnteredAmountMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/EquipItemHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/ItemOnItemVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/ItemOnObjectVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/ItemVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/MessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/MessageHandlerChain.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/MessageHandlerChainSet.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/NpcActionVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/ObjectActionVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/PlayerActionVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/PlayerDesignMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/PlayerDesignVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/PublicChatMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/PublicChatVerificationHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/RemoveEquippedItemHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/SwitchItemMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/WalkMessageHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/handler/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/AddFriendMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/AddIgnoreMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ArrowKeyMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ButtonMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ChatMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ClearRegionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/CloseInterfaceMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ClosedInterfaceMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/CommandMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ConfigMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/DialogueContinueMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/DisplayCrossbonesMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/DisplayTabInterfaceMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/EnterAmountMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/EnteredAmountMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/FlaggedMouseEventMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/FlashTabInterfaceMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/FlashingTabClickedMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/FocusUpdateMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ForwardPrivateChatMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/FriendServerStatusMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/GroupedRegionUpdateMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/HintIconMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/IdAssignmentMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/IgnoreListMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/InventoryItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ItemActionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ItemOnItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ItemOnNpcMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ItemOnObjectMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ItemOptionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/KeepAliveMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/LogoutMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/MagicOnItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/MagicOnMobMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/MagicOnNpcMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/MagicOnPlayerMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/MobAnimationResetMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/MobHintIconMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/MouseClickedMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/NpcActionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/NpcSynchronizationMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ObjectActionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/OpenDialogueInterfaceMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/OpenDialogueOverlayMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/OpenInterfaceMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/OpenInterfaceSidebarMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/OpenOverlayMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/OpenSidebarMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/PlayerActionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/PlayerDesignMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/PlayerSynchronizationMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/PositionHintIconMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/PrivacyOptionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/PrivateChatMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/PublicChatMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/RegionChangeMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/RegionUpdateMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/RemoveFriendMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/RemoveIgnoreMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/RemoveObjectMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/RemoveTileItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ReportAbuseMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SendFriendMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SendObjectMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SendProjectileMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SendPublicTileItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SendTileItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/ServerChatMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetPlayerActionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetUpdatedRegionMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetWidgetItemModelMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetWidgetModelAnimationMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetWidgetModelMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetWidgetNpcModelMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetWidgetPlayerModelMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetWidgetTextMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SetWidgetVisibilityMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SpamPacketMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SwitchItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/SwitchTabInterfaceMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/TakeTileItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/UpdateItemsMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/UpdateRunEnergyMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/UpdateSkillMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/UpdateSlottedItemsMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/UpdateTileItemMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/UpdateWeightMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/WalkMessage.java (100%) rename game/src/main/{ => java}/org/apollo/game/message/impl/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/Animation.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/Appearance.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/Direction.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/Graphic.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/Item.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/Position.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/World.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/WorldConstants.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/EntityUpdateType.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/Region.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/RegionCoordinates.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/RegionListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/RegionRepository.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/collision/CollisionFlag.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/collision/CollisionManager.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/collision/CollisionMatrix.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/collision/CollisionUpdate.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/collision/CollisionUpdateListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/collision/CollisionUpdateType.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/collision/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/update/GroupableEntity.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/update/ItemUpdateOperation.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/update/ObjectUpdateOperation.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/update/ProjectileUpdateOperation.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/update/UpdateOperation.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/area/update/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/Entity.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/EntityType.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/EquipmentConstants.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/GroundItem.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/Mob.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/MobRepository.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/Npc.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/Player.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/Projectile.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/Skill.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/SkillSet.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/WalkingQueue.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/Attribute.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/AttributeDefinition.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/AttributeMap.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/AttributePersistence.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/AttributeType.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/BooleanAttribute.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/NumericalAttribute.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/StringAttribute.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/attr/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/obj/DynamicGameObject.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/obj/GameObject.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/obj/ObjectGroup.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/obj/ObjectType.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/obj/StaticGameObject.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/obj/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/ChebyshevHeuristic.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/EuclideanHeuristic.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/Heuristic.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/ManhattanHeuristic.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/Node.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/PathfindingAlgorithm.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/path/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/setting/Gender.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/setting/MembershipStatus.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/setting/PrivacyState.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/setting/PrivilegeLevel.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/setting/ScreenBrightness.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/setting/ServerStatus.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/entity/setting/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/Event.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/EventListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/EventListenerChain.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/EventListenerChainSet.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/PlayerEvent.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/ProxyEvent.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/ProxyEventListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/impl/CloseInterfacesEvent.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/impl/LoginEvent.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/impl/LogoutEvent.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/impl/MobPositionUpdateEvent.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/impl/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/event/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/EnterAmountListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/InterfaceConstants.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/InterfaceListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/InterfaceSet.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/InterfaceType.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/bank/BankConstants.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/bank/BankDepositEnterAmountListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/bank/BankInterfaceListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/bank/BankUtils.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/bank/BankWithdrawEnterAmountListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/bank/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/dialogue/DialogueAdapter.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/dialogue/DialogueListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/dialogue/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inter/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/AppearanceInventoryListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/FullInventoryListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/Inventory.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/InventoryAdapter.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/InventoryConstants.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/InventoryListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/SlottedItem.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/SynchronizationInventoryListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/inv/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/skill/LevelUpSkillListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/skill/SkillAdapter.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/skill/SkillListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/skill/SynchronizationSkillListener.java (100%) rename game/src/main/{ => java}/org/apollo/game/model/skill/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/plugin/DependencyException.java (100%) create mode 100644 game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java create mode 100644 game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java rename game/src/main/{ => java}/org/apollo/game/plugin/PluginContext.java (100%) rename game/src/main/{ => java}/org/apollo/game/plugin/PluginEnvironment.java (100%) rename game/src/main/{ => java}/org/apollo/game/plugin/PluginManager.java (92%) rename game/src/main/{ => java}/org/apollo/game/plugin/PluginMetaData.java (100%) rename game/src/main/{ => java}/org/apollo/game/plugin/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/AddFriendMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/AddGlobalTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/AddIgnoreMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/AddTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ArrowKeyMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ButtonMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ClearRegionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/CloseInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ClosedInterfaceMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/CommandMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ConfigMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/DialogueContinueMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/DisplayCrossbonesMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/DisplayTabInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/EnterAmountMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/EnteredAmountMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FifthItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FifthItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FifthNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FifthPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FirstItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FirstItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FirstNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FirstObjectActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FirstPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FlaggedMouseEventMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FlashTabInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FlashingTabClickedMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FocusUpdateMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ForwardPrivateChatMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FourthItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FourthItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FourthNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FourthPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/FriendServerStatusMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/IdAssignmentMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/IgnoreListMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ItemOnItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ItemOnNpcMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ItemOnObjectMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/KeepAliveMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/LogoutMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/MagicOnItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/MagicOnNpcMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/MagicOnPlayerMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/MobAnimationResetMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/MobHintIconMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/MouseClickedMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/NpcSynchronizationMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/OpenDialogueInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/OpenDialogueOverlayMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/OpenInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/OpenInterfaceSidebarMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/OpenOverlayMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/OpenSidebarMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/PlayerDesignMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/PlayerSynchronizationMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/PositionHintIconMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/PrivacyOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/PrivacyOptionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/PrivateChatMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/PublicChatMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/RegionChangeMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/Release317.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/RemoveFriendMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/RemoveIgnoreMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/RemoveObjectMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/RemoveTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ReportAbuseMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SecondItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SecondItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SecondNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SecondObjectActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SecondPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SendFriendMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SendObjectMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ServerMessageMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetPlayerActionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetUpdatedRegionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetWidgetItemModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetWidgetModelAnimationMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetWidgetModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetWidgetNpcModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetWidgetPlayerModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetWidgetTextMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SetWidgetVisibilityMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SpamPacketMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SwitchItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/SwitchTabInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/TakeTileItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ThirdItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ThirdItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ThirdNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ThirdObjectActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/ThirdPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/UpdateItemsMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/UpdateRunEnergyMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/UpdateSkillMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/UpdateSlottedItemsMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/UpdateTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/UpdateWeightMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/WalkMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r317/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/AddFriendMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/AddGlobalTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/AddIgnoreMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/AddTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ArrowKeyMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ButtonMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ClearRegionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/CloseInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ClosedInterfaceMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/CommandMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ConfigMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/DialogueContinueMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/DisplayCrossbonesMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/DisplayTabInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/EnterAmountMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/EnteredAmountMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FifthItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FifthItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FifthNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FifthPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FirstItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FirstItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FirstNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FirstObjectActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FirstPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FlaggedMouseEventMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FlashingTabClickedMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FocusUpdateMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ForwardPrivateChatMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FourthItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FourthItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FourthNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FourthPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/FriendServerStatusMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/GroupedRegionUpdateMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/IdAssignmentMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/IgnoreListMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ItemOnItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ItemOnNpcMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ItemOnObjectMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/KeepAliveMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/LogoutMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/MagicOnItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/MagicOnNpcMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/MagicOnPlayerMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/MobAnimationResetMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/MobHintIconMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/MouseClickedMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/NpcSynchronizationMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/OpenDialogueInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/OpenDialogueOverlayMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/OpenInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/OpenInterfaceSidebarMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/OpenOverlayMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/OpenSidebarMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/PlayerDesignMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/PlayerSynchronizationMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/PositionHintIconMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/PrivacyOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/PrivacyOptionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/PrivateChatMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/PublicChatMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/RegionChangeMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/Release377.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/RemoveFriendMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/RemoveIgnoreMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/RemoveObjectMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/RemoveTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ReportAbuseMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SecondItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SecondItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SecondNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SecondObjectActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SecondPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SendFriendMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SendObjectMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SendProjectileMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ServerMessageMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetPlayerActionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetUpdatedRegionMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetWidgetItemModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetWidgetModelAnimationMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetWidgetModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetWidgetNpcModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetWidgetPlayerModelMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetWidgetTextMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SetWidgetVisibilityMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SpamPacketMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SwitchItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/SwitchTabInterfaceMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/TakeTileItemMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ThirdItemActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ThirdItemOptionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ThirdNpcActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ThirdObjectActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/ThirdPlayerActionMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/UpdateItemsMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/UpdateRunEnergyMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/UpdateSkillMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/UpdateSlottedItemsMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/UpdateTileItemMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/UpdateWeightMessageEncoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/WalkMessageDecoder.java (100%) rename game/src/main/{ => java}/org/apollo/game/release/r377/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/scheduling/ScheduledTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/scheduling/Scheduler.java (100%) rename game/src/main/{ => java}/org/apollo/game/scheduling/impl/NpcMovementTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/scheduling/impl/SkillNormalizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/scheduling/impl/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/scheduling/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/service/GameService.java (100%) rename game/src/main/{ => java}/org/apollo/game/service/LoginService.java (100%) rename game/src/main/{ => java}/org/apollo/game/service/UpdateService.java (100%) rename game/src/main/{ => java}/org/apollo/game/service/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/session/ApolloHandler.java (100%) rename game/src/main/{ => java}/org/apollo/game/session/GameSession.java (100%) rename game/src/main/{ => java}/org/apollo/game/session/LoginSession.java (100%) rename game/src/main/{ => java}/org/apollo/game/session/Session.java (100%) rename game/src/main/{ => java}/org/apollo/game/session/UpdateSession.java (100%) rename game/src/main/{ => java}/org/apollo/game/session/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/ClientSynchronizer.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/ParallelClientSynchronizer.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/SequentialClientSynchronizer.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/AnimationBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/AppearanceBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/ChatBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/ForceChatBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/ForceMovementBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/GraphicBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/HitUpdateBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/InteractingMobBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/SecondaryHitUpdateBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/SynchronizationBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/SynchronizationBlockSet.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/TransformBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/TurnToPositionBlock.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/block/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/AddNpcSegment.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/AddPlayerSegment.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/MovementSegment.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/RemoveMobSegment.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/SegmentType.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/SynchronizationSegment.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/TeleportSegment.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/seg/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/NpcSynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/PhasedSynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/PlayerSynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/PostNpcSynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/PostPlayerSynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/PreNpcSynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/PrePlayerSynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/SynchronizationTask.java (100%) rename game/src/main/{ => java}/org/apollo/game/sync/task/package-info.java (100%) rename game/src/main/{ => java}/org/apollo/package-info.java (100%) rename game/src/{ => main}/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt (97%) rename game/src/{ => main}/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt (75%) delete mode 100644 game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java rename game/{data => src}/plugins/bank/bank.plugin.kts (96%) rename game/{data => src}/plugins/bank/plugin.xml (100%) create mode 100644 game/src/plugins/chat/private-messaging/friends.plugin.kts create mode 100644 game/src/plugins/chat/private-messaging/ignores.plugin.kts create mode 100644 game/src/plugins/entity/spawn/spawn.kt create mode 100644 game/src/plugins/entity/spawn/spawn.plugin.kts create mode 100644 game/src/plugins/locations/lumbridge/lumbridge-npcs.kts rename game/{data => src}/plugins/stub.kt (84%) create mode 100644 game/src/plugins/util/lookup/lookup.kt rename game/src/test/{ => java}/org/apollo/game/message/handler/ItemOnItemVerificationHandlerTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/message/handler/ItemOnObjectVerificationHandlerTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/message/handler/ObjectActionVerificationHandlerTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/message/handler/PublicChatMessageHandlerTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/model/PositionTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/model/area/collision/CollisionManagerTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/model/entity/MobRepositoryTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/model/entity/SkillSetTests.java (100%) rename game/src/test/{ => java}/org/apollo/game/model/entity/attr/AttributeTests.java (100%) rename net/src/main/{ => java}/org/apollo/net/HttpChannelInitializer.java (100%) rename net/src/main/{ => java}/org/apollo/net/JagGrabChannelInitializer.java (100%) rename net/src/main/{ => java}/org/apollo/net/NetworkConstants.java (100%) rename net/src/main/{ => java}/org/apollo/net/ServiceChannelInitializer.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/AccessMode.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/DataConstants.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/DataOrder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/DataTransformation.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/DataType.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GameDecoderState.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GameMessageDecoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GameMessageEncoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GamePacket.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GamePacketBuilder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GamePacketDecoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GamePacketEncoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/GamePacketReader.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/game/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/handshake/HandshakeConstants.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/handshake/HandshakeDecoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/handshake/HandshakeMessage.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/handshake/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/jaggrab/JagGrabRequest.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/jaggrab/JagGrabResponse.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/jaggrab/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/login/LoginConstants.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/login/LoginDecoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/login/LoginDecoderState.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/login/LoginEncoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/login/LoginRequest.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/login/LoginResponse.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/login/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/update/OnDemandRequest.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/update/OnDemandResponse.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/update/UpdateDecoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/update/UpdateEncoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/codec/update/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/message/Message.java (100%) rename net/src/main/{ => java}/org/apollo/net/message/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/meta/PacketMetaData.java (100%) rename net/src/main/{ => java}/org/apollo/net/meta/PacketMetaDataGroup.java (100%) rename net/src/main/{ => java}/org/apollo/net/meta/PacketType.java (100%) rename net/src/main/{ => java}/org/apollo/net/meta/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/release/MessageDecoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/release/MessageEncoder.java (100%) rename net/src/main/{ => java}/org/apollo/net/release/Release.java (100%) rename net/src/main/{ => java}/org/apollo/net/release/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/ChannelRequest.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/ComparableChannelRequest.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/HttpRequestWorker.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/JagGrabRequestWorker.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/OnDemandRequestWorker.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/RequestWorker.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/UpdateConstants.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/UpdateDispatcher.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/package-info.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/resource/CombinedResourceProvider.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/resource/HypertextResourceProvider.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/resource/ResourceProvider.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/resource/VirtualResourceProvider.java (100%) rename net/src/main/{ => java}/org/apollo/net/update/resource/package-info.java (100%) rename net/src/test/{ => java}/org/apollo/net/codec/game/GamePacketEncoderTests.java (100%) rename util/src/main/{ => java}/org/apollo/util/BufferUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/CollectionUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/CompressionUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/LanguageUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/NameUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/Point.java (100%) rename util/src/main/{ => java}/org/apollo/util/StatefulFrameDecoder.java (100%) rename util/src/main/{ => java}/org/apollo/util/StreamUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/TextUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/ThreadUtil.java (100%) rename util/src/main/{ => java}/org/apollo/util/package-info.java (100%) rename util/src/main/{ => java}/org/apollo/util/security/IsaacRandom.java (100%) rename util/src/main/{ => java}/org/apollo/util/security/IsaacRandomPair.java (100%) rename util/src/main/{ => java}/org/apollo/util/security/PlayerCredentials.java (100%) rename util/src/main/{ => java}/org/apollo/util/security/package-info.java (100%) rename util/src/main/{ => java}/org/apollo/util/tools/EquipmentConstants.java (100%) rename util/src/main/{ => java}/org/apollo/util/tools/RsaKeyGenerator.java (100%) rename util/src/main/{ => java}/org/apollo/util/tools/package-info.java (100%) rename util/src/main/{ => java}/org/apollo/util/xml/XmlNode.java (100%) rename util/src/main/{ => java}/org/apollo/util/xml/XmlParser.java (100%) rename util/src/main/{ => java}/org/apollo/util/xml/package-info.java (100%) rename util/src/test/{ => java}/org/apollo/util/BufferUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/CollectionUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/CompressionUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/LanguageUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/NameUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/StreamUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/TextUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/ThreadUtilTests.java (100%) rename util/src/test/{ => java}/org/apollo/util/xml/XmlParserTests.java (100%) diff --git a/build.gradle b/build.gradle index a4bdcb9a8..c5dda50ae 100644 --- a/build.gradle +++ b/build.gradle @@ -34,13 +34,13 @@ subprojects { sourceSets { main { java { - srcDirs = ['src/main'] + srcDirs = ['src/main/java'] } } test { java { - srcDirs = ['src/test'] + srcDirs = ['src/test/java'] } } } diff --git a/cache/src/main/org/apollo/cache/FileDescriptor.java b/cache/src/main/java/org/apollo/cache/FileDescriptor.java similarity index 100% rename from cache/src/main/org/apollo/cache/FileDescriptor.java rename to cache/src/main/java/org/apollo/cache/FileDescriptor.java diff --git a/cache/src/main/org/apollo/cache/FileSystemConstants.java b/cache/src/main/java/org/apollo/cache/FileSystemConstants.java similarity index 100% rename from cache/src/main/org/apollo/cache/FileSystemConstants.java rename to cache/src/main/java/org/apollo/cache/FileSystemConstants.java diff --git a/cache/src/main/org/apollo/cache/Index.java b/cache/src/main/java/org/apollo/cache/Index.java similarity index 100% rename from cache/src/main/org/apollo/cache/Index.java rename to cache/src/main/java/org/apollo/cache/Index.java diff --git a/cache/src/main/org/apollo/cache/IndexedFileSystem.java b/cache/src/main/java/org/apollo/cache/IndexedFileSystem.java similarity index 100% rename from cache/src/main/org/apollo/cache/IndexedFileSystem.java rename to cache/src/main/java/org/apollo/cache/IndexedFileSystem.java diff --git a/cache/src/main/org/apollo/cache/archive/Archive.java b/cache/src/main/java/org/apollo/cache/archive/Archive.java similarity index 100% rename from cache/src/main/org/apollo/cache/archive/Archive.java rename to cache/src/main/java/org/apollo/cache/archive/Archive.java diff --git a/cache/src/main/org/apollo/cache/archive/ArchiveEntry.java b/cache/src/main/java/org/apollo/cache/archive/ArchiveEntry.java similarity index 100% rename from cache/src/main/org/apollo/cache/archive/ArchiveEntry.java rename to cache/src/main/java/org/apollo/cache/archive/ArchiveEntry.java diff --git a/cache/src/main/org/apollo/cache/archive/package-info.java b/cache/src/main/java/org/apollo/cache/archive/package-info.java similarity index 100% rename from cache/src/main/org/apollo/cache/archive/package-info.java rename to cache/src/main/java/org/apollo/cache/archive/package-info.java diff --git a/cache/src/main/org/apollo/cache/decoder/ItemDefinitionDecoder.java b/cache/src/main/java/org/apollo/cache/decoder/ItemDefinitionDecoder.java similarity index 100% rename from cache/src/main/org/apollo/cache/decoder/ItemDefinitionDecoder.java rename to cache/src/main/java/org/apollo/cache/decoder/ItemDefinitionDecoder.java diff --git a/cache/src/main/org/apollo/cache/decoder/NpcDefinitionDecoder.java b/cache/src/main/java/org/apollo/cache/decoder/NpcDefinitionDecoder.java similarity index 100% rename from cache/src/main/org/apollo/cache/decoder/NpcDefinitionDecoder.java rename to cache/src/main/java/org/apollo/cache/decoder/NpcDefinitionDecoder.java diff --git a/cache/src/main/org/apollo/cache/decoder/ObjectDefinitionDecoder.java b/cache/src/main/java/org/apollo/cache/decoder/ObjectDefinitionDecoder.java similarity index 100% rename from cache/src/main/org/apollo/cache/decoder/ObjectDefinitionDecoder.java rename to cache/src/main/java/org/apollo/cache/decoder/ObjectDefinitionDecoder.java diff --git a/cache/src/main/org/apollo/cache/decoder/package-info.java b/cache/src/main/java/org/apollo/cache/decoder/package-info.java similarity index 100% rename from cache/src/main/org/apollo/cache/decoder/package-info.java rename to cache/src/main/java/org/apollo/cache/decoder/package-info.java diff --git a/cache/src/main/org/apollo/cache/def/EquipmentDefinition.java b/cache/src/main/java/org/apollo/cache/def/EquipmentDefinition.java similarity index 100% rename from cache/src/main/org/apollo/cache/def/EquipmentDefinition.java rename to cache/src/main/java/org/apollo/cache/def/EquipmentDefinition.java diff --git a/cache/src/main/org/apollo/cache/def/ItemDefinition.java b/cache/src/main/java/org/apollo/cache/def/ItemDefinition.java similarity index 100% rename from cache/src/main/org/apollo/cache/def/ItemDefinition.java rename to cache/src/main/java/org/apollo/cache/def/ItemDefinition.java diff --git a/cache/src/main/org/apollo/cache/def/NpcDefinition.java b/cache/src/main/java/org/apollo/cache/def/NpcDefinition.java similarity index 100% rename from cache/src/main/org/apollo/cache/def/NpcDefinition.java rename to cache/src/main/java/org/apollo/cache/def/NpcDefinition.java diff --git a/cache/src/main/org/apollo/cache/def/ObjectDefinition.java b/cache/src/main/java/org/apollo/cache/def/ObjectDefinition.java similarity index 100% rename from cache/src/main/org/apollo/cache/def/ObjectDefinition.java rename to cache/src/main/java/org/apollo/cache/def/ObjectDefinition.java diff --git a/cache/src/main/org/apollo/cache/def/package-info.java b/cache/src/main/java/org/apollo/cache/def/package-info.java similarity index 100% rename from cache/src/main/org/apollo/cache/def/package-info.java rename to cache/src/main/java/org/apollo/cache/def/package-info.java diff --git a/cache/src/main/org/apollo/cache/map/MapConstants.java b/cache/src/main/java/org/apollo/cache/map/MapConstants.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapConstants.java rename to cache/src/main/java/org/apollo/cache/map/MapConstants.java diff --git a/cache/src/main/org/apollo/cache/map/MapFile.java b/cache/src/main/java/org/apollo/cache/map/MapFile.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapFile.java rename to cache/src/main/java/org/apollo/cache/map/MapFile.java diff --git a/cache/src/main/org/apollo/cache/map/MapFileDecoder.java b/cache/src/main/java/org/apollo/cache/map/MapFileDecoder.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapFileDecoder.java rename to cache/src/main/java/org/apollo/cache/map/MapFileDecoder.java diff --git a/cache/src/main/org/apollo/cache/map/MapIndex.java b/cache/src/main/java/org/apollo/cache/map/MapIndex.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapIndex.java rename to cache/src/main/java/org/apollo/cache/map/MapIndex.java diff --git a/cache/src/main/org/apollo/cache/map/MapIndexDecoder.java b/cache/src/main/java/org/apollo/cache/map/MapIndexDecoder.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapIndexDecoder.java rename to cache/src/main/java/org/apollo/cache/map/MapIndexDecoder.java diff --git a/cache/src/main/org/apollo/cache/map/MapObject.java b/cache/src/main/java/org/apollo/cache/map/MapObject.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapObject.java rename to cache/src/main/java/org/apollo/cache/map/MapObject.java diff --git a/cache/src/main/org/apollo/cache/map/MapObjectsDecoder.java b/cache/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapObjectsDecoder.java rename to cache/src/main/java/org/apollo/cache/map/MapObjectsDecoder.java diff --git a/cache/src/main/org/apollo/cache/map/MapPlane.java b/cache/src/main/java/org/apollo/cache/map/MapPlane.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/MapPlane.java rename to cache/src/main/java/org/apollo/cache/map/MapPlane.java diff --git a/cache/src/main/org/apollo/cache/map/Tile.java b/cache/src/main/java/org/apollo/cache/map/Tile.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/Tile.java rename to cache/src/main/java/org/apollo/cache/map/Tile.java diff --git a/cache/src/main/org/apollo/cache/map/TileUtils.java b/cache/src/main/java/org/apollo/cache/map/TileUtils.java similarity index 100% rename from cache/src/main/org/apollo/cache/map/TileUtils.java rename to cache/src/main/java/org/apollo/cache/map/TileUtils.java diff --git a/cache/src/main/org/apollo/cache/package-info.java b/cache/src/main/java/org/apollo/cache/package-info.java similarity index 100% rename from cache/src/main/org/apollo/cache/package-info.java rename to cache/src/main/java/org/apollo/cache/package-info.java diff --git a/cache/src/main/org/apollo/cache/tools/EquipmentUpdater.java b/cache/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java similarity index 100% rename from cache/src/main/org/apollo/cache/tools/EquipmentUpdater.java rename to cache/src/main/java/org/apollo/cache/tools/EquipmentUpdater.java diff --git a/cache/src/main/org/apollo/cache/tools/package-info.java b/cache/src/main/java/org/apollo/cache/tools/package-info.java similarity index 100% rename from cache/src/main/org/apollo/cache/tools/package-info.java rename to cache/src/main/java/org/apollo/cache/tools/package-info.java diff --git a/game/build.gradle b/game/build.gradle index 92df95e84..bcce47908 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -12,14 +12,12 @@ buildscript { apply plugin: 'kotlin' -sourceSets { - main.kotlin.srcDirs += 'src/kotlin' - main.kotlin.excludes += 'stub.kt' - main.kotlin.excludes += '**/*.kts' +ext.pluginsDir = "$projectDir/src/plugins" +sourceSets { plugins { kotlin { - srcDir 'data/plugins' + srcDir "$pluginsDir" exclude 'stub.kt' exclude '**/*.kts' } @@ -42,7 +40,10 @@ dependencies { } -task('compilePluginScripts', dependsOn: [classes, pluginsClasses], type: JavaExec) { +task compilePluginScripts(type: JavaExec, dependsOn: [classes, pluginsClasses]) { + group = LifecycleBasePlugin.BUILD_GROUP + description = 'Compile plugin script files (.plugin.kts) to java bytecode' + def compilerClasspath = [ configurations.compile.asPath, configurations.runtime.asPath, @@ -50,17 +51,15 @@ task('compilePluginScripts', dependsOn: [classes, pluginsClasses], type: JavaExe sourceSets.main.runtimeClasspath.asPath ] - def inputDir = "$projectDir/data/plugins" def outputDir = "$buildDir/plugins" def manifestPath = "$buildDir/plugins/manifest.txt" - inputs.source inputDir + inputs.source "$pluginsDir" outputs.dir outputDir - println compilerClasspath.join(':') classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath main = 'org.apollo.game.plugin.kotlin.KotlinPluginCompiler' - args = [inputDir, outputDir, manifestPath, compilerClasspath.join(':')] + args = ["$pluginsDir", outputDir, manifestPath, compilerClasspath.join(':')] } -assemble.dependsOn(compilePluginScripts) \ No newline at end of file +assemble.dependsOn compilePluginScripts \ No newline at end of file diff --git a/game/data/plugins/dialogue/dialogue.plugin.kts b/game/data/plugins/dialogue/dialogue.plugin.kts deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/data/plugins/dialogue/plugin.xml b/game/data/plugins/dialogue/plugin.xml deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/src/main/org/apollo/Server.java b/game/src/main/java/org/apollo/Server.java similarity index 100% rename from game/src/main/org/apollo/Server.java rename to game/src/main/java/org/apollo/Server.java diff --git a/game/src/main/org/apollo/ServerContext.java b/game/src/main/java/org/apollo/ServerContext.java similarity index 100% rename from game/src/main/org/apollo/ServerContext.java rename to game/src/main/java/org/apollo/ServerContext.java diff --git a/game/src/main/org/apollo/Service.java b/game/src/main/java/org/apollo/Service.java similarity index 100% rename from game/src/main/org/apollo/Service.java rename to game/src/main/java/org/apollo/Service.java diff --git a/game/src/main/org/apollo/ServiceManager.java b/game/src/main/java/org/apollo/ServiceManager.java similarity index 100% rename from game/src/main/org/apollo/ServiceManager.java rename to game/src/main/java/org/apollo/ServiceManager.java diff --git a/game/src/main/org/apollo/game/GameConstants.java b/game/src/main/java/org/apollo/game/GameConstants.java similarity index 100% rename from game/src/main/org/apollo/game/GameConstants.java rename to game/src/main/java/org/apollo/game/GameConstants.java diff --git a/game/src/main/org/apollo/game/GamePulseHandler.java b/game/src/main/java/org/apollo/game/GamePulseHandler.java similarity index 100% rename from game/src/main/org/apollo/game/GamePulseHandler.java rename to game/src/main/java/org/apollo/game/GamePulseHandler.java diff --git a/game/src/main/org/apollo/game/action/Action.java b/game/src/main/java/org/apollo/game/action/Action.java similarity index 100% rename from game/src/main/org/apollo/game/action/Action.java rename to game/src/main/java/org/apollo/game/action/Action.java diff --git a/game/src/main/org/apollo/game/action/DistancedAction.java b/game/src/main/java/org/apollo/game/action/DistancedAction.java similarity index 100% rename from game/src/main/org/apollo/game/action/DistancedAction.java rename to game/src/main/java/org/apollo/game/action/DistancedAction.java diff --git a/game/src/main/org/apollo/game/action/package-info.java b/game/src/main/java/org/apollo/game/action/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/action/package-info.java rename to game/src/main/java/org/apollo/game/action/package-info.java diff --git a/game/src/main/org/apollo/game/command/Command.java b/game/src/main/java/org/apollo/game/command/Command.java similarity index 100% rename from game/src/main/org/apollo/game/command/Command.java rename to game/src/main/java/org/apollo/game/command/Command.java diff --git a/game/src/main/org/apollo/game/command/CommandDispatcher.java b/game/src/main/java/org/apollo/game/command/CommandDispatcher.java similarity index 100% rename from game/src/main/org/apollo/game/command/CommandDispatcher.java rename to game/src/main/java/org/apollo/game/command/CommandDispatcher.java diff --git a/game/src/main/org/apollo/game/command/CommandListener.java b/game/src/main/java/org/apollo/game/command/CommandListener.java similarity index 100% rename from game/src/main/org/apollo/game/command/CommandListener.java rename to game/src/main/java/org/apollo/game/command/CommandListener.java diff --git a/game/src/main/org/apollo/game/command/CreditsCommandListener.java b/game/src/main/java/org/apollo/game/command/CreditsCommandListener.java similarity index 100% rename from game/src/main/org/apollo/game/command/CreditsCommandListener.java rename to game/src/main/java/org/apollo/game/command/CreditsCommandListener.java diff --git a/game/src/main/org/apollo/game/command/package-info.java b/game/src/main/java/org/apollo/game/command/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/command/package-info.java rename to game/src/main/java/org/apollo/game/command/package-info.java diff --git a/game/src/main/org/apollo/game/fs/decoder/SynchronousDecoder.java b/game/src/main/java/org/apollo/game/fs/decoder/SynchronousDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/fs/decoder/SynchronousDecoder.java rename to game/src/main/java/org/apollo/game/fs/decoder/SynchronousDecoder.java diff --git a/game/src/main/org/apollo/game/fs/decoder/SynchronousDecoderException.java b/game/src/main/java/org/apollo/game/fs/decoder/SynchronousDecoderException.java similarity index 100% rename from game/src/main/org/apollo/game/fs/decoder/SynchronousDecoderException.java rename to game/src/main/java/org/apollo/game/fs/decoder/SynchronousDecoderException.java diff --git a/game/src/main/org/apollo/game/fs/decoder/WorldMapDecoder.java b/game/src/main/java/org/apollo/game/fs/decoder/WorldMapDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/fs/decoder/WorldMapDecoder.java rename to game/src/main/java/org/apollo/game/fs/decoder/WorldMapDecoder.java diff --git a/game/src/main/org/apollo/game/fs/decoder/WorldObjectsDecoder.java b/game/src/main/java/org/apollo/game/fs/decoder/WorldObjectsDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/fs/decoder/WorldObjectsDecoder.java rename to game/src/main/java/org/apollo/game/fs/decoder/WorldObjectsDecoder.java diff --git a/game/src/main/org/apollo/game/fs/decoder/package-info.java b/game/src/main/java/org/apollo/game/fs/decoder/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/fs/decoder/package-info.java rename to game/src/main/java/org/apollo/game/fs/decoder/package-info.java diff --git a/game/src/main/org/apollo/game/io/EquipmentDefinitionParser.java b/game/src/main/java/org/apollo/game/io/EquipmentDefinitionParser.java similarity index 100% rename from game/src/main/org/apollo/game/io/EquipmentDefinitionParser.java rename to game/src/main/java/org/apollo/game/io/EquipmentDefinitionParser.java diff --git a/game/src/main/org/apollo/game/io/MessageHandlerChainSetParser.java b/game/src/main/java/org/apollo/game/io/MessageHandlerChainSetParser.java similarity index 100% rename from game/src/main/org/apollo/game/io/MessageHandlerChainSetParser.java rename to game/src/main/java/org/apollo/game/io/MessageHandlerChainSetParser.java diff --git a/game/src/main/org/apollo/game/io/PluginMetaDataParser.java b/game/src/main/java/org/apollo/game/io/PluginMetaDataParser.java similarity index 100% rename from game/src/main/org/apollo/game/io/PluginMetaDataParser.java rename to game/src/main/java/org/apollo/game/io/PluginMetaDataParser.java diff --git a/game/src/main/org/apollo/game/io/package-info.java b/game/src/main/java/org/apollo/game/io/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/io/package-info.java rename to game/src/main/java/org/apollo/game/io/package-info.java diff --git a/game/src/main/org/apollo/game/io/player/BinaryPlayerSerializer.java b/game/src/main/java/org/apollo/game/io/player/BinaryPlayerSerializer.java similarity index 100% rename from game/src/main/org/apollo/game/io/player/BinaryPlayerSerializer.java rename to game/src/main/java/org/apollo/game/io/player/BinaryPlayerSerializer.java diff --git a/game/src/main/org/apollo/game/io/player/DummyPlayerSerializer.java b/game/src/main/java/org/apollo/game/io/player/DummyPlayerSerializer.java similarity index 100% rename from game/src/main/org/apollo/game/io/player/DummyPlayerSerializer.java rename to game/src/main/java/org/apollo/game/io/player/DummyPlayerSerializer.java diff --git a/game/src/main/org/apollo/game/io/player/JdbcPlayerSerializer.java b/game/src/main/java/org/apollo/game/io/player/JdbcPlayerSerializer.java similarity index 100% rename from game/src/main/org/apollo/game/io/player/JdbcPlayerSerializer.java rename to game/src/main/java/org/apollo/game/io/player/JdbcPlayerSerializer.java diff --git a/game/src/main/org/apollo/game/io/player/PlayerLoaderResponse.java b/game/src/main/java/org/apollo/game/io/player/PlayerLoaderResponse.java similarity index 100% rename from game/src/main/org/apollo/game/io/player/PlayerLoaderResponse.java rename to game/src/main/java/org/apollo/game/io/player/PlayerLoaderResponse.java diff --git a/game/src/main/org/apollo/game/io/player/PlayerSerializer.java b/game/src/main/java/org/apollo/game/io/player/PlayerSerializer.java similarity index 100% rename from game/src/main/org/apollo/game/io/player/PlayerSerializer.java rename to game/src/main/java/org/apollo/game/io/player/PlayerSerializer.java diff --git a/game/src/main/org/apollo/game/io/player/package-info.java b/game/src/main/java/org/apollo/game/io/player/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/io/player/package-info.java rename to game/src/main/java/org/apollo/game/io/player/package-info.java diff --git a/game/src/main/org/apollo/game/login/PlayerLoaderWorker.java b/game/src/main/java/org/apollo/game/login/PlayerLoaderWorker.java similarity index 100% rename from game/src/main/org/apollo/game/login/PlayerLoaderWorker.java rename to game/src/main/java/org/apollo/game/login/PlayerLoaderWorker.java diff --git a/game/src/main/org/apollo/game/login/PlayerSaverWorker.java b/game/src/main/java/org/apollo/game/login/PlayerSaverWorker.java similarity index 100% rename from game/src/main/org/apollo/game/login/PlayerSaverWorker.java rename to game/src/main/java/org/apollo/game/login/PlayerSaverWorker.java diff --git a/game/src/main/org/apollo/game/login/package-info.java b/game/src/main/java/org/apollo/game/login/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/login/package-info.java rename to game/src/main/java/org/apollo/game/login/package-info.java diff --git a/game/src/main/org/apollo/game/message/handler/BankButtonMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/BankButtonMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/BankButtonMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/BankButtonMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/BankMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/BankMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/BankMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/BankMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/ClosedInterfaceMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/ClosedInterfaceMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/ClosedInterfaceMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/ClosedInterfaceMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/CommandMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/CommandMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/CommandMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/CommandMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/DialogueButtonHandler.java b/game/src/main/java/org/apollo/game/message/handler/DialogueButtonHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/DialogueButtonHandler.java rename to game/src/main/java/org/apollo/game/message/handler/DialogueButtonHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/DialogueContinueMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/DialogueContinueMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/DialogueContinueMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/DialogueContinueMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/EnteredAmountMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/EnteredAmountMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/EnteredAmountMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/EnteredAmountMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/EquipItemHandler.java b/game/src/main/java/org/apollo/game/message/handler/EquipItemHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/EquipItemHandler.java rename to game/src/main/java/org/apollo/game/message/handler/EquipItemHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/ItemOnItemVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/ItemOnItemVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/ItemOnItemVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/ItemOnItemVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/ItemOnObjectVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/ItemOnObjectVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/ItemOnObjectVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/ItemOnObjectVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/ItemVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/ItemVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/ItemVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/ItemVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/MessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/MessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/MessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/MessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/MessageHandlerChain.java b/game/src/main/java/org/apollo/game/message/handler/MessageHandlerChain.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/MessageHandlerChain.java rename to game/src/main/java/org/apollo/game/message/handler/MessageHandlerChain.java diff --git a/game/src/main/org/apollo/game/message/handler/MessageHandlerChainSet.java b/game/src/main/java/org/apollo/game/message/handler/MessageHandlerChainSet.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/MessageHandlerChainSet.java rename to game/src/main/java/org/apollo/game/message/handler/MessageHandlerChainSet.java diff --git a/game/src/main/org/apollo/game/message/handler/NpcActionVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/NpcActionVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/NpcActionVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/NpcActionVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/ObjectActionVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/ObjectActionVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/ObjectActionVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/ObjectActionVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/PlayerActionVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/PlayerActionVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/PlayerActionVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/PlayerActionVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/PlayerDesignMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/PlayerDesignMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/PlayerDesignMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/PlayerDesignMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/PlayerDesignVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/PlayerDesignVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/PlayerDesignVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/PlayerDesignVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/PublicChatMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/PublicChatMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/PublicChatMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/PublicChatMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/PublicChatVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/PublicChatVerificationHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/PublicChatVerificationHandler.java rename to game/src/main/java/org/apollo/game/message/handler/PublicChatVerificationHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/RemoveEquippedItemHandler.java b/game/src/main/java/org/apollo/game/message/handler/RemoveEquippedItemHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/RemoveEquippedItemHandler.java rename to game/src/main/java/org/apollo/game/message/handler/RemoveEquippedItemHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/SwitchItemMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/SwitchItemMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/SwitchItemMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/SwitchItemMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/WalkMessageHandler.java b/game/src/main/java/org/apollo/game/message/handler/WalkMessageHandler.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/WalkMessageHandler.java rename to game/src/main/java/org/apollo/game/message/handler/WalkMessageHandler.java diff --git a/game/src/main/org/apollo/game/message/handler/package-info.java b/game/src/main/java/org/apollo/game/message/handler/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/message/handler/package-info.java rename to game/src/main/java/org/apollo/game/message/handler/package-info.java diff --git a/game/src/main/org/apollo/game/message/impl/AddFriendMessage.java b/game/src/main/java/org/apollo/game/message/impl/AddFriendMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/AddFriendMessage.java rename to game/src/main/java/org/apollo/game/message/impl/AddFriendMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/AddIgnoreMessage.java b/game/src/main/java/org/apollo/game/message/impl/AddIgnoreMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/AddIgnoreMessage.java rename to game/src/main/java/org/apollo/game/message/impl/AddIgnoreMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ArrowKeyMessage.java b/game/src/main/java/org/apollo/game/message/impl/ArrowKeyMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ArrowKeyMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ArrowKeyMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ButtonMessage.java b/game/src/main/java/org/apollo/game/message/impl/ButtonMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ButtonMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ButtonMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ChatMessage.java b/game/src/main/java/org/apollo/game/message/impl/ChatMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ChatMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ChatMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ClearRegionMessage.java b/game/src/main/java/org/apollo/game/message/impl/ClearRegionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ClearRegionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ClearRegionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/CloseInterfaceMessage.java b/game/src/main/java/org/apollo/game/message/impl/CloseInterfaceMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/CloseInterfaceMessage.java rename to game/src/main/java/org/apollo/game/message/impl/CloseInterfaceMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ClosedInterfaceMessage.java b/game/src/main/java/org/apollo/game/message/impl/ClosedInterfaceMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ClosedInterfaceMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ClosedInterfaceMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/CommandMessage.java b/game/src/main/java/org/apollo/game/message/impl/CommandMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/CommandMessage.java rename to game/src/main/java/org/apollo/game/message/impl/CommandMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ConfigMessage.java b/game/src/main/java/org/apollo/game/message/impl/ConfigMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ConfigMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ConfigMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/DialogueContinueMessage.java b/game/src/main/java/org/apollo/game/message/impl/DialogueContinueMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/DialogueContinueMessage.java rename to game/src/main/java/org/apollo/game/message/impl/DialogueContinueMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/DisplayCrossbonesMessage.java b/game/src/main/java/org/apollo/game/message/impl/DisplayCrossbonesMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/DisplayCrossbonesMessage.java rename to game/src/main/java/org/apollo/game/message/impl/DisplayCrossbonesMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/DisplayTabInterfaceMessage.java b/game/src/main/java/org/apollo/game/message/impl/DisplayTabInterfaceMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/DisplayTabInterfaceMessage.java rename to game/src/main/java/org/apollo/game/message/impl/DisplayTabInterfaceMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/EnterAmountMessage.java b/game/src/main/java/org/apollo/game/message/impl/EnterAmountMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/EnterAmountMessage.java rename to game/src/main/java/org/apollo/game/message/impl/EnterAmountMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/EnteredAmountMessage.java b/game/src/main/java/org/apollo/game/message/impl/EnteredAmountMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/EnteredAmountMessage.java rename to game/src/main/java/org/apollo/game/message/impl/EnteredAmountMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/FlaggedMouseEventMessage.java b/game/src/main/java/org/apollo/game/message/impl/FlaggedMouseEventMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/FlaggedMouseEventMessage.java rename to game/src/main/java/org/apollo/game/message/impl/FlaggedMouseEventMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/FlashTabInterfaceMessage.java b/game/src/main/java/org/apollo/game/message/impl/FlashTabInterfaceMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/FlashTabInterfaceMessage.java rename to game/src/main/java/org/apollo/game/message/impl/FlashTabInterfaceMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/FlashingTabClickedMessage.java b/game/src/main/java/org/apollo/game/message/impl/FlashingTabClickedMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/FlashingTabClickedMessage.java rename to game/src/main/java/org/apollo/game/message/impl/FlashingTabClickedMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/FocusUpdateMessage.java b/game/src/main/java/org/apollo/game/message/impl/FocusUpdateMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/FocusUpdateMessage.java rename to game/src/main/java/org/apollo/game/message/impl/FocusUpdateMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ForwardPrivateChatMessage.java b/game/src/main/java/org/apollo/game/message/impl/ForwardPrivateChatMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ForwardPrivateChatMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ForwardPrivateChatMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/FriendServerStatusMessage.java b/game/src/main/java/org/apollo/game/message/impl/FriendServerStatusMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/FriendServerStatusMessage.java rename to game/src/main/java/org/apollo/game/message/impl/FriendServerStatusMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/GroupedRegionUpdateMessage.java b/game/src/main/java/org/apollo/game/message/impl/GroupedRegionUpdateMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/GroupedRegionUpdateMessage.java rename to game/src/main/java/org/apollo/game/message/impl/GroupedRegionUpdateMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/HintIconMessage.java b/game/src/main/java/org/apollo/game/message/impl/HintIconMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/HintIconMessage.java rename to game/src/main/java/org/apollo/game/message/impl/HintIconMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/IdAssignmentMessage.java b/game/src/main/java/org/apollo/game/message/impl/IdAssignmentMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/IdAssignmentMessage.java rename to game/src/main/java/org/apollo/game/message/impl/IdAssignmentMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/IgnoreListMessage.java b/game/src/main/java/org/apollo/game/message/impl/IgnoreListMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/IgnoreListMessage.java rename to game/src/main/java/org/apollo/game/message/impl/IgnoreListMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/InventoryItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/InventoryItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/InventoryItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/InventoryItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ItemActionMessage.java b/game/src/main/java/org/apollo/game/message/impl/ItemActionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ItemActionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ItemActionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ItemOnItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/ItemOnItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ItemOnItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ItemOnItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ItemOnNpcMessage.java b/game/src/main/java/org/apollo/game/message/impl/ItemOnNpcMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ItemOnNpcMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ItemOnNpcMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ItemOnObjectMessage.java b/game/src/main/java/org/apollo/game/message/impl/ItemOnObjectMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ItemOnObjectMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ItemOnObjectMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ItemOptionMessage.java b/game/src/main/java/org/apollo/game/message/impl/ItemOptionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ItemOptionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ItemOptionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/KeepAliveMessage.java b/game/src/main/java/org/apollo/game/message/impl/KeepAliveMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/KeepAliveMessage.java rename to game/src/main/java/org/apollo/game/message/impl/KeepAliveMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/LogoutMessage.java b/game/src/main/java/org/apollo/game/message/impl/LogoutMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/LogoutMessage.java rename to game/src/main/java/org/apollo/game/message/impl/LogoutMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/MagicOnItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/MagicOnItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/MagicOnItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/MagicOnItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/MagicOnMobMessage.java b/game/src/main/java/org/apollo/game/message/impl/MagicOnMobMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/MagicOnMobMessage.java rename to game/src/main/java/org/apollo/game/message/impl/MagicOnMobMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/MagicOnNpcMessage.java b/game/src/main/java/org/apollo/game/message/impl/MagicOnNpcMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/MagicOnNpcMessage.java rename to game/src/main/java/org/apollo/game/message/impl/MagicOnNpcMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/MagicOnPlayerMessage.java b/game/src/main/java/org/apollo/game/message/impl/MagicOnPlayerMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/MagicOnPlayerMessage.java rename to game/src/main/java/org/apollo/game/message/impl/MagicOnPlayerMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/MobAnimationResetMessage.java b/game/src/main/java/org/apollo/game/message/impl/MobAnimationResetMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/MobAnimationResetMessage.java rename to game/src/main/java/org/apollo/game/message/impl/MobAnimationResetMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/MobHintIconMessage.java b/game/src/main/java/org/apollo/game/message/impl/MobHintIconMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/MobHintIconMessage.java rename to game/src/main/java/org/apollo/game/message/impl/MobHintIconMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/MouseClickedMessage.java b/game/src/main/java/org/apollo/game/message/impl/MouseClickedMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/MouseClickedMessage.java rename to game/src/main/java/org/apollo/game/message/impl/MouseClickedMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/NpcActionMessage.java b/game/src/main/java/org/apollo/game/message/impl/NpcActionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/NpcActionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/NpcActionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/NpcSynchronizationMessage.java b/game/src/main/java/org/apollo/game/message/impl/NpcSynchronizationMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/NpcSynchronizationMessage.java rename to game/src/main/java/org/apollo/game/message/impl/NpcSynchronizationMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ObjectActionMessage.java b/game/src/main/java/org/apollo/game/message/impl/ObjectActionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ObjectActionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ObjectActionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/OpenDialogueInterfaceMessage.java b/game/src/main/java/org/apollo/game/message/impl/OpenDialogueInterfaceMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/OpenDialogueInterfaceMessage.java rename to game/src/main/java/org/apollo/game/message/impl/OpenDialogueInterfaceMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/OpenDialogueOverlayMessage.java b/game/src/main/java/org/apollo/game/message/impl/OpenDialogueOverlayMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/OpenDialogueOverlayMessage.java rename to game/src/main/java/org/apollo/game/message/impl/OpenDialogueOverlayMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/OpenInterfaceMessage.java b/game/src/main/java/org/apollo/game/message/impl/OpenInterfaceMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/OpenInterfaceMessage.java rename to game/src/main/java/org/apollo/game/message/impl/OpenInterfaceMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/OpenInterfaceSidebarMessage.java b/game/src/main/java/org/apollo/game/message/impl/OpenInterfaceSidebarMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/OpenInterfaceSidebarMessage.java rename to game/src/main/java/org/apollo/game/message/impl/OpenInterfaceSidebarMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/OpenOverlayMessage.java b/game/src/main/java/org/apollo/game/message/impl/OpenOverlayMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/OpenOverlayMessage.java rename to game/src/main/java/org/apollo/game/message/impl/OpenOverlayMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/OpenSidebarMessage.java b/game/src/main/java/org/apollo/game/message/impl/OpenSidebarMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/OpenSidebarMessage.java rename to game/src/main/java/org/apollo/game/message/impl/OpenSidebarMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/PlayerActionMessage.java b/game/src/main/java/org/apollo/game/message/impl/PlayerActionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/PlayerActionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/PlayerActionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/PlayerDesignMessage.java b/game/src/main/java/org/apollo/game/message/impl/PlayerDesignMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/PlayerDesignMessage.java rename to game/src/main/java/org/apollo/game/message/impl/PlayerDesignMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/PlayerSynchronizationMessage.java b/game/src/main/java/org/apollo/game/message/impl/PlayerSynchronizationMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/PlayerSynchronizationMessage.java rename to game/src/main/java/org/apollo/game/message/impl/PlayerSynchronizationMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/PositionHintIconMessage.java b/game/src/main/java/org/apollo/game/message/impl/PositionHintIconMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/PositionHintIconMessage.java rename to game/src/main/java/org/apollo/game/message/impl/PositionHintIconMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/PrivacyOptionMessage.java b/game/src/main/java/org/apollo/game/message/impl/PrivacyOptionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/PrivacyOptionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/PrivacyOptionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/PrivateChatMessage.java b/game/src/main/java/org/apollo/game/message/impl/PrivateChatMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/PrivateChatMessage.java rename to game/src/main/java/org/apollo/game/message/impl/PrivateChatMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/PublicChatMessage.java b/game/src/main/java/org/apollo/game/message/impl/PublicChatMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/PublicChatMessage.java rename to game/src/main/java/org/apollo/game/message/impl/PublicChatMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/RegionChangeMessage.java b/game/src/main/java/org/apollo/game/message/impl/RegionChangeMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/RegionChangeMessage.java rename to game/src/main/java/org/apollo/game/message/impl/RegionChangeMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/RegionUpdateMessage.java b/game/src/main/java/org/apollo/game/message/impl/RegionUpdateMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/RegionUpdateMessage.java rename to game/src/main/java/org/apollo/game/message/impl/RegionUpdateMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/RemoveFriendMessage.java b/game/src/main/java/org/apollo/game/message/impl/RemoveFriendMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/RemoveFriendMessage.java rename to game/src/main/java/org/apollo/game/message/impl/RemoveFriendMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/RemoveIgnoreMessage.java b/game/src/main/java/org/apollo/game/message/impl/RemoveIgnoreMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/RemoveIgnoreMessage.java rename to game/src/main/java/org/apollo/game/message/impl/RemoveIgnoreMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/RemoveObjectMessage.java b/game/src/main/java/org/apollo/game/message/impl/RemoveObjectMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/RemoveObjectMessage.java rename to game/src/main/java/org/apollo/game/message/impl/RemoveObjectMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/RemoveTileItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/RemoveTileItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/RemoveTileItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/RemoveTileItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ReportAbuseMessage.java b/game/src/main/java/org/apollo/game/message/impl/ReportAbuseMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ReportAbuseMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ReportAbuseMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SendFriendMessage.java b/game/src/main/java/org/apollo/game/message/impl/SendFriendMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SendFriendMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SendFriendMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SendObjectMessage.java b/game/src/main/java/org/apollo/game/message/impl/SendObjectMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SendObjectMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SendObjectMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SendProjectileMessage.java b/game/src/main/java/org/apollo/game/message/impl/SendProjectileMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SendProjectileMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SendProjectileMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SendPublicTileItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/SendPublicTileItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SendPublicTileItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SendPublicTileItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SendTileItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/SendTileItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SendTileItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SendTileItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/ServerChatMessage.java b/game/src/main/java/org/apollo/game/message/impl/ServerChatMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/ServerChatMessage.java rename to game/src/main/java/org/apollo/game/message/impl/ServerChatMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetPlayerActionMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetPlayerActionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetPlayerActionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetPlayerActionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetUpdatedRegionMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetUpdatedRegionMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetUpdatedRegionMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetUpdatedRegionMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetWidgetItemModelMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetWidgetItemModelMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetWidgetItemModelMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetWidgetItemModelMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetWidgetModelAnimationMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetWidgetModelAnimationMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetWidgetModelAnimationMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetWidgetModelAnimationMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetWidgetModelMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetWidgetModelMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetWidgetModelMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetWidgetModelMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetWidgetNpcModelMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetWidgetNpcModelMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetWidgetNpcModelMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetWidgetNpcModelMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetWidgetPlayerModelMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetWidgetPlayerModelMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetWidgetPlayerModelMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetWidgetPlayerModelMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetWidgetTextMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetWidgetTextMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetWidgetTextMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetWidgetTextMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SetWidgetVisibilityMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetWidgetVisibilityMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SetWidgetVisibilityMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SetWidgetVisibilityMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SpamPacketMessage.java b/game/src/main/java/org/apollo/game/message/impl/SpamPacketMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SpamPacketMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SpamPacketMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SwitchItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/SwitchItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SwitchItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SwitchItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/SwitchTabInterfaceMessage.java b/game/src/main/java/org/apollo/game/message/impl/SwitchTabInterfaceMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/SwitchTabInterfaceMessage.java rename to game/src/main/java/org/apollo/game/message/impl/SwitchTabInterfaceMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/TakeTileItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/TakeTileItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/TakeTileItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/TakeTileItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/UpdateItemsMessage.java b/game/src/main/java/org/apollo/game/message/impl/UpdateItemsMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/UpdateItemsMessage.java rename to game/src/main/java/org/apollo/game/message/impl/UpdateItemsMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/UpdateRunEnergyMessage.java b/game/src/main/java/org/apollo/game/message/impl/UpdateRunEnergyMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/UpdateRunEnergyMessage.java rename to game/src/main/java/org/apollo/game/message/impl/UpdateRunEnergyMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/UpdateSkillMessage.java b/game/src/main/java/org/apollo/game/message/impl/UpdateSkillMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/UpdateSkillMessage.java rename to game/src/main/java/org/apollo/game/message/impl/UpdateSkillMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/UpdateSlottedItemsMessage.java b/game/src/main/java/org/apollo/game/message/impl/UpdateSlottedItemsMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/UpdateSlottedItemsMessage.java rename to game/src/main/java/org/apollo/game/message/impl/UpdateSlottedItemsMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/UpdateTileItemMessage.java b/game/src/main/java/org/apollo/game/message/impl/UpdateTileItemMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/UpdateTileItemMessage.java rename to game/src/main/java/org/apollo/game/message/impl/UpdateTileItemMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/UpdateWeightMessage.java b/game/src/main/java/org/apollo/game/message/impl/UpdateWeightMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/UpdateWeightMessage.java rename to game/src/main/java/org/apollo/game/message/impl/UpdateWeightMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/WalkMessage.java b/game/src/main/java/org/apollo/game/message/impl/WalkMessage.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/WalkMessage.java rename to game/src/main/java/org/apollo/game/message/impl/WalkMessage.java diff --git a/game/src/main/org/apollo/game/message/impl/package-info.java b/game/src/main/java/org/apollo/game/message/impl/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/message/impl/package-info.java rename to game/src/main/java/org/apollo/game/message/impl/package-info.java diff --git a/game/src/main/org/apollo/game/model/Animation.java b/game/src/main/java/org/apollo/game/model/Animation.java similarity index 100% rename from game/src/main/org/apollo/game/model/Animation.java rename to game/src/main/java/org/apollo/game/model/Animation.java diff --git a/game/src/main/org/apollo/game/model/Appearance.java b/game/src/main/java/org/apollo/game/model/Appearance.java similarity index 100% rename from game/src/main/org/apollo/game/model/Appearance.java rename to game/src/main/java/org/apollo/game/model/Appearance.java diff --git a/game/src/main/org/apollo/game/model/Direction.java b/game/src/main/java/org/apollo/game/model/Direction.java similarity index 100% rename from game/src/main/org/apollo/game/model/Direction.java rename to game/src/main/java/org/apollo/game/model/Direction.java diff --git a/game/src/main/org/apollo/game/model/Graphic.java b/game/src/main/java/org/apollo/game/model/Graphic.java similarity index 100% rename from game/src/main/org/apollo/game/model/Graphic.java rename to game/src/main/java/org/apollo/game/model/Graphic.java diff --git a/game/src/main/org/apollo/game/model/Item.java b/game/src/main/java/org/apollo/game/model/Item.java similarity index 100% rename from game/src/main/org/apollo/game/model/Item.java rename to game/src/main/java/org/apollo/game/model/Item.java diff --git a/game/src/main/org/apollo/game/model/Position.java b/game/src/main/java/org/apollo/game/model/Position.java similarity index 100% rename from game/src/main/org/apollo/game/model/Position.java rename to game/src/main/java/org/apollo/game/model/Position.java diff --git a/game/src/main/org/apollo/game/model/World.java b/game/src/main/java/org/apollo/game/model/World.java similarity index 100% rename from game/src/main/org/apollo/game/model/World.java rename to game/src/main/java/org/apollo/game/model/World.java diff --git a/game/src/main/org/apollo/game/model/WorldConstants.java b/game/src/main/java/org/apollo/game/model/WorldConstants.java similarity index 100% rename from game/src/main/org/apollo/game/model/WorldConstants.java rename to game/src/main/java/org/apollo/game/model/WorldConstants.java diff --git a/game/src/main/org/apollo/game/model/area/EntityUpdateType.java b/game/src/main/java/org/apollo/game/model/area/EntityUpdateType.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/EntityUpdateType.java rename to game/src/main/java/org/apollo/game/model/area/EntityUpdateType.java diff --git a/game/src/main/org/apollo/game/model/area/Region.java b/game/src/main/java/org/apollo/game/model/area/Region.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/Region.java rename to game/src/main/java/org/apollo/game/model/area/Region.java diff --git a/game/src/main/org/apollo/game/model/area/RegionCoordinates.java b/game/src/main/java/org/apollo/game/model/area/RegionCoordinates.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/RegionCoordinates.java rename to game/src/main/java/org/apollo/game/model/area/RegionCoordinates.java diff --git a/game/src/main/org/apollo/game/model/area/RegionListener.java b/game/src/main/java/org/apollo/game/model/area/RegionListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/RegionListener.java rename to game/src/main/java/org/apollo/game/model/area/RegionListener.java diff --git a/game/src/main/org/apollo/game/model/area/RegionRepository.java b/game/src/main/java/org/apollo/game/model/area/RegionRepository.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/RegionRepository.java rename to game/src/main/java/org/apollo/game/model/area/RegionRepository.java diff --git a/game/src/main/org/apollo/game/model/area/collision/CollisionFlag.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionFlag.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/collision/CollisionFlag.java rename to game/src/main/java/org/apollo/game/model/area/collision/CollisionFlag.java diff --git a/game/src/main/org/apollo/game/model/area/collision/CollisionManager.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionManager.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/collision/CollisionManager.java rename to game/src/main/java/org/apollo/game/model/area/collision/CollisionManager.java diff --git a/game/src/main/org/apollo/game/model/area/collision/CollisionMatrix.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionMatrix.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/collision/CollisionMatrix.java rename to game/src/main/java/org/apollo/game/model/area/collision/CollisionMatrix.java diff --git a/game/src/main/org/apollo/game/model/area/collision/CollisionUpdate.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdate.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/collision/CollisionUpdate.java rename to game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdate.java diff --git a/game/src/main/org/apollo/game/model/area/collision/CollisionUpdateListener.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdateListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/collision/CollisionUpdateListener.java rename to game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdateListener.java diff --git a/game/src/main/org/apollo/game/model/area/collision/CollisionUpdateType.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdateType.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/collision/CollisionUpdateType.java rename to game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdateType.java diff --git a/game/src/main/org/apollo/game/model/area/collision/package-info.java b/game/src/main/java/org/apollo/game/model/area/collision/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/collision/package-info.java rename to game/src/main/java/org/apollo/game/model/area/collision/package-info.java diff --git a/game/src/main/org/apollo/game/model/area/package-info.java b/game/src/main/java/org/apollo/game/model/area/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/package-info.java rename to game/src/main/java/org/apollo/game/model/area/package-info.java diff --git a/game/src/main/org/apollo/game/model/area/update/GroupableEntity.java b/game/src/main/java/org/apollo/game/model/area/update/GroupableEntity.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/update/GroupableEntity.java rename to game/src/main/java/org/apollo/game/model/area/update/GroupableEntity.java diff --git a/game/src/main/org/apollo/game/model/area/update/ItemUpdateOperation.java b/game/src/main/java/org/apollo/game/model/area/update/ItemUpdateOperation.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/update/ItemUpdateOperation.java rename to game/src/main/java/org/apollo/game/model/area/update/ItemUpdateOperation.java diff --git a/game/src/main/org/apollo/game/model/area/update/ObjectUpdateOperation.java b/game/src/main/java/org/apollo/game/model/area/update/ObjectUpdateOperation.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/update/ObjectUpdateOperation.java rename to game/src/main/java/org/apollo/game/model/area/update/ObjectUpdateOperation.java diff --git a/game/src/main/org/apollo/game/model/area/update/ProjectileUpdateOperation.java b/game/src/main/java/org/apollo/game/model/area/update/ProjectileUpdateOperation.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/update/ProjectileUpdateOperation.java rename to game/src/main/java/org/apollo/game/model/area/update/ProjectileUpdateOperation.java diff --git a/game/src/main/org/apollo/game/model/area/update/UpdateOperation.java b/game/src/main/java/org/apollo/game/model/area/update/UpdateOperation.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/update/UpdateOperation.java rename to game/src/main/java/org/apollo/game/model/area/update/UpdateOperation.java diff --git a/game/src/main/org/apollo/game/model/area/update/package-info.java b/game/src/main/java/org/apollo/game/model/area/update/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/area/update/package-info.java rename to game/src/main/java/org/apollo/game/model/area/update/package-info.java diff --git a/game/src/main/org/apollo/game/model/entity/Entity.java b/game/src/main/java/org/apollo/game/model/entity/Entity.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/Entity.java rename to game/src/main/java/org/apollo/game/model/entity/Entity.java diff --git a/game/src/main/org/apollo/game/model/entity/EntityType.java b/game/src/main/java/org/apollo/game/model/entity/EntityType.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/EntityType.java rename to game/src/main/java/org/apollo/game/model/entity/EntityType.java diff --git a/game/src/main/org/apollo/game/model/entity/EquipmentConstants.java b/game/src/main/java/org/apollo/game/model/entity/EquipmentConstants.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/EquipmentConstants.java rename to game/src/main/java/org/apollo/game/model/entity/EquipmentConstants.java diff --git a/game/src/main/org/apollo/game/model/entity/GroundItem.java b/game/src/main/java/org/apollo/game/model/entity/GroundItem.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/GroundItem.java rename to game/src/main/java/org/apollo/game/model/entity/GroundItem.java diff --git a/game/src/main/org/apollo/game/model/entity/Mob.java b/game/src/main/java/org/apollo/game/model/entity/Mob.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/Mob.java rename to game/src/main/java/org/apollo/game/model/entity/Mob.java diff --git a/game/src/main/org/apollo/game/model/entity/MobRepository.java b/game/src/main/java/org/apollo/game/model/entity/MobRepository.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/MobRepository.java rename to game/src/main/java/org/apollo/game/model/entity/MobRepository.java diff --git a/game/src/main/org/apollo/game/model/entity/Npc.java b/game/src/main/java/org/apollo/game/model/entity/Npc.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/Npc.java rename to game/src/main/java/org/apollo/game/model/entity/Npc.java diff --git a/game/src/main/org/apollo/game/model/entity/Player.java b/game/src/main/java/org/apollo/game/model/entity/Player.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/Player.java rename to game/src/main/java/org/apollo/game/model/entity/Player.java diff --git a/game/src/main/org/apollo/game/model/entity/Projectile.java b/game/src/main/java/org/apollo/game/model/entity/Projectile.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/Projectile.java rename to game/src/main/java/org/apollo/game/model/entity/Projectile.java diff --git a/game/src/main/org/apollo/game/model/entity/Skill.java b/game/src/main/java/org/apollo/game/model/entity/Skill.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/Skill.java rename to game/src/main/java/org/apollo/game/model/entity/Skill.java diff --git a/game/src/main/org/apollo/game/model/entity/SkillSet.java b/game/src/main/java/org/apollo/game/model/entity/SkillSet.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/SkillSet.java rename to game/src/main/java/org/apollo/game/model/entity/SkillSet.java diff --git a/game/src/main/org/apollo/game/model/entity/WalkingQueue.java b/game/src/main/java/org/apollo/game/model/entity/WalkingQueue.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/WalkingQueue.java rename to game/src/main/java/org/apollo/game/model/entity/WalkingQueue.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/Attribute.java b/game/src/main/java/org/apollo/game/model/entity/attr/Attribute.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/Attribute.java rename to game/src/main/java/org/apollo/game/model/entity/attr/Attribute.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/AttributeDefinition.java b/game/src/main/java/org/apollo/game/model/entity/attr/AttributeDefinition.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/AttributeDefinition.java rename to game/src/main/java/org/apollo/game/model/entity/attr/AttributeDefinition.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/AttributeMap.java b/game/src/main/java/org/apollo/game/model/entity/attr/AttributeMap.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/AttributeMap.java rename to game/src/main/java/org/apollo/game/model/entity/attr/AttributeMap.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/AttributePersistence.java b/game/src/main/java/org/apollo/game/model/entity/attr/AttributePersistence.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/AttributePersistence.java rename to game/src/main/java/org/apollo/game/model/entity/attr/AttributePersistence.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/AttributeType.java b/game/src/main/java/org/apollo/game/model/entity/attr/AttributeType.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/AttributeType.java rename to game/src/main/java/org/apollo/game/model/entity/attr/AttributeType.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/BooleanAttribute.java b/game/src/main/java/org/apollo/game/model/entity/attr/BooleanAttribute.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/BooleanAttribute.java rename to game/src/main/java/org/apollo/game/model/entity/attr/BooleanAttribute.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/NumericalAttribute.java b/game/src/main/java/org/apollo/game/model/entity/attr/NumericalAttribute.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/NumericalAttribute.java rename to game/src/main/java/org/apollo/game/model/entity/attr/NumericalAttribute.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/StringAttribute.java b/game/src/main/java/org/apollo/game/model/entity/attr/StringAttribute.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/StringAttribute.java rename to game/src/main/java/org/apollo/game/model/entity/attr/StringAttribute.java diff --git a/game/src/main/org/apollo/game/model/entity/attr/package-info.java b/game/src/main/java/org/apollo/game/model/entity/attr/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/attr/package-info.java rename to game/src/main/java/org/apollo/game/model/entity/attr/package-info.java diff --git a/game/src/main/org/apollo/game/model/entity/obj/DynamicGameObject.java b/game/src/main/java/org/apollo/game/model/entity/obj/DynamicGameObject.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/obj/DynamicGameObject.java rename to game/src/main/java/org/apollo/game/model/entity/obj/DynamicGameObject.java diff --git a/game/src/main/org/apollo/game/model/entity/obj/GameObject.java b/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/obj/GameObject.java rename to game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java diff --git a/game/src/main/org/apollo/game/model/entity/obj/ObjectGroup.java b/game/src/main/java/org/apollo/game/model/entity/obj/ObjectGroup.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/obj/ObjectGroup.java rename to game/src/main/java/org/apollo/game/model/entity/obj/ObjectGroup.java diff --git a/game/src/main/org/apollo/game/model/entity/obj/ObjectType.java b/game/src/main/java/org/apollo/game/model/entity/obj/ObjectType.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/obj/ObjectType.java rename to game/src/main/java/org/apollo/game/model/entity/obj/ObjectType.java diff --git a/game/src/main/org/apollo/game/model/entity/obj/StaticGameObject.java b/game/src/main/java/org/apollo/game/model/entity/obj/StaticGameObject.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/obj/StaticGameObject.java rename to game/src/main/java/org/apollo/game/model/entity/obj/StaticGameObject.java diff --git a/game/src/main/org/apollo/game/model/entity/obj/package-info.java b/game/src/main/java/org/apollo/game/model/entity/obj/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/obj/package-info.java rename to game/src/main/java/org/apollo/game/model/entity/obj/package-info.java diff --git a/game/src/main/org/apollo/game/model/entity/package-info.java b/game/src/main/java/org/apollo/game/model/entity/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/package-info.java rename to game/src/main/java/org/apollo/game/model/entity/package-info.java diff --git a/game/src/main/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java b/game/src/main/java/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java rename to game/src/main/java/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java diff --git a/game/src/main/org/apollo/game/model/entity/path/ChebyshevHeuristic.java b/game/src/main/java/org/apollo/game/model/entity/path/ChebyshevHeuristic.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/ChebyshevHeuristic.java rename to game/src/main/java/org/apollo/game/model/entity/path/ChebyshevHeuristic.java diff --git a/game/src/main/org/apollo/game/model/entity/path/EuclideanHeuristic.java b/game/src/main/java/org/apollo/game/model/entity/path/EuclideanHeuristic.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/EuclideanHeuristic.java rename to game/src/main/java/org/apollo/game/model/entity/path/EuclideanHeuristic.java diff --git a/game/src/main/org/apollo/game/model/entity/path/Heuristic.java b/game/src/main/java/org/apollo/game/model/entity/path/Heuristic.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/Heuristic.java rename to game/src/main/java/org/apollo/game/model/entity/path/Heuristic.java diff --git a/game/src/main/org/apollo/game/model/entity/path/ManhattanHeuristic.java b/game/src/main/java/org/apollo/game/model/entity/path/ManhattanHeuristic.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/ManhattanHeuristic.java rename to game/src/main/java/org/apollo/game/model/entity/path/ManhattanHeuristic.java diff --git a/game/src/main/org/apollo/game/model/entity/path/Node.java b/game/src/main/java/org/apollo/game/model/entity/path/Node.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/Node.java rename to game/src/main/java/org/apollo/game/model/entity/path/Node.java diff --git a/game/src/main/org/apollo/game/model/entity/path/PathfindingAlgorithm.java b/game/src/main/java/org/apollo/game/model/entity/path/PathfindingAlgorithm.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/PathfindingAlgorithm.java rename to game/src/main/java/org/apollo/game/model/entity/path/PathfindingAlgorithm.java diff --git a/game/src/main/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java b/game/src/main/java/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java rename to game/src/main/java/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java diff --git a/game/src/main/org/apollo/game/model/entity/path/package-info.java b/game/src/main/java/org/apollo/game/model/entity/path/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/path/package-info.java rename to game/src/main/java/org/apollo/game/model/entity/path/package-info.java diff --git a/game/src/main/org/apollo/game/model/entity/setting/Gender.java b/game/src/main/java/org/apollo/game/model/entity/setting/Gender.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/setting/Gender.java rename to game/src/main/java/org/apollo/game/model/entity/setting/Gender.java diff --git a/game/src/main/org/apollo/game/model/entity/setting/MembershipStatus.java b/game/src/main/java/org/apollo/game/model/entity/setting/MembershipStatus.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/setting/MembershipStatus.java rename to game/src/main/java/org/apollo/game/model/entity/setting/MembershipStatus.java diff --git a/game/src/main/org/apollo/game/model/entity/setting/PrivacyState.java b/game/src/main/java/org/apollo/game/model/entity/setting/PrivacyState.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/setting/PrivacyState.java rename to game/src/main/java/org/apollo/game/model/entity/setting/PrivacyState.java diff --git a/game/src/main/org/apollo/game/model/entity/setting/PrivilegeLevel.java b/game/src/main/java/org/apollo/game/model/entity/setting/PrivilegeLevel.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/setting/PrivilegeLevel.java rename to game/src/main/java/org/apollo/game/model/entity/setting/PrivilegeLevel.java diff --git a/game/src/main/org/apollo/game/model/entity/setting/ScreenBrightness.java b/game/src/main/java/org/apollo/game/model/entity/setting/ScreenBrightness.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/setting/ScreenBrightness.java rename to game/src/main/java/org/apollo/game/model/entity/setting/ScreenBrightness.java diff --git a/game/src/main/org/apollo/game/model/entity/setting/ServerStatus.java b/game/src/main/java/org/apollo/game/model/entity/setting/ServerStatus.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/setting/ServerStatus.java rename to game/src/main/java/org/apollo/game/model/entity/setting/ServerStatus.java diff --git a/game/src/main/org/apollo/game/model/entity/setting/package-info.java b/game/src/main/java/org/apollo/game/model/entity/setting/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/entity/setting/package-info.java rename to game/src/main/java/org/apollo/game/model/entity/setting/package-info.java diff --git a/game/src/main/org/apollo/game/model/event/Event.java b/game/src/main/java/org/apollo/game/model/event/Event.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/Event.java rename to game/src/main/java/org/apollo/game/model/event/Event.java diff --git a/game/src/main/org/apollo/game/model/event/EventListener.java b/game/src/main/java/org/apollo/game/model/event/EventListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/EventListener.java rename to game/src/main/java/org/apollo/game/model/event/EventListener.java diff --git a/game/src/main/org/apollo/game/model/event/EventListenerChain.java b/game/src/main/java/org/apollo/game/model/event/EventListenerChain.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/EventListenerChain.java rename to game/src/main/java/org/apollo/game/model/event/EventListenerChain.java diff --git a/game/src/main/org/apollo/game/model/event/EventListenerChainSet.java b/game/src/main/java/org/apollo/game/model/event/EventListenerChainSet.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/EventListenerChainSet.java rename to game/src/main/java/org/apollo/game/model/event/EventListenerChainSet.java diff --git a/game/src/main/org/apollo/game/model/event/PlayerEvent.java b/game/src/main/java/org/apollo/game/model/event/PlayerEvent.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/PlayerEvent.java rename to game/src/main/java/org/apollo/game/model/event/PlayerEvent.java diff --git a/game/src/main/org/apollo/game/model/event/ProxyEvent.java b/game/src/main/java/org/apollo/game/model/event/ProxyEvent.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/ProxyEvent.java rename to game/src/main/java/org/apollo/game/model/event/ProxyEvent.java diff --git a/game/src/main/org/apollo/game/model/event/ProxyEventListener.java b/game/src/main/java/org/apollo/game/model/event/ProxyEventListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/ProxyEventListener.java rename to game/src/main/java/org/apollo/game/model/event/ProxyEventListener.java diff --git a/game/src/main/org/apollo/game/model/event/impl/CloseInterfacesEvent.java b/game/src/main/java/org/apollo/game/model/event/impl/CloseInterfacesEvent.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/impl/CloseInterfacesEvent.java rename to game/src/main/java/org/apollo/game/model/event/impl/CloseInterfacesEvent.java diff --git a/game/src/main/org/apollo/game/model/event/impl/LoginEvent.java b/game/src/main/java/org/apollo/game/model/event/impl/LoginEvent.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/impl/LoginEvent.java rename to game/src/main/java/org/apollo/game/model/event/impl/LoginEvent.java diff --git a/game/src/main/org/apollo/game/model/event/impl/LogoutEvent.java b/game/src/main/java/org/apollo/game/model/event/impl/LogoutEvent.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/impl/LogoutEvent.java rename to game/src/main/java/org/apollo/game/model/event/impl/LogoutEvent.java diff --git a/game/src/main/org/apollo/game/model/event/impl/MobPositionUpdateEvent.java b/game/src/main/java/org/apollo/game/model/event/impl/MobPositionUpdateEvent.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/impl/MobPositionUpdateEvent.java rename to game/src/main/java/org/apollo/game/model/event/impl/MobPositionUpdateEvent.java diff --git a/game/src/main/org/apollo/game/model/event/impl/package-info.java b/game/src/main/java/org/apollo/game/model/event/impl/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/impl/package-info.java rename to game/src/main/java/org/apollo/game/model/event/impl/package-info.java diff --git a/game/src/main/org/apollo/game/model/event/package-info.java b/game/src/main/java/org/apollo/game/model/event/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/event/package-info.java rename to game/src/main/java/org/apollo/game/model/event/package-info.java diff --git a/game/src/main/org/apollo/game/model/inter/EnterAmountListener.java b/game/src/main/java/org/apollo/game/model/inter/EnterAmountListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/EnterAmountListener.java rename to game/src/main/java/org/apollo/game/model/inter/EnterAmountListener.java diff --git a/game/src/main/org/apollo/game/model/inter/InterfaceConstants.java b/game/src/main/java/org/apollo/game/model/inter/InterfaceConstants.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/InterfaceConstants.java rename to game/src/main/java/org/apollo/game/model/inter/InterfaceConstants.java diff --git a/game/src/main/org/apollo/game/model/inter/InterfaceListener.java b/game/src/main/java/org/apollo/game/model/inter/InterfaceListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/InterfaceListener.java rename to game/src/main/java/org/apollo/game/model/inter/InterfaceListener.java diff --git a/game/src/main/org/apollo/game/model/inter/InterfaceSet.java b/game/src/main/java/org/apollo/game/model/inter/InterfaceSet.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/InterfaceSet.java rename to game/src/main/java/org/apollo/game/model/inter/InterfaceSet.java diff --git a/game/src/main/org/apollo/game/model/inter/InterfaceType.java b/game/src/main/java/org/apollo/game/model/inter/InterfaceType.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/InterfaceType.java rename to game/src/main/java/org/apollo/game/model/inter/InterfaceType.java diff --git a/game/src/main/org/apollo/game/model/inter/bank/BankConstants.java b/game/src/main/java/org/apollo/game/model/inter/bank/BankConstants.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/bank/BankConstants.java rename to game/src/main/java/org/apollo/game/model/inter/bank/BankConstants.java diff --git a/game/src/main/org/apollo/game/model/inter/bank/BankDepositEnterAmountListener.java b/game/src/main/java/org/apollo/game/model/inter/bank/BankDepositEnterAmountListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/bank/BankDepositEnterAmountListener.java rename to game/src/main/java/org/apollo/game/model/inter/bank/BankDepositEnterAmountListener.java diff --git a/game/src/main/org/apollo/game/model/inter/bank/BankInterfaceListener.java b/game/src/main/java/org/apollo/game/model/inter/bank/BankInterfaceListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/bank/BankInterfaceListener.java rename to game/src/main/java/org/apollo/game/model/inter/bank/BankInterfaceListener.java diff --git a/game/src/main/org/apollo/game/model/inter/bank/BankUtils.java b/game/src/main/java/org/apollo/game/model/inter/bank/BankUtils.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/bank/BankUtils.java rename to game/src/main/java/org/apollo/game/model/inter/bank/BankUtils.java diff --git a/game/src/main/org/apollo/game/model/inter/bank/BankWithdrawEnterAmountListener.java b/game/src/main/java/org/apollo/game/model/inter/bank/BankWithdrawEnterAmountListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/bank/BankWithdrawEnterAmountListener.java rename to game/src/main/java/org/apollo/game/model/inter/bank/BankWithdrawEnterAmountListener.java diff --git a/game/src/main/org/apollo/game/model/inter/bank/package-info.java b/game/src/main/java/org/apollo/game/model/inter/bank/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/bank/package-info.java rename to game/src/main/java/org/apollo/game/model/inter/bank/package-info.java diff --git a/game/src/main/org/apollo/game/model/inter/dialogue/DialogueAdapter.java b/game/src/main/java/org/apollo/game/model/inter/dialogue/DialogueAdapter.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/dialogue/DialogueAdapter.java rename to game/src/main/java/org/apollo/game/model/inter/dialogue/DialogueAdapter.java diff --git a/game/src/main/org/apollo/game/model/inter/dialogue/DialogueListener.java b/game/src/main/java/org/apollo/game/model/inter/dialogue/DialogueListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/dialogue/DialogueListener.java rename to game/src/main/java/org/apollo/game/model/inter/dialogue/DialogueListener.java diff --git a/game/src/main/org/apollo/game/model/inter/dialogue/package-info.java b/game/src/main/java/org/apollo/game/model/inter/dialogue/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/dialogue/package-info.java rename to game/src/main/java/org/apollo/game/model/inter/dialogue/package-info.java diff --git a/game/src/main/org/apollo/game/model/inter/package-info.java b/game/src/main/java/org/apollo/game/model/inter/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/inter/package-info.java rename to game/src/main/java/org/apollo/game/model/inter/package-info.java diff --git a/game/src/main/org/apollo/game/model/inv/AppearanceInventoryListener.java b/game/src/main/java/org/apollo/game/model/inv/AppearanceInventoryListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/AppearanceInventoryListener.java rename to game/src/main/java/org/apollo/game/model/inv/AppearanceInventoryListener.java diff --git a/game/src/main/org/apollo/game/model/inv/FullInventoryListener.java b/game/src/main/java/org/apollo/game/model/inv/FullInventoryListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/FullInventoryListener.java rename to game/src/main/java/org/apollo/game/model/inv/FullInventoryListener.java diff --git a/game/src/main/org/apollo/game/model/inv/Inventory.java b/game/src/main/java/org/apollo/game/model/inv/Inventory.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/Inventory.java rename to game/src/main/java/org/apollo/game/model/inv/Inventory.java diff --git a/game/src/main/org/apollo/game/model/inv/InventoryAdapter.java b/game/src/main/java/org/apollo/game/model/inv/InventoryAdapter.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/InventoryAdapter.java rename to game/src/main/java/org/apollo/game/model/inv/InventoryAdapter.java diff --git a/game/src/main/org/apollo/game/model/inv/InventoryConstants.java b/game/src/main/java/org/apollo/game/model/inv/InventoryConstants.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/InventoryConstants.java rename to game/src/main/java/org/apollo/game/model/inv/InventoryConstants.java diff --git a/game/src/main/org/apollo/game/model/inv/InventoryListener.java b/game/src/main/java/org/apollo/game/model/inv/InventoryListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/InventoryListener.java rename to game/src/main/java/org/apollo/game/model/inv/InventoryListener.java diff --git a/game/src/main/org/apollo/game/model/inv/SlottedItem.java b/game/src/main/java/org/apollo/game/model/inv/SlottedItem.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/SlottedItem.java rename to game/src/main/java/org/apollo/game/model/inv/SlottedItem.java diff --git a/game/src/main/org/apollo/game/model/inv/SynchronizationInventoryListener.java b/game/src/main/java/org/apollo/game/model/inv/SynchronizationInventoryListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/SynchronizationInventoryListener.java rename to game/src/main/java/org/apollo/game/model/inv/SynchronizationInventoryListener.java diff --git a/game/src/main/org/apollo/game/model/inv/package-info.java b/game/src/main/java/org/apollo/game/model/inv/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/inv/package-info.java rename to game/src/main/java/org/apollo/game/model/inv/package-info.java diff --git a/game/src/main/org/apollo/game/model/package-info.java b/game/src/main/java/org/apollo/game/model/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/package-info.java rename to game/src/main/java/org/apollo/game/model/package-info.java diff --git a/game/src/main/org/apollo/game/model/skill/LevelUpSkillListener.java b/game/src/main/java/org/apollo/game/model/skill/LevelUpSkillListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/skill/LevelUpSkillListener.java rename to game/src/main/java/org/apollo/game/model/skill/LevelUpSkillListener.java diff --git a/game/src/main/org/apollo/game/model/skill/SkillAdapter.java b/game/src/main/java/org/apollo/game/model/skill/SkillAdapter.java similarity index 100% rename from game/src/main/org/apollo/game/model/skill/SkillAdapter.java rename to game/src/main/java/org/apollo/game/model/skill/SkillAdapter.java diff --git a/game/src/main/org/apollo/game/model/skill/SkillListener.java b/game/src/main/java/org/apollo/game/model/skill/SkillListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/skill/SkillListener.java rename to game/src/main/java/org/apollo/game/model/skill/SkillListener.java diff --git a/game/src/main/org/apollo/game/model/skill/SynchronizationSkillListener.java b/game/src/main/java/org/apollo/game/model/skill/SynchronizationSkillListener.java similarity index 100% rename from game/src/main/org/apollo/game/model/skill/SynchronizationSkillListener.java rename to game/src/main/java/org/apollo/game/model/skill/SynchronizationSkillListener.java diff --git a/game/src/main/org/apollo/game/model/skill/package-info.java b/game/src/main/java/org/apollo/game/model/skill/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/model/skill/package-info.java rename to game/src/main/java/org/apollo/game/model/skill/package-info.java diff --git a/game/src/main/org/apollo/game/package-info.java b/game/src/main/java/org/apollo/game/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/package-info.java rename to game/src/main/java/org/apollo/game/package-info.java diff --git a/game/src/main/org/apollo/game/plugin/DependencyException.java b/game/src/main/java/org/apollo/game/plugin/DependencyException.java similarity index 100% rename from game/src/main/org/apollo/game/plugin/DependencyException.java rename to game/src/main/java/org/apollo/game/plugin/DependencyException.java diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java new file mode 100644 index 000000000..1912d4070 --- /dev/null +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java @@ -0,0 +1,9 @@ +package org.apollo.game.plugin; + +import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; + +public class KotlinPluginCompilerStub { + public static void main(String[] argv) { + KotlinPluginCompiler.main(argv); + } +} diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java new file mode 100644 index 000000000..d433db178 --- /dev/null +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -0,0 +1,66 @@ +package org.apollo.game.plugin; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Constructor; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import org.apollo.game.model.World; +import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; +import org.apollo.game.plugin.kotlin.KotlinPluginScript; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; +import org.jetbrains.kotlin.cli.common.messages.MessageCollector; + +public class KotlinPluginEnvironment implements PluginEnvironment { + + private static final Logger logger = Logger.getLogger(KotlinPluginEnvironment.class.getName()); + + private final World world; + private PluginContext context; + + public KotlinPluginEnvironment(World world) { + this.world = world; + } + + @Override + public void load(Collection plugins) { + List pluginScripts = new ArrayList<>(); + + try (InputStream resource = KotlinPluginEnvironment.class.getResourceAsStream("/manifest.txt")) { + BufferedReader reader = new BufferedReader(new InputStreamReader(resource)); + List pluginClassNames = reader.lines().collect(Collectors.toList()); + + for (String pluginClassName : pluginClassNames) { + Class pluginClass = + (Class) Class.forName(pluginClassName); + + Constructor pluginConstructor = + pluginClass.getConstructor(World.class, PluginContext.class); + + pluginScripts.add(pluginConstructor.newInstance(world, context)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + pluginScripts.forEach(KotlinPluginScript::doStart); + } + + @Override + public void setContext(PluginContext context) { + this.context = context; + } + +} diff --git a/game/src/main/org/apollo/game/plugin/PluginContext.java b/game/src/main/java/org/apollo/game/plugin/PluginContext.java similarity index 100% rename from game/src/main/org/apollo/game/plugin/PluginContext.java rename to game/src/main/java/org/apollo/game/plugin/PluginContext.java diff --git a/game/src/main/org/apollo/game/plugin/PluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/PluginEnvironment.java similarity index 100% rename from game/src/main/org/apollo/game/plugin/PluginEnvironment.java rename to game/src/main/java/org/apollo/game/plugin/PluginEnvironment.java diff --git a/game/src/main/org/apollo/game/plugin/PluginManager.java b/game/src/main/java/org/apollo/game/plugin/PluginManager.java similarity index 92% rename from game/src/main/org/apollo/game/plugin/PluginManager.java rename to game/src/main/java/org/apollo/game/plugin/PluginManager.java index db1b45dde..5471cb697 100644 --- a/game/src/main/org/apollo/game/plugin/PluginManager.java +++ b/game/src/main/java/org/apollo/game/plugin/PluginManager.java @@ -4,14 +4,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -143,8 +136,8 @@ private void initAuthors() { * @throws DependencyException If a dependency could not be resolved. */ public void start() throws IOException, SAXException, DependencyException { - Map plugins = createMap(findPlugins()); - Set started = new HashSet<>(); + //@todo - load metadata and respective plugins + Map plugins = new HashMap<>(); PluginEnvironment env = new KotlinPluginEnvironment(world); // TODO isolate plugins if possible in the future! env.setContext(context); diff --git a/game/src/main/org/apollo/game/plugin/PluginMetaData.java b/game/src/main/java/org/apollo/game/plugin/PluginMetaData.java similarity index 100% rename from game/src/main/org/apollo/game/plugin/PluginMetaData.java rename to game/src/main/java/org/apollo/game/plugin/PluginMetaData.java diff --git a/game/src/main/org/apollo/game/plugin/package-info.java b/game/src/main/java/org/apollo/game/plugin/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/plugin/package-info.java rename to game/src/main/java/org/apollo/game/plugin/package-info.java diff --git a/game/src/main/org/apollo/game/release/r317/AddFriendMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/AddFriendMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/AddFriendMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/AddFriendMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/AddGlobalTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/AddGlobalTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/AddGlobalTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/AddGlobalTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/AddIgnoreMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/AddIgnoreMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/AddIgnoreMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/AddIgnoreMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/AddTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/AddTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/AddTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/AddTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ArrowKeyMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ArrowKeyMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ArrowKeyMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ArrowKeyMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ButtonMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ButtonMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ButtonMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ButtonMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ClearRegionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/ClearRegionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ClearRegionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/ClearRegionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/CloseInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/CloseInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/CloseInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/CloseInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ClosedInterfaceMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ClosedInterfaceMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ClosedInterfaceMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ClosedInterfaceMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/CommandMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/CommandMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/CommandMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/CommandMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ConfigMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/ConfigMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ConfigMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/ConfigMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/DialogueContinueMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/DialogueContinueMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/DialogueContinueMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/DialogueContinueMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/DisplayCrossbonesMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/DisplayCrossbonesMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/DisplayCrossbonesMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/DisplayCrossbonesMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/DisplayTabInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/DisplayTabInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/DisplayTabInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/DisplayTabInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/EnterAmountMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/EnterAmountMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/EnterAmountMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/EnterAmountMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/EnteredAmountMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/EnteredAmountMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/EnteredAmountMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/EnteredAmountMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FifthItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FifthItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FifthItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FifthItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FifthItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FifthItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FifthItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FifthItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FifthNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FifthNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FifthNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FifthNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FifthPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FifthPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FifthPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FifthPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FirstItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FirstItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FirstItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FirstItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FirstItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FirstItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FirstItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FirstItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FirstNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FirstNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FirstNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FirstNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FirstObjectActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FirstObjectActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FirstObjectActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FirstObjectActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FirstPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FirstPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FirstPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FirstPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FlaggedMouseEventMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FlaggedMouseEventMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FlaggedMouseEventMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FlaggedMouseEventMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FlashTabInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/FlashTabInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FlashTabInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/FlashTabInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FlashingTabClickedMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FlashingTabClickedMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FlashingTabClickedMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FlashingTabClickedMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FocusUpdateMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FocusUpdateMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FocusUpdateMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FocusUpdateMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ForwardPrivateChatMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/ForwardPrivateChatMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ForwardPrivateChatMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/ForwardPrivateChatMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FourthItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FourthItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FourthItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FourthItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FourthItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FourthItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FourthItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FourthItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FourthNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FourthNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FourthNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FourthNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FourthPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/FourthPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FourthPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/FourthPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/FriendServerStatusMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/FriendServerStatusMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/FriendServerStatusMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/FriendServerStatusMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/IdAssignmentMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/IdAssignmentMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/IdAssignmentMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/IdAssignmentMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/IgnoreListMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/IgnoreListMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/IgnoreListMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/IgnoreListMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ItemOnItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ItemOnItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ItemOnItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ItemOnItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ItemOnNpcMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ItemOnNpcMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ItemOnNpcMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ItemOnNpcMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ItemOnObjectMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ItemOnObjectMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ItemOnObjectMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ItemOnObjectMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/KeepAliveMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/KeepAliveMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/KeepAliveMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/KeepAliveMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/LogoutMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/LogoutMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/LogoutMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/LogoutMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/MagicOnItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/MagicOnItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/MagicOnItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/MagicOnItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/MagicOnNpcMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/MagicOnNpcMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/MagicOnNpcMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/MagicOnNpcMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/MagicOnPlayerMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/MagicOnPlayerMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/MagicOnPlayerMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/MagicOnPlayerMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/MobAnimationResetMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/MobAnimationResetMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/MobAnimationResetMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/MobAnimationResetMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/MobHintIconMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/MobHintIconMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/MobHintIconMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/MobHintIconMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/MouseClickedMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/MouseClickedMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/MouseClickedMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/MouseClickedMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/NpcSynchronizationMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/NpcSynchronizationMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/NpcSynchronizationMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/NpcSynchronizationMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/OpenDialogueInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/OpenDialogueInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/OpenDialogueInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/OpenDialogueInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/OpenDialogueOverlayMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/OpenDialogueOverlayMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/OpenDialogueOverlayMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/OpenDialogueOverlayMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/OpenInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/OpenInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/OpenInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/OpenInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/OpenInterfaceSidebarMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/OpenInterfaceSidebarMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/OpenInterfaceSidebarMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/OpenInterfaceSidebarMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/OpenOverlayMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/OpenOverlayMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/OpenOverlayMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/OpenOverlayMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/OpenSidebarMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/OpenSidebarMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/OpenSidebarMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/OpenSidebarMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/PlayerDesignMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/PlayerDesignMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/PlayerDesignMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/PlayerDesignMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/PlayerSynchronizationMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/PlayerSynchronizationMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/PlayerSynchronizationMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/PlayerSynchronizationMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/PositionHintIconMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/PositionHintIconMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/PositionHintIconMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/PositionHintIconMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/PrivacyOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/PrivacyOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/PrivacyOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/PrivacyOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/PrivacyOptionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/PrivacyOptionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/PrivacyOptionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/PrivacyOptionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/PrivateChatMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/PrivateChatMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/PrivateChatMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/PrivateChatMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/PublicChatMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/PublicChatMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/PublicChatMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/PublicChatMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/RegionChangeMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/RegionChangeMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/RegionChangeMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/RegionChangeMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/Release317.java b/game/src/main/java/org/apollo/game/release/r317/Release317.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/Release317.java rename to game/src/main/java/org/apollo/game/release/r317/Release317.java diff --git a/game/src/main/org/apollo/game/release/r317/RemoveFriendMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/RemoveFriendMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/RemoveFriendMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/RemoveFriendMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/RemoveIgnoreMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/RemoveIgnoreMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/RemoveIgnoreMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/RemoveIgnoreMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/RemoveObjectMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/RemoveObjectMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/RemoveObjectMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/RemoveObjectMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/RemoveTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/RemoveTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/RemoveTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/RemoveTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ReportAbuseMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ReportAbuseMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ReportAbuseMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ReportAbuseMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SecondItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SecondItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SecondItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/SecondItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SecondItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SecondItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SecondItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/SecondItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SecondNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SecondNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SecondNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/SecondNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SecondObjectActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SecondObjectActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SecondObjectActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/SecondObjectActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SecondPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SecondPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SecondPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/SecondPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SendFriendMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SendFriendMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SendFriendMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SendFriendMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SendObjectMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SendObjectMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SendObjectMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SendObjectMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ServerMessageMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/ServerMessageMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ServerMessageMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/ServerMessageMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetPlayerActionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetPlayerActionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetPlayerActionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetPlayerActionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetUpdatedRegionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetUpdatedRegionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetUpdatedRegionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetUpdatedRegionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetWidgetItemModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetWidgetItemModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetWidgetItemModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetWidgetItemModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetWidgetModelAnimationMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetWidgetModelAnimationMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetWidgetModelAnimationMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetWidgetModelAnimationMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetWidgetModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetWidgetModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetWidgetModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetWidgetModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetWidgetNpcModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetWidgetNpcModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetWidgetNpcModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetWidgetNpcModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetWidgetPlayerModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetWidgetPlayerModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetWidgetPlayerModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetWidgetPlayerModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetWidgetTextMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetWidgetTextMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetWidgetTextMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetWidgetTextMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SetWidgetVisibilityMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SetWidgetVisibilityMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SetWidgetVisibilityMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SetWidgetVisibilityMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SpamPacketMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SpamPacketMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SpamPacketMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/SpamPacketMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SwitchItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SwitchItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SwitchItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/SwitchItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/SwitchTabInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SwitchTabInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/SwitchTabInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/SwitchTabInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/TakeTileItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/TakeTileItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/TakeTileItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/TakeTileItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ThirdItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ThirdItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ThirdItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ThirdItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ThirdItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ThirdItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ThirdItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ThirdItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ThirdNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ThirdNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ThirdNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ThirdNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ThirdObjectActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ThirdObjectActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ThirdObjectActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ThirdObjectActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/ThirdPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/ThirdPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/ThirdPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/ThirdPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/UpdateItemsMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/UpdateItemsMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/UpdateItemsMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/UpdateItemsMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/UpdateRunEnergyMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/UpdateRunEnergyMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/UpdateRunEnergyMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/UpdateRunEnergyMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/UpdateSkillMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/UpdateSkillMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/UpdateSkillMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/UpdateSkillMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/UpdateSlottedItemsMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/UpdateSlottedItemsMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/UpdateSlottedItemsMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/UpdateSlottedItemsMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/UpdateTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/UpdateTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/UpdateTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/UpdateTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/UpdateWeightMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/UpdateWeightMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/UpdateWeightMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r317/UpdateWeightMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r317/WalkMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/WalkMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/WalkMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r317/WalkMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r317/package-info.java b/game/src/main/java/org/apollo/game/release/r317/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/release/r317/package-info.java rename to game/src/main/java/org/apollo/game/release/r317/package-info.java diff --git a/game/src/main/org/apollo/game/release/r377/AddFriendMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/AddFriendMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/AddFriendMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/AddFriendMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/AddGlobalTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/AddGlobalTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/AddGlobalTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/AddGlobalTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/AddIgnoreMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/AddIgnoreMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/AddIgnoreMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/AddIgnoreMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/AddTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/AddTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/AddTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/AddTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ArrowKeyMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ArrowKeyMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ArrowKeyMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ArrowKeyMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ButtonMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ButtonMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ButtonMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ButtonMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ClearRegionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/ClearRegionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ClearRegionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/ClearRegionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/CloseInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/CloseInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/CloseInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/CloseInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ClosedInterfaceMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ClosedInterfaceMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ClosedInterfaceMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ClosedInterfaceMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/CommandMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/CommandMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/CommandMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/CommandMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ConfigMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/ConfigMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ConfigMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/ConfigMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/DialogueContinueMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/DialogueContinueMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/DialogueContinueMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/DialogueContinueMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/DisplayCrossbonesMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/DisplayCrossbonesMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/DisplayCrossbonesMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/DisplayCrossbonesMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/DisplayTabInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/DisplayTabInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/DisplayTabInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/DisplayTabInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/EnterAmountMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/EnterAmountMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/EnterAmountMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/EnterAmountMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/EnteredAmountMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/EnteredAmountMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/EnteredAmountMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/EnteredAmountMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FifthItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FifthItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FifthItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FifthItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FifthItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FifthItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FifthItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FifthItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FifthNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FifthNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FifthNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FifthNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FifthPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FifthPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FifthPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FifthPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FirstItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FirstItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FirstItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FirstItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FirstItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FirstItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FirstItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FirstItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FirstNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FirstNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FirstNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FirstNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FirstObjectActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FirstObjectActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FirstObjectActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FirstObjectActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FirstPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FirstPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FirstPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FirstPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FlaggedMouseEventMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FlaggedMouseEventMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FlaggedMouseEventMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FlaggedMouseEventMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/FlashTabInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FlashingTabClickedMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FlashingTabClickedMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FlashingTabClickedMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FlashingTabClickedMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FocusUpdateMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FocusUpdateMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FocusUpdateMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FocusUpdateMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ForwardPrivateChatMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/ForwardPrivateChatMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ForwardPrivateChatMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/ForwardPrivateChatMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FourthItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FourthItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FourthItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FourthItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FourthItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FourthItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FourthItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FourthItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FourthNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FourthNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FourthNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FourthNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FourthPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/FourthPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FourthPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/FourthPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/FriendServerStatusMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/FriendServerStatusMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/FriendServerStatusMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/FriendServerStatusMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/GroupedRegionUpdateMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/GroupedRegionUpdateMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/GroupedRegionUpdateMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/GroupedRegionUpdateMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/IdAssignmentMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/IdAssignmentMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/IdAssignmentMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/IdAssignmentMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/IgnoreListMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/IgnoreListMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/IgnoreListMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/IgnoreListMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ItemOnItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ItemOnItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ItemOnItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ItemOnItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ItemOnNpcMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ItemOnNpcMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ItemOnNpcMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ItemOnNpcMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ItemOnObjectMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ItemOnObjectMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ItemOnObjectMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ItemOnObjectMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/KeepAliveMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/KeepAliveMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/KeepAliveMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/KeepAliveMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/LogoutMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/LogoutMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/LogoutMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/LogoutMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/MagicOnItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/MagicOnItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/MagicOnItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/MagicOnItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/MagicOnNpcMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/MagicOnNpcMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/MagicOnNpcMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/MagicOnNpcMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/MagicOnPlayerMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/MagicOnPlayerMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/MagicOnPlayerMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/MagicOnPlayerMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/MobAnimationResetMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/MobAnimationResetMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/MobAnimationResetMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/MobAnimationResetMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/MobHintIconMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/MobHintIconMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/MobHintIconMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/MobHintIconMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/MouseClickedMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/MouseClickedMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/MouseClickedMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/MouseClickedMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/NpcSynchronizationMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/NpcSynchronizationMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/NpcSynchronizationMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/NpcSynchronizationMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/OpenDialogueInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/OpenDialogueInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/OpenDialogueInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/OpenDialogueInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/OpenDialogueOverlayMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/OpenDialogueOverlayMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/OpenDialogueOverlayMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/OpenDialogueOverlayMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/OpenInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/OpenInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/OpenInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/OpenInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/OpenInterfaceSidebarMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/OpenInterfaceSidebarMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/OpenInterfaceSidebarMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/OpenInterfaceSidebarMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/OpenOverlayMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/OpenOverlayMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/OpenOverlayMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/OpenOverlayMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/OpenSidebarMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/OpenSidebarMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/OpenSidebarMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/OpenSidebarMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/PlayerDesignMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/PlayerDesignMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/PlayerDesignMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/PlayerDesignMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/PlayerSynchronizationMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/PlayerSynchronizationMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/PlayerSynchronizationMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/PlayerSynchronizationMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/PositionHintIconMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/PositionHintIconMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/PositionHintIconMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/PositionHintIconMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/PrivacyOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/PrivacyOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/PrivacyOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/PrivacyOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/PrivacyOptionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/PrivacyOptionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/PrivacyOptionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/PrivacyOptionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/PrivateChatMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/PrivateChatMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/PrivateChatMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/PrivateChatMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/PublicChatMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/PublicChatMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/PublicChatMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/PublicChatMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/RegionChangeMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/RegionChangeMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/RegionChangeMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/RegionChangeMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/Release377.java b/game/src/main/java/org/apollo/game/release/r377/Release377.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/Release377.java rename to game/src/main/java/org/apollo/game/release/r377/Release377.java diff --git a/game/src/main/org/apollo/game/release/r377/RemoveFriendMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/RemoveFriendMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/RemoveFriendMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/RemoveFriendMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/RemoveIgnoreMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/RemoveIgnoreMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/RemoveIgnoreMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/RemoveIgnoreMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/RemoveObjectMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/RemoveObjectMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/RemoveObjectMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/RemoveObjectMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/RemoveTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/RemoveTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/RemoveTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/RemoveTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ReportAbuseMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ReportAbuseMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ReportAbuseMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ReportAbuseMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SecondItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/SecondItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SecondItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/SecondItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SecondItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/SecondItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SecondItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/SecondItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SecondNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/SecondNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SecondNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/SecondNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SecondObjectActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/SecondObjectActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SecondObjectActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/SecondObjectActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SecondPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/SecondPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SecondPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/SecondPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SendFriendMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SendFriendMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SendFriendMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SendFriendMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SendObjectMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SendObjectMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SendObjectMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SendObjectMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SendProjectileMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SendProjectileMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SendProjectileMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SendProjectileMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ServerMessageMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/ServerMessageMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ServerMessageMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/ServerMessageMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetPlayerActionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetPlayerActionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetPlayerActionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetPlayerActionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetUpdatedRegionMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetUpdatedRegionMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetUpdatedRegionMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetUpdatedRegionMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetWidgetItemModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetWidgetItemModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetWidgetItemModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetWidgetItemModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetWidgetModelAnimationMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetWidgetModelAnimationMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetWidgetModelAnimationMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetWidgetModelAnimationMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetWidgetModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetWidgetModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetWidgetModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetWidgetModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetWidgetNpcModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetWidgetNpcModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetWidgetNpcModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetWidgetNpcModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetWidgetPlayerModelMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetWidgetPlayerModelMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetWidgetPlayerModelMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetWidgetPlayerModelMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetWidgetTextMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetWidgetTextMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetWidgetTextMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetWidgetTextMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SetWidgetVisibilityMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SetWidgetVisibilityMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SetWidgetVisibilityMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SetWidgetVisibilityMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SpamPacketMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/SpamPacketMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SpamPacketMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/SpamPacketMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SwitchItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/SwitchItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SwitchItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/SwitchItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/SwitchTabInterfaceMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/SwitchTabInterfaceMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/SwitchTabInterfaceMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/SwitchTabInterfaceMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/TakeTileItemMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/TakeTileItemMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/TakeTileItemMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/TakeTileItemMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ThirdItemActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ThirdItemActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ThirdItemActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ThirdItemActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ThirdItemOptionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ThirdItemOptionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ThirdItemOptionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ThirdItemOptionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ThirdNpcActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ThirdNpcActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ThirdNpcActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ThirdNpcActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ThirdObjectActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ThirdObjectActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ThirdObjectActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ThirdObjectActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/ThirdPlayerActionMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/ThirdPlayerActionMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/ThirdPlayerActionMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/ThirdPlayerActionMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/UpdateItemsMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/UpdateItemsMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/UpdateItemsMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/UpdateItemsMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/UpdateRunEnergyMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/UpdateRunEnergyMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/UpdateRunEnergyMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/UpdateRunEnergyMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/UpdateSkillMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/UpdateSkillMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/UpdateSkillMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/UpdateSkillMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/UpdateSlottedItemsMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/UpdateSlottedItemsMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/UpdateSlottedItemsMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/UpdateSlottedItemsMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/UpdateTileItemMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/UpdateTileItemMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/UpdateTileItemMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/UpdateTileItemMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/UpdateWeightMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r377/UpdateWeightMessageEncoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/UpdateWeightMessageEncoder.java rename to game/src/main/java/org/apollo/game/release/r377/UpdateWeightMessageEncoder.java diff --git a/game/src/main/org/apollo/game/release/r377/WalkMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r377/WalkMessageDecoder.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/WalkMessageDecoder.java rename to game/src/main/java/org/apollo/game/release/r377/WalkMessageDecoder.java diff --git a/game/src/main/org/apollo/game/release/r377/package-info.java b/game/src/main/java/org/apollo/game/release/r377/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/release/r377/package-info.java rename to game/src/main/java/org/apollo/game/release/r377/package-info.java diff --git a/game/src/main/org/apollo/game/scheduling/ScheduledTask.java b/game/src/main/java/org/apollo/game/scheduling/ScheduledTask.java similarity index 100% rename from game/src/main/org/apollo/game/scheduling/ScheduledTask.java rename to game/src/main/java/org/apollo/game/scheduling/ScheduledTask.java diff --git a/game/src/main/org/apollo/game/scheduling/Scheduler.java b/game/src/main/java/org/apollo/game/scheduling/Scheduler.java similarity index 100% rename from game/src/main/org/apollo/game/scheduling/Scheduler.java rename to game/src/main/java/org/apollo/game/scheduling/Scheduler.java diff --git a/game/src/main/org/apollo/game/scheduling/impl/NpcMovementTask.java b/game/src/main/java/org/apollo/game/scheduling/impl/NpcMovementTask.java similarity index 100% rename from game/src/main/org/apollo/game/scheduling/impl/NpcMovementTask.java rename to game/src/main/java/org/apollo/game/scheduling/impl/NpcMovementTask.java diff --git a/game/src/main/org/apollo/game/scheduling/impl/SkillNormalizationTask.java b/game/src/main/java/org/apollo/game/scheduling/impl/SkillNormalizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/scheduling/impl/SkillNormalizationTask.java rename to game/src/main/java/org/apollo/game/scheduling/impl/SkillNormalizationTask.java diff --git a/game/src/main/org/apollo/game/scheduling/impl/package-info.java b/game/src/main/java/org/apollo/game/scheduling/impl/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/scheduling/impl/package-info.java rename to game/src/main/java/org/apollo/game/scheduling/impl/package-info.java diff --git a/game/src/main/org/apollo/game/scheduling/package-info.java b/game/src/main/java/org/apollo/game/scheduling/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/scheduling/package-info.java rename to game/src/main/java/org/apollo/game/scheduling/package-info.java diff --git a/game/src/main/org/apollo/game/service/GameService.java b/game/src/main/java/org/apollo/game/service/GameService.java similarity index 100% rename from game/src/main/org/apollo/game/service/GameService.java rename to game/src/main/java/org/apollo/game/service/GameService.java diff --git a/game/src/main/org/apollo/game/service/LoginService.java b/game/src/main/java/org/apollo/game/service/LoginService.java similarity index 100% rename from game/src/main/org/apollo/game/service/LoginService.java rename to game/src/main/java/org/apollo/game/service/LoginService.java diff --git a/game/src/main/org/apollo/game/service/UpdateService.java b/game/src/main/java/org/apollo/game/service/UpdateService.java similarity index 100% rename from game/src/main/org/apollo/game/service/UpdateService.java rename to game/src/main/java/org/apollo/game/service/UpdateService.java diff --git a/game/src/main/org/apollo/game/service/package-info.java b/game/src/main/java/org/apollo/game/service/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/service/package-info.java rename to game/src/main/java/org/apollo/game/service/package-info.java diff --git a/game/src/main/org/apollo/game/session/ApolloHandler.java b/game/src/main/java/org/apollo/game/session/ApolloHandler.java similarity index 100% rename from game/src/main/org/apollo/game/session/ApolloHandler.java rename to game/src/main/java/org/apollo/game/session/ApolloHandler.java diff --git a/game/src/main/org/apollo/game/session/GameSession.java b/game/src/main/java/org/apollo/game/session/GameSession.java similarity index 100% rename from game/src/main/org/apollo/game/session/GameSession.java rename to game/src/main/java/org/apollo/game/session/GameSession.java diff --git a/game/src/main/org/apollo/game/session/LoginSession.java b/game/src/main/java/org/apollo/game/session/LoginSession.java similarity index 100% rename from game/src/main/org/apollo/game/session/LoginSession.java rename to game/src/main/java/org/apollo/game/session/LoginSession.java diff --git a/game/src/main/org/apollo/game/session/Session.java b/game/src/main/java/org/apollo/game/session/Session.java similarity index 100% rename from game/src/main/org/apollo/game/session/Session.java rename to game/src/main/java/org/apollo/game/session/Session.java diff --git a/game/src/main/org/apollo/game/session/UpdateSession.java b/game/src/main/java/org/apollo/game/session/UpdateSession.java similarity index 100% rename from game/src/main/org/apollo/game/session/UpdateSession.java rename to game/src/main/java/org/apollo/game/session/UpdateSession.java diff --git a/game/src/main/org/apollo/game/session/package-info.java b/game/src/main/java/org/apollo/game/session/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/session/package-info.java rename to game/src/main/java/org/apollo/game/session/package-info.java diff --git a/game/src/main/org/apollo/game/sync/ClientSynchronizer.java b/game/src/main/java/org/apollo/game/sync/ClientSynchronizer.java similarity index 100% rename from game/src/main/org/apollo/game/sync/ClientSynchronizer.java rename to game/src/main/java/org/apollo/game/sync/ClientSynchronizer.java diff --git a/game/src/main/org/apollo/game/sync/ParallelClientSynchronizer.java b/game/src/main/java/org/apollo/game/sync/ParallelClientSynchronizer.java similarity index 100% rename from game/src/main/org/apollo/game/sync/ParallelClientSynchronizer.java rename to game/src/main/java/org/apollo/game/sync/ParallelClientSynchronizer.java diff --git a/game/src/main/org/apollo/game/sync/SequentialClientSynchronizer.java b/game/src/main/java/org/apollo/game/sync/SequentialClientSynchronizer.java similarity index 100% rename from game/src/main/org/apollo/game/sync/SequentialClientSynchronizer.java rename to game/src/main/java/org/apollo/game/sync/SequentialClientSynchronizer.java diff --git a/game/src/main/org/apollo/game/sync/block/AnimationBlock.java b/game/src/main/java/org/apollo/game/sync/block/AnimationBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/AnimationBlock.java rename to game/src/main/java/org/apollo/game/sync/block/AnimationBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/AppearanceBlock.java b/game/src/main/java/org/apollo/game/sync/block/AppearanceBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/AppearanceBlock.java rename to game/src/main/java/org/apollo/game/sync/block/AppearanceBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/ChatBlock.java b/game/src/main/java/org/apollo/game/sync/block/ChatBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/ChatBlock.java rename to game/src/main/java/org/apollo/game/sync/block/ChatBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/ForceChatBlock.java b/game/src/main/java/org/apollo/game/sync/block/ForceChatBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/ForceChatBlock.java rename to game/src/main/java/org/apollo/game/sync/block/ForceChatBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/ForceMovementBlock.java b/game/src/main/java/org/apollo/game/sync/block/ForceMovementBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/ForceMovementBlock.java rename to game/src/main/java/org/apollo/game/sync/block/ForceMovementBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/GraphicBlock.java b/game/src/main/java/org/apollo/game/sync/block/GraphicBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/GraphicBlock.java rename to game/src/main/java/org/apollo/game/sync/block/GraphicBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/HitUpdateBlock.java b/game/src/main/java/org/apollo/game/sync/block/HitUpdateBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/HitUpdateBlock.java rename to game/src/main/java/org/apollo/game/sync/block/HitUpdateBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/InteractingMobBlock.java b/game/src/main/java/org/apollo/game/sync/block/InteractingMobBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/InteractingMobBlock.java rename to game/src/main/java/org/apollo/game/sync/block/InteractingMobBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/SecondaryHitUpdateBlock.java b/game/src/main/java/org/apollo/game/sync/block/SecondaryHitUpdateBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/SecondaryHitUpdateBlock.java rename to game/src/main/java/org/apollo/game/sync/block/SecondaryHitUpdateBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/SynchronizationBlock.java b/game/src/main/java/org/apollo/game/sync/block/SynchronizationBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/SynchronizationBlock.java rename to game/src/main/java/org/apollo/game/sync/block/SynchronizationBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/SynchronizationBlockSet.java b/game/src/main/java/org/apollo/game/sync/block/SynchronizationBlockSet.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/SynchronizationBlockSet.java rename to game/src/main/java/org/apollo/game/sync/block/SynchronizationBlockSet.java diff --git a/game/src/main/org/apollo/game/sync/block/TransformBlock.java b/game/src/main/java/org/apollo/game/sync/block/TransformBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/TransformBlock.java rename to game/src/main/java/org/apollo/game/sync/block/TransformBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/TurnToPositionBlock.java b/game/src/main/java/org/apollo/game/sync/block/TurnToPositionBlock.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/TurnToPositionBlock.java rename to game/src/main/java/org/apollo/game/sync/block/TurnToPositionBlock.java diff --git a/game/src/main/org/apollo/game/sync/block/package-info.java b/game/src/main/java/org/apollo/game/sync/block/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/sync/block/package-info.java rename to game/src/main/java/org/apollo/game/sync/block/package-info.java diff --git a/game/src/main/org/apollo/game/sync/package-info.java b/game/src/main/java/org/apollo/game/sync/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/sync/package-info.java rename to game/src/main/java/org/apollo/game/sync/package-info.java diff --git a/game/src/main/org/apollo/game/sync/seg/AddNpcSegment.java b/game/src/main/java/org/apollo/game/sync/seg/AddNpcSegment.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/AddNpcSegment.java rename to game/src/main/java/org/apollo/game/sync/seg/AddNpcSegment.java diff --git a/game/src/main/org/apollo/game/sync/seg/AddPlayerSegment.java b/game/src/main/java/org/apollo/game/sync/seg/AddPlayerSegment.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/AddPlayerSegment.java rename to game/src/main/java/org/apollo/game/sync/seg/AddPlayerSegment.java diff --git a/game/src/main/org/apollo/game/sync/seg/MovementSegment.java b/game/src/main/java/org/apollo/game/sync/seg/MovementSegment.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/MovementSegment.java rename to game/src/main/java/org/apollo/game/sync/seg/MovementSegment.java diff --git a/game/src/main/org/apollo/game/sync/seg/RemoveMobSegment.java b/game/src/main/java/org/apollo/game/sync/seg/RemoveMobSegment.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/RemoveMobSegment.java rename to game/src/main/java/org/apollo/game/sync/seg/RemoveMobSegment.java diff --git a/game/src/main/org/apollo/game/sync/seg/SegmentType.java b/game/src/main/java/org/apollo/game/sync/seg/SegmentType.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/SegmentType.java rename to game/src/main/java/org/apollo/game/sync/seg/SegmentType.java diff --git a/game/src/main/org/apollo/game/sync/seg/SynchronizationSegment.java b/game/src/main/java/org/apollo/game/sync/seg/SynchronizationSegment.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/SynchronizationSegment.java rename to game/src/main/java/org/apollo/game/sync/seg/SynchronizationSegment.java diff --git a/game/src/main/org/apollo/game/sync/seg/TeleportSegment.java b/game/src/main/java/org/apollo/game/sync/seg/TeleportSegment.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/TeleportSegment.java rename to game/src/main/java/org/apollo/game/sync/seg/TeleportSegment.java diff --git a/game/src/main/org/apollo/game/sync/seg/package-info.java b/game/src/main/java/org/apollo/game/sync/seg/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/sync/seg/package-info.java rename to game/src/main/java/org/apollo/game/sync/seg/package-info.java diff --git a/game/src/main/org/apollo/game/sync/task/NpcSynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/NpcSynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/NpcSynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/NpcSynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/PhasedSynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/PhasedSynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/PhasedSynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/PhasedSynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/PlayerSynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/PlayerSynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/PlayerSynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/PlayerSynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/PostNpcSynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/PostNpcSynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/PostNpcSynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/PostNpcSynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/PostPlayerSynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/PostPlayerSynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/PostPlayerSynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/PostPlayerSynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/PreNpcSynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/PreNpcSynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/PreNpcSynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/PreNpcSynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/PrePlayerSynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/PrePlayerSynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/PrePlayerSynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/PrePlayerSynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/SynchronizationTask.java b/game/src/main/java/org/apollo/game/sync/task/SynchronizationTask.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/SynchronizationTask.java rename to game/src/main/java/org/apollo/game/sync/task/SynchronizationTask.java diff --git a/game/src/main/org/apollo/game/sync/task/package-info.java b/game/src/main/java/org/apollo/game/sync/task/package-info.java similarity index 100% rename from game/src/main/org/apollo/game/sync/task/package-info.java rename to game/src/main/java/org/apollo/game/sync/task/package-info.java diff --git a/game/src/main/org/apollo/package-info.java b/game/src/main/java/org/apollo/package-info.java similarity index 100% rename from game/src/main/org/apollo/package-info.java rename to game/src/main/java/org/apollo/package-info.java diff --git a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt similarity index 97% rename from game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt rename to game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt index 71bfb4cff..4c615583e 100644 --- a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt @@ -97,7 +97,11 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess val compiledScriptClasses = mutableListOf() try { - Files.createDirectory(outputDir) + try { + Files.createDirectory(outputDir) + } catch (e: FileAlreadyExistsException) { + // do nothing... + } inputScripts.forEach { compiledScriptClasses.add(compiler.compile(it, outputDir).fqName) diff --git a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt similarity index 75% rename from game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt rename to game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index 29a84213c..c26febccd 100644 --- a/game/src/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -4,6 +4,7 @@ import org.apollo.game.message.handler.MessageHandler import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.plugin.PluginContext +import org.apollo.game.scheduling.ScheduledTask import org.apollo.net.message.Message import kotlin.reflect.KClass import kotlin.script.templates.ScriptTemplateDefinition @@ -12,11 +13,28 @@ import kotlin.script.templates.ScriptTemplateDefinition scriptFilePattern = ".*\\.plugin\\.kts" ) abstract class KotlinPluginScript(val world: World, val context: PluginContext) { + var startListener: () -> Unit = {}; + var stopListener: () -> Unit = {}; protected fun on(type: () -> KClass): KotlinMessageHandler { return KotlinMessageHandler(world, context, type.invoke()) } + protected fun start(callback: () -> Unit) { + this.startListener = callback + } + + protected fun stop(callback: () -> Unit) { + this.stopListener = callback + } + + fun doStart() { + this.startListener.invoke() + } + + fun doStop() { + this.stopListener.invoke() + } } diff --git a/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java deleted file mode 100644 index dce8bb602..000000000 --- a/game/src/main/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.apollo.game.plugin; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Constructor; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import org.apollo.game.model.World; -import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; -import org.apollo.game.plugin.kotlin.KotlinPluginScript; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.kotlin.cli.common.messages.MessageCollector; - -public class KotlinPluginEnvironment implements PluginEnvironment, MessageCollector { - - private static final Logger logger = Logger.getLogger(KotlinPluginEnvironment.class.getName()); - - private final World world; - private final KotlinPluginCompiler pluginCompiler; - - private PluginContext context; - - public KotlinPluginEnvironment(World world) { - this.world = world; - this.pluginCompiler = new KotlinPluginCompiler(resolveClasspath(), this); - } - - /** - * Resolve the classpath of the current running {@link Thread}. - * - * @return A {@link List} of {@link File}s pointing to classpath entries. - */ - private static List resolveClasspath() { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - - if (!(classLoader instanceof URLClassLoader)) { - throw new RuntimeException("Unable to resolve classpath for current ClassLoader"); - } - - URLClassLoader urlClassLoader = (URLClassLoader) classLoader; - URL[] classpathUrls = urlClassLoader.getURLs(); - List classpath = new ArrayList<>(); - - for (URL classpathUrl : classpathUrls) { - try { - classpath.add(new File(classpathUrl.toURI())); - } catch (URISyntaxException e) { - throw new RuntimeException("URL returned by ClassLoader is invalid"); - } - } - - return classpath; - } - - @Override - public void load(Collection plugins) { - try (InputStream resource = KotlinPluginEnvironment.class.getResourceAsStream("/manifest.txt")) { - BufferedReader reader = new BufferedReader(new InputStreamReader(resource)); - List pluginClassNames = reader.lines().collect(Collectors.toList()); - - for (String pluginClassName : pluginClassNames) { - Class pluginClass = - (Class) Class.forName(pluginClassName); - - Constructor pluginConstructor = - pluginClass.getConstructor(World.class, PluginContext.class); - - KotlinPluginScript plugin = pluginConstructor.newInstance(world, context); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - - List> pluginClasses = new ArrayList<>(); - List sourceRoots = new ArrayList<>(); - - for (PluginMetaData plugin : plugins) { - List pluginSourceRoots = Arrays.stream(plugin.getScripts()) - .map(script -> plugin.getBase() + "/" + script) - .collect(Collectors.toList()); - - sourceRoots.addAll(pluginSourceRoots); - } - - for (String scriptSource : sourceRoots) { -// try { - List dependencySourceRoots = new ArrayList<>(sourceRoots); - dependencySourceRoots.remove(scriptSource); - -// pluginClasses.add(pluginCompiler.compile(scriptSource)); -// } catch (KotlinPluginCompilerException e) { -// throw new RuntimeException(e); -// } - } - - for (Class pluginClass : pluginClasses) { - try { - Constructor constructor = pluginClass - .getConstructor(World.class, PluginContext.class); - - KotlinPluginScript script = constructor.newInstance(world, context); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - - @Override - public void setContext(PluginContext context) { - this.context = context; - } - - @Override - public void clear() { - - } - - @Override - public void report(@NotNull CompilerMessageSeverity severity, @NotNull String message, - @NotNull CompilerMessageLocation location) { - if (severity.isError()) { - logger.log(Level.SEVERE, String.format("%s:%s-%s: %s", location.getPath(), location.getLine(), - location.getColumn(), message)); - } - } - - @Override - public boolean hasErrors() { - return false; - } - -} diff --git a/game/data/plugins/bank/bank.plugin.kts b/game/src/plugins/bank/bank.plugin.kts similarity index 96% rename from game/data/plugins/bank/bank.plugin.kts rename to game/src/plugins/bank/bank.plugin.kts index 929ffacda..960823289 100644 --- a/game/data/plugins/bank/bank.plugin.kts +++ b/game/src/plugins/bank/bank.plugin.kts @@ -9,6 +9,7 @@ import org.apollo.net.message.Message val BANK_BOOTH_ID = 2213 + /** * Hook into the [ObjectActionMessage] and listen for when a bank booth's second action ("Open Bank") is selected. */ @@ -22,7 +23,7 @@ on { ObjectActionMessage::class } on { NpcActionMessage::class } .where { option == 2 } .then { - val npc: Npc = Any() as Npc // TODO world.npcRepository.get(index) + val npc = world.npcRepository[index] if (npc.id in BANKER_NPCS) { BankAction.start(this, it, npc.position) diff --git a/game/data/plugins/bank/plugin.xml b/game/src/plugins/bank/plugin.xml similarity index 100% rename from game/data/plugins/bank/plugin.xml rename to game/src/plugins/bank/plugin.xml diff --git a/game/src/plugins/chat/private-messaging/friends.plugin.kts b/game/src/plugins/chat/private-messaging/friends.plugin.kts new file mode 100644 index 000000000..e7fef1bb8 --- /dev/null +++ b/game/src/plugins/chat/private-messaging/friends.plugin.kts @@ -0,0 +1,23 @@ +import org.apollo.game.message.impl.AddFriendMessage +import org.apollo.game.message.impl.SendFriendMessage +import org.apollo.game.model.entity.setting.PrivacyState + +on { AddFriendMessage::class } + .then { player -> + player.addFriend(username) + + val playerUsername = player.username + val friend = world.getPlayer(username) + + if (friend == null) { + player.send(SendFriendMessage(username, 0)) + } else if (friend.friendsWith(playerUsername) || friend.friendPrivacy == PrivacyState.ON) { + if (player.friendPrivacy != PrivacyState.OFF) { + friend.send(SendFriendMessage(playerUsername, player.worldId)) + } + + if (friend.friendPrivacy != PrivacyState.OFF) { + player.send(SendFriendMessage(username, friend.worldId)) + } + } + } \ No newline at end of file diff --git a/game/src/plugins/chat/private-messaging/ignores.plugin.kts b/game/src/plugins/chat/private-messaging/ignores.plugin.kts new file mode 100644 index 000000000..a42816da1 --- /dev/null +++ b/game/src/plugins/chat/private-messaging/ignores.plugin.kts @@ -0,0 +1,8 @@ +import org.apollo.game.message.impl.AddIgnoreMessage +import org.apollo.game.message.impl.RemoveIgnoreMessage + +on { AddIgnoreMessage::class } + .then { player -> player.addIgnore(username) } + +on { RemoveIgnoreMessage::class } + .then { player -> player.removeIgnore(username) } \ No newline at end of file diff --git a/game/src/plugins/entity/spawn/spawn.kt b/game/src/plugins/entity/spawn/spawn.kt new file mode 100644 index 000000000..684bcdc0b --- /dev/null +++ b/game/src/plugins/entity/spawn/spawn.kt @@ -0,0 +1,15 @@ +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.model.* +import org.apollo.game.model.entity.Npc + +data class Spawn(val id: Int?, val name: String, val position: Position, val facing: Direction, + val spawnAnimation: Animation? = null, + val spawnGraphic: Graphic? = null) + +object Spawns { + val list = mutableListOf() +} + +fun npc_spawn(name: String, x: Int, y: Int, id: Int? = null) { + Spawns.list.add(Spawn(id, name, Position(x, y), Direction.NORTH)) +} diff --git a/game/src/plugins/entity/spawn/spawn.plugin.kts b/game/src/plugins/entity/spawn/spawn.plugin.kts new file mode 100644 index 000000000..878ab4e39 --- /dev/null +++ b/game/src/plugins/entity/spawn/spawn.plugin.kts @@ -0,0 +1,27 @@ +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.model.entity.Npc + +start { + Spawns.list.forEach { + val definition = if (it.id != null) NpcDefinition.lookup(it.id) else lookup_npc(it.name) + if (definition == null) { + throw IllegalArgumentException("Invalid NPC name or ID ${it.name}, ${it.id}") + } + + val npc = Npc(world, definition.id, it.position) + npc.turnTo(it.position.step(1, it.facing)) + + if (it.spawnAnimation != null) { + npc.playAnimation(it.spawnAnimation) + } + + if (it.spawnGraphic != null) { + npc.playGraphic(it.spawnGraphic) + } + + world.register(npc) + } +} + +stop { +} diff --git a/game/src/plugins/locations/lumbridge/lumbridge-npcs.kts b/game/src/plugins/locations/lumbridge/lumbridge-npcs.kts new file mode 100644 index 000000000..aa92c5847 --- /dev/null +++ b/game/src/plugins/locations/lumbridge/lumbridge-npcs.kts @@ -0,0 +1,10 @@ +npc_spawn("woman", id = 4, x = 3232, y = 3207) +npc_spawn("man", id = 1, x = 3231, y = 3237) +npc_spawn("man", id = 2, x = 3224, y = 3240) +npc_spawn("woman", id = 5, x = 3229, y = 2329) + +npc_spawn("hans", x = 3221, y = 3221) +npc_spawn("father aereck", x = 3243, y = 3210) +npc_spawn("shop keeper", x = 3212, y = 3247) +npc_spawn("shop assistant", x = 3211, y = 3245) +npc_spawn("lumbridge guide", x = 323, y = 3229) diff --git a/game/data/plugins/stub.kt b/game/src/plugins/stub.kt similarity index 84% rename from game/data/plugins/stub.kt rename to game/src/plugins/stub.kt index 4e6fe63f2..1f0fe80d2 100644 --- a/game/data/plugins/stub.kt +++ b/game/src/plugins/stub.kt @@ -8,7 +8,7 @@ import org.apollo.game.model.World import org.apollo.game.plugin.PluginContext -import org.apollo.game.plugin.kotlin.KotlinMessageHandler +import org.apollo.game.plugin.kotlin.* import org.apollo.net.message.Message import kotlin.reflect.KClass @@ -17,4 +17,12 @@ var context: PluginContext = null!! fun on(type: () -> KClass): KotlinMessageHandler { null!! -} \ No newline at end of file +} + +fun start(callback: () -> Unit) { + +} + +fun stop(callback: () -> Unit) { + +} diff --git a/game/src/plugins/util/lookup/lookup.kt b/game/src/plugins/util/lookup/lookup.kt new file mode 100644 index 000000000..c7395e10d --- /dev/null +++ b/game/src/plugins/util/lookup/lookup.kt @@ -0,0 +1,17 @@ +import org.apollo.cache.def.* + +fun lookup_object(name: String): ObjectDefinition? { + val definitions = ObjectDefinition.getDefinitions() + return definitions.filter { name.equals(it.name, true) }.firstOrNull() +} + +fun lookup_npc(name: String): NpcDefinition? { + val definitions = NpcDefinition.getDefinitions() + return definitions.filter { name.equals(it.name, true) }.firstOrNull() +} + +fun lookup_item(name: String): ItemDefinition? { + val definitions = ItemDefinition.getDefinitions() + return definitions.filter { name.equals(it.name, true) }.firstOrNull() +} + diff --git a/game/src/test/org/apollo/game/message/handler/ItemOnItemVerificationHandlerTests.java b/game/src/test/java/org/apollo/game/message/handler/ItemOnItemVerificationHandlerTests.java similarity index 100% rename from game/src/test/org/apollo/game/message/handler/ItemOnItemVerificationHandlerTests.java rename to game/src/test/java/org/apollo/game/message/handler/ItemOnItemVerificationHandlerTests.java diff --git a/game/src/test/org/apollo/game/message/handler/ItemOnObjectVerificationHandlerTests.java b/game/src/test/java/org/apollo/game/message/handler/ItemOnObjectVerificationHandlerTests.java similarity index 100% rename from game/src/test/org/apollo/game/message/handler/ItemOnObjectVerificationHandlerTests.java rename to game/src/test/java/org/apollo/game/message/handler/ItemOnObjectVerificationHandlerTests.java diff --git a/game/src/test/org/apollo/game/message/handler/ObjectActionVerificationHandlerTests.java b/game/src/test/java/org/apollo/game/message/handler/ObjectActionVerificationHandlerTests.java similarity index 100% rename from game/src/test/org/apollo/game/message/handler/ObjectActionVerificationHandlerTests.java rename to game/src/test/java/org/apollo/game/message/handler/ObjectActionVerificationHandlerTests.java diff --git a/game/src/test/org/apollo/game/message/handler/PublicChatMessageHandlerTests.java b/game/src/test/java/org/apollo/game/message/handler/PublicChatMessageHandlerTests.java similarity index 100% rename from game/src/test/org/apollo/game/message/handler/PublicChatMessageHandlerTests.java rename to game/src/test/java/org/apollo/game/message/handler/PublicChatMessageHandlerTests.java diff --git a/game/src/test/org/apollo/game/model/PositionTests.java b/game/src/test/java/org/apollo/game/model/PositionTests.java similarity index 100% rename from game/src/test/org/apollo/game/model/PositionTests.java rename to game/src/test/java/org/apollo/game/model/PositionTests.java diff --git a/game/src/test/org/apollo/game/model/area/collision/CollisionManagerTests.java b/game/src/test/java/org/apollo/game/model/area/collision/CollisionManagerTests.java similarity index 100% rename from game/src/test/org/apollo/game/model/area/collision/CollisionManagerTests.java rename to game/src/test/java/org/apollo/game/model/area/collision/CollisionManagerTests.java diff --git a/game/src/test/org/apollo/game/model/entity/MobRepositoryTests.java b/game/src/test/java/org/apollo/game/model/entity/MobRepositoryTests.java similarity index 100% rename from game/src/test/org/apollo/game/model/entity/MobRepositoryTests.java rename to game/src/test/java/org/apollo/game/model/entity/MobRepositoryTests.java diff --git a/game/src/test/org/apollo/game/model/entity/SkillSetTests.java b/game/src/test/java/org/apollo/game/model/entity/SkillSetTests.java similarity index 100% rename from game/src/test/org/apollo/game/model/entity/SkillSetTests.java rename to game/src/test/java/org/apollo/game/model/entity/SkillSetTests.java diff --git a/game/src/test/org/apollo/game/model/entity/attr/AttributeTests.java b/game/src/test/java/org/apollo/game/model/entity/attr/AttributeTests.java similarity index 100% rename from game/src/test/org/apollo/game/model/entity/attr/AttributeTests.java rename to game/src/test/java/org/apollo/game/model/entity/attr/AttributeTests.java diff --git a/net/src/main/org/apollo/net/HttpChannelInitializer.java b/net/src/main/java/org/apollo/net/HttpChannelInitializer.java similarity index 100% rename from net/src/main/org/apollo/net/HttpChannelInitializer.java rename to net/src/main/java/org/apollo/net/HttpChannelInitializer.java diff --git a/net/src/main/org/apollo/net/JagGrabChannelInitializer.java b/net/src/main/java/org/apollo/net/JagGrabChannelInitializer.java similarity index 100% rename from net/src/main/org/apollo/net/JagGrabChannelInitializer.java rename to net/src/main/java/org/apollo/net/JagGrabChannelInitializer.java diff --git a/net/src/main/org/apollo/net/NetworkConstants.java b/net/src/main/java/org/apollo/net/NetworkConstants.java similarity index 100% rename from net/src/main/org/apollo/net/NetworkConstants.java rename to net/src/main/java/org/apollo/net/NetworkConstants.java diff --git a/net/src/main/org/apollo/net/ServiceChannelInitializer.java b/net/src/main/java/org/apollo/net/ServiceChannelInitializer.java similarity index 100% rename from net/src/main/org/apollo/net/ServiceChannelInitializer.java rename to net/src/main/java/org/apollo/net/ServiceChannelInitializer.java diff --git a/net/src/main/org/apollo/net/codec/game/AccessMode.java b/net/src/main/java/org/apollo/net/codec/game/AccessMode.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/AccessMode.java rename to net/src/main/java/org/apollo/net/codec/game/AccessMode.java diff --git a/net/src/main/org/apollo/net/codec/game/DataConstants.java b/net/src/main/java/org/apollo/net/codec/game/DataConstants.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/DataConstants.java rename to net/src/main/java/org/apollo/net/codec/game/DataConstants.java diff --git a/net/src/main/org/apollo/net/codec/game/DataOrder.java b/net/src/main/java/org/apollo/net/codec/game/DataOrder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/DataOrder.java rename to net/src/main/java/org/apollo/net/codec/game/DataOrder.java diff --git a/net/src/main/org/apollo/net/codec/game/DataTransformation.java b/net/src/main/java/org/apollo/net/codec/game/DataTransformation.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/DataTransformation.java rename to net/src/main/java/org/apollo/net/codec/game/DataTransformation.java diff --git a/net/src/main/org/apollo/net/codec/game/DataType.java b/net/src/main/java/org/apollo/net/codec/game/DataType.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/DataType.java rename to net/src/main/java/org/apollo/net/codec/game/DataType.java diff --git a/net/src/main/org/apollo/net/codec/game/GameDecoderState.java b/net/src/main/java/org/apollo/net/codec/game/GameDecoderState.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GameDecoderState.java rename to net/src/main/java/org/apollo/net/codec/game/GameDecoderState.java diff --git a/net/src/main/org/apollo/net/codec/game/GameMessageDecoder.java b/net/src/main/java/org/apollo/net/codec/game/GameMessageDecoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GameMessageDecoder.java rename to net/src/main/java/org/apollo/net/codec/game/GameMessageDecoder.java diff --git a/net/src/main/org/apollo/net/codec/game/GameMessageEncoder.java b/net/src/main/java/org/apollo/net/codec/game/GameMessageEncoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GameMessageEncoder.java rename to net/src/main/java/org/apollo/net/codec/game/GameMessageEncoder.java diff --git a/net/src/main/org/apollo/net/codec/game/GamePacket.java b/net/src/main/java/org/apollo/net/codec/game/GamePacket.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GamePacket.java rename to net/src/main/java/org/apollo/net/codec/game/GamePacket.java diff --git a/net/src/main/org/apollo/net/codec/game/GamePacketBuilder.java b/net/src/main/java/org/apollo/net/codec/game/GamePacketBuilder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GamePacketBuilder.java rename to net/src/main/java/org/apollo/net/codec/game/GamePacketBuilder.java diff --git a/net/src/main/org/apollo/net/codec/game/GamePacketDecoder.java b/net/src/main/java/org/apollo/net/codec/game/GamePacketDecoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GamePacketDecoder.java rename to net/src/main/java/org/apollo/net/codec/game/GamePacketDecoder.java diff --git a/net/src/main/org/apollo/net/codec/game/GamePacketEncoder.java b/net/src/main/java/org/apollo/net/codec/game/GamePacketEncoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GamePacketEncoder.java rename to net/src/main/java/org/apollo/net/codec/game/GamePacketEncoder.java diff --git a/net/src/main/org/apollo/net/codec/game/GamePacketReader.java b/net/src/main/java/org/apollo/net/codec/game/GamePacketReader.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/GamePacketReader.java rename to net/src/main/java/org/apollo/net/codec/game/GamePacketReader.java diff --git a/net/src/main/org/apollo/net/codec/game/package-info.java b/net/src/main/java/org/apollo/net/codec/game/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/codec/game/package-info.java rename to net/src/main/java/org/apollo/net/codec/game/package-info.java diff --git a/net/src/main/org/apollo/net/codec/handshake/HandshakeConstants.java b/net/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java similarity index 100% rename from net/src/main/org/apollo/net/codec/handshake/HandshakeConstants.java rename to net/src/main/java/org/apollo/net/codec/handshake/HandshakeConstants.java diff --git a/net/src/main/org/apollo/net/codec/handshake/HandshakeDecoder.java b/net/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/handshake/HandshakeDecoder.java rename to net/src/main/java/org/apollo/net/codec/handshake/HandshakeDecoder.java diff --git a/net/src/main/org/apollo/net/codec/handshake/HandshakeMessage.java b/net/src/main/java/org/apollo/net/codec/handshake/HandshakeMessage.java similarity index 100% rename from net/src/main/org/apollo/net/codec/handshake/HandshakeMessage.java rename to net/src/main/java/org/apollo/net/codec/handshake/HandshakeMessage.java diff --git a/net/src/main/org/apollo/net/codec/handshake/package-info.java b/net/src/main/java/org/apollo/net/codec/handshake/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/codec/handshake/package-info.java rename to net/src/main/java/org/apollo/net/codec/handshake/package-info.java diff --git a/net/src/main/org/apollo/net/codec/jaggrab/JagGrabRequest.java b/net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequest.java similarity index 100% rename from net/src/main/org/apollo/net/codec/jaggrab/JagGrabRequest.java rename to net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequest.java diff --git a/net/src/main/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java b/net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java rename to net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabRequestDecoder.java diff --git a/net/src/main/org/apollo/net/codec/jaggrab/JagGrabResponse.java b/net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponse.java similarity index 100% rename from net/src/main/org/apollo/net/codec/jaggrab/JagGrabResponse.java rename to net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponse.java diff --git a/net/src/main/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java b/net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java rename to net/src/main/java/org/apollo/net/codec/jaggrab/JagGrabResponseEncoder.java diff --git a/net/src/main/org/apollo/net/codec/jaggrab/package-info.java b/net/src/main/java/org/apollo/net/codec/jaggrab/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/codec/jaggrab/package-info.java rename to net/src/main/java/org/apollo/net/codec/jaggrab/package-info.java diff --git a/net/src/main/org/apollo/net/codec/login/LoginConstants.java b/net/src/main/java/org/apollo/net/codec/login/LoginConstants.java similarity index 100% rename from net/src/main/org/apollo/net/codec/login/LoginConstants.java rename to net/src/main/java/org/apollo/net/codec/login/LoginConstants.java diff --git a/net/src/main/org/apollo/net/codec/login/LoginDecoder.java b/net/src/main/java/org/apollo/net/codec/login/LoginDecoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/login/LoginDecoder.java rename to net/src/main/java/org/apollo/net/codec/login/LoginDecoder.java diff --git a/net/src/main/org/apollo/net/codec/login/LoginDecoderState.java b/net/src/main/java/org/apollo/net/codec/login/LoginDecoderState.java similarity index 100% rename from net/src/main/org/apollo/net/codec/login/LoginDecoderState.java rename to net/src/main/java/org/apollo/net/codec/login/LoginDecoderState.java diff --git a/net/src/main/org/apollo/net/codec/login/LoginEncoder.java b/net/src/main/java/org/apollo/net/codec/login/LoginEncoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/login/LoginEncoder.java rename to net/src/main/java/org/apollo/net/codec/login/LoginEncoder.java diff --git a/net/src/main/org/apollo/net/codec/login/LoginRequest.java b/net/src/main/java/org/apollo/net/codec/login/LoginRequest.java similarity index 100% rename from net/src/main/org/apollo/net/codec/login/LoginRequest.java rename to net/src/main/java/org/apollo/net/codec/login/LoginRequest.java diff --git a/net/src/main/org/apollo/net/codec/login/LoginResponse.java b/net/src/main/java/org/apollo/net/codec/login/LoginResponse.java similarity index 100% rename from net/src/main/org/apollo/net/codec/login/LoginResponse.java rename to net/src/main/java/org/apollo/net/codec/login/LoginResponse.java diff --git a/net/src/main/org/apollo/net/codec/login/package-info.java b/net/src/main/java/org/apollo/net/codec/login/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/codec/login/package-info.java rename to net/src/main/java/org/apollo/net/codec/login/package-info.java diff --git a/net/src/main/org/apollo/net/codec/update/OnDemandRequest.java b/net/src/main/java/org/apollo/net/codec/update/OnDemandRequest.java similarity index 100% rename from net/src/main/org/apollo/net/codec/update/OnDemandRequest.java rename to net/src/main/java/org/apollo/net/codec/update/OnDemandRequest.java diff --git a/net/src/main/org/apollo/net/codec/update/OnDemandResponse.java b/net/src/main/java/org/apollo/net/codec/update/OnDemandResponse.java similarity index 100% rename from net/src/main/org/apollo/net/codec/update/OnDemandResponse.java rename to net/src/main/java/org/apollo/net/codec/update/OnDemandResponse.java diff --git a/net/src/main/org/apollo/net/codec/update/UpdateDecoder.java b/net/src/main/java/org/apollo/net/codec/update/UpdateDecoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/update/UpdateDecoder.java rename to net/src/main/java/org/apollo/net/codec/update/UpdateDecoder.java diff --git a/net/src/main/org/apollo/net/codec/update/UpdateEncoder.java b/net/src/main/java/org/apollo/net/codec/update/UpdateEncoder.java similarity index 100% rename from net/src/main/org/apollo/net/codec/update/UpdateEncoder.java rename to net/src/main/java/org/apollo/net/codec/update/UpdateEncoder.java diff --git a/net/src/main/org/apollo/net/codec/update/package-info.java b/net/src/main/java/org/apollo/net/codec/update/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/codec/update/package-info.java rename to net/src/main/java/org/apollo/net/codec/update/package-info.java diff --git a/net/src/main/org/apollo/net/message/Message.java b/net/src/main/java/org/apollo/net/message/Message.java similarity index 100% rename from net/src/main/org/apollo/net/message/Message.java rename to net/src/main/java/org/apollo/net/message/Message.java diff --git a/net/src/main/org/apollo/net/message/package-info.java b/net/src/main/java/org/apollo/net/message/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/message/package-info.java rename to net/src/main/java/org/apollo/net/message/package-info.java diff --git a/net/src/main/org/apollo/net/meta/PacketMetaData.java b/net/src/main/java/org/apollo/net/meta/PacketMetaData.java similarity index 100% rename from net/src/main/org/apollo/net/meta/PacketMetaData.java rename to net/src/main/java/org/apollo/net/meta/PacketMetaData.java diff --git a/net/src/main/org/apollo/net/meta/PacketMetaDataGroup.java b/net/src/main/java/org/apollo/net/meta/PacketMetaDataGroup.java similarity index 100% rename from net/src/main/org/apollo/net/meta/PacketMetaDataGroup.java rename to net/src/main/java/org/apollo/net/meta/PacketMetaDataGroup.java diff --git a/net/src/main/org/apollo/net/meta/PacketType.java b/net/src/main/java/org/apollo/net/meta/PacketType.java similarity index 100% rename from net/src/main/org/apollo/net/meta/PacketType.java rename to net/src/main/java/org/apollo/net/meta/PacketType.java diff --git a/net/src/main/org/apollo/net/meta/package-info.java b/net/src/main/java/org/apollo/net/meta/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/meta/package-info.java rename to net/src/main/java/org/apollo/net/meta/package-info.java diff --git a/net/src/main/org/apollo/net/package-info.java b/net/src/main/java/org/apollo/net/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/package-info.java rename to net/src/main/java/org/apollo/net/package-info.java diff --git a/net/src/main/org/apollo/net/release/MessageDecoder.java b/net/src/main/java/org/apollo/net/release/MessageDecoder.java similarity index 100% rename from net/src/main/org/apollo/net/release/MessageDecoder.java rename to net/src/main/java/org/apollo/net/release/MessageDecoder.java diff --git a/net/src/main/org/apollo/net/release/MessageEncoder.java b/net/src/main/java/org/apollo/net/release/MessageEncoder.java similarity index 100% rename from net/src/main/org/apollo/net/release/MessageEncoder.java rename to net/src/main/java/org/apollo/net/release/MessageEncoder.java diff --git a/net/src/main/org/apollo/net/release/Release.java b/net/src/main/java/org/apollo/net/release/Release.java similarity index 100% rename from net/src/main/org/apollo/net/release/Release.java rename to net/src/main/java/org/apollo/net/release/Release.java diff --git a/net/src/main/org/apollo/net/release/package-info.java b/net/src/main/java/org/apollo/net/release/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/release/package-info.java rename to net/src/main/java/org/apollo/net/release/package-info.java diff --git a/net/src/main/org/apollo/net/update/ChannelRequest.java b/net/src/main/java/org/apollo/net/update/ChannelRequest.java similarity index 100% rename from net/src/main/org/apollo/net/update/ChannelRequest.java rename to net/src/main/java/org/apollo/net/update/ChannelRequest.java diff --git a/net/src/main/org/apollo/net/update/ComparableChannelRequest.java b/net/src/main/java/org/apollo/net/update/ComparableChannelRequest.java similarity index 100% rename from net/src/main/org/apollo/net/update/ComparableChannelRequest.java rename to net/src/main/java/org/apollo/net/update/ComparableChannelRequest.java diff --git a/net/src/main/org/apollo/net/update/HttpRequestWorker.java b/net/src/main/java/org/apollo/net/update/HttpRequestWorker.java similarity index 100% rename from net/src/main/org/apollo/net/update/HttpRequestWorker.java rename to net/src/main/java/org/apollo/net/update/HttpRequestWorker.java diff --git a/net/src/main/org/apollo/net/update/JagGrabRequestWorker.java b/net/src/main/java/org/apollo/net/update/JagGrabRequestWorker.java similarity index 100% rename from net/src/main/org/apollo/net/update/JagGrabRequestWorker.java rename to net/src/main/java/org/apollo/net/update/JagGrabRequestWorker.java diff --git a/net/src/main/org/apollo/net/update/OnDemandRequestWorker.java b/net/src/main/java/org/apollo/net/update/OnDemandRequestWorker.java similarity index 100% rename from net/src/main/org/apollo/net/update/OnDemandRequestWorker.java rename to net/src/main/java/org/apollo/net/update/OnDemandRequestWorker.java diff --git a/net/src/main/org/apollo/net/update/RequestWorker.java b/net/src/main/java/org/apollo/net/update/RequestWorker.java similarity index 100% rename from net/src/main/org/apollo/net/update/RequestWorker.java rename to net/src/main/java/org/apollo/net/update/RequestWorker.java diff --git a/net/src/main/org/apollo/net/update/UpdateConstants.java b/net/src/main/java/org/apollo/net/update/UpdateConstants.java similarity index 100% rename from net/src/main/org/apollo/net/update/UpdateConstants.java rename to net/src/main/java/org/apollo/net/update/UpdateConstants.java diff --git a/net/src/main/org/apollo/net/update/UpdateDispatcher.java b/net/src/main/java/org/apollo/net/update/UpdateDispatcher.java similarity index 100% rename from net/src/main/org/apollo/net/update/UpdateDispatcher.java rename to net/src/main/java/org/apollo/net/update/UpdateDispatcher.java diff --git a/net/src/main/org/apollo/net/update/package-info.java b/net/src/main/java/org/apollo/net/update/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/update/package-info.java rename to net/src/main/java/org/apollo/net/update/package-info.java diff --git a/net/src/main/org/apollo/net/update/resource/CombinedResourceProvider.java b/net/src/main/java/org/apollo/net/update/resource/CombinedResourceProvider.java similarity index 100% rename from net/src/main/org/apollo/net/update/resource/CombinedResourceProvider.java rename to net/src/main/java/org/apollo/net/update/resource/CombinedResourceProvider.java diff --git a/net/src/main/org/apollo/net/update/resource/HypertextResourceProvider.java b/net/src/main/java/org/apollo/net/update/resource/HypertextResourceProvider.java similarity index 100% rename from net/src/main/org/apollo/net/update/resource/HypertextResourceProvider.java rename to net/src/main/java/org/apollo/net/update/resource/HypertextResourceProvider.java diff --git a/net/src/main/org/apollo/net/update/resource/ResourceProvider.java b/net/src/main/java/org/apollo/net/update/resource/ResourceProvider.java similarity index 100% rename from net/src/main/org/apollo/net/update/resource/ResourceProvider.java rename to net/src/main/java/org/apollo/net/update/resource/ResourceProvider.java diff --git a/net/src/main/org/apollo/net/update/resource/VirtualResourceProvider.java b/net/src/main/java/org/apollo/net/update/resource/VirtualResourceProvider.java similarity index 100% rename from net/src/main/org/apollo/net/update/resource/VirtualResourceProvider.java rename to net/src/main/java/org/apollo/net/update/resource/VirtualResourceProvider.java diff --git a/net/src/main/org/apollo/net/update/resource/package-info.java b/net/src/main/java/org/apollo/net/update/resource/package-info.java similarity index 100% rename from net/src/main/org/apollo/net/update/resource/package-info.java rename to net/src/main/java/org/apollo/net/update/resource/package-info.java diff --git a/net/src/test/org/apollo/net/codec/game/GamePacketEncoderTests.java b/net/src/test/java/org/apollo/net/codec/game/GamePacketEncoderTests.java similarity index 100% rename from net/src/test/org/apollo/net/codec/game/GamePacketEncoderTests.java rename to net/src/test/java/org/apollo/net/codec/game/GamePacketEncoderTests.java diff --git a/util/src/main/org/apollo/util/BufferUtil.java b/util/src/main/java/org/apollo/util/BufferUtil.java similarity index 100% rename from util/src/main/org/apollo/util/BufferUtil.java rename to util/src/main/java/org/apollo/util/BufferUtil.java diff --git a/util/src/main/org/apollo/util/CollectionUtil.java b/util/src/main/java/org/apollo/util/CollectionUtil.java similarity index 100% rename from util/src/main/org/apollo/util/CollectionUtil.java rename to util/src/main/java/org/apollo/util/CollectionUtil.java diff --git a/util/src/main/org/apollo/util/CompressionUtil.java b/util/src/main/java/org/apollo/util/CompressionUtil.java similarity index 100% rename from util/src/main/org/apollo/util/CompressionUtil.java rename to util/src/main/java/org/apollo/util/CompressionUtil.java diff --git a/util/src/main/org/apollo/util/LanguageUtil.java b/util/src/main/java/org/apollo/util/LanguageUtil.java similarity index 100% rename from util/src/main/org/apollo/util/LanguageUtil.java rename to util/src/main/java/org/apollo/util/LanguageUtil.java diff --git a/util/src/main/org/apollo/util/NameUtil.java b/util/src/main/java/org/apollo/util/NameUtil.java similarity index 100% rename from util/src/main/org/apollo/util/NameUtil.java rename to util/src/main/java/org/apollo/util/NameUtil.java diff --git a/util/src/main/org/apollo/util/Point.java b/util/src/main/java/org/apollo/util/Point.java similarity index 100% rename from util/src/main/org/apollo/util/Point.java rename to util/src/main/java/org/apollo/util/Point.java diff --git a/util/src/main/org/apollo/util/StatefulFrameDecoder.java b/util/src/main/java/org/apollo/util/StatefulFrameDecoder.java similarity index 100% rename from util/src/main/org/apollo/util/StatefulFrameDecoder.java rename to util/src/main/java/org/apollo/util/StatefulFrameDecoder.java diff --git a/util/src/main/org/apollo/util/StreamUtil.java b/util/src/main/java/org/apollo/util/StreamUtil.java similarity index 100% rename from util/src/main/org/apollo/util/StreamUtil.java rename to util/src/main/java/org/apollo/util/StreamUtil.java diff --git a/util/src/main/org/apollo/util/TextUtil.java b/util/src/main/java/org/apollo/util/TextUtil.java similarity index 100% rename from util/src/main/org/apollo/util/TextUtil.java rename to util/src/main/java/org/apollo/util/TextUtil.java diff --git a/util/src/main/org/apollo/util/ThreadUtil.java b/util/src/main/java/org/apollo/util/ThreadUtil.java similarity index 100% rename from util/src/main/org/apollo/util/ThreadUtil.java rename to util/src/main/java/org/apollo/util/ThreadUtil.java diff --git a/util/src/main/org/apollo/util/package-info.java b/util/src/main/java/org/apollo/util/package-info.java similarity index 100% rename from util/src/main/org/apollo/util/package-info.java rename to util/src/main/java/org/apollo/util/package-info.java diff --git a/util/src/main/org/apollo/util/security/IsaacRandom.java b/util/src/main/java/org/apollo/util/security/IsaacRandom.java similarity index 100% rename from util/src/main/org/apollo/util/security/IsaacRandom.java rename to util/src/main/java/org/apollo/util/security/IsaacRandom.java diff --git a/util/src/main/org/apollo/util/security/IsaacRandomPair.java b/util/src/main/java/org/apollo/util/security/IsaacRandomPair.java similarity index 100% rename from util/src/main/org/apollo/util/security/IsaacRandomPair.java rename to util/src/main/java/org/apollo/util/security/IsaacRandomPair.java diff --git a/util/src/main/org/apollo/util/security/PlayerCredentials.java b/util/src/main/java/org/apollo/util/security/PlayerCredentials.java similarity index 100% rename from util/src/main/org/apollo/util/security/PlayerCredentials.java rename to util/src/main/java/org/apollo/util/security/PlayerCredentials.java diff --git a/util/src/main/org/apollo/util/security/package-info.java b/util/src/main/java/org/apollo/util/security/package-info.java similarity index 100% rename from util/src/main/org/apollo/util/security/package-info.java rename to util/src/main/java/org/apollo/util/security/package-info.java diff --git a/util/src/main/org/apollo/util/tools/EquipmentConstants.java b/util/src/main/java/org/apollo/util/tools/EquipmentConstants.java similarity index 100% rename from util/src/main/org/apollo/util/tools/EquipmentConstants.java rename to util/src/main/java/org/apollo/util/tools/EquipmentConstants.java diff --git a/util/src/main/org/apollo/util/tools/RsaKeyGenerator.java b/util/src/main/java/org/apollo/util/tools/RsaKeyGenerator.java similarity index 100% rename from util/src/main/org/apollo/util/tools/RsaKeyGenerator.java rename to util/src/main/java/org/apollo/util/tools/RsaKeyGenerator.java diff --git a/util/src/main/org/apollo/util/tools/package-info.java b/util/src/main/java/org/apollo/util/tools/package-info.java similarity index 100% rename from util/src/main/org/apollo/util/tools/package-info.java rename to util/src/main/java/org/apollo/util/tools/package-info.java diff --git a/util/src/main/org/apollo/util/xml/XmlNode.java b/util/src/main/java/org/apollo/util/xml/XmlNode.java similarity index 100% rename from util/src/main/org/apollo/util/xml/XmlNode.java rename to util/src/main/java/org/apollo/util/xml/XmlNode.java diff --git a/util/src/main/org/apollo/util/xml/XmlParser.java b/util/src/main/java/org/apollo/util/xml/XmlParser.java similarity index 100% rename from util/src/main/org/apollo/util/xml/XmlParser.java rename to util/src/main/java/org/apollo/util/xml/XmlParser.java diff --git a/util/src/main/org/apollo/util/xml/package-info.java b/util/src/main/java/org/apollo/util/xml/package-info.java similarity index 100% rename from util/src/main/org/apollo/util/xml/package-info.java rename to util/src/main/java/org/apollo/util/xml/package-info.java diff --git a/util/src/test/org/apollo/util/BufferUtilTests.java b/util/src/test/java/org/apollo/util/BufferUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/BufferUtilTests.java rename to util/src/test/java/org/apollo/util/BufferUtilTests.java diff --git a/util/src/test/org/apollo/util/CollectionUtilTests.java b/util/src/test/java/org/apollo/util/CollectionUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/CollectionUtilTests.java rename to util/src/test/java/org/apollo/util/CollectionUtilTests.java diff --git a/util/src/test/org/apollo/util/CompressionUtilTests.java b/util/src/test/java/org/apollo/util/CompressionUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/CompressionUtilTests.java rename to util/src/test/java/org/apollo/util/CompressionUtilTests.java diff --git a/util/src/test/org/apollo/util/LanguageUtilTests.java b/util/src/test/java/org/apollo/util/LanguageUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/LanguageUtilTests.java rename to util/src/test/java/org/apollo/util/LanguageUtilTests.java diff --git a/util/src/test/org/apollo/util/NameUtilTests.java b/util/src/test/java/org/apollo/util/NameUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/NameUtilTests.java rename to util/src/test/java/org/apollo/util/NameUtilTests.java diff --git a/util/src/test/org/apollo/util/StreamUtilTests.java b/util/src/test/java/org/apollo/util/StreamUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/StreamUtilTests.java rename to util/src/test/java/org/apollo/util/StreamUtilTests.java diff --git a/util/src/test/org/apollo/util/TextUtilTests.java b/util/src/test/java/org/apollo/util/TextUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/TextUtilTests.java rename to util/src/test/java/org/apollo/util/TextUtilTests.java diff --git a/util/src/test/org/apollo/util/ThreadUtilTests.java b/util/src/test/java/org/apollo/util/ThreadUtilTests.java similarity index 100% rename from util/src/test/org/apollo/util/ThreadUtilTests.java rename to util/src/test/java/org/apollo/util/ThreadUtilTests.java diff --git a/util/src/test/org/apollo/util/xml/XmlParserTests.java b/util/src/test/java/org/apollo/util/xml/XmlParserTests.java similarity index 100% rename from util/src/test/org/apollo/util/xml/XmlParserTests.java rename to util/src/test/java/org/apollo/util/xml/XmlParserTests.java From 48e1726bc09fc030264562d05cea4115308248d7 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 28 May 2017 23:07:05 +0100 Subject: [PATCH 005/209] Remove 'world' object from global script scope --- .../game/plugin/KotlinPluginEnvironment.java | 2 +- .../game/plugin/kotlin/KotlinPluginScript.kt | 18 +++++++++--------- game/src/plugins/bank/bank.plugin.kts | 2 +- .../chat/private-messaging/friends.plugin.kts | 18 +++++++++--------- .../chat/private-messaging/ignores.plugin.kts | 4 ++-- game/src/plugins/entity/spawn/spawn.plugin.kts | 5 +---- game/src/plugins/stub.kt | 7 ++----- 7 files changed, 25 insertions(+), 31 deletions(-) diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java index d433db178..b2e74222f 100644 --- a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -55,7 +55,7 @@ public void load(Collection plugins) { throw new RuntimeException(e); } - pluginScripts.forEach(KotlinPluginScript::doStart); + pluginScripts.forEach(script -> script.doStart(world)); } @Override diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index c26febccd..1a9541a30 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -12,28 +12,28 @@ import kotlin.script.templates.ScriptTemplateDefinition @ScriptTemplateDefinition( scriptFilePattern = ".*\\.plugin\\.kts" ) -abstract class KotlinPluginScript(val world: World, val context: PluginContext) { - var startListener: () -> Unit = {}; - var stopListener: () -> Unit = {}; +abstract class KotlinPluginScript(private var world: World, val context: PluginContext) { + var startListener: (World) -> Unit = { _ -> }; + var stopListener: (World) -> Unit = { _ -> }; protected fun on(type: () -> KClass): KotlinMessageHandler { return KotlinMessageHandler(world, context, type.invoke()) } - protected fun start(callback: () -> Unit) { + protected fun start(callback: (World) -> Unit) { this.startListener = callback } - protected fun stop(callback: () -> Unit) { + protected fun stop(callback: (World) -> Unit) { this.stopListener = callback } - fun doStart() { - this.startListener.invoke() + fun doStart(world: World) { + this.startListener.invoke(world) } - fun doStop() { - this.stopListener.invoke() + fun doStop(world: World) { + this.stopListener.invoke(world) } } diff --git a/game/src/plugins/bank/bank.plugin.kts b/game/src/plugins/bank/bank.plugin.kts index 960823289..10d424e34 100644 --- a/game/src/plugins/bank/bank.plugin.kts +++ b/game/src/plugins/bank/bank.plugin.kts @@ -23,7 +23,7 @@ on { ObjectActionMessage::class } on { NpcActionMessage::class } .where { option == 2 } .then { - val npc = world.npcRepository[index] + val npc = it.world.npcRepository[index] if (npc.id in BANKER_NPCS) { BankAction.start(this, it, npc.position) diff --git a/game/src/plugins/chat/private-messaging/friends.plugin.kts b/game/src/plugins/chat/private-messaging/friends.plugin.kts index e7fef1bb8..ea7ced88c 100644 --- a/game/src/plugins/chat/private-messaging/friends.plugin.kts +++ b/game/src/plugins/chat/private-messaging/friends.plugin.kts @@ -3,21 +3,21 @@ import org.apollo.game.message.impl.SendFriendMessage import org.apollo.game.model.entity.setting.PrivacyState on { AddFriendMessage::class } - .then { player -> - player.addFriend(username) + .then { + it.addFriend(username) - val playerUsername = player.username - val friend = world.getPlayer(username) + val playerUsername = it.username + val friend = it.world.getPlayer(username) if (friend == null) { - player.send(SendFriendMessage(username, 0)) + it.send(SendFriendMessage(username, 0)) } else if (friend.friendsWith(playerUsername) || friend.friendPrivacy == PrivacyState.ON) { - if (player.friendPrivacy != PrivacyState.OFF) { - friend.send(SendFriendMessage(playerUsername, player.worldId)) + if (it.friendPrivacy != PrivacyState.OFF) { + friend.send(SendFriendMessage(playerUsername, it.worldId)) } if (friend.friendPrivacy != PrivacyState.OFF) { - player.send(SendFriendMessage(username, friend.worldId)) + it.send(SendFriendMessage(username, friend.worldId)) } } - } \ No newline at end of file + } diff --git a/game/src/plugins/chat/private-messaging/ignores.plugin.kts b/game/src/plugins/chat/private-messaging/ignores.plugin.kts index a42816da1..47b0f29fe 100644 --- a/game/src/plugins/chat/private-messaging/ignores.plugin.kts +++ b/game/src/plugins/chat/private-messaging/ignores.plugin.kts @@ -2,7 +2,7 @@ import org.apollo.game.message.impl.AddIgnoreMessage import org.apollo.game.message.impl.RemoveIgnoreMessage on { AddIgnoreMessage::class } - .then { player -> player.addIgnore(username) } + .then { it.addIgnore(username) } on { RemoveIgnoreMessage::class } - .then { player -> player.removeIgnore(username) } \ No newline at end of file + .then { it.removeIgnore(username) } \ No newline at end of file diff --git a/game/src/plugins/entity/spawn/spawn.plugin.kts b/game/src/plugins/entity/spawn/spawn.plugin.kts index 878ab4e39..cb65aacec 100644 --- a/game/src/plugins/entity/spawn/spawn.plugin.kts +++ b/game/src/plugins/entity/spawn/spawn.plugin.kts @@ -1,7 +1,7 @@ import org.apollo.cache.def.NpcDefinition import org.apollo.game.model.entity.Npc -start { +start { world -> Spawns.list.forEach { val definition = if (it.id != null) NpcDefinition.lookup(it.id) else lookup_npc(it.name) if (definition == null) { @@ -22,6 +22,3 @@ start { world.register(npc) } } - -stop { -} diff --git a/game/src/plugins/stub.kt b/game/src/plugins/stub.kt index 1f0fe80d2..8c5837043 100644 --- a/game/src/plugins/stub.kt +++ b/game/src/plugins/stub.kt @@ -12,17 +12,14 @@ import org.apollo.game.plugin.kotlin.* import org.apollo.net.message.Message import kotlin.reflect.KClass -val world: World = null!! -var context: PluginContext = null!! - fun on(type: () -> KClass): KotlinMessageHandler { null!! } -fun start(callback: () -> Unit) { +fun start(callback: (World) -> Unit) { } -fun stop(callback: () -> Unit) { +fun stop(callback: (World) -> Unit) { } From ad72036853ff845141038a7e4d179ff2124df55f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 28 May 2017 23:07:41 +0100 Subject: [PATCH 006/209] Add port of the 'dummys' plugin from Ruby --- game/src/plugins/dummy/dummy.plugin.kts | 74 +++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 game/src/plugins/dummy/dummy.plugin.kts diff --git a/game/src/plugins/dummy/dummy.plugin.kts b/game/src/plugins/dummy/dummy.plugin.kts new file mode 100644 index 000000000..eed2880d8 --- /dev/null +++ b/game/src/plugins/dummy/dummy.plugin.kts @@ -0,0 +1,74 @@ +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Animation +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.net.message.Message + +/** + * A list of [ObjectDefinition] identifiers which are training dummies. + */ +val DUMMY_IDS = setOf(823) + +on { ObjectActionMessage::class } + .where { option == 2 && id in DUMMY_IDS } + .then { DummyAction.start(this, it, position) } + +class DummyAction(val player: Player, position: Position) : DistancedAction(0, true, player, position, DISTANCE) { + + companion object { + + /** + * The maximum level a player can be before the dummy stops giving XP. + */ + const val LEVEL_THRESHOLD = 8 + + /** + * The number of experience points per hit. + */ + const val EXP_PER_HIT = 5.0 + + /** + * The minimum distance a player can be from the dummy. + */ + const val DISTANCE = 1 + + /** + * The [Animation] played when a player hits a dummy. + */ + val PUNCH_ANIMATION = Animation(422) + + /** + * Starts a [DummyAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: Message, player: Player, position: Position) { + player.startAction(DummyAction(player, position)) + message.terminate() + } + + } + + var started = false + + override fun executeAction() { + if (started) { + val skills = player.skillSet + + if (skills.getSkill(Skill.ATTACK).maximumLevel >= LEVEL_THRESHOLD) { + player.sendMessage("There is nothing more you can learn from hitting a dummy.") + } else { + skills.addExperience(Skill.ATTACK, EXP_PER_HIT) + } + + stop() + } else { + mob.sendMessage("You hit the dummy.") + mob.turnTo(this.position) + mob.playAnimation(PUNCH_ANIMATION) + + started = true + } + } + +} From 4ee123a59dfd693e70615676c2843abef07d3fac Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 28 May 2017 23:20:07 +0100 Subject: [PATCH 007/209] Add private messaging plugin --- .../private-messaging/messaging.plugin.kts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 game/src/plugins/chat/private-messaging/messaging.plugin.kts diff --git a/game/src/plugins/chat/private-messaging/messaging.plugin.kts b/game/src/plugins/chat/private-messaging/messaging.plugin.kts new file mode 100644 index 000000000..d9fd21e92 --- /dev/null +++ b/game/src/plugins/chat/private-messaging/messaging.plugin.kts @@ -0,0 +1,25 @@ +import org.apollo.game.message.impl.ForwardPrivateChatMessage +import org.apollo.game.message.impl.PrivateChatMessage +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivacyState.OFF +import org.apollo.game.model.entity.setting.PrivacyState.ON + +on { PrivateChatMessage::class } + .then { + val friend = it.world.getPlayer(username) + + if (interactionPermitted(it, friend)) { + friend.send(ForwardPrivateChatMessage(it.username, it.privilegeLevel, compressedMessage)) + } + } + +fun interactionPermitted(player: Player, friend: Player?): Boolean { + val username = player.username + val privacy = friend?.friendPrivacy + + if (friend == null || friend.hasIgnored(username)) { + return false + } else { + return if (friend.friendsWith(username)) privacy != OFF else privacy == ON + } +} From 3fb6d3f792fd3558f33aae71a478843cd62e5179 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 30 May 2017 02:19:09 +0100 Subject: [PATCH 008/209] Treat each plugin as an individual source set Adds separate build tasks for each plugin by auto-discovering plugin meta files in the build script. Each plugin will automatically have its main sources and tests compiled, and then it's output added to the game modules classpath. This enables support for incremental compilation of scripts, as well as unit testing using Gradle's test framework. --- game/build.gradle | 48 +----- game/plugins.gradle | 161 ++++++++++++++++++ .../game/plugin/KotlinPluginEnvironment.java | 21 ++- .../plugin/kotlin/KotlinPluginCompiler.kt | 22 +-- game/src/plugins/bank/meta.toml | 7 + game/src/plugins/bank/plugin.xml | 14 -- .../plugins/bank/{ => src}/bank.plugin.kts | 0 game/src/plugins/bank/test/BankingTests.kt | 0 .../plugins/chat/private-messaging/meta.toml | 0 .../{ => src}/friends.plugin.kts | 0 .../{ => src}/ignores.plugin.kts | 0 .../{ => src}/messaging.plugin.kts | 0 game/src/plugins/dummy/meta.toml | 0 .../plugins/dummy/{ => src}/dummy.plugin.kts | 0 game/src/plugins/entity/spawn/meta.toml | 8 + .../plugins/entity/spawn/{ => src}/spawn.kt | 0 .../entity/spawn/{ => src}/spawn.plugin.kts | 0 .../src/plugins/locations/lumbridge/meta.toml | 8 + .../lumbridge/{ => src}/lumbridge-npcs.kts | 0 game/src/plugins/{ => stub}/stub.kt | 0 game/src/plugins/util/lookup/meta.toml | 2 + .../plugins/util/lookup/{ => src}/lookup.kt | 0 .../plugins/util/lookup/test/LookupTests.kt | 14 ++ 23 files changed, 225 insertions(+), 80 deletions(-) create mode 100644 game/plugins.gradle create mode 100644 game/src/plugins/bank/meta.toml delete mode 100644 game/src/plugins/bank/plugin.xml rename game/src/plugins/bank/{ => src}/bank.plugin.kts (100%) create mode 100644 game/src/plugins/bank/test/BankingTests.kt create mode 100644 game/src/plugins/chat/private-messaging/meta.toml rename game/src/plugins/chat/private-messaging/{ => src}/friends.plugin.kts (100%) rename game/src/plugins/chat/private-messaging/{ => src}/ignores.plugin.kts (100%) rename game/src/plugins/chat/private-messaging/{ => src}/messaging.plugin.kts (100%) create mode 100644 game/src/plugins/dummy/meta.toml rename game/src/plugins/dummy/{ => src}/dummy.plugin.kts (100%) create mode 100644 game/src/plugins/entity/spawn/meta.toml rename game/src/plugins/entity/spawn/{ => src}/spawn.kt (100%) rename game/src/plugins/entity/spawn/{ => src}/spawn.plugin.kts (100%) create mode 100644 game/src/plugins/locations/lumbridge/meta.toml rename game/src/plugins/locations/lumbridge/{ => src}/lumbridge-npcs.kts (100%) rename game/src/plugins/{ => stub}/stub.kt (100%) create mode 100644 game/src/plugins/util/lookup/meta.toml rename game/src/plugins/util/lookup/{ => src}/lookup.kt (100%) create mode 100644 game/src/plugins/util/lookup/test/LookupTests.kt diff --git a/game/build.gradle b/game/build.gradle index bcce47908..f6581a2e2 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -7,59 +7,23 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath group: 'com.moandjiezana.toml', name: 'toml4j', version: '0.7.1' } } -apply plugin: 'kotlin' - ext.pluginsDir = "$projectDir/src/plugins" -sourceSets { - plugins { - kotlin { - srcDir "$pluginsDir" - exclude 'stub.kt' - exclude '**/*.kts' - } - } -} +apply plugin: 'kotlin' +apply from: 'plugins.gradle' dependencies { compile project(':cache') compile project(':net') compile project(':util') - pluginsCompile(configurations.compile) - pluginsCompile(sourceSets.main.output) - + compile group: 'io.github.lukehutch', name: 'fast-classpath-scanner', version: '2.0.21' compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlinVersion" - runtime files("$buildDir/plugins") - runtime sourceSets.plugins.output -} - - -task compilePluginScripts(type: JavaExec, dependsOn: [classes, pluginsClasses]) { - group = LifecycleBasePlugin.BUILD_GROUP - description = 'Compile plugin script files (.plugin.kts) to java bytecode' - - def compilerClasspath = [ - configurations.compile.asPath, - configurations.runtime.asPath, - sourceSets.main.compileClasspath.asPath, - sourceSets.main.runtimeClasspath.asPath - ] - - def outputDir = "$buildDir/plugins" - def manifestPath = "$buildDir/plugins/manifest.txt" - - inputs.source "$pluginsDir" - outputs.dir outputDir - - classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath - main = 'org.apollo.game.plugin.kotlin.KotlinPluginCompiler' - args = ["$pluginsDir", outputDir, manifestPath, compilerClasspath.join(':')] -} - -assemble.dependsOn compilePluginScripts \ No newline at end of file + testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" +} \ No newline at end of file diff --git a/game/plugins.gradle b/game/plugins.gradle new file mode 100644 index 000000000..fb405acfa --- /dev/null +++ b/game/plugins.gradle @@ -0,0 +1,161 @@ +import com.moandjiezana.toml.Toml + +import java.nio.file.Paths + +def PLUGIN_VERIFICATION_GROUP = "plugin-verification" +def PLUGIN_BUILD_GROUP = "plugin-build" + +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath group: 'com.moandjiezana.toml', name: 'toml4j', version: '0.7.1' + } +} + +sourceSets { + pluginStub { + kotlin { + srcDir "$pluginsDir/stub" + exclude 'stub.kt' + } + } +} + +dependencies { + pluginStubCompile(project(":game")) +} + +task pluginTests { + group = "plugin-verification" + + doLast { + println("Finished executing plugin tests") + } +} + +class PluginBuildData { + PluginBuildData(String normalizedName, SourceSet mainSources, SourceSet testSources, + FileCollection scriptFiles, List dependencyNames) { + this.normalizedName = normalizedName + this.mainSources = mainSources + this.testSources = testSources + this.scriptFiles = scriptFiles + this.dependencyNames = dependencyNames + } + + String normalizedName + SourceSet mainSources + SourceSet testSources + FileCollection scriptFiles + List dependencyNames +} + +Map pluginMap = new HashMap<>() + +def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, + List pluginDependencies) { + + def testConfiguration = testSources.compileConfigurationName + def mainConfiguration = mainSources.compileConfigurationName + def runtimeConfiguration = mainSources.runtimeConfigurationName + + // Add this plugin as a runtime dependency to the main game project + dependencies.add(configurations.runtime.name, mainSources.output) + + pluginDependencies.each { + dependencies.add(mainConfiguration, it.mainSources.output) + dependencies.add(testConfiguration, it.testSources.output) + } + + dependencies.add(mainConfiguration, configurations.compile) + dependencies.add(mainConfiguration, sourceSets.main.output) + dependencies.add(runtimeConfiguration, sourceSets.pluginStub.output) + + dependencies.add(testConfiguration, mainSources.output) + dependencies.add(testConfiguration, configurations.testCompile) + dependencies.add(testConfiguration, sourceSets.test.output) +} + +def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSources, + FileCollection scriptFiles, List pluginDependencies) { + + task("${name}Tests", type: Test) { + group = "plugin-verification" + + testClassesDir = testSources.output.classesDir + classpath = testSources.runtimeClasspath + mainSources.runtimeClasspath + + binResultsDir = file("$buildDir/plugin-test-results/binary/$name") + + reports { + html.destination = "$buildDir/reports/plugin-tests/$name" + junitXml.destination = "$buildDir/plugin-tests/$name" + } + } + + task("compile${name}Scripts", type: JavaExec) { + group = "plugin-compile" + + def outputDir = mainSources.output.classesDir.toString() + + inputs.files scriptFiles + outputs.dir outputDir + + classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath + main = 'org.apollo.game.plugin.kotlin.KotlinPluginCompiler' + args = [outputDir] + scriptFiles.collect { it.absoluteFile.toString() } + } + + def testsTask = tasks["${name}Tests"] + pluginTests.dependsOn testsTask +} + +def pluginTree = fileTree(dir: "$pluginsDir") +def pluginDefinitions = pluginTree.matching { + include '**/meta.toml' +} + +pluginDefinitions.each { file -> + def meta = new Toml() + meta.read(file.absoluteFile) + + def pluginFolder = Paths.get(file.parentFile.absolutePath) + def name = meta.getString("name", pluginFolder.getFileName().toString()) + def normalizedName = name.replaceAll("[^a-zA-Z0-9_]", '_').toLowerCase() + def packageName = meta.getString("package", "org.apollo.game.plugin") + def authors = meta.getList("authors", new ArrayList()) + def dependencies = meta.getList("dependencies", new ArrayList()) + + def scripts = fileTree(file.parentFile) { + include '**/*.plugin.kts' + } + + def srcsDir = meta.getString("config.src", "src/") + def testDir = meta.getString("config.test", "test/") + + def mainSources = sourceSets.create("${normalizedName}_main") { + kotlin { + srcDir pluginFolder.resolve(srcsDir).toString() + exclude '*.kts' + } + } + + def testSources = sourceSets.create("${normalizedName}_test") { + kotlin { + srcDir pluginFolder.resolve(testDir).toString() + } + } + + def pluginData = new PluginBuildData(normalizedName, mainSources, testSources, scripts, dependencies) + pluginMap.put(normalizedName, pluginData) +} + +pluginMap.values().each { + def dependencies = it.dependencyNames.collect { name -> pluginMap.get(name) } + + configurePluginDependencies(it.mainSources, it.testSources, dependencies) + configurePluginTasks(it.normalizedName, it.mainSources, it.testSources, it.scriptFiles, dependencies) +} diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java index b2e74222f..dba144690 100644 --- a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -15,6 +15,9 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; + +import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; +import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult; import org.apollo.game.model.World; import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; import org.apollo.game.plugin.kotlin.KotlinPluginScript; @@ -37,15 +40,14 @@ public KotlinPluginEnvironment(World world) { @Override public void load(Collection plugins) { List pluginScripts = new ArrayList<>(); + List> pluginClasses = new ArrayList<>(); - try (InputStream resource = KotlinPluginEnvironment.class.getResourceAsStream("/manifest.txt")) { - BufferedReader reader = new BufferedReader(new InputStreamReader(resource)); - List pluginClassNames = reader.lines().collect(Collectors.toList()); - - for (String pluginClassName : pluginClassNames) { - Class pluginClass = - (Class) Class.forName(pluginClassName); + new FastClasspathScanner() + .matchSubclassesOf(KotlinPluginScript.class, pluginClasses::add) + .scan(); + try { + for (Class pluginClass : pluginClasses) { Constructor pluginConstructor = pluginClass.getConstructor(World.class, PluginContext.class); @@ -55,7 +57,10 @@ public void load(Collection plugins) { throw new RuntimeException(e); } - pluginScripts.forEach(script -> script.doStart(world)); + pluginScripts.forEach(script -> { + logger.info("Starting script: " + script.getClass().getName()); + script.doStart(world); + }); } @Override diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt index 4c615583e..ee655af34 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt @@ -43,8 +43,6 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess companion object { - private val maxSearchDepth = 1024; - fun currentClasspath(): List { val classLoader = Thread.currentThread().contextClassLoader as? URLClassLoader ?: throw RuntimeException("Unable to resolve classpath for current ClassLoader") @@ -66,12 +64,10 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess @JvmStatic fun main(args: Array) { - if (args.size < 4) throw RuntimeException("Usage: ") + if (args.size < 2) throw RuntimeException("Usage: script1.kts script2.kts ...") - val inputDir = Paths.get(args[0]) - val outputDir = Paths.get(args[1]) - val manifestPath = Paths.get(args[2]) - val classpathEntries = args[3].split(':') + val outputDir = Paths.get(args[0]) + val inputScripts = args.slice(1..args.size - 1).map { Paths.get(it) } val classpath = mutableListOf() val runtimeBean = ManagementFactory.getRuntimeMXBean() @@ -83,15 +79,11 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess } /** - * Classpath entries on the command line contain the kotlin runtime - * and plugin API code. We use our current classpath to provide - * Kotlin with access to the JRE and apollo modules. + * Our current classpath should contain all compile time dependencies for the plugin as well as Apollo's + * own sources. We can also achieve this via Gradle but doing it at runtime prevents Gradle from thinking + * the build has been modified after evaluation. */ classpath.addAll(currentClasspath()) - classpath.addAll(classpathEntries.map { File(it) }) - - val inputScriptsMatcher = { path: Path, _: BasicFileAttributes -> path.toString().endsWith(".plugin.kts") } - val inputScripts = Files.find(inputDir, maxSearchDepth, BiPredicate(inputScriptsMatcher)) val compiler = KotlinPluginCompiler(classpath, MessageCollector.NONE) val compiledScriptClasses = mutableListOf() @@ -106,8 +98,6 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess inputScripts.forEach { compiledScriptClasses.add(compiler.compile(it, outputDir).fqName) } - - Files.write(manifestPath, compiledScriptClasses, CREATE, TRUNCATE_EXISTING) } catch (t: Throwable) { t.printStackTrace() System.exit(1) diff --git a/game/src/plugins/bank/meta.toml b/game/src/plugins/bank/meta.toml new file mode 100644 index 000000000..e7895a9e1 --- /dev/null +++ b/game/src/plugins/bank/meta.toml @@ -0,0 +1,7 @@ +name = "Banking" +package = "org.apollo.game.plugin.banking" +authors = [ "Major" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/bank/plugin.xml b/game/src/plugins/bank/plugin.xml deleted file mode 100644 index 4402e5f09..000000000 --- a/game/src/plugins/bank/plugin.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - bank - 1 - Bank - Opens the bank interface when players select 'use-quickly' on a bank booth. - - Major - - - - - - diff --git a/game/src/plugins/bank/bank.plugin.kts b/game/src/plugins/bank/src/bank.plugin.kts similarity index 100% rename from game/src/plugins/bank/bank.plugin.kts rename to game/src/plugins/bank/src/bank.plugin.kts diff --git a/game/src/plugins/bank/test/BankingTests.kt b/game/src/plugins/bank/test/BankingTests.kt new file mode 100644 index 000000000..e69de29bb diff --git a/game/src/plugins/chat/private-messaging/meta.toml b/game/src/plugins/chat/private-messaging/meta.toml new file mode 100644 index 000000000..e69de29bb diff --git a/game/src/plugins/chat/private-messaging/friends.plugin.kts b/game/src/plugins/chat/private-messaging/src/friends.plugin.kts similarity index 100% rename from game/src/plugins/chat/private-messaging/friends.plugin.kts rename to game/src/plugins/chat/private-messaging/src/friends.plugin.kts diff --git a/game/src/plugins/chat/private-messaging/ignores.plugin.kts b/game/src/plugins/chat/private-messaging/src/ignores.plugin.kts similarity index 100% rename from game/src/plugins/chat/private-messaging/ignores.plugin.kts rename to game/src/plugins/chat/private-messaging/src/ignores.plugin.kts diff --git a/game/src/plugins/chat/private-messaging/messaging.plugin.kts b/game/src/plugins/chat/private-messaging/src/messaging.plugin.kts similarity index 100% rename from game/src/plugins/chat/private-messaging/messaging.plugin.kts rename to game/src/plugins/chat/private-messaging/src/messaging.plugin.kts diff --git a/game/src/plugins/dummy/meta.toml b/game/src/plugins/dummy/meta.toml new file mode 100644 index 000000000..e69de29bb diff --git a/game/src/plugins/dummy/dummy.plugin.kts b/game/src/plugins/dummy/src/dummy.plugin.kts similarity index 100% rename from game/src/plugins/dummy/dummy.plugin.kts rename to game/src/plugins/dummy/src/dummy.plugin.kts diff --git a/game/src/plugins/entity/spawn/meta.toml b/game/src/plugins/entity/spawn/meta.toml new file mode 100644 index 000000000..3551199da --- /dev/null +++ b/game/src/plugins/entity/spawn/meta.toml @@ -0,0 +1,8 @@ +name = "spawning" +package = "org.apollo.game.plugin.entity" +authors = [ "Gary Tierney" ] +dependencies = [ "entity_lookup" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/entity/spawn/spawn.kt b/game/src/plugins/entity/spawn/src/spawn.kt similarity index 100% rename from game/src/plugins/entity/spawn/spawn.kt rename to game/src/plugins/entity/spawn/src/spawn.kt diff --git a/game/src/plugins/entity/spawn/spawn.plugin.kts b/game/src/plugins/entity/spawn/src/spawn.plugin.kts similarity index 100% rename from game/src/plugins/entity/spawn/spawn.plugin.kts rename to game/src/plugins/entity/spawn/src/spawn.plugin.kts diff --git a/game/src/plugins/locations/lumbridge/meta.toml b/game/src/plugins/locations/lumbridge/meta.toml new file mode 100644 index 000000000..17ab1025b --- /dev/null +++ b/game/src/plugins/locations/lumbridge/meta.toml @@ -0,0 +1,8 @@ +name = "lumbridge npc spawns" +package = "org.apollo.game.plugin.locations" +authors = [ "Gary Tierney" ] +dependencies = [ "spawning" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/locations/lumbridge/lumbridge-npcs.kts b/game/src/plugins/locations/lumbridge/src/lumbridge-npcs.kts similarity index 100% rename from game/src/plugins/locations/lumbridge/lumbridge-npcs.kts rename to game/src/plugins/locations/lumbridge/src/lumbridge-npcs.kts diff --git a/game/src/plugins/stub.kt b/game/src/plugins/stub/stub.kt similarity index 100% rename from game/src/plugins/stub.kt rename to game/src/plugins/stub/stub.kt diff --git a/game/src/plugins/util/lookup/meta.toml b/game/src/plugins/util/lookup/meta.toml new file mode 100644 index 000000000..91b1757be --- /dev/null +++ b/game/src/plugins/util/lookup/meta.toml @@ -0,0 +1,2 @@ +name = "entity lookup" +package = "org.apollo.game.plugins.util" diff --git a/game/src/plugins/util/lookup/lookup.kt b/game/src/plugins/util/lookup/src/lookup.kt similarity index 100% rename from game/src/plugins/util/lookup/lookup.kt rename to game/src/plugins/util/lookup/src/lookup.kt diff --git a/game/src/plugins/util/lookup/test/LookupTests.kt b/game/src/plugins/util/lookup/test/LookupTests.kt new file mode 100644 index 000000000..545cbc41f --- /dev/null +++ b/game/src/plugins/util/lookup/test/LookupTests.kt @@ -0,0 +1,14 @@ +import org.apollo.cache.def.ItemDefinition +import org.junit.Test +import kotlin.test.assertEquals + +class LookupTests { + @Test fun itemLookup() { + val testItem = ItemDefinition(0) + testItem.name = "sword" + + ItemDefinition.init(arrayOf(testItem)) + + assertEquals(testItem, lookup_item("sword")) + } +} \ No newline at end of file From 9353daabc3c087bb119d779d8be6fcfca998b6e0 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 30 May 2017 21:11:40 +0100 Subject: [PATCH 009/209] Add plugin tests to the game build --- game/plugins.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/game/plugins.gradle b/game/plugins.gradle index fb405acfa..0cce9fa81 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -36,6 +36,8 @@ task pluginTests { } } +check.dependsOn pluginTests + class PluginBuildData { PluginBuildData(String normalizedName, SourceSet mainSources, SourceSet testSources, FileCollection scriptFiles, List dependencyNames) { From 258fc6c97b5bfcc46dbe991b4f34ac38703a3549 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 31 May 2017 10:55:12 +0100 Subject: [PATCH 010/209] Add stub to plugin compile-time classpath --- game/plugins.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/game/plugins.gradle b/game/plugins.gradle index 0cce9fa81..a6f73768d 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -62,7 +62,6 @@ def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, def testConfiguration = testSources.compileConfigurationName def mainConfiguration = mainSources.compileConfigurationName - def runtimeConfiguration = mainSources.runtimeConfigurationName // Add this plugin as a runtime dependency to the main game project dependencies.add(configurations.runtime.name, mainSources.output) @@ -74,7 +73,7 @@ def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, dependencies.add(mainConfiguration, configurations.compile) dependencies.add(mainConfiguration, sourceSets.main.output) - dependencies.add(runtimeConfiguration, sourceSets.pluginStub.output) + dependencies.add(mainConfiguration, sourceSets.pluginStub.output) dependencies.add(testConfiguration, mainSources.output) dependencies.add(testConfiguration, configurations.testCompile) From eed32efcf90ee99476ceba25cf40e15cf01f8d6b Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 31 May 2017 21:04:13 +0100 Subject: [PATCH 011/209] Move stub.kt to main game module --- game/build.gradle | 8 ++++++++ game/plugins.gradle | 14 -------------- game/src/main/kotlin/stub.kt | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 game/src/main/kotlin/stub.kt diff --git a/game/build.gradle b/game/build.gradle index f6581a2e2..be38e2606 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -16,6 +16,14 @@ ext.pluginsDir = "$projectDir/src/plugins" apply plugin: 'kotlin' apply from: 'plugins.gradle' +sourceSets { + main { + kotlin { + exclude 'stub.kt' + } + } +} + dependencies { compile project(':cache') compile project(':net') diff --git a/game/plugins.gradle b/game/plugins.gradle index a6f73768d..41904c9c9 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -15,19 +15,6 @@ buildscript { } } -sourceSets { - pluginStub { - kotlin { - srcDir "$pluginsDir/stub" - exclude 'stub.kt' - } - } -} - -dependencies { - pluginStubCompile(project(":game")) -} - task pluginTests { group = "plugin-verification" @@ -73,7 +60,6 @@ def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, dependencies.add(mainConfiguration, configurations.compile) dependencies.add(mainConfiguration, sourceSets.main.output) - dependencies.add(mainConfiguration, sourceSets.pluginStub.output) dependencies.add(testConfiguration, mainSources.output) dependencies.add(testConfiguration, configurations.testCompile) diff --git a/game/src/main/kotlin/stub.kt b/game/src/main/kotlin/stub.kt new file mode 100644 index 000000000..8c5837043 --- /dev/null +++ b/game/src/main/kotlin/stub.kt @@ -0,0 +1,25 @@ +/** + * NOTE: This file is a stub, intended only for use within an IDE. It should be updated + * each time [org.apollo.game.plugin.kotlin.KotlinPluginScript] has a new method added to it. + * + * Until IntelliJ IDEA starts to support ScriptTemplateDefinitions this is + * required to resolve references within plugin code. + */ + +import org.apollo.game.model.World +import org.apollo.game.plugin.PluginContext +import org.apollo.game.plugin.kotlin.* +import org.apollo.net.message.Message +import kotlin.reflect.KClass + +fun on(type: () -> KClass): KotlinMessageHandler { + null!! +} + +fun start(callback: (World) -> Unit) { + +} + +fun stop(callback: (World) -> Unit) { + +} From 42fdaee8b8ad1d07b8cf7ad935ef99d5ccdce65a Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 1 Jun 2017 22:47:50 +0100 Subject: [PATCH 012/209] Make run task depend on plugin scripts --- build.gradle | 14 +++++--------- game/build.gradle | 9 +++++++++ game/plugins.gradle | 35 +++++++++++++++++++++++------------ 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index c5dda50ae..f482903b9 100644 --- a/build.gradle +++ b/build.gradle @@ -44,14 +44,10 @@ subprojects { } } } -} - -def gameSubproject = project(':game') - -task(run, dependsOn: gameSubproject.tasks['assemble'], type: JavaExec) { - def gameClasspath = gameSubproject.sourceSets.main.runtimeClasspath - main = 'org.apollo.Server' - classpath = gameClasspath - jvmArgs = ['-Xmx1750M'] + test { + testLogging { + events "passed", "skipped", "failed" + } + } } diff --git a/game/build.gradle b/game/build.gradle index be38e2606..8db5ebe1a 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -34,4 +34,13 @@ dependencies { compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" +} + +task run(type: JavaExec, dependsOn: [classes, pluginClasses]) { + FileCollection gameClasspath = sourceSets.main.runtimeClasspath + sourceSets.main.compileClasspath + + main = 'org.apollo.Server' + classpath = gameClasspath + jvmArgs = ['-Xmx1750M'] + workingDir = "$rootDir" } \ No newline at end of file diff --git a/game/plugins.gradle b/game/plugins.gradle index 41904c9c9..5bdfd2f46 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -23,6 +23,10 @@ task pluginTests { } } +task pluginClasses { + group = "plugin-build" +} + check.dependsOn pluginTests class PluginBuildData { @@ -69,7 +73,7 @@ def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSources, FileCollection scriptFiles, List pluginDependencies) { - task("${name}Tests", type: Test) { + def testsTask = task("${name}Tests", type: Test) { group = "plugin-verification" testClassesDir = testSources.output.classesDir @@ -81,23 +85,30 @@ def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSourc html.destination = "$buildDir/reports/plugin-tests/$name" junitXml.destination = "$buildDir/plugin-tests/$name" } + + testLogging { + events "passed", "skipped", "failed" + } } - task("compile${name}Scripts", type: JavaExec) { - group = "plugin-compile" + pluginTests.dependsOn testsTask + + if (!scriptFiles.empty) { + def compileScriptsTask = task("compile${name}Scripts", type: JavaExec) { + group = "plugin-compile" - def outputDir = mainSources.output.classesDir.toString() + def outputDir = mainSources.output.classesDir.toString() - inputs.files scriptFiles - outputs.dir outputDir + inputs.files scriptFiles + outputs.dir outputDir - classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath - main = 'org.apollo.game.plugin.kotlin.KotlinPluginCompiler' - args = [outputDir] + scriptFiles.collect { it.absoluteFile.toString() } - } + classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath + main = 'org.apollo.game.plugin.kotlin.KotlinPluginCompiler' + args = [outputDir] + scriptFiles.collect { it.absoluteFile.toString() } + } - def testsTask = tasks["${name}Tests"] - pluginTests.dependsOn testsTask + pluginClasses.dependsOn compileScriptsTask + } } def pluginTree = fileTree(dir: "$pluginsDir") From 7ecc2e315896462a1371076a3a7ab4b7cfa8ee1f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 1 Jun 2017 23:09:24 +0100 Subject: [PATCH 013/209] Clean up plugin script compilation --- game/build.gradle | 6 ++---- game/plugins.gradle | 9 ++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/game/build.gradle b/game/build.gradle index 8db5ebe1a..e7db42a3a 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -36,11 +36,9 @@ dependencies { testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" } -task run(type: JavaExec, dependsOn: [classes, pluginClasses]) { - FileCollection gameClasspath = sourceSets.main.runtimeClasspath + sourceSets.main.compileClasspath - +task run(type: JavaExec, dependsOn: classes) { main = 'org.apollo.Server' - classpath = gameClasspath + classpath = sourceSets.main.runtimeClasspath jvmArgs = ['-Xmx1750M'] workingDir = "$rootDir" } \ No newline at end of file diff --git a/game/plugins.gradle b/game/plugins.gradle index 5bdfd2f46..e16aa141a 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -23,10 +23,6 @@ task pluginTests { } } -task pluginClasses { - group = "plugin-build" -} - check.dependsOn pluginTests class PluginBuildData { @@ -107,7 +103,10 @@ def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSourc args = [outputDir] + scriptFiles.collect { it.absoluteFile.toString() } } - pluginClasses.dependsOn compileScriptsTask + tasks[mainSources.classesTaskName].outputs.upToDateWhen { false } + tasks[mainSources.classesTaskName].doLast { + compileScriptsTask.execute() + } } } From 8d00dcc7c88ca6a3c7f8432445fa6a3e0687bc6c Mon Sep 17 00:00:00 2001 From: Jesse Date: Wed, 31 May 2017 21:35:47 -0400 Subject: [PATCH 014/209] Add height and direction params to npc_spawn --- game/src/plugins/entity/spawn/src/spawn.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/game/src/plugins/entity/spawn/src/spawn.kt b/game/src/plugins/entity/spawn/src/spawn.kt index 684bcdc0b..cb49a6afe 100644 --- a/game/src/plugins/entity/spawn/src/spawn.kt +++ b/game/src/plugins/entity/spawn/src/spawn.kt @@ -1,6 +1,4 @@ -import org.apollo.cache.def.NpcDefinition import org.apollo.game.model.* -import org.apollo.game.model.entity.Npc data class Spawn(val id: Int?, val name: String, val position: Position, val facing: Direction, val spawnAnimation: Animation? = null, @@ -10,6 +8,6 @@ object Spawns { val list = mutableListOf() } -fun npc_spawn(name: String, x: Int, y: Int, id: Int? = null) { - Spawns.list.add(Spawn(id, name, Position(x, y), Direction.NORTH)) +fun npc_spawn(name: String, x: Int, y: Int, z: Int = 0, id: Int? = null, facing: Direction = Direction.NORTH) { + Spawns.list.add(Spawn(id, name, Position(x, y, z), facing)) } From 35ab034f3d6a677679a0ed990c25c0ca3047c310 Mon Sep 17 00:00:00 2001 From: Jesse Date: Thu, 1 Jun 2017 01:39:13 -0400 Subject: [PATCH 015/209] Port location NPC spawns from Ruby to Kotlin --- .../src/plugins/locations/al-kharid/meta.toml | 8 + .../al-kharid/src/al-kharid-npcs.plugin.kts | 111 ++++++++ .../src/plugins/locations/edgeville/meta.toml | 8 + .../edgeville/src/edgeville-npcs.plugin.kts | 51 ++++ game/src/plugins/locations/falador/meta.toml | 8 + .../falador/src/falador-npcs.plugin.kts | 168 +++++++++++ ...dge-npcs.kts => lumbridge-npcs.plugin.kts} | 1 + .../locations/tutorial-island/meta.toml | 8 + .../src/tutorial-island-npcs.plugin.kts | 41 +++ game/src/plugins/locations/varrock/meta.toml | 8 + .../varrock/src/varrock-npcs.plugin.kts | 267 ++++++++++++++++++ 11 files changed, 679 insertions(+) create mode 100644 game/src/plugins/locations/al-kharid/meta.toml create mode 100644 game/src/plugins/locations/al-kharid/src/al-kharid-npcs.plugin.kts create mode 100644 game/src/plugins/locations/edgeville/meta.toml create mode 100644 game/src/plugins/locations/edgeville/src/edgeville-npcs.plugin.kts create mode 100644 game/src/plugins/locations/falador/meta.toml create mode 100644 game/src/plugins/locations/falador/src/falador-npcs.plugin.kts rename game/src/plugins/locations/lumbridge/src/{lumbridge-npcs.kts => lumbridge-npcs.plugin.kts} (91%) create mode 100644 game/src/plugins/locations/tutorial-island/meta.toml create mode 100644 game/src/plugins/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts create mode 100644 game/src/plugins/locations/varrock/meta.toml create mode 100644 game/src/plugins/locations/varrock/src/varrock-npcs.plugin.kts diff --git a/game/src/plugins/locations/al-kharid/meta.toml b/game/src/plugins/locations/al-kharid/meta.toml new file mode 100644 index 000000000..4e0d3dc68 --- /dev/null +++ b/game/src/plugins/locations/al-kharid/meta.toml @@ -0,0 +1,8 @@ +name = "al-kharid npc spawns" +package = "org.apollo.game.plugin.locations" +authors = [ "Jesse W" ] +dependencies = [ "spawning" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/locations/al-kharid/src/al-kharid-npcs.plugin.kts b/game/src/plugins/locations/al-kharid/src/al-kharid-npcs.plugin.kts new file mode 100644 index 000000000..ba5acf903 --- /dev/null +++ b/game/src/plugins/locations/al-kharid/src/al-kharid-npcs.plugin.kts @@ -0,0 +1,111 @@ +import org.apollo.game.model.Direction + +// Generic npcs + +npc_spawn("man", x = 3276, y = 3186) +npc_spawn("man", x = 3282, y = 3197) + +npc_spawn("man", id = 3, x = 3301, y = 3200) +npc_spawn("man", id = 3, x = 3300, y = 3208) + +npc_spawn("man", id = 2, x = 3297, y = 3196) + +npc_spawn("man", id = 16, x = 3294, y = 3204) + +npc_spawn("spider", x = 3319, y = 3145) +npc_spawn("spider", x = 3319, y = 3140) +npc_spawn("spider", x = 3323, y = 3138) + +npc_spawn("scorpion", x = 3282, y = 3149) + +//Camels + +npc_spawn("cam_the_camel", x = 3295, y = 3232) +npc_spawn("elly_the_camel", x = 3312, y = 3210) +npc_spawn("camel", x = 3285, y = 3198) +npc_spawn("ollie_the_camel", x = 3291, y = 3209) +npc_spawn("al_the_camel", x = 3275, y = 3162) + +// Quest npc + +npc_spawn("osman", x = 3286, y = 3180, facing = Direction.EAST) + +npc_spawn("hassan", x = 3302, y = 3163) + +npc_spawn("father_reen", x = 3272, y = 3158) + +npc_spawn("man", id = 663, x = 3297, y = 3287) + +// Boarder guards + +npc_spawn("border_guard", x = 3268, y = 3226) +npc_spawn("border_guard", x = 3267, y = 3226) +npc_spawn("border_guard", x = 3268, y = 3229, facing = Direction.SOUTH) +npc_spawn("border_guard", x = 3267, y = 3229, facing = Direction.SOUTH) + +// Palace guards + +npc_spawn("Al-Kharid warrior", x = 3285, y = 3174) +npc_spawn("Al-Kharid warrior", x = 3283, y = 3168) +npc_spawn("Al-Kharid warrior", x = 3285, y = 3169) +npc_spawn("Al-Kharid warrior", x = 3290, y = 3162) +npc_spawn("Al-Kharid warrior", x = 3295, y = 3170) +npc_spawn("Al-Kharid warrior", x = 3300, y = 3175) +npc_spawn("Al-Kharid warrior", x = 3300, y = 3171) +npc_spawn("Al-Kharid warrior", x = 3301, y = 3168) + +// Shanty pass + +npc_spawn("shantay_guard", x = 3301, y = 3120) +npc_spawn("shantay_guard", x = 3302, y = 3126) +npc_spawn("shantay_guard", x = 3306, y = 3126) +npc_spawn("shantay_guard", id = 838, x = 3303, y = 3118) + +// Mine + +npc_spawn("scorpion", x = 3296, y = 3294) +npc_spawn("scorpion", x = 3298, y = 3280) +npc_spawn("scorpion", x = 3299, y = 3299) +npc_spawn("scorpion", x = 3299, y = 3309) +npc_spawn("scorpion", x = 3300, y = 3287) +npc_spawn("scorpion", x = 3300, y = 3315) +npc_spawn("scorpion", x = 3301, y = 3305) +npc_spawn("scorpion", x = 3301, y = 3312) + +// Functional npcs + +npc_spawn("gnome_pilot", x = 3279, y = 3213) + +npc_spawn("banker", id = 496, x = 3267, y = 3164, facing = Direction.EAST) +npc_spawn("banker", id = 496, x = 3267, y = 3167, facing = Direction.EAST) +npc_spawn("banker", id = 496, x = 3267, y = 3169, facing = Direction.EAST) + +npc_spawn("banker", id = 497, x = 3267, y = 3166, facing = Direction.EAST) +npc_spawn("banker", id = 497, x = 3267, y = 3168, facing = Direction.EAST) + +npc_spawn("gem_trader", x = 3287, y = 3210) + +npc_spawn("zeke", x = 3289, y = 3189) + +npc_spawn("shantay", x = 3304, y = 3124) + +npc_spawn("rug_merchant", id = 2296, x = 3311, y = 3109, facing = Direction.WEST) + +npc_spawn("ranael", x = 3315, y = 3163) + +npc_spawn("shop_keeper", id = 524, x = 3315, y = 3178) +npc_spawn("shop_assistant", id = 525, x = 3315, y = 3180, facing = Direction.WEST) + +npc_spawn("louie_legs", x = 3316, y = 3175, facing = Direction.WEST) + +npc_spawn("ellis", x = 3274, y = 3192) + +npc_spawn("dommik", x = 3321, y = 3193) + +npc_spawn("tool_leprechaun", x = 3319, y = 3204) + +npc_spawn("ali_morrisane", x = 3304, y = 3211, facing = Direction.EAST) + +npc_spawn("silk_trader", x = 3300, y = 3203) + +npc_spawn("karim", x = 3273, y = 3180) \ No newline at end of file diff --git a/game/src/plugins/locations/edgeville/meta.toml b/game/src/plugins/locations/edgeville/meta.toml new file mode 100644 index 000000000..01a8dc336 --- /dev/null +++ b/game/src/plugins/locations/edgeville/meta.toml @@ -0,0 +1,8 @@ +name = "edgeville npc spawns" +package = "org.apollo.game.plugin.locations" +authors = [ "Jesse W" ] +dependencies = [ "spawning" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/locations/edgeville/src/edgeville-npcs.plugin.kts b/game/src/plugins/locations/edgeville/src/edgeville-npcs.plugin.kts new file mode 100644 index 000000000..719195104 --- /dev/null +++ b/game/src/plugins/locations/edgeville/src/edgeville-npcs.plugin.kts @@ -0,0 +1,51 @@ +import org.apollo.game.model.Direction + +// Generic npcs + +npc_spawn("man", x = 3095, y = 3508) +npc_spawn("man", x = 3095, y = 3511) +npc_spawn("man", x = 3098, y = 3509) +npc_spawn("man", id = 2, x = 3093, y = 3511) +npc_spawn("man", id = 3, x = 3097, y = 3508) +npc_spawn("man", id = 3, x = 3092, y = 3508) +npc_spawn("man", id = 3, x = 3097, y = 3512) + +npc_spawn("guard", x = 3086, y = 3516) +npc_spawn("guard", x = 3094, y = 3518) +npc_spawn("guard", x = 3108, y = 3514) +npc_spawn("guard", x = 3110, y = 3514) +npc_spawn("guard", x = 3113, y = 3514) +npc_spawn("guard", x = 3113, y = 3516) + +npc_spawn("sheep", id = 43, x = 3050, y = 3516) +npc_spawn("sheep", id = 43, x = 3051, y = 3514) +npc_spawn("sheep", id = 43, x = 3056, y = 3517) +npc_spawn("ram", id = 3673, x = 3048, y = 3515) + +npc_spawn("monk", x = 3044, y = 3491) +npc_spawn("monk", x = 3045, y = 3483) +npc_spawn("monk", x = 3045, y = 3497) +npc_spawn("monk", x = 3050, y = 3490) +npc_spawn("monk", x = 3054, y = 3490) +npc_spawn("monk", x = 3058, y = 3497) + +// Functional npcs + +npc_spawn("richard", x = 3098, y = 3516) +npc_spawn("doris", x = 3079, y = 3491) +npc_spawn("brother_jered", x = 3045, y = 3488) +npc_spawn("brother_althric", x = 3054, y = 3504) + +npc_spawn("abbot_langley", x = 3059, y = 3484) +npc_spawn("oziach", x = 3067, y = 3518, facing = Direction.EAST) + +npc_spawn("shop_keeper", id = 528, x = 3079, y = 3509) +npc_spawn("shop_assistant", id = 529, x = 3082, y = 3513) + + +npc_spawn("banker", x = 3096, y = 3489, facing = Direction.WEST) +npc_spawn("banker", x = 3096, y = 3491, facing = Direction.WEST) +npc_spawn("banker", x = 3096, y = 3492) +npc_spawn("banker", x = 3098, y = 3492) + +npc_spawn("mage_of_zamorak", x = 3106, y = 3560) \ No newline at end of file diff --git a/game/src/plugins/locations/falador/meta.toml b/game/src/plugins/locations/falador/meta.toml new file mode 100644 index 000000000..6ba11a574 --- /dev/null +++ b/game/src/plugins/locations/falador/meta.toml @@ -0,0 +1,8 @@ +name = "falador npc spawns" +package = "org.apollo.game.plugin.locations" +authors = [ "Jesse W" ] +dependencies = [ "spawning" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/locations/falador/src/falador-npcs.plugin.kts b/game/src/plugins/locations/falador/src/falador-npcs.plugin.kts new file mode 100644 index 000000000..1663b60ca --- /dev/null +++ b/game/src/plugins/locations/falador/src/falador-npcs.plugin.kts @@ -0,0 +1,168 @@ + +// Generic npcs + +npc_spawn("chicken", x = 2965, y = 3345) + +npc_spawn("duck", x = 2988, y = 3383) +npc_spawn("duck", x = 2992, y = 3383) +npc_spawn("duck", x = 2993, y = 3385) + +npc_spawn("drunken_man", x = 2957, y = 3368, z = 1) + +npc_spawn("dwarf", id = 118, x = 3023, y = 3334) +npc_spawn("dwarf", id = 118, x = 3027, y = 3341) +npc_spawn("dwarf", id = 118, x = 3012, y = 3341) +npc_spawn("dwarf", id = 118, x = 3017, y = 3346, z = 1) +npc_spawn("dwarf", id = 118, x = 3011, y = 3341, z = 1) + +npc_spawn("dwarf", id = 121, x = 3027, y = 3341) + +npc_spawn("dwarf", id = 382, x = 3017, y = 3340) + +npc_spawn("dwarf", id = 3294, x = 3022, y = 3338) +npc_spawn("dwarf", id = 3295, x = 3021, y = 3341) + +npc_spawn("gardener", x = 2998, y = 3385) +npc_spawn("gardener", x = 3019, y = 3369) +npc_spawn("gardener", id = 3234, x = 3016, y = 3386) + +npc_spawn("guard", x = 2965, y = 3394) +npc_spawn("guard", x = 2964, y = 3396) +npc_spawn("guard", x = 2966, y = 3397) +npc_spawn("guard", x = 2964, y = 3384) +npc_spawn("guard", x = 2963, y = 3380) +npc_spawn("guard", x = 3006, y = 3325) +npc_spawn("guard", x = 3008, y = 3320) +npc_spawn("guard", x = 3006, y = 3322) +npc_spawn("guard", x = 3038, y = 3356) + +npc_spawn("guard", id = 10, x = 2942, y = 3375) +npc_spawn("guard", id = 10, x = 3040, y = 3352) + +npc_spawn("guard", id = 3230, x = 2967, y = 3395) +npc_spawn("guard", id = 3230, x = 2966, y = 3392) +npc_spawn("guard", id = 3230, x = 2963, y = 3376) +npc_spawn("guard", id = 3230, x = 2954, y = 3382) +npc_spawn("guard", id = 3230, x = 2950, y = 3377) +npc_spawn("guard", id = 3230, x = 2968, y = 3381) + +npc_spawn("guard", id = 3231, x = 3033, y = 3389, z = 1) +npc_spawn("guard", id = 3231, x = 3041, y = 3388, z = 1) +npc_spawn("guard", id = 3231, x = 3048, y = 3389, z = 1) +npc_spawn("guard", id = 3231, x = 3056, y = 3389, z = 1) +npc_spawn("guard", id = 3231, x = 3062, y = 3386, z = 1) +npc_spawn("guard", id = 3231, x = 3058, y = 3329, z = 1) +npc_spawn("guard", id = 3231, x = 3050, y = 3329, z = 1) +npc_spawn("guard", id = 3231, x = 3038, y = 3329, z = 1) +npc_spawn("guard", id = 3231, x = 3029, y = 3329, z = 1) + +npc_spawn("swan", x = 2960, y = 3359) +npc_spawn("swan", x = 2963, y = 3360) +npc_spawn("swan", x = 2968, y = 3359) +npc_spawn("swan", x = 2971, y = 3360) +npc_spawn("swan", x = 2976, y = 3358) +npc_spawn("swan", x = 2989, y = 3384) + +npc_spawn("man", id = 3223, x = 2991, y = 3365) +npc_spawn("man", id = 3225, x = 3037, y = 3345, z = 1) + +npc_spawn("white_knight", x = 2983, y = 3343) +npc_spawn("white_knight", x = 2981, y = 3334) +npc_spawn("white_knight", x = 2988, y = 3335) +npc_spawn("white_knight", x = 2996, y = 3342) +npc_spawn("white_knight", x = 2960, y = 3340) +npc_spawn("white_knight", x = 2962, y = 3336) +npc_spawn("white_knight", x = 2974, y = 3342) +npc_spawn("white_knight", x = 2972, y = 3345) +npc_spawn("white_knight", x = 2977, y = 3348) + +npc_spawn("white_knight", id = 3348, x = 2971, y = 3340) +npc_spawn("white_knight", id = 3348, x = 2978, y = 3350) + +npc_spawn("white_knight", x = 2964, y = 3330, z = 1) +npc_spawn("white_knight", x = 2968, y = 3334, z = 1) +npc_spawn("white_knight", x = 2969, y = 3339, z = 1) +npc_spawn("white_knight", x = 2978, y = 3332, z = 1) +npc_spawn("white_knight", x = 2958, y = 3340, z = 1) +npc_spawn("white_knight", x = 2960, y = 3343, z = 1) + +npc_spawn("white_knight", id = 3348, x = 2987, y = 3334, z = 1) +npc_spawn("white_knight", id = 3348, x = 2983, y = 3336, z = 1) +npc_spawn("white_knight", id = 3348, x = 2987, y = 3334, z = 1) +npc_spawn("white_knight", id = 3348, x = 2979, y = 3348, z = 1) +npc_spawn("white_knight", id = 3348, x = 2964, y = 3337, z = 1) + +npc_spawn("white_knight", id = 3349, x = 2989, y = 3344, z = 1) + +npc_spawn("white_knight", x = 2985, y = 3342, z = 2) + +npc_spawn("white_knight", id = 3348, x = 2979, y = 3348, z = 2) +npc_spawn("white_knight", id = 3348, x = 2974, y = 3329, z = 2) +npc_spawn("white_knight", id = 3348, x = 2982, y = 3341, z = 2) + +npc_spawn("white_knight", id = 3349, x = 2990, y = 3341, z = 2) +npc_spawn("white_knight", id = 3349, x = 2971, y = 3330, z = 2) +npc_spawn("white_knight", id = 3349, x = 2965, y = 3350, z = 2) +npc_spawn("white_knight", id = 3349, x = 2965, y = 3329, z = 2) + +npc_spawn("white_knight", id = 3350, x = 2961, y = 3347, z = 2) + +npc_spawn("white_knight", id = 3349, x = 2962, y = 3339, z = 3) + +npc_spawn("white_knight", id = 3350, x = 2960, y = 3336, z = 3) +npc_spawn("white_knight", id = 3350, x = 2984, y = 3349, z = 3) + +npc_spawn("woman", id = 3226, x = 2991, y = 3384) + +// Functional npcs + +npc_spawn("apprentice_workman", id = 3235, x = 2971, y = 3369, z = 1) + +npc_spawn("banker", id = 495, x = 2945, y = 3366) +npc_spawn("banker", id = 495, x = 2946, y = 3366) +npc_spawn("banker", id = 495, x = 2947, y = 3366) +npc_spawn("banker", id = 495, x = 2948, y = 3366) + +npc_spawn("banker", x = 2949, y = 3366) + +npc_spawn("banker", x = 3015, y = 3353) +npc_spawn("banker", x = 3014, y = 3353) +npc_spawn("banker", x = 3013, y = 3353) +npc_spawn("banker", x = 3012, y = 3353) +npc_spawn("banker", x = 3011, y = 3353) +npc_spawn("banker", x = 3010, y = 3353) + +npc_spawn("cassie", x = 2976, y = 3383) + +npc_spawn("emily", x = 2954, y = 3372) + +npc_spawn("flynn", x = 2950, y = 3387) + +npc_spawn("hairdresser", x = 2944, y = 3380) + +npc_spawn("herquin", x = 2945, y = 3335) + +npc_spawn("heskel", x = 3007, y = 3374) + +npc_spawn("kaylee", x = 2957, y = 3372) + +npc_spawn("tina", x = 2955, y = 3371, z = 1) + +npc_spawn("tool_leprechaun", x = 3005, y = 3370) + +npc_spawn("squire", x = 2977, y = 3343) + +npc_spawn("sir_tiffy_cashien", x = 2997, y = 3373) + +npc_spawn("sir_amik_varze", x = 2960, y = 3336, z = 2) + +npc_spawn("sir_vyvin", x = 2983, y = 3335, z = 2) + +npc_spawn("shop_keeper", id = 524, x = 2955, y = 3389) +npc_spawn("shop_assistant", id = 525, x = 2957, y = 3387) + +npc_spawn("wayne", x = 2972, y = 3312) + +npc_spawn("workman", id = 3236, x = 2975, y = 3369, z = 1) + +npc_spawn("wyson_the_gardener", x = 3028, y = 3381) \ No newline at end of file diff --git a/game/src/plugins/locations/lumbridge/src/lumbridge-npcs.kts b/game/src/plugins/locations/lumbridge/src/lumbridge-npcs.plugin.kts similarity index 91% rename from game/src/plugins/locations/lumbridge/src/lumbridge-npcs.kts rename to game/src/plugins/locations/lumbridge/src/lumbridge-npcs.plugin.kts index aa92c5847..fe547d0df 100644 --- a/game/src/plugins/locations/lumbridge/src/lumbridge-npcs.kts +++ b/game/src/plugins/locations/lumbridge/src/lumbridge-npcs.plugin.kts @@ -5,6 +5,7 @@ npc_spawn("woman", id = 5, x = 3229, y = 2329) npc_spawn("hans", x = 3221, y = 3221) npc_spawn("father aereck", x = 3243, y = 3210) +npc_spawn("bob", x = 3231, y = 3203) npc_spawn("shop keeper", x = 3212, y = 3247) npc_spawn("shop assistant", x = 3211, y = 3245) npc_spawn("lumbridge guide", x = 323, y = 3229) diff --git a/game/src/plugins/locations/tutorial-island/meta.toml b/game/src/plugins/locations/tutorial-island/meta.toml new file mode 100644 index 000000000..837b3c9ac --- /dev/null +++ b/game/src/plugins/locations/tutorial-island/meta.toml @@ -0,0 +1,8 @@ +name = "tutorial island npc spawns" +package = "org.apollo.game.plugin.locations" +authors = [ "Jesse W" ] +dependencies = [ "spawning" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts b/game/src/plugins/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts new file mode 100644 index 000000000..d6c6501fc --- /dev/null +++ b/game/src/plugins/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts @@ -0,0 +1,41 @@ +import org.apollo.game.model.Direction + +// Functional npcs + +// 'Above-ground' npcs + +npc_spawn("master_chef", x = 3076, y = 3085) +npc_spawn("quest_guide", x = 3086, y = 3122) +npc_spawn("financial_advisor", x = 3127, y = 3124, facing = Direction.WEST) +npc_spawn("brother_brace", x = 3124, y = 3107, facing = Direction.EAST) +npc_spawn("magic_instructor", x = 3140, y = 3085) + +// 'Below-ground' npcs +// Note: They aren't actually on a different plane, they're just in a different location that +// pretends to be underground. + +npc_spawn("mining_instructor", x = 3081, y = 9504) +npc_spawn("combat_instructor", x = 3104, y = 9506) + +// Non-humanoid npcs + +npc_spawn("fishing_spot", id = 316, x = 3102, y = 3093) + +npc_spawn("chicken", x = 3140, y = 3095) +npc_spawn("chicken", x = 3140, y = 3093) +npc_spawn("chicken", x = 3138, y = 3092) +npc_spawn("chicken", x = 3137, y = 3094) +npc_spawn("chicken", x = 3138, y = 3095) + +// 'Below-ground' npcs +// Note: They aren't actually on a different plane, they're just in a different location that +// pretends to be underground. + +npc_spawn("giant_rat", id = 87, x = 3105, y = 9514) +npc_spawn("giant_rat", id = 87, x = 3105, y = 9517) +npc_spawn("giant_rat", id = 87, x = 3106, y = 9514) +npc_spawn("giant_rat", id = 87, x = 3104, y = 9514) +npc_spawn("giant_rat", id = 87, x = 3105, y = 9519) +npc_spawn("giant_rat", id = 87, x = 3109, y = 9516) +npc_spawn("giant_rat", id = 87, x = 3108, y = 9520) +npc_spawn("giant_rat", id = 87, x = 3102, y = 9517) \ No newline at end of file diff --git a/game/src/plugins/locations/varrock/meta.toml b/game/src/plugins/locations/varrock/meta.toml new file mode 100644 index 000000000..d56f16d58 --- /dev/null +++ b/game/src/plugins/locations/varrock/meta.toml @@ -0,0 +1,8 @@ +name = "varrock npc spawns" +package = "org.apollo.game.plugin.locations" +authors = [ "Jesse W" ] +dependencies = [ "spawning" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/locations/varrock/src/varrock-npcs.plugin.kts b/game/src/plugins/locations/varrock/src/varrock-npcs.plugin.kts new file mode 100644 index 000000000..b8d40abb9 --- /dev/null +++ b/game/src/plugins/locations/varrock/src/varrock-npcs.plugin.kts @@ -0,0 +1,267 @@ +import org.apollo.game.model.Direction + +npc_spawn("barbarian_woman", x = 3222, y = 3399) + +npc_spawn("bear", id = 106, x = 3289, y = 3351) + +npc_spawn("black_knight", x = 3238, y = 3514) +npc_spawn("black_knight", x = 3227, y = 3518) +npc_spawn("black_knight", x = 3279, y = 3502) + +npc_spawn("dark_wizard", id = 174, x = 3230, y = 3366) + +npc_spawn("dark_wizard", id = 174, x = 3228, y = 3368) +npc_spawn("dark_wizard", id = 174, x = 3225, y = 3367) +npc_spawn("dark_wizard", id = 174, x = 3226, y = 3365) +npc_spawn("dark_wizard", id = 174, x = 3226, y = 3372) +npc_spawn("dark_wizard", id = 174, x = 3231, y = 3371) + +npc_spawn("dark_wizard", id = 172, x = 3229, y = 3372) +npc_spawn("dark_wizard", id = 172, x = 3224, y = 3370) +npc_spawn("dark_wizard", id = 172, x = 3228, y = 3366) +npc_spawn("dark_wizard", id = 172, x = 3232, y = 3368) +npc_spawn("dark_wizard", id = 172, x = 3226, y = 3369) + +npc_spawn("giant_rat", id = 87, x = 3292, y = 3375) +npc_spawn("giant_rat", id = 87, x = 3265, y = 3384) +npc_spawn("giant_rat", id = 87, x = 3267, y = 3381) + +npc_spawn("guard", id = 368, x = 3263, y = 3407, facing = Direction.SOUTH) + +npc_spawn("jeremy_clerksin", x = 3253, y = 3477) +npc_spawn("martina_scorsby", x = 3256, y = 3481) + +npc_spawn("man", x = 3281, y = 3500) +npc_spawn("man", x = 3193, y = 3394) +npc_spawn("man", x = 3159, y = 3429) +npc_spawn("man", x = 3245, y = 3394) +npc_spawn("man", x = 3283, y = 3492, z = 1) + +npc_spawn("man", id = 2, x = 3283, y = 3492, z = 1) +npc_spawn("man", id = 2, x = 3263, y = 3400) + +npc_spawn("man", id = 3, x = 3227, y = 3395, z = 1) +npc_spawn("man", id = 3, x = 3231, y = 3399, z = 1) + +npc_spawn("mugger", x = 3251, y = 3390) +npc_spawn("mugger", x = 3177, y = 3363) + +npc_spawn("tramp", id = 2792, x = 3177, y = 3363) + +npc_spawn("woman", x = 3221, y = 3396) + +npc_spawn("woman", id = 5, x = 3279, y = 3497) +npc_spawn("woman", id = 25, x = 3278, y = 3492) + + +npc_spawn("thief", x = 3285, y = 3500) +npc_spawn("thief", x = 3234, y = 3389) +npc_spawn("thief", x = 3188, y = 3383) +npc_spawn("thief", x = 3184, y = 3390) +npc_spawn("thief", x = 3188, y = 3394) + +npc_spawn("unicorn", x = 3286, y = 3342) +npc_spawn("unicorn", x = 3279, y = 3345) + +// North Guards + +npc_spawn("guard", x = 3244, y = 3500) +npc_spawn("guard", x = 3247, y = 3503) + +// East Guards + +npc_spawn("guard", x = 3271, y = 3431) +npc_spawn("guard", x = 3270, y = 3425) +npc_spawn("guard", x = 3274, y = 3421) +npc_spawn("guard", x = 3274, y = 3427) + +// South Guards + +npc_spawn("guard", x = 3210, y = 3382) +npc_spawn("guard", x = 3212, y = 3380) +npc_spawn("guard", x = 3207, y = 3376) + +// West Guards + +npc_spawn("guard", x = 3174, y = 3427) +npc_spawn("guard", x = 3176, y = 3430) +npc_spawn("guard", x = 3176, y = 3427) +npc_spawn("guard", x = 3180, y = 3399) +npc_spawn("guard", x = 3175, y = 3415, z = 1) +npc_spawn("guard", x = 3174, y = 3403, z = 1) + +// Varrock Palace + +npc_spawn("guard", x = 3210, y = 3461) +npc_spawn("guard", x = 3211, y = 3465) +npc_spawn("guard", x = 3214, y = 3462) +npc_spawn("guard", x = 3216, y = 3464) +npc_spawn("guard", x = 3220, y = 3461) +npc_spawn("guard", x = 3206, y = 3461) +npc_spawn("guard", x = 3204, y = 3495) + +npc_spawn("guard", x = 3204, y = 3495, z = 1) +npc_spawn("guard", x = 3205, y = 3492, z = 1) +npc_spawn("guard", x = 3203, y = 3492, z = 1) +npc_spawn("guard", x = 3205, y = 3497, z = 1) + +npc_spawn("guard", x = 3221, y = 3471, z = 2) +npc_spawn("guard", x = 3214, y = 3474, z = 2) +npc_spawn("guard", x = 3215, y = 3471, z = 2) +npc_spawn("guard", x = 3211, y = 3471, z = 2) +npc_spawn("guard", x = 3209, y = 3473, z = 2) +npc_spawn("guard", x = 3212, y = 3475, z = 2) +npc_spawn("guard", x = 3207, y = 3477, z = 2) +npc_spawn("guard", x = 3203, y = 3476, z = 2) +npc_spawn("guard", x = 3205, y = 3479, z = 2) +npc_spawn("guard", x = 3203, y = 3483, z = 2) +npc_spawn("guard", x = 3221, y = 3485, z = 2) + +npc_spawn("monk_of_zamorak", id = 189, x = 3213, y = 3476) + +npc_spawn("warrior_woman", x = 3203, y = 3490) +npc_spawn("warrior_woman", x = 3205, y = 3493) + +// Varrock/Lumbridge Pen + +npc_spawn("swan", x = 3261, y = 3354) +npc_spawn("swan", x = 3260, y = 3356) + + +npc_spawn("ram", id = 3673, x = 3238, y = 3346) +npc_spawn("ram", id = 3673, x = 3248, y = 3352) +npc_spawn("ram", id = 3673, x = 3260, y = 3348) + +npc_spawn("sheep", id = 42, x = 3263, y = 3347) +npc_spawn("sheep", id = 42, x = 3268, y = 3350) +npc_spawn("sheep", id = 42, x = 3252, y = 3352) +npc_spawn("sheep", id = 42, x = 3243, y = 3344) +npc_spawn("sheep", id = 42, x = 3235, y = 3347) + +npc_spawn("sheep", id = 3579, x = 3234, y = 3344) +npc_spawn("sheep", id = 3579, x = 3241, y = 3347) +npc_spawn("sheep", id = 3579, x = 3257, y = 3350) + +// Champions Guild + +npc_spawn("chicken", x = 3195, y = 3359) +npc_spawn("chicken", x = 3198, y = 3356) +npc_spawn("chicken", x = 3195, y = 3355) + +npc_spawn("chicken", id = 1017, x = 3196, y = 3353) +npc_spawn("chicken", id = 1017, x = 3197, y = 3356) + +npc_spawn("evil_chicken", x = 3198, y = 3359) + +// Function Npc + +npc_spawn("apothecary", x = 3196, y = 3403) + +npc_spawn("captain_rovin", x = 3204, y = 3496, z = 2) + +npc_spawn("curator", x = 3256, y = 3447) + +npc_spawn("dimintheis", x = 3280, y = 3403) + +npc_spawn("dr_harlow", x = 3224, y = 3398) + +npc_spawn("ellamaria", x = 3228, y = 3475) + +npc_spawn("father_lawrence", x = 3253, y = 3484) + +npc_spawn("guidors_wife", id = 342, x = 3280, y = 3382) + +npc_spawn("guidor", x = 3284, y = 3381, facing = Direction.SOUTH) + +npc_spawn("guild_master", x = 3189, y = 3360) + +npc_spawn("gypsy", x = 3203, y = 3423) + +npc_spawn("hooknosed_jack", x = 3268, y = 3400) + +npc_spawn("jonny_the_beard", x = 3223, y = 3395) + +npc_spawn("johnathon", x = 3278, y = 3503, z = 1) + +npc_spawn("katrine", x = 3185, y = 3386) + +npc_spawn("king_roald", x = 3223, y = 3473) + +npc_spawn("master_farmer", x = 3243, y = 3349) + +npc_spawn("pox", x = 3267, y = 3399) + +npc_spawn("reldo", x = 3210, y = 3492) + +npc_spawn("romeo", x = 3211, y = 3423) + +npc_spawn("shilop", x = 3211, y = 3435) + +npc_spawn("sir_prysin", x = 3204, y = 3472) + +npc_spawn("tarquin", x = 3203, y = 3344, facing = Direction.SOUTH) + +npc_spawn("tool_leprechaun", x = 3182, y = 3355) + +npc_spawn("tool_leprechaun", x = 3229, y = 3455) + +npc_spawn("tramp", id = 641, x = 3207, y = 3392) + +npc_spawn("wilough", x = 3222, y = 3437) + +// Shop Npc + +npc_spawn("aubury", x = 3253, y = 3401) + +npc_spawn("baraek", x = 3217, y = 3434) + +npc_spawn("bartender", x = 3226, y = 3400) + +npc_spawn("bartender", id = 1921, x = 3277, y = 3487) + +npc_spawn("fancy_dress_shop_owner", x = 3281, y = 3398) + +npc_spawn("horvik", x = 3229, y = 3438) + +npc_spawn("lowe", x = 3233, y = 3421) + +npc_spawn("scavvo", x = 3192, y = 3353, z = 1) + +npc_spawn("shop_keeper", id = 551, x = 3206, y = 3399) +npc_spawn("shop_assistant", id = 552, x = 3207, y = 3396) + +npc_spawn("shop_keeper", id = 522, x = 3216, y = 3414) +npc_spawn("shop_assistant", id = 523, x = 3216, y = 3417) + +npc_spawn("tea_seller", x = 3271, y = 3411) + +npc_spawn("thessalia", x = 3206, y = 3417) + +npc_spawn("zaff", x = 3203, y = 3434) + +// Juliet House + +npc_spawn("draul_leptoc", x = 3228, y = 3475) +npc_spawn("juliet", x = 3159, y = 3425, z = 1) +npc_spawn("phillipa", x = 3160, y = 3429, z = 1) + +// Gertrude House + +npc_spawn("gertrude", x = 3153, y = 3413) +npc_spawn("kanel", x = 3155, y = 3405, facing = Direction.EAST) +npc_spawn("philop", x = 3150, y = 3405, facing = Direction.SOUTH) + +// Small Bank + +npc_spawn("banker", id = 495, x = 3252, y = 3418) +npc_spawn("banker", id = 494, x = 3252, y = 3418) +npc_spawn("banker", id = 494, x = 3252, y = 3418) +npc_spawn("banker", id = 494, x = 3252, y = 3418) + +// Big Bank + +npc_spawn("banker", id = 494, x = 3187, y = 3436, facing = Direction.WEST) +npc_spawn("banker", id = 494, x = 3187, y = 3440, facing = Direction.WEST) +npc_spawn("banker", id = 494, x = 3187, y = 3444, facing = Direction.WEST) +npc_spawn("banker", id = 495, x = 3187, y = 3438, facing = Direction.WEST) +npc_spawn("banker", id = 495, x = 3187, y = 3442, facing = Direction.WEST) \ No newline at end of file From ce3150082d7bc409331190861bc4bd6b8bb8810a Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Fri, 2 Jun 2017 22:30:39 +0100 Subject: [PATCH 016/209] Fix builds on other platforms (non-Unix) --- game/build.gradle | 2 +- .../org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/game/build.gradle b/game/build.gradle index e7db42a3a..d421fc937 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -31,7 +31,7 @@ dependencies { compile group: 'io.github.lukehutch', name: 'fast-classpath-scanner', version: '2.0.21' compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" - compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlinVersion" + compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt index ee655af34..85840729f 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt @@ -1,12 +1,11 @@ package org.apollo.game.plugin.kotlin -import com.google.common.base.CaseFormat -import com.intellij.openapi.util.Disposer import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.cli.jvm.compiler.* import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot import org.jetbrains.kotlin.codegen.CompilationException +import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate import java.io.File @@ -15,9 +14,7 @@ import java.net.URISyntaxException import java.net.URLClassLoader import java.nio.file.* import java.nio.file.StandardOpenOption.* -import java.nio.file.attribute.BasicFileAttributes import java.util.* -import java.util.function.BiPredicate class KotlinMessageCollector : MessageCollector { @@ -75,7 +72,7 @@ class KotlinPluginCompiler(val classpath: List, val messageCollector: Mess println("Warning! Boot class path is not supported, must be supplied on the command line") } else { val bootClasspath = runtimeBean.bootClassPath - classpath.addAll(bootClasspath.split(':').map { File(it) }) + classpath.addAll(bootClasspath.split(File.pathSeparatorChar).map { File(it) }) } /** From 30fc810d61341ca27cd20351317165491c619c04 Mon Sep 17 00:00:00 2001 From: Cube Date: Sat, 3 Jun 2017 02:22:37 +0300 Subject: [PATCH 017/209] Add base for Kotlin commands --- .../game/plugin/kotlin/KotlinPluginScript.kt | 28 +++++++++++++++++-- game/src/main/kotlin/stub.kt | 9 ++++-- game/src/plugins/cmd/meta.toml | 7 +++++ game/src/plugins/cmd/src/bank-cmd.plugin.kts | 5 ++++ game/src/plugins/stub/stub.kt | 4 +++ 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 game/src/plugins/cmd/meta.toml create mode 100644 game/src/plugins/cmd/src/bank-cmd.plugin.kts diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index 1a9541a30..710b3ac18 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -1,10 +1,12 @@ package org.apollo.game.plugin.kotlin +import org.apollo.game.command.Command +import org.apollo.game.command.CommandListener import org.apollo.game.message.handler.MessageHandler import org.apollo.game.model.World import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel import org.apollo.game.plugin.PluginContext -import org.apollo.game.scheduling.ScheduledTask import org.apollo.net.message.Message import kotlin.reflect.KClass import kotlin.script.templates.ScriptTemplateDefinition @@ -20,6 +22,10 @@ abstract class KotlinPluginScript(private var world: World, val context: PluginC return KotlinMessageHandler(world, context, type.invoke()) } + protected fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { + return KotlinCommandHandler(world, command, privileges) + } + protected fun start(callback: (World) -> Unit) { this.startListener = callback } @@ -37,7 +43,6 @@ abstract class KotlinPluginScript(private var world: World, val context: PluginC } } - class KotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : MessageHandler(world) { override fun handle(player: Player, message: T) { @@ -61,3 +66,22 @@ class KotlinMessageHandler(val world: World, val context: PluginCon } } + +class KotlinCommandListener(val level: PrivilegeLevel, val function: (Player, Command) -> Unit) : CommandListener(level) { + + override fun execute(player: Player, command: Command) { + function.invoke(player, command) + } + +} + +class KotlinCommandHandler(val world : World, val command: String, val privileges: PrivilegeLevel) { + + var function: (Player, Command) -> Unit = { _, _ -> } + + fun then(function: (Player, Command) -> Unit) { + this.function = function + world.commandDispatcher.register(command, KotlinCommandListener(privileges, function)) + } + +} diff --git a/game/src/main/kotlin/stub.kt b/game/src/main/kotlin/stub.kt index 8c5837043..a7e212c7b 100644 --- a/game/src/main/kotlin/stub.kt +++ b/game/src/main/kotlin/stub.kt @@ -7,8 +7,9 @@ */ import org.apollo.game.model.World -import org.apollo.game.plugin.PluginContext -import org.apollo.game.plugin.kotlin.* +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.kotlin.KotlinCommandHandler +import org.apollo.game.plugin.kotlin.KotlinMessageHandler import org.apollo.net.message.Message import kotlin.reflect.KClass @@ -16,6 +17,10 @@ fun on(type: () -> KClass): KotlinMessageHandler { null!! } +fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { + null!! +} + fun start(callback: (World) -> Unit) { } diff --git a/game/src/plugins/cmd/meta.toml b/game/src/plugins/cmd/meta.toml new file mode 100644 index 000000000..141c3a7b1 --- /dev/null +++ b/game/src/plugins/cmd/meta.toml @@ -0,0 +1,7 @@ +name = "Chat commands" +package = "org.apollo.game.plugin.cmd" +authors = [ "Graham", "cubeee" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/cmd/src/bank-cmd.plugin.kts b/game/src/plugins/cmd/src/bank-cmd.plugin.kts new file mode 100644 index 000000000..84de8f0d6 --- /dev/null +++ b/game/src/plugins/cmd/src/bank-cmd.plugin.kts @@ -0,0 +1,5 @@ +import org.apollo.game.model.entity.setting.PrivilegeLevel + +// Opens the player's bank if they are an administrator. +on_command("bank", PrivilegeLevel.ADMINISTRATOR) + .then { player, _ -> player.openBank() } \ No newline at end of file diff --git a/game/src/plugins/stub/stub.kt b/game/src/plugins/stub/stub.kt index 8c5837043..f82da254d 100644 --- a/game/src/plugins/stub/stub.kt +++ b/game/src/plugins/stub/stub.kt @@ -16,6 +16,10 @@ fun on(type: () -> KClass): KotlinMessageHandler { null!! } +fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { + null!! +} + fun start(callback: (World) -> Unit) { } From 8e8e2d0991e37b39c83d61c35ebd18a3f896a801 Mon Sep 17 00:00:00 2001 From: Cube Date: Sat, 3 Jun 2017 15:23:03 +0300 Subject: [PATCH 018/209] Simplify on_command arguments --- .../org/apollo/game/plugin/kotlin/KotlinPluginScript.kt | 8 ++++---- game/src/plugins/cmd/src/bank-cmd.plugin.kts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index 710b3ac18..e186a700e 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -67,19 +67,19 @@ class KotlinMessageHandler(val world: World, val context: PluginCon } -class KotlinCommandListener(val level: PrivilegeLevel, val function: (Player, Command) -> Unit) : CommandListener(level) { +class KotlinCommandListener(val level: PrivilegeLevel, val function: Command.(Player) -> Unit) : CommandListener(level) { override fun execute(player: Player, command: Command) { - function.invoke(player, command) + function.invoke(command, player) } } class KotlinCommandHandler(val world : World, val command: String, val privileges: PrivilegeLevel) { - var function: (Player, Command) -> Unit = { _, _ -> } + var function: Command.(Player) -> Unit = { _ -> } - fun then(function: (Player, Command) -> Unit) { + fun then(function: Command.(Player) -> Unit) { this.function = function world.commandDispatcher.register(command, KotlinCommandListener(privileges, function)) } diff --git a/game/src/plugins/cmd/src/bank-cmd.plugin.kts b/game/src/plugins/cmd/src/bank-cmd.plugin.kts index 84de8f0d6..181a11943 100644 --- a/game/src/plugins/cmd/src/bank-cmd.plugin.kts +++ b/game/src/plugins/cmd/src/bank-cmd.plugin.kts @@ -2,4 +2,4 @@ import org.apollo.game.model.entity.setting.PrivilegeLevel // Opens the player's bank if they are an administrator. on_command("bank", PrivilegeLevel.ADMINISTRATOR) - .then { player, _ -> player.openBank() } \ No newline at end of file + .then { player -> player.openBank() } \ No newline at end of file From b99ee9ba31a4ddc8d7412f9191dc7c8785990c31 Mon Sep 17 00:00:00 2001 From: Cube Date: Sat, 3 Jun 2017 18:55:40 +0300 Subject: [PATCH 019/209] Convert ::animate command to Kotlin --- game/src/plugins/cmd/meta.toml | 7 ++++++- .../plugins/cmd/src/animate-cmd.plugin.kts | 9 +++++++++ game/src/plugins/util/command/meta.toml | 5 +++++ game/src/plugins/util/command/src/command.kt | 19 +++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 game/src/plugins/cmd/src/animate-cmd.plugin.kts create mode 100644 game/src/plugins/util/command/meta.toml create mode 100644 game/src/plugins/util/command/src/command.kt diff --git a/game/src/plugins/cmd/meta.toml b/game/src/plugins/cmd/meta.toml index 141c3a7b1..84ece10b3 100644 --- a/game/src/plugins/cmd/meta.toml +++ b/game/src/plugins/cmd/meta.toml @@ -1,6 +1,11 @@ name = "Chat commands" package = "org.apollo.game.plugin.cmd" -authors = [ "Graham", "cubeee" ] +dependencies = [ "command_utilities" ] +authors = [ + "Graham", + "Major", + "cubeee" +] [config] srcDir = "src/" diff --git a/game/src/plugins/cmd/src/animate-cmd.plugin.kts b/game/src/plugins/cmd/src/animate-cmd.plugin.kts new file mode 100644 index 000000000..55b713062 --- /dev/null +++ b/game/src/plugins/cmd/src/animate-cmd.plugin.kts @@ -0,0 +1,9 @@ +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.setting.PrivilegeLevel + +on_command("animate", PrivilegeLevel.MODERATOR) + .then { player -> + if(valid_arg_length(arguments, 1, player, "Invalid syntax - ::animate [animation-id]")) { + player.playAnimation(Animation(arguments[0].toInt())) + } + } \ No newline at end of file diff --git a/game/src/plugins/util/command/meta.toml b/game/src/plugins/util/command/meta.toml new file mode 100644 index 000000000..2d962919d --- /dev/null +++ b/game/src/plugins/util/command/meta.toml @@ -0,0 +1,5 @@ +name = "command utilities" +package = "org.apollo.game.plugins.util" + +[config] +srcDir = "src/" \ No newline at end of file diff --git a/game/src/plugins/util/command/src/command.kt b/game/src/plugins/util/command/src/command.kt new file mode 100644 index 000000000..bd693948f --- /dev/null +++ b/game/src/plugins/util/command/src/command.kt @@ -0,0 +1,19 @@ +import org.apollo.game.model.entity.Player + +/** + * Checks whether the amount of arguments provided is correct, sending the player the specified + * message if not. + */ +fun valid_arg_length(args: Array, length: Any, player: Player, message: String): Boolean { + val valid = when (length) { + is Int -> length == args.size + is IntRange -> length.contains(args.size) + else -> { + throw IllegalArgumentException("length must be one of the following: Int, IntRange") + } + } + if (!valid) { + player.sendMessage(message) + } + return valid +} \ No newline at end of file From 7df948e12f1195460d306379638c9cca81f6b063 Mon Sep 17 00:00:00 2001 From: Cube Date: Sat, 3 Jun 2017 19:08:52 +0300 Subject: [PATCH 020/209] Convert ::item command to Kotlin --- game/src/plugins/cmd/src/item-cmd.plugin.kts | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 game/src/plugins/cmd/src/item-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/item-cmd.plugin.kts b/game/src/plugins/cmd/src/item-cmd.plugin.kts new file mode 100644 index 000000000..7f6f22557 --- /dev/null +++ b/game/src/plugins/cmd/src/item-cmd.plugin.kts @@ -0,0 +1,24 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.setting.PrivilegeLevel + +on_command("item", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + if (!valid_arg_length(arguments, 1..2, player, "Invalid syntax - ::item [id] [amount]")) { + return@then + } + + val id = arguments[0].toInt() + val amount = if (arguments.size == 2) arguments[1].toInt() else 1 + + if (id < 0 || id >= ItemDefinition.count()) { + player.sendMessage("The item id you specified is out of bounds!") + return@then + } + + if (amount < 0) { + player.sendMessage("The amount you specified is out of bounds!") + return@then + } + + player.inventory.add(id, amount) + } \ No newline at end of file From 5ea52e00f03d5faf63fbc4f3710ddc34657e4d9c Mon Sep 17 00:00:00 2001 From: Cube Date: Sat, 3 Jun 2017 19:30:22 +0300 Subject: [PATCH 021/209] Convert messaging commands to Kotlin --- game/src/plugins/cmd/src/messaging-cmd.plugin.kts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 game/src/plugins/cmd/src/messaging-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/messaging-cmd.plugin.kts b/game/src/plugins/cmd/src/messaging-cmd.plugin.kts new file mode 100644 index 000000000..883d7a513 --- /dev/null +++ b/game/src/plugins/cmd/src/messaging-cmd.plugin.kts @@ -0,0 +1,11 @@ +import org.apollo.game.model.entity.setting.PrivilegeLevel + +on_command("broadcast", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val message = arguments.joinToString(" ") + val broadcast = "[Broadcast] ${player.username.capitalize()}: $message" + + player.world.playerRepository.forEach { other -> + other.sendMessage(broadcast) + } + } From 6db98406d51c334653ff194743b436ca503e90e2 Mon Sep 17 00:00:00 2001 From: Cube Date: Sun, 4 Jun 2017 18:08:53 +0300 Subject: [PATCH 022/209] Overload valid_arg_length --- game/src/plugins/util/command/src/command.kt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/game/src/plugins/util/command/src/command.kt b/game/src/plugins/util/command/src/command.kt index bd693948f..7746d948b 100644 --- a/game/src/plugins/util/command/src/command.kt +++ b/game/src/plugins/util/command/src/command.kt @@ -4,16 +4,17 @@ import org.apollo.game.model.entity.Player * Checks whether the amount of arguments provided is correct, sending the player the specified * message if not. */ -fun valid_arg_length(args: Array, length: Any, player: Player, message: String): Boolean { - val valid = when (length) { - is Int -> length == args.size - is IntRange -> length.contains(args.size) - else -> { - throw IllegalArgumentException("length must be one of the following: Int, IntRange") - } - } +fun valid_arg_length(args: Array, length: IntRange, player: Player, message: String): Boolean { + val valid = length.contains(args.size) if (!valid) { player.sendMessage(message) } return valid -} \ No newline at end of file +} + +/** + * Checks whether the amount of arguments provided is correct, sending the player the specified + * message if not. + */ +fun valid_arg_length(args: Array, length: Int, player: Player, message: String) + = valid_arg_length(args, IntRange(length, length), player, message) \ No newline at end of file From 72c0be8ac627fcf9e9608812394a701d13ec8379 Mon Sep 17 00:00:00 2001 From: Cube Date: Sun, 4 Jun 2017 19:56:51 +0300 Subject: [PATCH 023/209] Convert punishment commands to Kotlin --- .../org/apollo/game/model/entity/Player.java | 17 ++++++ game/src/plugins/cmd/meta.toml | 1 + .../src/plugins/cmd/src/punish-cmd.plugin.kts | 60 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 game/src/plugins/cmd/src/punish-cmd.plugin.kts diff --git a/game/src/main/java/org/apollo/game/model/entity/Player.java b/game/src/main/java/org/apollo/game/model/entity/Player.java index 2a323b109..76c06db95 100644 --- a/game/src/main/java/org/apollo/game/model/entity/Player.java +++ b/game/src/main/java/org/apollo/game/model/entity/Player.java @@ -28,6 +28,7 @@ import org.apollo.game.model.entity.attr.AttributeMap; import org.apollo.game.model.entity.attr.AttributePersistence; import org.apollo.game.model.entity.attr.NumericalAttribute; +import org.apollo.game.model.entity.attr.BooleanAttribute; import org.apollo.game.model.entity.obj.DynamicGameObject; import org.apollo.game.model.entity.setting.MembershipStatus; import org.apollo.game.model.entity.setting.PrivacyState; @@ -943,6 +944,22 @@ public void setWithdrawingNotes(boolean withdrawingNotes) { this.withdrawingNotes = withdrawingNotes; } + /** + * Ban the player. + */ + public void ban() { + attributes.set("banned", new BooleanAttribute(true)); + } + + /** + * Sets the mute status of a player. + * + * @param muted Whether the player is muted. + */ + public void setMuted(boolean muted) { + attributes.set("muted", new BooleanAttribute(muted)); + } + @Override public void shout(String message, boolean chatOnly) { blockSet.add(SynchronizationBlock.createForceChatBlock(chatOnly ? message : '~' + message)); diff --git a/game/src/plugins/cmd/meta.toml b/game/src/plugins/cmd/meta.toml index 84ece10b3..7a255f397 100644 --- a/game/src/plugins/cmd/meta.toml +++ b/game/src/plugins/cmd/meta.toml @@ -4,6 +4,7 @@ dependencies = [ "command_utilities" ] authors = [ "Graham", "Major", + "lare96", "cubeee" ] diff --git a/game/src/plugins/cmd/src/punish-cmd.plugin.kts b/game/src/plugins/cmd/src/punish-cmd.plugin.kts new file mode 100644 index 000000000..619d46741 --- /dev/null +++ b/game/src/plugins/cmd/src/punish-cmd.plugin.kts @@ -0,0 +1,60 @@ + +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel + +/** + * Adds a command to mute a player. Admins cannot be muted. + */ +on_command("mute", PrivilegeLevel.MODERATOR) + .then { player -> + val name = arguments.joinToString(" ") + val targetPlayer = player.world.getPlayer(name) + + if (validate(player, targetPlayer)) { + targetPlayer.isMuted = true + player.sendMessage("You have just unmuted ${targetPlayer.username}.") + } + } + +/** + * Adds a command to unmute a player. + */ +on_command("unmute", PrivilegeLevel.MODERATOR) + .then { player -> + val name = arguments.joinToString(" ") + val targetPlayer = player.world.getPlayer(name) + + if (validate(player, targetPlayer)) { + targetPlayer.isMuted = false + player.sendMessage("You have just unmuted ${targetPlayer.username}.") + } + } + +/** + * Adds a command to ban a player. Admins cannot be banned. + */ +on_command("ban", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val name = arguments.joinToString(" ") + val targetPlayer = player.world.getPlayer(name) + + if (validate(player, targetPlayer)) { + targetPlayer.ban() + targetPlayer.logout() // TODO force logout + player.sendMessage("You have just banned ${targetPlayer.username}.") + } + } + +/** + * Ensures the player isn't null, and that they aren't an Administrator. + */ +fun validate(player: Player, targetPlayer: Player?): Boolean { + if (targetPlayer == null) { + player.sendMessage("That player does not exist.") + return false + } else if (targetPlayer.privilegeLevel == PrivilegeLevel.ADMINISTRATOR) { + player.sendMessage("You cannot perform this action on Administrators.") + return false + } + return true +} \ No newline at end of file From 9f67c308930d790c82d8898f8c9794fbaa2d034a Mon Sep 17 00:00:00 2001 From: Cube Date: Sun, 4 Jun 2017 20:06:29 +0300 Subject: [PATCH 024/209] Convert teleport commands to Kotlin --- .../plugins/cmd/src/teleport-cmd.plugin.kts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 game/src/plugins/cmd/src/teleport-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/teleport-cmd.plugin.kts b/game/src/plugins/cmd/src/teleport-cmd.plugin.kts new file mode 100644 index 000000000..c6bdba4f4 --- /dev/null +++ b/game/src/plugins/cmd/src/teleport-cmd.plugin.kts @@ -0,0 +1,28 @@ +import org.apollo.game.model.Position +import org.apollo.game.model.entity.setting.PrivilegeLevel + +/** + * Sends the player's position. + */ +on_command("pos", PrivilegeLevel.MODERATOR) + .then { player -> + player.sendMessage("You are at: ${player.position}.") + } + +/** + * Teleports the player to the specified position. + */ +on_command("tele", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + if (!valid_arg_length(arguments, 2..3, player, "Invalid syntax - ::tele [x] [y] [optional-z]")) { + return@then + } + + val x = arguments[0].toInt() + val y = arguments[1].toInt() + val z = if (arguments.size == 3) arguments[2].toInt() else player.position.height + + if (z in 0..4) { + player.teleport(Position(x, y, z)) + } + } \ No newline at end of file From 4f45f5f1ff3d012678e9f54dd80bd0324f3a6e26 Mon Sep 17 00:00:00 2001 From: Cube Date: Sun, 4 Jun 2017 20:35:23 +0300 Subject: [PATCH 025/209] Convert experience commands to Kotlin --- game/src/plugins/cmd/src/skill-cmd.plugin.kts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 game/src/plugins/cmd/src/skill-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/skill-cmd.plugin.kts b/game/src/plugins/cmd/src/skill-cmd.plugin.kts new file mode 100644 index 000000000..519e77012 --- /dev/null +++ b/game/src/plugins/cmd/src/skill-cmd.plugin.kts @@ -0,0 +1,66 @@ + +import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.SkillSet +import org.apollo.game.model.entity.setting.PrivilegeLevel + +/** + * Maximises the player's skill set. + */ +on_command("max", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val skills = player.skillSet + + for (skill in 0 until skills.size()) { + skills.addExperience(skill, SkillSet.MAXIMUM_EXP) + } + } + +/** + * Levels the specified skill to the specified level, optionally updating the current level as well. + */ +on_command("level", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val invalidSyntax = "Invalid syntax - ::level [skill-id] [level] " + if (arguments.size !in 2..3) { + player.sendMessage(invalidSyntax) + return@then + } + + val skillId = arguments[0].toInt() + val level = arguments[1].toInt() + if (skillId !in 0..20 || level !in 1..99) { + player.sendMessage(invalidSyntax) + return@then + } + + val experience = SkillSet.getExperienceForLevel(level).toDouble() + var current = level + + if (arguments.size == 3 && arguments[2] == "old") { + val skill = player.skillSet.getSkill(skillId) + current = skill.currentLevel + } + + player.skillSet.setSkill(skillId, Skill(experience, current, level)) + } + +/** + * Adds the specified amount of experience to the specified skill. + */ +on_command("xp", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val invalidSyntax = "Invalid syntax - ::xp [skill-id] [experience]" + if (arguments.size != 2) { + player.sendMessage(invalidSyntax) + return@then + } + + val skillId = arguments[0].toInt() + val experience = arguments[1].toDouble() + if (skillId !in 0..20 || experience <= 0) { + player.sendMessage("Invalid syntax - ::xp [skill-id] [experience]") + return@then + } + + player.skillSet.addExperience(skillId, experience) + } \ No newline at end of file From 3616753d7fabcc70b595e552c680605825b8583e Mon Sep 17 00:00:00 2001 From: Cube Date: Sun, 4 Jun 2017 21:11:37 +0300 Subject: [PATCH 026/209] Convert npc spawn commands to Kotlin --- game/src/plugins/cmd/src/spawn-cmd.plugin.kts | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 game/src/plugins/cmd/src/spawn-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/spawn-cmd.plugin.kts b/game/src/plugins/cmd/src/spawn-cmd.plugin.kts new file mode 100644 index 000000000..7f124d895 --- /dev/null +++ b/game/src/plugins/cmd/src/spawn-cmd.plugin.kts @@ -0,0 +1,110 @@ +import com.google.common.primitives.Ints +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.setting.PrivilegeLevel + +/** + * An array of npcs that cannot be spawned. + */ +val blacklist: IntArray = intArrayOf() + +/** + * Spawns a non-blacklisted npc in the specified position, or the player's position if both 'x' and + * 'y' are not supplied. + */ +on_command("spawn", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val invalidSyntax = "Invalid syntax - ::spawn [npc id] [optional-x] [optional-y] [optional-z]" + if (arguments.size !in intArrayOf(1, 3, 4)) { + player.sendMessage(invalidSyntax) + return@then + } + + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } + + if (id in blacklist) { + player.sendMessage("Sorry, npc $id is blacklisted!") + return@then + } + + val position: Position? + if (arguments.size == 1) { + position = player.position + } else { + var height = player.position.height + if (arguments.size == 4) { + val h = Ints.tryParse(arguments[3]) + if (h == null) { + player.sendMessage(invalidSyntax) + return@then + } + height = h + } + position = Position(arguments[1].toInt(), arguments[2].toInt(), height) + } + + player.world.register(Npc(player.world, id, position)) + } + +/** + * Mass spawns npcs around the player. + */ +on_command("mass", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val invalidSyntax = "Invalid syntax - ::mass [npc id] [range (1-5)]" + if (arguments.size != 2) { + player.sendMessage(invalidSyntax) + return@then + } + + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } + + val range = Ints.tryParse(arguments[1]) + if (range == null) { + player.sendMessage(invalidSyntax) + return@then + } + + if (id < 0 || range !in 1..5) { + player.sendMessage(invalidSyntax) + return@then + } + + if (id in blacklist) { + player.sendMessage("Sorry, npc $id is blacklisted!") + return@then + } + + val centerPosition = player.position + + val minX = centerPosition.x - range + val minY = centerPosition.y - range + val maxX = centerPosition.x + range + val maxY = centerPosition.y + range + val z = centerPosition.height + + for (x in minX..maxX) { + for (y in minY..maxY) { + player.world.register(Npc(player.world, id, Position(x, y, z))) + } + } + + player.sendMessage("Mass spawning npcs with id $id.") + } + +/** + * Unregisters all npcs from the world npc repository. + */ +on_command("clearnpcs", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + player.world.npcRepository.forEach { npc -> player.world.unregister(npc) } + player.sendMessage("Unregistered all npcs from the world.") + } \ No newline at end of file From 4ca8978ff386d26cb3e9eaa7caebd7847f2eb97c Mon Sep 17 00:00:00 2001 From: Cube Date: Thu, 15 Jun 2017 23:14:34 +0300 Subject: [PATCH 027/209] Convert lookup commands to Kotlin --- game/src/plugins/cmd/src/lookup.plugin.kts | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 game/src/plugins/cmd/src/lookup.plugin.kts diff --git a/game/src/plugins/cmd/src/lookup.plugin.kts b/game/src/plugins/cmd/src/lookup.plugin.kts new file mode 100644 index 000000000..4e15713ed --- /dev/null +++ b/game/src/plugins/cmd/src/lookup.plugin.kts @@ -0,0 +1,47 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.model.entity.setting.PrivilegeLevel + +on_command("iteminfo", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + if (!valid_arg_length(arguments, 1, player, "Invalid syntax - ::npcinfo [npc id]")) { + return@then + } + + val id = arguments[0].toInt() + val definition = ItemDefinition.lookup(id) + val members = if (definition.isMembersOnly) "members" else "not members" + + player.sendMessage("Item $id is called ${definition.name}, is $members only, and has a " + + "team of ${definition.team}.") + player.sendMessage("Its description is \"${definition.description}\".") + } + +on_command("npcinfo", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + if (!valid_arg_length(arguments, 1, player, "Invalid syntax - ::npcinfo [npc id]")) { + return@then + } + + val id = arguments[0].toInt() + val definition = NpcDefinition.lookup(id) + val isCombative = if (definition.hasCombatLevel()) "has a combat level of ${definition.combatLevel}" else + "does not have a combat level" + + player.sendMessage("Npc $id is called ${definition.name} and $isCombative.") + player.sendMessage("Its description is \"${definition.description}\".") + } + +on_command("objectinfo", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + if (!valid_arg_length(arguments, 1, player, "Invalid syntax - ::objectinfo [object id]")) { + return@then + } + + val id = arguments[0].toInt() + val definition = ObjectDefinition.lookup(id) + player.sendMessage("Object $id is called ${definition.name} and its description is " + + "\"${definition.description}\".") + player.sendMessage("Its width is ${definition.width} and its length is ${definition.length}.") + } \ No newline at end of file From c082f407ad3448510128c4df0dbaf2383d7ba54c Mon Sep 17 00:00:00 2001 From: Cube Date: Thu, 15 Jun 2017 23:39:47 +0300 Subject: [PATCH 028/209] Add input type checking to commands --- .../plugins/cmd/src/animate-cmd.plugin.kts | 12 +++++-- game/src/plugins/cmd/src/item-cmd.plugin.kts | 21 +++++++++++-- game/src/plugins/cmd/src/lookup.plugin.kts | 31 +++++++++++++++---- game/src/plugins/cmd/src/skill-cmd.plugin.kts | 28 ++++++++++++++--- .../plugins/cmd/src/teleport-cmd.plugin.kts | 28 ++++++++++++++--- 5 files changed, 101 insertions(+), 19 deletions(-) diff --git a/game/src/plugins/cmd/src/animate-cmd.plugin.kts b/game/src/plugins/cmd/src/animate-cmd.plugin.kts index 55b713062..cab210419 100644 --- a/game/src/plugins/cmd/src/animate-cmd.plugin.kts +++ b/game/src/plugins/cmd/src/animate-cmd.plugin.kts @@ -1,9 +1,17 @@ +import com.google.common.primitives.Ints import org.apollo.game.model.Animation import org.apollo.game.model.entity.setting.PrivilegeLevel on_command("animate", PrivilegeLevel.MODERATOR) .then { player -> - if(valid_arg_length(arguments, 1, player, "Invalid syntax - ::animate [animation-id]")) { - player.playAnimation(Animation(arguments[0].toInt())) + val invalidSyntax = "Invalid syntax - ::animate [animation-id]" + if(valid_arg_length(arguments, 1, player, invalidSyntax)) { + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } + + player.playAnimation(Animation(id)) } } \ No newline at end of file diff --git a/game/src/plugins/cmd/src/item-cmd.plugin.kts b/game/src/plugins/cmd/src/item-cmd.plugin.kts index 7f6f22557..52eafb181 100644 --- a/game/src/plugins/cmd/src/item-cmd.plugin.kts +++ b/game/src/plugins/cmd/src/item-cmd.plugin.kts @@ -1,14 +1,29 @@ +import com.google.common.primitives.Ints import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.entity.setting.PrivilegeLevel on_command("item", PrivilegeLevel.ADMINISTRATOR) .then { player -> - if (!valid_arg_length(arguments, 1..2, player, "Invalid syntax - ::item [id] [amount]")) { + val invalidSyntax = "Invalid syntax - ::item [id] [amount]" + if (!valid_arg_length(arguments, 1..2, player, invalidSyntax)) { return@then } - val id = arguments[0].toInt() - val amount = if (arguments.size == 2) arguments[1].toInt() else 1 + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } + + var amount = 1 + if (arguments.size == 2) { + val amt = Ints.tryParse(arguments[1]) + if (amt == null) { + player.sendMessage(invalidSyntax) + return@then + } + amount = amt + } if (id < 0 || id >= ItemDefinition.count()) { player.sendMessage("The item id you specified is out of bounds!") diff --git a/game/src/plugins/cmd/src/lookup.plugin.kts b/game/src/plugins/cmd/src/lookup.plugin.kts index 4e15713ed..a599c0f4c 100644 --- a/game/src/plugins/cmd/src/lookup.plugin.kts +++ b/game/src/plugins/cmd/src/lookup.plugin.kts @@ -1,3 +1,4 @@ +import com.google.common.primitives.Ints import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition @@ -5,11 +6,17 @@ import org.apollo.game.model.entity.setting.PrivilegeLevel on_command("iteminfo", PrivilegeLevel.ADMINISTRATOR) .then { player -> - if (!valid_arg_length(arguments, 1, player, "Invalid syntax - ::npcinfo [npc id]")) { + val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" + if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { + return@then + } + + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) return@then } - val id = arguments[0].toInt() val definition = ItemDefinition.lookup(id) val members = if (definition.isMembersOnly) "members" else "not members" @@ -20,11 +27,17 @@ on_command("iteminfo", PrivilegeLevel.ADMINISTRATOR) on_command("npcinfo", PrivilegeLevel.ADMINISTRATOR) .then { player -> - if (!valid_arg_length(arguments, 1, player, "Invalid syntax - ::npcinfo [npc id]")) { + val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" + if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { + return@then + } + + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) return@then } - val id = arguments[0].toInt() val definition = NpcDefinition.lookup(id) val isCombative = if (definition.hasCombatLevel()) "has a combat level of ${definition.combatLevel}" else "does not have a combat level" @@ -35,11 +48,17 @@ on_command("npcinfo", PrivilegeLevel.ADMINISTRATOR) on_command("objectinfo", PrivilegeLevel.ADMINISTRATOR) .then { player -> - if (!valid_arg_length(arguments, 1, player, "Invalid syntax - ::objectinfo [object id]")) { + val invalidSyntax = "Invalid syntax - ::objectinfo [object id]" + if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { + return@then + } + + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) return@then } - val id = arguments[0].toInt() val definition = ObjectDefinition.lookup(id) player.sendMessage("Object $id is called ${definition.name} and its description is " + "\"${definition.description}\".") diff --git a/game/src/plugins/cmd/src/skill-cmd.plugin.kts b/game/src/plugins/cmd/src/skill-cmd.plugin.kts index 519e77012..ade6e6c02 100644 --- a/game/src/plugins/cmd/src/skill-cmd.plugin.kts +++ b/game/src/plugins/cmd/src/skill-cmd.plugin.kts @@ -1,4 +1,6 @@ +import com.google.common.primitives.Doubles +import com.google.common.primitives.Ints import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.SkillSet import org.apollo.game.model.entity.setting.PrivilegeLevel @@ -26,8 +28,17 @@ on_command("level", PrivilegeLevel.ADMINISTRATOR) return@then } - val skillId = arguments[0].toInt() - val level = arguments[1].toInt() + val skillId = Ints.tryParse(arguments[0]) + if (skillId == null) { + player.sendMessage(invalidSyntax) + return@then + } + val level = Ints.tryParse(arguments[1]) + if (level == null) { + player.sendMessage(invalidSyntax) + return@then + } + if (skillId !in 0..20 || level !in 1..99) { player.sendMessage(invalidSyntax) return@then @@ -55,8 +66,17 @@ on_command("xp", PrivilegeLevel.ADMINISTRATOR) return@then } - val skillId = arguments[0].toInt() - val experience = arguments[1].toDouble() + val skillId = Ints.tryParse(arguments[0]) + if (skillId == null) { + player.sendMessage(invalidSyntax) + return@then + } + val experience = Doubles.tryParse(arguments[1]) + if (experience == null) { + player.sendMessage(invalidSyntax) + return@then + } + if (skillId !in 0..20 || experience <= 0) { player.sendMessage("Invalid syntax - ::xp [skill-id] [experience]") return@then diff --git a/game/src/plugins/cmd/src/teleport-cmd.plugin.kts b/game/src/plugins/cmd/src/teleport-cmd.plugin.kts index c6bdba4f4..75490b9fc 100644 --- a/game/src/plugins/cmd/src/teleport-cmd.plugin.kts +++ b/game/src/plugins/cmd/src/teleport-cmd.plugin.kts @@ -1,3 +1,4 @@ +import com.google.common.primitives.Ints import org.apollo.game.model.Position import org.apollo.game.model.entity.setting.PrivilegeLevel @@ -14,13 +15,32 @@ on_command("pos", PrivilegeLevel.MODERATOR) */ on_command("tele", PrivilegeLevel.ADMINISTRATOR) .then { player -> - if (!valid_arg_length(arguments, 2..3, player, "Invalid syntax - ::tele [x] [y] [optional-z]")) { + val invalidSyntax = "Invalid syntax - ::tele [x] [y] [optional-z]" + if (!valid_arg_length(arguments, 2..3, player, invalidSyntax)) { return@then } - val x = arguments[0].toInt() - val y = arguments[1].toInt() - val z = if (arguments.size == 3) arguments[2].toInt() else player.position.height + val x = Ints.tryParse(arguments[0]) + if (x == null) { + player.sendMessage(invalidSyntax) + return@then + } + + val y = Ints.tryParse(arguments[1]) + if (y == null) { + player.sendMessage(invalidSyntax) + return@then + } + + var z = player.position.height + if (arguments.size == 3) { + val plane = Ints.tryParse(arguments[2]) + if (plane == null) { + player.sendMessage(invalidSyntax) + return@then + } + z = plane + } if (z in 0..4) { player.teleport(Position(x, y, z)) From adaaae2129cabfd963a6f7bcffbafa977558f719 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 18 Jun 2017 21:12:39 +0100 Subject: [PATCH 029/209] Refactor the plugin compile task for performance Integrates the plugin script compilation task with Gradle so we no longer need to start a new instance of the JVM for each set of plugin scripts that we want to compile. --- buildSrc/build.gradle | 26 ++++ .../build/compile/KotlinScriptCompiler.kt | 139 ++++++++++++++++++ .../build/tasks/KotlinScriptCompileTask.kt | 54 +++++++ game/plugins.gradle | 41 ++++-- 4 files changed, 244 insertions(+), 16 deletions(-) create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt create mode 100644 buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 000000000..b559f2239 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'kotlin' + +buildscript { + ext { + kotlinVersion = '1.1.2-4' + } + + repositories { + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + } +} + +repositories { + mavenLocal() + maven { url "https://repo.maven.apache.org/maven2" } +} + +dependencies { + compile gradleApi() + compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" + compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt b/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt new file mode 100644 index 000000000..9384f16e0 --- /dev/null +++ b/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt @@ -0,0 +1,139 @@ +package org.apollo.build.compile + +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.messages.* +import org.jetbrains.kotlin.cli.jvm.compiler.* +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot +import org.jetbrains.kotlin.codegen.CompilationException +import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer +import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate +import java.io.File +import java.lang.management.ManagementFactory +import java.net.URISyntaxException +import java.net.URLClassLoader +import java.nio.file.* +import java.util.* + + +class KotlinMessageCollector : MessageCollector { + + override fun clear() { + } + + override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { + if (severity.isError) { + println("${location.path}:${location.line}-${location.column}: $message") + println(">>> ${location.lineContent}") + } + } + + override fun hasErrors(): Boolean { + return false + } + +} + +data class KotlinCompilerResult(val fqName: String, val outputPath: Path) + +class KotlinScriptCompiler { + + val classpath: List + val messageCollector: MessageCollector + val compilerConfiguration: CompilerConfiguration + + constructor(scriptDefinitionClassName: String, classpath: Collection, messageCollector: MessageCollector) { + this.classpath = classpath + currentClasspath() + this.messageCollector = messageCollector + this.compilerConfiguration = createCompilerConfiguration(scriptDefinitionClassName) + } + + companion object { + + fun currentClasspath(): List { + val classLoader = Thread.currentThread().contextClassLoader as? URLClassLoader ?: + throw RuntimeException("Unable to resolve classpath for current ClassLoader") + + val classpathUrls = classLoader.urLs + val classpath = ArrayList() + + for (classpathUrl in classpathUrls) { + try { + classpath.add(File(classpathUrl.toURI())) + } catch (e: URISyntaxException) { + throw RuntimeException("URL returned by ClassLoader is invalid") + } + + } + + val runtimeBean = ManagementFactory.getRuntimeMXBean() + if (!runtimeBean.isBootClassPathSupported) { + println("Warning! Boot class path is not supported, must be supplied on the command line") + } else { + val bootClasspath = runtimeBean.bootClassPath + classpath.addAll(bootClasspath.split(File.pathSeparatorChar).map { File(it) }) + } + + return classpath + } + } + + private fun createCompilerConfiguration(scriptDefinitionClassName: String): CompilerConfiguration { + val classLoader = URLClassLoader(classpath.map { it.toURL() }.toTypedArray()) + val configuration = CompilerConfiguration() + val scriptDefinitionClass = classLoader.loadClass(scriptDefinitionClassName) + val scriptDefinition = KotlinScriptDefinitionFromAnnotatedTemplate(scriptDefinitionClass.kotlin) + + configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.map { JvmClasspathRoot(it) }) + configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, KotlinMessageCollector()) + configuration.copy() + + return configuration + } + + @Throws(KotlinPluginCompilerException::class) + fun compile(inputPath: Path, outputPath: Path): KotlinCompilerResult { + val rootDisposable = Disposer.newDisposable() + val configuration = compilerConfiguration.copy() + + configuration.put(CommonConfigurationKeys.MODULE_NAME, inputPath.toString()) + configuration.addKotlinSourceRoot(inputPath.toAbsolutePath().toString()) + + val configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES + val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, configFiles) + + try { + val generationState = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(environment) + if (generationState == null) { + throw KotlinPluginCompilerException("Failed to generate bytecode for kotlin script") + } + + val sourceFiles = environment.getSourceFiles() + val script = sourceFiles[0].script ?: throw KotlinPluginCompilerException("Main script file isnt a script") + + val scriptFilePath = script.fqName.asString().replace('.', '/') + ".class" + val scriptFileClass = generationState.factory.get(scriptFilePath) + + if (scriptFileClass == null) { + throw KotlinPluginCompilerException("Unable to find compiled plugin class file $scriptFilePath") + } + + generationState.factory.asList().forEach { + Files.write(outputPath.resolve(it.relativePath), it.asByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING) + } + + return KotlinCompilerResult(script.fqName.asString(), outputPath.resolve(scriptFileClass.relativePath)) + } catch (e: CompilationException) { + throw KotlinPluginCompilerException("Compilation failed", e) + } finally { + Disposer.dispose(rootDisposable) + } + } + +} + +class KotlinPluginCompilerException(message: String, cause: Throwable? = null) : Exception(message, cause) { + +} diff --git a/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt b/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt new file mode 100644 index 000000000..373e64784 --- /dev/null +++ b/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt @@ -0,0 +1,54 @@ +package org.apollo.build.tasks + +import org.apollo.build.compile.KotlinMessageCollector +import org.apollo.build.compile.KotlinScriptCompiler +import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.* +import org.gradle.api.tasks.incremental.IncrementalTaskInputs +import java.io.File + +open class KotlinScriptCompileTask : DefaultTask() { + @OutputDirectory + var outputsDir: File? = null + + @Input + var compileClasspath: FileCollection? = null + + @Input + var scriptDefinitionClass: String? = null + + @TaskAction + fun execute(inputs: IncrementalTaskInputs) { + if (scriptDefinitionClass == null) { + throw Exception("No script definition class given") + } + + if (compileClasspath == null) { + throw Exception("No compile classpath given") + } + + val classpath = compileClasspath!!.files + val compiler = KotlinScriptCompiler(scriptDefinitionClass!!, classpath, KotlinMessageCollector()) + + inputs.outOfDate { + removeBinariesFor(it.file) + compiler.compile(it.file.toPath(), outputsDir!!.toPath()) + } + + inputs.removed { + removeBinariesFor(it.file) + } + } + + private fun removeBinariesFor(file: File) { + val normalizedFilename = file.name.replace("[^A-Z_]", "_") + val normalizedPrefix = normalizedFilename.subSequence(0, normalizedFilename.lastIndexOf('.')) + + val binaries = outputsDir!!.listFiles { dir, name -> name.startsWith(normalizedPrefix) } + + binaries.forEach { + it.delete() + } + } +} diff --git a/game/plugins.gradle b/game/plugins.gradle index e16aa141a..cacf150af 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -1,4 +1,5 @@ import com.moandjiezana.toml.Toml +import org.apollo.build.tasks.KotlinScriptCompileTask import java.nio.file.Paths @@ -15,7 +16,7 @@ buildscript { } } -task pluginTests { +task testPlugins { group = "plugin-verification" doLast { @@ -23,7 +24,7 @@ task pluginTests { } } -check.dependsOn pluginTests +check.dependsOn testPlugins class PluginBuildData { PluginBuildData(String normalizedName, SourceSet mainSources, SourceSet testSources, @@ -68,8 +69,9 @@ def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSources, FileCollection scriptFiles, List pluginDependencies) { + def taskName = name.split("_").collect { it.capitalize() }.join("") - def testsTask = task("${name}Tests", type: Test) { + def testsTask = task("test${taskName}", type: Test) { group = "plugin-verification" testClassesDir = testSources.output.classesDir @@ -87,26 +89,27 @@ def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSourc } } - pluginTests.dependsOn testsTask + testPlugins.dependsOn testsTask if (!scriptFiles.empty) { - def compileScriptsTask = task("compile${name}Scripts", type: JavaExec) { + def compileScriptsTask = task("compile${taskName}Scripts", type: KotlinScriptCompileTask) { group = "plugin-compile" - def outputDir = mainSources.output.classesDir.toString() + def outputDir = mainSources.output.classesDir inputs.files scriptFiles - outputs.dir outputDir + outputsDir = outputDir - classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath - main = 'org.apollo.game.plugin.kotlin.KotlinPluginCompiler' - args = [outputDir] + scriptFiles.collect { it.absoluteFile.toString() } - } + compileClasspath = sourceSets.main.compileClasspath + + sourceSets.main.runtimeClasspath + + mainSources.compileClasspath + + mainSources.runtimeClasspath - tasks[mainSources.classesTaskName].outputs.upToDateWhen { false } - tasks[mainSources.classesTaskName].doLast { - compileScriptsTask.execute() + scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript" + mustRunAfter tasks[mainSources.classesTaskName] } + + testPlugins.dependsOn compileScriptsTask } } @@ -122,25 +125,31 @@ pluginDefinitions.each { file -> def pluginFolder = Paths.get(file.parentFile.absolutePath) def name = meta.getString("name", pluginFolder.getFileName().toString()) def normalizedName = name.replaceAll("[^a-zA-Z0-9_]", '_').toLowerCase() + def displayNameArray = normalizedName.split("_").collect { it.capitalize() }.join("").toCharArray() + displayNameArray[0] = displayNameArray[0].toLowerCase() + + def sourceSetName = new String(displayNameArray) + def packageName = meta.getString("package", "org.apollo.game.plugin") def authors = meta.getList("authors", new ArrayList()) def dependencies = meta.getList("dependencies", new ArrayList()) def scripts = fileTree(file.parentFile) { include '**/*.plugin.kts' + exclude '*.kt' } def srcsDir = meta.getString("config.src", "src/") def testDir = meta.getString("config.test", "test/") - def mainSources = sourceSets.create("${normalizedName}_main") { + def mainSources = sourceSets.create("${sourceSetName}Main") { kotlin { srcDir pluginFolder.resolve(srcsDir).toString() exclude '*.kts' } } - def testSources = sourceSets.create("${normalizedName}_test") { + def testSources = sourceSets.create("${sourceSetName}Test") { kotlin { srcDir pluginFolder.resolve(testDir).toString() } From 3f714831c75e68c3f9a138d18b3278550b3140f6 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 18 Jun 2017 21:25:04 +0100 Subject: [PATCH 030/209] Make plugin classes dependant on scripts --- game/plugins.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/game/plugins.gradle b/game/plugins.gradle index cacf150af..0b66a34d6 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -110,6 +110,7 @@ def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSourc } testPlugins.dependsOn compileScriptsTask + tasks[mainSources.classesTaskName].finalizedBy compileScriptsTask } } From 1019cc8e6ac2ea03e981e04774b543c32d397f86 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 18 Jun 2017 21:37:44 +0100 Subject: [PATCH 031/209] Check for conflicting plugin names at build-time --- game/plugins.gradle | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/game/plugins.gradle b/game/plugins.gradle index 0b66a34d6..ca12f8331 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -119,6 +119,18 @@ def pluginDefinitions = pluginTree.matching { include '**/meta.toml' } +class PluginScriptFile { + def scriptFileName + def pluginDir + + PluginScriptFile(scriptFileName, pluginDir) { + this.scriptFileName = scriptFileName + this.pluginDir = pluginDir + } +} + +def pluginFiles = new ArrayList() + pluginDefinitions.each { file -> def meta = new Toml() meta.read(file.absoluteFile) @@ -156,6 +168,19 @@ pluginDefinitions.each { file -> } } + scripts.files.forEach { + def scriptFileName = it.getName() + + //@todo - also compare package + def existingFile = pluginFiles.find { it.scriptFileName == scriptFileName } + if (existingFile != null) { + throw new GradleException("Duplicate script file found named ${scriptFileName} in ${pluginFolder}, " + + "also exists in ${existingFile.pluginDir}") + } + + pluginFiles.add(new PluginScriptFile(scriptFileName, pluginFolder)) + } + def pluginData = new PluginBuildData(normalizedName, mainSources, testSources, scripts, dependencies) pluginMap.put(normalizedName, pluginData) } From f40a3a3a5df36e28521bc4c949945e5378b8d7ea Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 18 Jun 2017 21:39:55 +0100 Subject: [PATCH 032/209] Update travis-ci configuration to cache build deps --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9bcf99945..031ceca60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,10 @@ language: java jdk: - oraclejdk8 +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock + - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ +cache: + directories: + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ \ No newline at end of file From d0fec15a84cc97c625930c4adbc09b400516aeb0 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 18 Jun 2017 21:45:52 +0100 Subject: [PATCH 033/209] Add missing name normalization to lookup plugin --- game/src/plugins/util/lookup/src/lookup.kt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/game/src/plugins/util/lookup/src/lookup.kt b/game/src/plugins/util/lookup/src/lookup.kt index c7395e10d..637f4fab6 100644 --- a/game/src/plugins/util/lookup/src/lookup.kt +++ b/game/src/plugins/util/lookup/src/lookup.kt @@ -1,17 +1,24 @@ import org.apollo.cache.def.* fun lookup_object(name: String): ObjectDefinition? { - val definitions = ObjectDefinition.getDefinitions() - return definitions.filter { name.equals(it.name, true) }.firstOrNull() + return find_entity(ObjectDefinition::getDefinitions, ObjectDefinition::getName, name) } fun lookup_npc(name: String): NpcDefinition? { - val definitions = NpcDefinition.getDefinitions() - return definitions.filter { name.equals(it.name, true) }.firstOrNull() + return find_entity(NpcDefinition::getDefinitions, NpcDefinition::getName, name) } fun lookup_item(name: String): ItemDefinition? { - val definitions = ItemDefinition.getDefinitions() - return definitions.filter { name.equals(it.name, true) }.firstOrNull() + return find_entity(ItemDefinition::getDefinitions, ItemDefinition::getName, name) } +private fun find_entity(definitionsProvider: () -> Array, + nameSupplier: T.() -> String, + name: String): T? { + + val normalizedName = name.replace('_', ' ') + val definitions = definitionsProvider.invoke(); + val matcher: (T) -> Boolean = { it.nameSupplier().equals(normalizedName, true) } + + return definitions.filter(matcher).firstOrNull() +} \ No newline at end of file From b536b2ed9da137c48810765bcd99f078ee0cce42 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 19 Jun 2017 02:50:50 +0100 Subject: [PATCH 034/209] Add start of test framework for plugins Adds a basic testing framework suitable for plugins that start simple Actions for players, which can be expanded on in the future. The banking and training dummy tests have been updated to use this framework and serve as samples. --- game/plugins.gradle | 15 ++++ .../apollo/game/scheduling/ScheduledTask.java | 2 +- .../game/plugins/testing/KotlinPluginTest.kt | 68 +++++++++++++++++ .../testing/KotlinPluginTestContext.kt | 74 +++++++++++++++++++ game/src/plugins/bank/test/BankingTests.kt | 0 game/src/plugins/bank/test/OpenBankTest.kt | 38 ++++++++++ game/src/plugins/dummy/meta.toml | 7 ++ .../plugins/dummy/test/TrainingDummyTest.kt | 45 +++++++++++ 8 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt create mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt delete mode 100644 game/src/plugins/bank/test/BankingTests.kt create mode 100644 game/src/plugins/bank/test/OpenBankTest.kt create mode 100644 game/src/plugins/dummy/test/TrainingDummyTest.kt diff --git a/game/plugins.gradle b/game/plugins.gradle index ca12f8331..017592265 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -24,6 +24,19 @@ task testPlugins { } } +sourceSets { + pluginTesting { + kotlin { + srcDir 'src/pluginTesting/kotlin' + } + } +} + +dependencies { + pluginTestingCompile sourceSets.test.output + pluginTestingCompile sourceSets.test.compileClasspath +} + check.dependsOn testPlugins class PluginBuildData { @@ -65,6 +78,8 @@ def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, dependencies.add(testConfiguration, mainSources.output) dependencies.add(testConfiguration, configurations.testCompile) dependencies.add(testConfiguration, sourceSets.test.output) + dependencies.add(testConfiguration, sourceSets.test.compileClasspath) + dependencies.add(testConfiguration, sourceSets.pluginTesting.output) } def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSources, diff --git a/game/src/main/java/org/apollo/game/scheduling/ScheduledTask.java b/game/src/main/java/org/apollo/game/scheduling/ScheduledTask.java index 3b3606738..f14b64d1c 100644 --- a/game/src/main/java/org/apollo/game/scheduling/ScheduledTask.java +++ b/game/src/main/java/org/apollo/game/scheduling/ScheduledTask.java @@ -71,7 +71,7 @@ public void stop() { /** * Pulses this task: updates the delay and calls {@link #execute()} if necessary. */ - final void pulse() { + public final void pulse() { if (running && --pulses <= 0) { execute(); pulses = delay; diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt new file mode 100644 index 000000000..cb2e620e3 --- /dev/null +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt @@ -0,0 +1,68 @@ +package org.apollo.game.plugins.testing + +import org.apollo.game.message.handler.MessageHandler +import org.apollo.game.message.handler.MessageHandlerChainSet +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.* +import org.apollo.net.message.Message +import org.apollo.util.security.PlayerCredentials +import org.junit.After +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.Matchers.any +import org.mockito.Mockito.mock +import org.mockito.invocation.InvocationOnMock +import org.mockito.stubbing.Answer +import org.powermock.api.mockito.PowerMockito.spy +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.PowerMockRunner +import java.util.* + +@RunWith(PowerMockRunner::class) +@PrepareForTest(World::class, PluginContext::class, Player::class) +abstract class KotlinPluginTest { + private var ctx: KotlinPluginTestContext? = null + + protected fun context(): KotlinPluginTestContext { + return ctx ?: throw IllegalStateException("Setup method not called") + } + + @Before + fun setup() { + val messageHandlerChainSet = MessageHandlerChainSet() + val world = spy(World()) + + val answer = Answer { invocation: InvocationOnMock -> + messageHandlerChainSet.putHandler( + invocation.arguments[0] as Class, + invocation.arguments[1] as MessageHandler<*>) + } + + val pluginContext = mock(PluginContext::class.java, answer) + val pluginEnvironment = KotlinPluginEnvironment(world) + + pluginEnvironment.setContext(pluginContext) + pluginEnvironment.load(ArrayList()) + + val credentials = PlayerCredentials("test", "test", 1, 1, "0.0.0.0") + val position = Position(3200, 3200, 0) + + val player = spy(Player(world, credentials, position)) + org.powermock.api.mockito.PowerMockito.doNothing().`when`(player).send(any()) + + world.register(player) + + val region = world.regionRepository.fromPosition(position) + region.addEntity(player) + + ctx = KotlinPluginTestContext(world, player, messageHandlerChainSet) + } + + @After + fun destroy() { + ctx!!.shutdown() + } + +} diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt new file mode 100644 index 000000000..2b1af62e1 --- /dev/null +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt @@ -0,0 +1,74 @@ +package org.apollo.game.plugins.testing + +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.action.Action +import org.apollo.game.message.handler.MessageHandlerChainSet +import org.apollo.game.message.impl.* +import org.apollo.game.model.* +import org.apollo.game.model.entity.* +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.entity.obj.StaticGameObject +import org.apollo.net.message.Message +import org.junit.Assert +import org.mockito.ArgumentCaptor +import org.mockito.Mockito + + +class KotlinPluginTestContext(val world: World, val activePlayer: Player, val messageHandlers: MessageHandlerChainSet) { + + fun interactWith(entity: Entity, option: Int = 1) { + activePlayer.position = entity.position.step(1, Direction.NORTH) + + when (entity) { + is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position)) + is Npc -> notify(NpcActionMessage(option, entity.index)) + is Player -> notify(PlayerActionMessage(option, entity.index)) + } + } + + fun spawnNpc(id: Int, position: Position): Npc { + val definition = NpcDefinition(id) + val npc = Npc(world, position, definition, arrayOfNulls(4)) + val region = world.regionRepository.fromPosition(position) + val npcs = world.npcRepository + + world.register(npc) + npcs.add(npc) + region.addEntity(npc) + + return npc + } + + fun spawnObject(id: Int, position: Position): GameObject { + val obj = StaticGameObject(world, id, position, 0, 0) + + world.spawn(obj) + + return obj + } + + fun notify(message: Message) { + messageHandlers.notify(activePlayer, message) + } + + fun shutdown() { + + } + + fun waitForActionCompletion(predicate: (Action) -> Boolean = { _ -> true }, timeout: Int = 15) { + val actionCaptor: ArgumentCaptor> = ArgumentCaptor.forClass(Action::class.java) + Mockito.verify(activePlayer).startAction(actionCaptor.capture()) + + val action: Action = actionCaptor.value as Action + Assert.assertTrue("Found wrong action type", predicate.invoke(action)) + + var pulses = 0 + + do { + action.pulse() + } while (action.isRunning && pulses++ < timeout) + + Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout) + } + +} diff --git a/game/src/plugins/bank/test/BankingTests.kt b/game/src/plugins/bank/test/BankingTests.kt deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/src/plugins/bank/test/OpenBankTest.kt b/game/src/plugins/bank/test/OpenBankTest.kt new file mode 100644 index 000000000..aba9b67ef --- /dev/null +++ b/game/src/plugins/bank/test/OpenBankTest.kt @@ -0,0 +1,38 @@ +import org.apollo.game.model.Position +import org.apollo.game.plugins.testing.KotlinPluginTest +import org.junit.Test +import org.mockito.Mockito.verify + +class OpenBankTest() : KotlinPluginTest() { + + companion object { + const val BANK_BOOTH_ID = 2213 + const val BANK_TELLER_ID = 166 + + val BANK_POSITION = Position(3200, 3200, 0) + } + + @Test + fun `Interacting with a bank teller should open the players bank`() { + val ctx = context() + val bankTeller = ctx.spawnNpc(BANK_TELLER_ID, BANK_POSITION) + + // @todo - these option numbers only match by coincidence, we should be looking up the correct ones + ctx.interactWith(bankTeller, option = 2) + ctx.waitForActionCompletion() + + verify(ctx.activePlayer).openBank() + } + + @Test + fun `Interacting with a bank booth object should open the players bank`() { + val ctx = context() + val bankBooth = ctx.spawnObject(BANK_BOOTH_ID, BANK_POSITION) + + ctx.interactWith(bankBooth, option = 2) + ctx.waitForActionCompletion() + + verify(ctx.activePlayer).openBank() + } + +} \ No newline at end of file diff --git a/game/src/plugins/dummy/meta.toml b/game/src/plugins/dummy/meta.toml index e69de29bb..46c61366d 100644 --- a/game/src/plugins/dummy/meta.toml +++ b/game/src/plugins/dummy/meta.toml @@ -0,0 +1,7 @@ +name = "training-dummy" +package = "org.apollo.game.plugin.entity" +authors = [ "Gary Tierney" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/dummy/test/TrainingDummyTest.kt b/game/src/plugins/dummy/test/TrainingDummyTest.kt new file mode 100644 index 000000000..d8a7ddaa9 --- /dev/null +++ b/game/src/plugins/dummy/test/TrainingDummyTest.kt @@ -0,0 +1,45 @@ +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.SkillSet +import org.apollo.game.plugins.testing.KotlinPluginTest +import org.junit.Assert.assertTrue +import org.junit.Test +import org.mockito.Matchers +import org.mockito.Matchers.* +import org.mockito.Mockito.verify + +class TrainingDummyTest : KotlinPluginTest() { + + companion object { + const val DUMMY_ID = 823 + val DUMMY_POSITION = Position(3200, 3230, 0) + } + + @Test fun `Hitting the training dummy should give the player attack experience`() { + val ctx = context() + val dummy = ctx.spawnObject(DUMMY_ID, DUMMY_POSITION) + val skills = ctx.activePlayer.skillSet + val attackExp = skills.getExperience(Skill.ATTACK) + + ctx.interactWith(dummy, option = 2) + ctx.waitForActionCompletion() + + assertTrue("Did not gain exp after hitting dummy", skills.getExperience(Skill.ATTACK) > attackExp) + } + + @Test fun `The player should stop getting attack experience from the training dummy at level 8`() { + val ctx = context() + + val dummy = ctx.spawnObject(DUMMY_ID, DUMMY_POSITION) + val skills = ctx.activePlayer.skillSet + skills.setMaximumLevel(Skill.ATTACK, 8) + val attackExp = skills.getExperience(Skill.ATTACK) + + ctx.interactWith(dummy, option = 2) + ctx.waitForActionCompletion() + + verify(ctx.activePlayer).sendMessage(contains("nothing more you can learn")) + assertTrue("Attack exp has changed since hitting the dummy", attackExp == skills.getExperience(Skill.ATTACK)) + } + +} \ No newline at end of file From b532168551fc886d3e652392cc5f5a06e59bfcb3 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 19 Jun 2017 17:14:24 +0100 Subject: [PATCH 035/209] Remove test context from plugin testing framework --- game/build.gradle | 2 + game/plugins.gradle | 12 ++- .../game/plugins/testing/KotlinPluginTest.kt | 91 ++++++++++++++----- .../testing/KotlinPluginTestContext.kt | 74 --------------- game/src/plugins/bank/test/OpenBankTest.kt | 18 ++-- .../plugins/dummy/test/TrainingDummyTest.kt | 40 ++++---- 6 files changed, 104 insertions(+), 133 deletions(-) delete mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt diff --git a/game/build.gradle b/game/build.gradle index d421fc937..7c5c8f0f1 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -33,6 +33,8 @@ dependencies { compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" + // https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all + testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3' testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" } diff --git a/game/plugins.gradle b/game/plugins.gradle index 017592265..47a1f793a 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -17,11 +17,7 @@ buildscript { } task testPlugins { - group = "plugin-verification" - doLast { - println("Finished executing plugin tests") - } } sourceSets { @@ -95,7 +91,6 @@ def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSourc binResultsDir = file("$buildDir/plugin-test-results/binary/$name") reports { - html.destination = "$buildDir/reports/plugin-tests/$name" junitXml.destination = "$buildDir/plugin-tests/$name" } @@ -206,3 +201,10 @@ pluginMap.values().each { configurePluginDependencies(it.mainSources, it.testSources, dependencies) configurePluginTasks(it.normalizedName, it.mainSources, it.testSources, it.scriptFiles, dependencies) } + +task testPluginsReport(type: TestReport) { + destinationDir = file("$buildDir/reports/plugin-tests") + reportOn tasks.findAll { it.group.equals("plugin-verification"); } +} + +testPlugins.finalizedBy testPluginsReport \ No newline at end of file diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt index cb2e620e3..827d8804e 100644 --- a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt @@ -1,21 +1,26 @@ package org.apollo.game.plugins.testing +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.action.Action import org.apollo.game.message.handler.MessageHandler import org.apollo.game.message.handler.MessageHandlerChainSet -import org.apollo.game.model.Position -import org.apollo.game.model.World -import org.apollo.game.model.entity.Player +import org.apollo.game.message.impl.* +import org.apollo.game.model.* +import org.apollo.game.model.entity.* +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.entity.obj.StaticGameObject import org.apollo.game.plugin.* import org.apollo.net.message.Message import org.apollo.util.security.PlayerCredentials -import org.junit.After +import org.junit.Assert import org.junit.Before import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor import org.mockito.Matchers.any -import org.mockito.Mockito.mock +import org.mockito.Mockito import org.mockito.invocation.InvocationOnMock import org.mockito.stubbing.Answer -import org.powermock.api.mockito.PowerMockito.spy +import org.powermock.api.mockito.PowerMockito import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner import java.util.* @@ -23,24 +28,22 @@ import java.util.* @RunWith(PowerMockRunner::class) @PrepareForTest(World::class, PluginContext::class, Player::class) abstract class KotlinPluginTest { - private var ctx: KotlinPluginTestContext? = null - - protected fun context(): KotlinPluginTestContext { - return ctx ?: throw IllegalStateException("Setup method not called") - } + lateinit var world: World + lateinit var player: Player + lateinit var messageHandlers: MessageHandlerChainSet @Before fun setup() { - val messageHandlerChainSet = MessageHandlerChainSet() - val world = spy(World()) + messageHandlers = MessageHandlerChainSet() + world = PowerMockito.spy(World()) val answer = Answer { invocation: InvocationOnMock -> - messageHandlerChainSet.putHandler( + messageHandlers.putHandler( invocation.arguments[0] as Class, invocation.arguments[1] as MessageHandler<*>) } - val pluginContext = mock(PluginContext::class.java, answer) + val pluginContext = PowerMockito.mock(PluginContext::class.java, answer) val pluginEnvironment = KotlinPluginEnvironment(world) pluginEnvironment.setContext(pluginContext) @@ -48,21 +51,63 @@ abstract class KotlinPluginTest { val credentials = PlayerCredentials("test", "test", 1, 1, "0.0.0.0") val position = Position(3200, 3200, 0) + val region = world.regionRepository.fromPosition(position) - val player = spy(Player(world, credentials, position)) - org.powermock.api.mockito.PowerMockito.doNothing().`when`(player).send(any()) - + player = PowerMockito.spy(Player(world, credentials, position)) world.register(player) + region.addEntity(player) + + PowerMockito.doNothing().`when`(player).send(any()) + } + + fun interactWith(entity: Entity, option: Int = 1) { + player.position = entity.position.step(1, Direction.NORTH) + + when (entity) { + is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position)) + is Npc -> notify(NpcActionMessage(option, entity.index)) + is Player -> notify(PlayerActionMessage(option, entity.index)) + } + } + fun spawnNpc(id: Int, position: Position): Npc { + val definition = NpcDefinition(id) + val npc = Npc(world, position, definition, arrayOfNulls(4)) val region = world.regionRepository.fromPosition(position) - region.addEntity(player) + val npcs = world.npcRepository - ctx = KotlinPluginTestContext(world, player, messageHandlerChainSet) + npcs.add(npc) + region.addEntity(npc) + + return npc + } + + fun spawnObject(id: Int, position: Position): GameObject { + val obj = StaticGameObject(world, id, position, 0, 0) + + world.spawn(obj) + + return obj } - @After - fun destroy() { - ctx!!.shutdown() + fun notify(message: Message) { + messageHandlers.notify(player, message) + } + + fun waitForActionCompletion(predicate: (Action) -> Boolean = { _ -> true }, timeout: Int = 15) { + val actionCaptor: ArgumentCaptor> = ArgumentCaptor.forClass(Action::class.java) + Mockito.verify(player).startAction(actionCaptor.capture()) + + val action: Action = actionCaptor.value as Action + Assert.assertTrue("Found wrong action type", predicate.invoke(action)) + + var pulses = 0 + + do { + action.pulse() + } while (action.isRunning && pulses++ < timeout) + + Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout) } } diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt deleted file mode 100644 index 2b1af62e1..000000000 --- a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTestContext.kt +++ /dev/null @@ -1,74 +0,0 @@ -package org.apollo.game.plugins.testing - -import org.apollo.cache.def.NpcDefinition -import org.apollo.game.action.Action -import org.apollo.game.message.handler.MessageHandlerChainSet -import org.apollo.game.message.impl.* -import org.apollo.game.model.* -import org.apollo.game.model.entity.* -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.model.entity.obj.StaticGameObject -import org.apollo.net.message.Message -import org.junit.Assert -import org.mockito.ArgumentCaptor -import org.mockito.Mockito - - -class KotlinPluginTestContext(val world: World, val activePlayer: Player, val messageHandlers: MessageHandlerChainSet) { - - fun interactWith(entity: Entity, option: Int = 1) { - activePlayer.position = entity.position.step(1, Direction.NORTH) - - when (entity) { - is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position)) - is Npc -> notify(NpcActionMessage(option, entity.index)) - is Player -> notify(PlayerActionMessage(option, entity.index)) - } - } - - fun spawnNpc(id: Int, position: Position): Npc { - val definition = NpcDefinition(id) - val npc = Npc(world, position, definition, arrayOfNulls(4)) - val region = world.regionRepository.fromPosition(position) - val npcs = world.npcRepository - - world.register(npc) - npcs.add(npc) - region.addEntity(npc) - - return npc - } - - fun spawnObject(id: Int, position: Position): GameObject { - val obj = StaticGameObject(world, id, position, 0, 0) - - world.spawn(obj) - - return obj - } - - fun notify(message: Message) { - messageHandlers.notify(activePlayer, message) - } - - fun shutdown() { - - } - - fun waitForActionCompletion(predicate: (Action) -> Boolean = { _ -> true }, timeout: Int = 15) { - val actionCaptor: ArgumentCaptor> = ArgumentCaptor.forClass(Action::class.java) - Mockito.verify(activePlayer).startAction(actionCaptor.capture()) - - val action: Action = actionCaptor.value as Action - Assert.assertTrue("Found wrong action type", predicate.invoke(action)) - - var pulses = 0 - - do { - action.pulse() - } while (action.isRunning && pulses++ < timeout) - - Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout) - } - -} diff --git a/game/src/plugins/bank/test/OpenBankTest.kt b/game/src/plugins/bank/test/OpenBankTest.kt index aba9b67ef..8bede6bee 100644 --- a/game/src/plugins/bank/test/OpenBankTest.kt +++ b/game/src/plugins/bank/test/OpenBankTest.kt @@ -14,25 +14,23 @@ class OpenBankTest() : KotlinPluginTest() { @Test fun `Interacting with a bank teller should open the players bank`() { - val ctx = context() - val bankTeller = ctx.spawnNpc(BANK_TELLER_ID, BANK_POSITION) + val bankTeller = spawnNpc(BANK_TELLER_ID, BANK_POSITION) // @todo - these option numbers only match by coincidence, we should be looking up the correct ones - ctx.interactWith(bankTeller, option = 2) - ctx.waitForActionCompletion() + interactWith(bankTeller, option = 2) + waitForActionCompletion() - verify(ctx.activePlayer).openBank() + verify(player).openBank() } @Test fun `Interacting with a bank booth object should open the players bank`() { - val ctx = context() - val bankBooth = ctx.spawnObject(BANK_BOOTH_ID, BANK_POSITION) + val bankBooth = spawnObject(BANK_BOOTH_ID, BANK_POSITION) - ctx.interactWith(bankBooth, option = 2) - ctx.waitForActionCompletion() + interactWith(bankBooth, option = 2) + waitForActionCompletion() - verify(ctx.activePlayer).openBank() + verify(player).openBank() } } \ No newline at end of file diff --git a/game/src/plugins/dummy/test/TrainingDummyTest.kt b/game/src/plugins/dummy/test/TrainingDummyTest.kt index d8a7ddaa9..0fc2da241 100644 --- a/game/src/plugins/dummy/test/TrainingDummyTest.kt +++ b/game/src/plugins/dummy/test/TrainingDummyTest.kt @@ -1,12 +1,10 @@ import org.apollo.game.model.Position import org.apollo.game.model.entity.Skill -import org.apollo.game.model.entity.SkillSet import org.apollo.game.plugins.testing.KotlinPluginTest -import org.junit.Assert.assertTrue +import org.hamcrest.Matchers.* +import org.junit.Assert.* import org.junit.Test -import org.mockito.Matchers -import org.mockito.Matchers.* -import org.mockito.Mockito.verify +import org.mockito.Mockito.* class TrainingDummyTest : KotlinPluginTest() { @@ -16,30 +14,30 @@ class TrainingDummyTest : KotlinPluginTest() { } @Test fun `Hitting the training dummy should give the player attack experience`() { - val ctx = context() - val dummy = ctx.spawnObject(DUMMY_ID, DUMMY_POSITION) - val skills = ctx.activePlayer.skillSet - val attackExp = skills.getExperience(Skill.ATTACK) + val dummy = spawnObject(DUMMY_ID, DUMMY_POSITION) + val skills = player.skillSet + val beforeExp = skills.getExperience(Skill.ATTACK) - ctx.interactWith(dummy, option = 2) - ctx.waitForActionCompletion() + interactWith(dummy, option = 2) + waitForActionCompletion() - assertTrue("Did not gain exp after hitting dummy", skills.getExperience(Skill.ATTACK) > attackExp) + val afterExp = skills.getExperience(Skill.ATTACK) + assertThat(afterExp, greaterThan(beforeExp)) } @Test fun `The player should stop getting attack experience from the training dummy at level 8`() { - val ctx = context() - - val dummy = ctx.spawnObject(DUMMY_ID, DUMMY_POSITION) - val skills = ctx.activePlayer.skillSet + val dummy = spawnObject(DUMMY_ID, DUMMY_POSITION) + val skills = player.skillSet skills.setMaximumLevel(Skill.ATTACK, 8) - val attackExp = skills.getExperience(Skill.ATTACK) + val beforeExp = skills.getExperience(Skill.ATTACK) + + interactWith(dummy, option = 2) + waitForActionCompletion() - ctx.interactWith(dummy, option = 2) - ctx.waitForActionCompletion() + val afterExp = skills.getExperience(Skill.ATTACK) - verify(ctx.activePlayer).sendMessage(contains("nothing more you can learn")) - assertTrue("Attack exp has changed since hitting the dummy", attackExp == skills.getExperience(Skill.ATTACK)) + verify(player).sendMessage(contains("nothing more you can learn")) + assertThat(afterExp, equalTo(beforeExp)) } } \ No newline at end of file From 182de0330f4ee1e56f99d9bd8ecab6ba4f358b46 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 20 Jun 2017 02:13:47 +0100 Subject: [PATCH 036/209] Allow multiple players per test Refactors the test helpers to use receiver functions so multiple players can exist in the world per test case. The AddFriendsTest is an example of where this is needed. Additionally, Hamcrest has been replaced with AssertJ for fluent assertions. --- game/build.gradle | 4 +- .../game/message/impl/SendFriendMessage.java | 10 +- .../r317/SendFriendMessageEncoder.java | 2 +- .../r377/SendFriendMessageEncoder.java | 2 +- .../game/plugin/testing/KotlinPluginTest.kt | 34 ++++++ .../plugin/testing/KotlinPluginTestHelpers.kt | 111 +++++++++++++++++ .../testing/fakes/FakePluginContextFactory.kt | 21 ++++ .../testing/mockito/KotlinArgMatcher.kt | 25 ++++ .../mockito/KotlinMockitoExtensions.kt | 14 +++ .../game/plugins/testing/KotlinPluginTest.kt | 113 ------------------ game/src/plugins/bank/test/OpenBankTest.kt | 14 +-- .../private-messaging/src/friends.plugin.kts | 26 ++-- .../plugins/dummy/test/TrainingDummyTest.kt | 26 ++-- game/src/plugins/stub/stub.kt | 29 ----- .../plugins/util/lookup/test/LookupTests.kt | 7 +- 15 files changed, 253 insertions(+), 185 deletions(-) create mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt create mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt create mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt create mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt create mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt delete mode 100644 game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt delete mode 100644 game/src/plugins/stub/stub.kt diff --git a/game/build.gradle b/game/build.gradle index 7c5c8f0f1..b9646593d 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -33,9 +33,7 @@ dependencies { compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" - // https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all - testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3' - testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.8.0' } task run(type: JavaExec, dependsOn: classes) { diff --git a/game/src/main/java/org/apollo/game/message/impl/SendFriendMessage.java b/game/src/main/java/org/apollo/game/message/impl/SendFriendMessage.java index 2900ab247..b86353c1a 100644 --- a/game/src/main/java/org/apollo/game/message/impl/SendFriendMessage.java +++ b/game/src/main/java/org/apollo/game/message/impl/SendFriendMessage.java @@ -27,7 +27,7 @@ public final class SendFriendMessage extends Message { */ public SendFriendMessage(String username, int world) { this.username = username; - this.world = world == 0 ? 0 : world + 9; + this.world = world; } /** @@ -48,4 +48,12 @@ public int getWorld() { return world; } + /** + * Gets the encoded world id to be sent to the client. + * + * @return The encoded world id. + */ + public int getEncodedWorld() { + return world == 0 ? 0 : world + 9; + } } \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/release/r317/SendFriendMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/SendFriendMessageEncoder.java index 15660fcbd..932dca8ef 100644 --- a/game/src/main/java/org/apollo/game/release/r317/SendFriendMessageEncoder.java +++ b/game/src/main/java/org/apollo/game/release/r317/SendFriendMessageEncoder.java @@ -18,7 +18,7 @@ public final class SendFriendMessageEncoder extends MessageEncoder()) + + player = world.spawnPlayer("testPlayer") + } + +} diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt new file mode 100644 index 000000000..b6a26f66f --- /dev/null +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt @@ -0,0 +1,111 @@ +package org.apollo.game.plugin.testing + +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.action.Action +import org.apollo.game.message.handler.MessageHandlerChainSet +import org.apollo.game.message.impl.* +import org.apollo.game.model.* +import org.apollo.game.model.entity.* +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.entity.obj.StaticGameObject +import org.apollo.net.message.Message +import org.apollo.util.security.PlayerCredentials +import org.junit.Assert +import org.mockito.* +import org.powermock.api.mockito.PowerMockito + +/** + * A base class containing a set of helper methods to be used within plugin tests. + */ +abstract class KotlinPluginTestHelpers { + abstract var world: World + abstract var player: Player + abstract var messageHandlers: MessageHandlerChainSet + + /** + * Waits for an [Action] to complete within a specified number of pulses, and with an optional predicate + * to test the [Action] against. + */ + fun Player.waitForActionCompletion(predicate: (Action) -> Boolean = { _ -> true }, timeout: Int = 15) { + val actionCaptor: ArgumentCaptor> = ArgumentCaptor.forClass(Action::class.java) + Mockito.verify(this).startAction(actionCaptor.capture()) + + val action: Action = actionCaptor.value as Action + Assert.assertTrue("Found wrong action type", predicate.invoke(action)) + + var pulses = 0 + + do { + action.pulse() + } while (action.isRunning && pulses++ < timeout) + + Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout) + } + + /** + * Spawns a new NPC with the minimum set of dependencies required to function correctly in the world. + */ + fun World.spawnNpc(id: Int, position: Position): Npc { + val definition = NpcDefinition(id) + val npc = Npc(this, position, definition, arrayOfNulls(4)) + val region = regionRepository.fromPosition(position) + val npcs = npcRepository + + npcs.add(npc) + region.addEntity(npc) + + return npc + } + + /** + * Spawn a new player stub in the world, with a dummy game session. + */ + fun World.spawnPlayer(username: String, position: Position = Position(3200, 3200, 0)): Player { + val credentials = PlayerCredentials(username, "test", 1, 1, "0.0.0.0") + val region = regionRepository.fromPosition(position) + + val player = PowerMockito.spy(Player(this, credentials, position)) + register(player) + region.addEntity(player) + + PowerMockito.doNothing().`when`(player).send(Matchers.any()) + + return player + } + + /** + * Spawn a new static game object into the world with the given id and position. + */ + fun World.spawnObject(id: Int, position: Position): GameObject { + val obj = StaticGameObject(this, id, position, 0, 0) + + spawn(obj) + + return obj + } + + /** + * Fake a client [Message] originating from a player and send it to the relevant + * message handlers. + */ + fun Player.notify(message: Message) { + messageHandlers.notify(this, message) + } + + /** + * Move the player within interaction distance to the given [Entity] and fake an action + * message. + */ + fun Player.interactWith(entity: Entity, option: Int = 1) { + position = entity.position.step(1, Direction.NORTH) + + when (entity) { + is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position)) + is Npc -> notify(NpcActionMessage(option, entity.index)) + is Player -> notify(PlayerActionMessage(option, entity.index)) + } + } + +} + diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt new file mode 100644 index 000000000..aac823298 --- /dev/null +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt @@ -0,0 +1,21 @@ +package org.apollo.game.plugin.testing.fakes + +import org.apollo.game.message.handler.MessageHandler +import org.apollo.game.message.handler.MessageHandlerChainSet +import org.apollo.game.plugin.PluginContext +import org.apollo.net.message.Message +import org.mockito.invocation.InvocationOnMock +import org.mockito.stubbing.Answer +import org.powermock.api.mockito.PowerMockito + +object FakePluginContextFactory { + fun create(messageHandlers: MessageHandlerChainSet): PluginContext { + val answer = Answer { invocation: InvocationOnMock -> + messageHandlers.putHandler( + invocation.arguments[0] as Class, + invocation.arguments[1] as MessageHandler<*>) + } + + return PowerMockito.mock(PluginContext::class.java, answer) + } +} \ No newline at end of file diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt new file mode 100644 index 000000000..748146266 --- /dev/null +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt @@ -0,0 +1,25 @@ +package org.apollo.game.plugin.testing.mockito + +import org.mockito.ArgumentMatcher +import java.lang.AssertionError +import java.util.function.Consumer + +class KotlinArgMatcher(val consumer: Consumer) : ArgumentMatcher() { + private var error: String? = null + + override fun matches(argument: Any?): Boolean { + try { + consumer.accept(argument as T) + return true + } catch (err: AssertionError) { + error = err.message + println(error) + return false + } + } + + override fun toString(): String { + return error ?: "" + } +} + diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt new file mode 100644 index 000000000..0bfad4915 --- /dev/null +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt @@ -0,0 +1,14 @@ +package org.apollo.game.plugin.testing.mockito + +import org.mockito.Mockito +import java.util.function.Consumer + + +object KotlinMockitoExtensions { + inline fun matches(crossinline callback: T.() -> Unit): T { + val consumer = Consumer { it.callback() } + val matcher = KotlinArgMatcher(consumer) + + return Mockito.argThat(matcher) + } +} diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt deleted file mode 100644 index 827d8804e..000000000 --- a/game/src/pluginTesting/kotlin/org/apollo/game/plugins/testing/KotlinPluginTest.kt +++ /dev/null @@ -1,113 +0,0 @@ -package org.apollo.game.plugins.testing - -import org.apollo.cache.def.NpcDefinition -import org.apollo.game.action.Action -import org.apollo.game.message.handler.MessageHandler -import org.apollo.game.message.handler.MessageHandlerChainSet -import org.apollo.game.message.impl.* -import org.apollo.game.model.* -import org.apollo.game.model.entity.* -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.model.entity.obj.StaticGameObject -import org.apollo.game.plugin.* -import org.apollo.net.message.Message -import org.apollo.util.security.PlayerCredentials -import org.junit.Assert -import org.junit.Before -import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.Matchers.any -import org.mockito.Mockito -import org.mockito.invocation.InvocationOnMock -import org.mockito.stubbing.Answer -import org.powermock.api.mockito.PowerMockito -import org.powermock.core.classloader.annotations.PrepareForTest -import org.powermock.modules.junit4.PowerMockRunner -import java.util.* - -@RunWith(PowerMockRunner::class) -@PrepareForTest(World::class, PluginContext::class, Player::class) -abstract class KotlinPluginTest { - lateinit var world: World - lateinit var player: Player - lateinit var messageHandlers: MessageHandlerChainSet - - @Before - fun setup() { - messageHandlers = MessageHandlerChainSet() - world = PowerMockito.spy(World()) - - val answer = Answer { invocation: InvocationOnMock -> - messageHandlers.putHandler( - invocation.arguments[0] as Class, - invocation.arguments[1] as MessageHandler<*>) - } - - val pluginContext = PowerMockito.mock(PluginContext::class.java, answer) - val pluginEnvironment = KotlinPluginEnvironment(world) - - pluginEnvironment.setContext(pluginContext) - pluginEnvironment.load(ArrayList()) - - val credentials = PlayerCredentials("test", "test", 1, 1, "0.0.0.0") - val position = Position(3200, 3200, 0) - val region = world.regionRepository.fromPosition(position) - - player = PowerMockito.spy(Player(world, credentials, position)) - world.register(player) - region.addEntity(player) - - PowerMockito.doNothing().`when`(player).send(any()) - } - - fun interactWith(entity: Entity, option: Int = 1) { - player.position = entity.position.step(1, Direction.NORTH) - - when (entity) { - is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position)) - is Npc -> notify(NpcActionMessage(option, entity.index)) - is Player -> notify(PlayerActionMessage(option, entity.index)) - } - } - - fun spawnNpc(id: Int, position: Position): Npc { - val definition = NpcDefinition(id) - val npc = Npc(world, position, definition, arrayOfNulls(4)) - val region = world.regionRepository.fromPosition(position) - val npcs = world.npcRepository - - npcs.add(npc) - region.addEntity(npc) - - return npc - } - - fun spawnObject(id: Int, position: Position): GameObject { - val obj = StaticGameObject(world, id, position, 0, 0) - - world.spawn(obj) - - return obj - } - - fun notify(message: Message) { - messageHandlers.notify(player, message) - } - - fun waitForActionCompletion(predicate: (Action) -> Boolean = { _ -> true }, timeout: Int = 15) { - val actionCaptor: ArgumentCaptor> = ArgumentCaptor.forClass(Action::class.java) - Mockito.verify(player).startAction(actionCaptor.capture()) - - val action: Action = actionCaptor.value as Action - Assert.assertTrue("Found wrong action type", predicate.invoke(action)) - - var pulses = 0 - - do { - action.pulse() - } while (action.isRunning && pulses++ < timeout) - - Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout) - } - -} diff --git a/game/src/plugins/bank/test/OpenBankTest.kt b/game/src/plugins/bank/test/OpenBankTest.kt index 8bede6bee..d7b4ed1cf 100644 --- a/game/src/plugins/bank/test/OpenBankTest.kt +++ b/game/src/plugins/bank/test/OpenBankTest.kt @@ -1,5 +1,5 @@ import org.apollo.game.model.Position -import org.apollo.game.plugins.testing.KotlinPluginTest +import org.apollo.game.plugin.testing.KotlinPluginTest import org.junit.Test import org.mockito.Mockito.verify @@ -14,21 +14,21 @@ class OpenBankTest() : KotlinPluginTest() { @Test fun `Interacting with a bank teller should open the players bank`() { - val bankTeller = spawnNpc(BANK_TELLER_ID, BANK_POSITION) + val bankTeller = world.spawnNpc(BANK_TELLER_ID, BANK_POSITION) // @todo - these option numbers only match by coincidence, we should be looking up the correct ones - interactWith(bankTeller, option = 2) - waitForActionCompletion() + player.interactWith(bankTeller, option = 2) + player.waitForActionCompletion() verify(player).openBank() } @Test fun `Interacting with a bank booth object should open the players bank`() { - val bankBooth = spawnObject(BANK_BOOTH_ID, BANK_POSITION) + val bankBooth = world.spawnObject(BANK_BOOTH_ID, BANK_POSITION) - interactWith(bankBooth, option = 2) - waitForActionCompletion() + player.interactWith(bankBooth, option = 2) + player.waitForActionCompletion() verify(player).openBank() } diff --git a/game/src/plugins/chat/private-messaging/src/friends.plugin.kts b/game/src/plugins/chat/private-messaging/src/friends.plugin.kts index ea7ced88c..6ac357d72 100644 --- a/game/src/plugins/chat/private-messaging/src/friends.plugin.kts +++ b/game/src/plugins/chat/private-messaging/src/friends.plugin.kts @@ -3,21 +3,19 @@ import org.apollo.game.message.impl.SendFriendMessage import org.apollo.game.model.entity.setting.PrivacyState on { AddFriendMessage::class } - .then { - it.addFriend(username) + .then { + it.addFriend(username) - val playerUsername = it.username - val friend = it.world.getPlayer(username) + val friend = it.world.getPlayer(username) - if (friend == null) { - it.send(SendFriendMessage(username, 0)) - } else if (friend.friendsWith(playerUsername) || friend.friendPrivacy == PrivacyState.ON) { - if (it.friendPrivacy != PrivacyState.OFF) { - friend.send(SendFriendMessage(playerUsername, it.worldId)) - } + if (friend == null || friend.friendPrivacy == PrivacyState.OFF) { + it.send(SendFriendMessage(username, 0)) + return@then + } else { + it.send(SendFriendMessage(username, friend.worldId)) + } - if (friend.friendPrivacy != PrivacyState.OFF) { - it.send(SendFriendMessage(username, friend.worldId)) - } - } + if (friend.friendsWith(it.username) && it.friendPrivacy != PrivacyState.OFF) { + friend.send(SendFriendMessage(it.username, it.worldId)) } + } diff --git a/game/src/plugins/dummy/test/TrainingDummyTest.kt b/game/src/plugins/dummy/test/TrainingDummyTest.kt index 0fc2da241..2e99e313c 100644 --- a/game/src/plugins/dummy/test/TrainingDummyTest.kt +++ b/game/src/plugins/dummy/test/TrainingDummyTest.kt @@ -1,10 +1,10 @@ import org.apollo.game.model.Position import org.apollo.game.model.entity.Skill -import org.apollo.game.plugins.testing.KotlinPluginTest -import org.hamcrest.Matchers.* -import org.junit.Assert.* +import org.apollo.game.plugin.testing.* +import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import org.mockito.Mockito.* +import org.mockito.Mockito.contains +import org.mockito.Mockito.verify class TrainingDummyTest : KotlinPluginTest() { @@ -14,30 +14,30 @@ class TrainingDummyTest : KotlinPluginTest() { } @Test fun `Hitting the training dummy should give the player attack experience`() { - val dummy = spawnObject(DUMMY_ID, DUMMY_POSITION) + val dummy = world.spawnObject(DUMMY_ID, DUMMY_POSITION) val skills = player.skillSet val beforeExp = skills.getExperience(Skill.ATTACK) - interactWith(dummy, option = 2) - waitForActionCompletion() + player.interactWith(dummy, option = 2) + player.waitForActionCompletion() val afterExp = skills.getExperience(Skill.ATTACK) - assertThat(afterExp, greaterThan(beforeExp)) + assertThat(afterExp).isGreaterThan(beforeExp) } @Test fun `The player should stop getting attack experience from the training dummy at level 8`() { - val dummy = spawnObject(DUMMY_ID, DUMMY_POSITION) + val dummy = world.spawnObject(DUMMY_ID, DUMMY_POSITION) val skills = player.skillSet skills.setMaximumLevel(Skill.ATTACK, 8) val beforeExp = skills.getExperience(Skill.ATTACK) - interactWith(dummy, option = 2) - waitForActionCompletion() + player.interactWith(dummy, option = 2) + player.waitForActionCompletion() val afterExp = skills.getExperience(Skill.ATTACK) verify(player).sendMessage(contains("nothing more you can learn")) - assertThat(afterExp, equalTo(beforeExp)) + assertThat(afterExp).isEqualTo(beforeExp) } -} \ No newline at end of file +} diff --git a/game/src/plugins/stub/stub.kt b/game/src/plugins/stub/stub.kt deleted file mode 100644 index f82da254d..000000000 --- a/game/src/plugins/stub/stub.kt +++ /dev/null @@ -1,29 +0,0 @@ -/** - * NOTE: This file is a stub, intended only for use within an IDE. It should be updated - * each time [org.apollo.game.plugin.kotlin.KotlinPluginScript] has a new method added to it. - * - * Until IntelliJ IDEA starts to support ScriptTemplateDefinitions this is - * required to resolve references within plugin code. - */ - -import org.apollo.game.model.World -import org.apollo.game.plugin.PluginContext -import org.apollo.game.plugin.kotlin.* -import org.apollo.net.message.Message -import kotlin.reflect.KClass - -fun on(type: () -> KClass): KotlinMessageHandler { - null!! -} - -fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { - null!! -} - -fun start(callback: (World) -> Unit) { - -} - -fun stop(callback: (World) -> Unit) { - -} diff --git a/game/src/plugins/util/lookup/test/LookupTests.kt b/game/src/plugins/util/lookup/test/LookupTests.kt index 545cbc41f..fc4c18f9c 100644 --- a/game/src/plugins/util/lookup/test/LookupTests.kt +++ b/game/src/plugins/util/lookup/test/LookupTests.kt @@ -1,14 +1,15 @@ import org.apollo.cache.def.ItemDefinition +import org.apollo.game.plugin.testing.* +import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import kotlin.test.assertEquals -class LookupTests { +class LookupTests : KotlinPluginTest() { @Test fun itemLookup() { val testItem = ItemDefinition(0) testItem.name = "sword" ItemDefinition.init(arrayOf(testItem)) - assertEquals(testItem, lookup_item("sword")) + assertThat(lookup_item("sword")).isEqualTo(testItem); } } \ No newline at end of file From 97e85868fff63cc07b6e940ebd72a6030a6137ab Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 20 Jun 2017 06:53:00 +0100 Subject: [PATCH 037/209] Add support for asynchronous Mob actions Adds asynchronous implementations of the Action and DistancedAction classes, allowing plugins to make use of suspendable functions in Kotlin instead of creating mini state machines to keep track of state. The asynchronicity works by creating coroutine backed Channels for each asynchronous action and having them listen on "pulse" events from the action scheduler. The action can then suspend execution until a pulse is received or until some expensive operation has completed (i.e., pathfinding). If an asynchronous action is still busy when a pulse arrives then the number of missed pulses will be accumulated and sent to the action at the next possible time. The training dummy plugin has been updated to use asycnrhonous actions as an example. --- game/build.gradle | 8 + .../game/plugin/KotlinPluginCompilerStub.java | 9 - .../game/plugin/KotlinPluginEnvironment.java | 1 - .../org/apollo/game/action/AsyncAction.kt | 26 +++ .../apollo/game/action/AsyncActionRunner.kt | 56 ++++++ .../apollo/game/action/AsyncActionTrait.kt | 9 + .../game/action/AsyncDistancedAction.kt | 32 ++++ .../plugin/kotlin/KotlinPluginCompiler.kt | 159 ------------------ .../plugin/testing/KotlinPluginTestHelpers.kt | 10 ++ game/src/plugins/dummy/src/dummy.plugin.kts | 33 ++-- 10 files changed, 156 insertions(+), 187 deletions(-) delete mode 100644 game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java create mode 100644 game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt create mode 100644 game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt create mode 100644 game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt create mode 100644 game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt delete mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt diff --git a/game/build.gradle b/game/build.gradle index b9646593d..b4441d4a0 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -24,6 +24,12 @@ sourceSets { } } +repositories { + maven { + url { 'https://dl.bintray.com/kotlin/kotlinx/' } + } +} + dependencies { compile project(':cache') compile project(':net') @@ -32,6 +38,8 @@ dependencies { compile group: 'io.github.lukehutch', name: 'fast-classpath-scanner', version: '2.0.21' compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" + compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-jdk8', version: '0.16' + compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '0.16' testCompile group: 'org.assertj', name: 'assertj-core', version: '3.8.0' } diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java deleted file mode 100644 index 1912d4070..000000000 --- a/game/src/main/java/org/apollo/game/plugin/KotlinPluginCompilerStub.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.apollo.game.plugin; - -import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; - -public class KotlinPluginCompilerStub { - public static void main(String[] argv) { - KotlinPluginCompiler.main(argv); - } -} diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java index dba144690..853326aa6 100644 --- a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -19,7 +19,6 @@ import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult; import org.apollo.game.model.World; -import org.apollo.game.plugin.kotlin.KotlinPluginCompiler; import org.apollo.game.plugin.kotlin.KotlinPluginScript; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt new file mode 100644 index 000000000..abf85dc8c --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt @@ -0,0 +1,26 @@ +package org.apollo.game.action + +import org.apollo.game.model.entity.Mob + +abstract class AsyncAction : Action, AsyncActionTrait { + override val runner: AsyncActionRunner + + constructor(delay: Int, immediate: Boolean, mob: T) : super(delay, immediate, mob) { + this.runner = AsyncActionRunner({ this }, { executeActionAsync() }) + } + + abstract suspend fun executeActionAsync() + + override fun execute() { + if (!runner.started()) { + runner.start() + } + + runner.pulse() + } + + override fun stop() { + super.stop() + runner.stop() + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt new file mode 100644 index 000000000..366af4e20 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt @@ -0,0 +1,56 @@ +package org.apollo.game.action + +import kotlinx.coroutines.experimental.* +import kotlinx.coroutines.experimental.channels.Channel +import kotlinx.coroutines.experimental.selects.select +import org.apollo.game.model.entity.Mob +import java.util.function.Supplier + +class AsyncActionRunner(val actionSupplier: () -> Action<*>, val callback: suspend () -> Unit) { + var job: Job? = null + var pulseChannel = Channel(1) + var unsentPulses = 0 + + fun pulse() { + if (pulseChannel.offer(unsentPulses + 1)) { + unsentPulses = 0 + } else { + unsentPulses++ + } + } + + fun start() { + if (job != null) { + return + } + + val action = actionSupplier.invoke() + + job = launch(CommonPool) { + select { + pulseChannel.onReceive { + callback() + action.stop() + } + } + } + } + + fun started(): Boolean { + return job != null + } + + fun stop() { + job?.cancel() + pulseChannel.close() + } + + suspend fun wait(pulses: Int = 1) { + var remainingPulses = pulses + + while (remainingPulses > 0) { + val numPulses = pulseChannel.receive() + remainingPulses -= numPulses + } + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt new file mode 100644 index 000000000..f398c5f9e --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt @@ -0,0 +1,9 @@ +package org.apollo.game.action + +interface AsyncActionTrait { + val runner: AsyncActionRunner + + suspend fun wait(pulses: Int = 1) { + runner.wait(pulses) + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt new file mode 100644 index 000000000..e947f8e4a --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt @@ -0,0 +1,32 @@ +package org.apollo.game.action + +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Mob + +abstract class AsyncDistancedAction : DistancedAction, AsyncActionTrait { + + override val runner: AsyncActionRunner + + constructor(delay: Int, immediate: Boolean, mob: T, position: Position, distance: Int) : + super(delay, immediate, mob, position, distance) { + + this.runner = AsyncActionRunner({ this }, { executeActionAsync() }) + } + + abstract suspend fun executeActionAsync() + + override fun stop() { + super.stop() + runner.stop() + } + + override fun executeAction() { + if (!runner.started()) { + runner.start() + } + + runner.pulse() + } + +} + diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt deleted file mode 100644 index 85840729f..000000000 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginCompiler.kt +++ /dev/null @@ -1,159 +0,0 @@ -package org.apollo.game.plugin.kotlin - -import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.messages.* -import org.jetbrains.kotlin.cli.jvm.compiler.* -import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot -import org.jetbrains.kotlin.codegen.CompilationException -import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer -import org.jetbrains.kotlin.config.* -import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate -import java.io.File -import java.lang.management.ManagementFactory -import java.net.URISyntaxException -import java.net.URLClassLoader -import java.nio.file.* -import java.nio.file.StandardOpenOption.* -import java.util.* - -class KotlinMessageCollector : MessageCollector { - - override fun clear() { - } - - override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { - if (severity.isError) { - println("${location.path}:${location.line}-${location.column}: $message") - println(">>> ${location.lineContent}") - } - } - - override fun hasErrors(): Boolean { - return false - } - -} - -data class KotlinCompilerResult(val fqName: String, val outputPath: Path) - -class KotlinPluginCompiler(val classpath: List, val messageCollector: MessageCollector) { - - companion object { - - fun currentClasspath(): List { - val classLoader = Thread.currentThread().contextClassLoader as? URLClassLoader ?: - throw RuntimeException("Unable to resolve classpath for current ClassLoader") - - val classpathUrls = classLoader.urLs - val classpath = ArrayList() - - for (classpathUrl in classpathUrls) { - try { - classpath.add(File(classpathUrl.toURI())) - } catch (e: URISyntaxException) { - throw RuntimeException("URL returned by ClassLoader is invalid") - } - - } - - return classpath - } - - @JvmStatic - fun main(args: Array) { - if (args.size < 2) throw RuntimeException("Usage: script1.kts script2.kts ...") - - val outputDir = Paths.get(args[0]) - val inputScripts = args.slice(1..args.size - 1).map { Paths.get(it) } - val classpath = mutableListOf() - - val runtimeBean = ManagementFactory.getRuntimeMXBean() - if (!runtimeBean.isBootClassPathSupported) { - println("Warning! Boot class path is not supported, must be supplied on the command line") - } else { - val bootClasspath = runtimeBean.bootClassPath - classpath.addAll(bootClasspath.split(File.pathSeparatorChar).map { File(it) }) - } - - /** - * Our current classpath should contain all compile time dependencies for the plugin as well as Apollo's - * own sources. We can also achieve this via Gradle but doing it at runtime prevents Gradle from thinking - * the build has been modified after evaluation. - */ - classpath.addAll(currentClasspath()) - - val compiler = KotlinPluginCompiler(classpath, MessageCollector.NONE) - val compiledScriptClasses = mutableListOf() - - try { - try { - Files.createDirectory(outputDir) - } catch (e: FileAlreadyExistsException) { - // do nothing... - } - - inputScripts.forEach { - compiledScriptClasses.add(compiler.compile(it, outputDir).fqName) - } - } catch (t: Throwable) { - t.printStackTrace() - System.exit(1) - } - } - } - - private fun createCompilerConfiguration(inputPath: Path): CompilerConfiguration { - val configuration = CompilerConfiguration() - val scriptDefinition = KotlinScriptDefinitionFromAnnotatedTemplate(KotlinPluginScript::class) - - configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) - configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.map { JvmClasspathRoot(it) }) - configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) - configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, KotlinMessageCollector()) - configuration.put(CommonConfigurationKeys.MODULE_NAME, inputPath.toString()) - configuration.addKotlinSourceRoot(inputPath.toAbsolutePath().toString()) - - return configuration - } - - @Throws(KotlinPluginCompilerException::class) - fun compile(inputPath: Path, outputPath: Path): KotlinCompilerResult { - val rootDisposable = Disposer.newDisposable() - val configuration = createCompilerConfiguration(inputPath) - - val configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES - val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, configFiles) - - try { - val generationState = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(environment) - if (generationState == null) { - throw KotlinPluginCompilerException("Failed to generate bytecode for kotlin script") - } - - val sourceFiles = environment.getSourceFiles() - val script = sourceFiles[0].script ?: throw KotlinPluginCompilerException("Main script file isnt a script") - - val scriptFilePath = script.fqName.asString().replace('.', '/') + ".class" - val scriptFileClass = generationState.factory.get(scriptFilePath) - - if (scriptFileClass == null) { - throw KotlinPluginCompilerException("Unable to find compiled plugin class file $scriptFilePath") - } - - generationState.factory.asList().forEach { - Files.write(outputPath.resolve(it.relativePath), it.asByteArray(), CREATE, WRITE, TRUNCATE_EXISTING) - } - - return KotlinCompilerResult(script.fqName.asString(), outputPath.resolve(scriptFileClass.relativePath)) - } catch (e: CompilationException) { - throw KotlinPluginCompilerException("Compilation failed", e) - } finally { - Disposer.dispose(rootDisposable) - } - } - -} - -class KotlinPluginCompilerException(message: String, cause: Throwable? = null) : Exception(message, cause) { - -} diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt index b6a26f66f..9dd4898a9 100644 --- a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt @@ -38,6 +38,16 @@ abstract class KotlinPluginTestHelpers { do { action.pulse() + + /** + * Introducing an artificial delay is necessary to prevent the timeout being exceeded before + * an asynchronous [Action] really starts. When a job is submitted to a new coroutine context + * there may be a delay before it is actually executed. + * + * This delay is typically sub-millisecond and is only incurred with startup. Since game actions + * have larger delays of their own this isn't a problem in practice. + */ + Thread.sleep(50L) } while (action.isRunning && pulses++ < timeout) Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout) diff --git a/game/src/plugins/dummy/src/dummy.plugin.kts b/game/src/plugins/dummy/src/dummy.plugin.kts index eed2880d8..ac7e90795 100644 --- a/game/src/plugins/dummy/src/dummy.plugin.kts +++ b/game/src/plugins/dummy/src/dummy.plugin.kts @@ -1,9 +1,12 @@ +import kotlinx.coroutines.experimental.* +import kotlinx.coroutines.experimental.channels.Channel +import kotlinx.coroutines.experimental.selects.select +import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.action.DistancedAction import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Animation import org.apollo.game.model.Position -import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.* import org.apollo.net.message.Message /** @@ -15,7 +18,7 @@ on { ObjectActionMessage::class } .where { option == 2 && id in DUMMY_IDS } .then { DummyAction.start(this, it, position) } -class DummyAction(val player: Player, position: Position) : DistancedAction(0, true, player, position, DISTANCE) { +class DummyAction(val player: Player, position: Position) : AsyncDistancedAction(0, true, player, position, DISTANCE) { companion object { @@ -49,25 +52,19 @@ class DummyAction(val player: Player, position: Position) : DistancedAction= LEVEL_THRESHOLD) { - player.sendMessage("There is nothing more you can learn from hitting a dummy.") - } else { - skills.addExperience(Skill.ATTACK, EXP_PER_HIT) - } + val skills = player.skillSet - stop() + if (skills.getSkill(Skill.ATTACK).maximumLevel >= LEVEL_THRESHOLD) { + player.sendMessage("There is nothing more you can learn from hitting a dummy.") } else { - mob.sendMessage("You hit the dummy.") - mob.turnTo(this.position) - mob.playAnimation(PUNCH_ANIMATION) - - started = true + skills.addExperience(Skill.ATTACK, EXP_PER_HIT) } } From b17ad487ab49e09033a192fdcabf9f4907d7da48 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 20 Jun 2017 07:42:47 +0100 Subject: [PATCH 038/209] Add Jenkinsfile --- Jenkinsfile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..7fb4e676b --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,14 @@ +node { + stage 'Stage Checkout' + checkout scm + + stage 'Stage Build' + gradle 'clean assemble' + + stage 'Stage Test' + gradle 'check' +} + +def gradle(command) { + sh "${tool name: 'gradle', type: 'hudson.plugins.gradle.GradleInstallation'}/bin/gradle ${command}" +} \ No newline at end of file From c15f18c60974029f2253963d20689cb5713a751b Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 22 Jun 2017 22:07:59 +0100 Subject: [PATCH 039/209] Add plugin for consumable food/drink --- .../game/plugin/testing/KotlinPluginTest.kt | 2 +- game/src/plugins/consumables/meta.toml | 8 + .../plugins/consumables/src/consumables.kt | 82 +++++++++ .../consumables/src/consumables.plugin.kts | 36 ++++ .../plugins/consumables/src/drinks.plugin.kts | 24 +++ .../plugins/consumables/src/foods.plugin.kts | 159 ++++++++++++++++++ .../consumables/test/FoodOrDrinkTests.kt | 86 ++++++++++ 7 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 game/src/plugins/consumables/meta.toml create mode 100644 game/src/plugins/consumables/src/consumables.kt create mode 100644 game/src/plugins/consumables/src/consumables.plugin.kts create mode 100644 game/src/plugins/consumables/src/drinks.plugin.kts create mode 100644 game/src/plugins/consumables/src/foods.plugin.kts create mode 100644 game/src/plugins/consumables/test/FoodOrDrinkTests.kt diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt index fce9fc411..08fecc641 100644 --- a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt +++ b/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt @@ -20,7 +20,7 @@ abstract class KotlinPluginTest: KotlinPluginTestHelpers() { override lateinit var messageHandlers: MessageHandlerChainSet @Before - fun setup() { + open fun setup() { messageHandlers = MessageHandlerChainSet() world = PowerMockito.spy(World()) diff --git a/game/src/plugins/consumables/meta.toml b/game/src/plugins/consumables/meta.toml new file mode 100644 index 000000000..e31a38c37 --- /dev/null +++ b/game/src/plugins/consumables/meta.toml @@ -0,0 +1,8 @@ +name = "consumables" +package = "org.apollo.game.plugin.consumables" +authors = [ "Gary Tierney" ] +dependencies = [] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/consumables/src/consumables.kt b/game/src/plugins/consumables/src/consumables.kt new file mode 100644 index 000000000..3fec3eaf5 --- /dev/null +++ b/game/src/plugins/consumables/src/consumables.kt @@ -0,0 +1,82 @@ +package org.apollo.plugin.consumables + +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill + +/** + * An item that can be consumed to restore or buff stats. + */ +abstract class Consumable(val name: String, val id: Int, val sound: Int, val delay: Int, val replacement: Int?) { + + abstract fun addEffect(player: Player) + + fun consume(player: Player, slot: Int) { + addEffect(player) + player.inventory.reset(slot) + + if (replacement != null) { + player.inventory.add(replacement) + } + } + +} + +private val consumables = mutableMapOf() + +fun isConsumable(itemId: Int) = consumables.containsKey(itemId) +fun lookupConsumable(itemId: Int): Consumable = consumables.get(itemId)!! +fun consumable(consumable: Consumable) = consumables.put(consumable.id, consumable) + +enum class FoodOrDrinkType(val action: String) { + FOOD("eat"), DRINK("drink") +} + +class FoodOrDrink : Consumable { + + companion object { + const val EAT_FOOD_SOUND = 317 + } + + val restoration: Int + val type: FoodOrDrinkType + + constructor( + name: String, + id: Int, + delay: Int, + type: FoodOrDrinkType, + restoration: Int, + replacement: Int? = null + ) : super(name, id, EAT_FOOD_SOUND, delay, replacement) { + this.type = type + this.restoration = restoration + } + + override fun addEffect(player: Player) { + val hitpoints = player.skillSet.getSkill(Skill.HITPOINTS) + val hitpointsLevel = hitpoints.currentLevel + val newHitpointsLevel = Math.min(hitpointsLevel + restoration, hitpoints.maximumLevel) + + player.sendMessage("You ${type.action} the $name.") + if (newHitpointsLevel > hitpointsLevel) { + player.sendMessage("It heals some health.") + } + + player.skillSet.setCurrentLevel(Skill.HITPOINTS, newHitpointsLevel) + } + +} + +/** + * Define a new type of [Consumable] food. + */ +fun food(name: String, id: Int, restoration: Int, replacement: Int? = null, delay: Int = 3) { + consumable(FoodOrDrink(name, id, delay, FoodOrDrinkType.FOOD, restoration, replacement)) +} + +/** + * Define a new type of [Consumable] drink. + */ +fun drink(name: String, id: Int, restoration: Int, replacement: Int? = null, delay: Int = 3) { + consumable(FoodOrDrink(name, id, delay, FoodOrDrinkType.DRINK, restoration, replacement)) +} \ No newline at end of file diff --git a/game/src/plugins/consumables/src/consumables.plugin.kts b/game/src/plugins/consumables/src/consumables.plugin.kts new file mode 100644 index 000000000..49c64312d --- /dev/null +++ b/game/src/plugins/consumables/src/consumables.plugin.kts @@ -0,0 +1,36 @@ +import org.apollo.game.action.AsyncAction +import org.apollo.game.message.impl.ItemOptionMessage +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import org.apollo.net.message.Message +import org.apollo.plugin.consumables.* + +on { ItemOptionMessage::class } + .where { option == 1 && isConsumable(id) } + .then { + ConsumeAction.start(this, it, lookupConsumable(id), slot) + } + +class ConsumeAction(val consumable: Consumable, player: Player, val slot: Int) : + AsyncAction(CONSUME_STARTUP_DELAY, true, player) { + + companion object { + const val CONSUME_ANIMATION_ID = 829 + const val CONSUME_STARTUP_DELAY = 2 + + /** + * Starts a [ConsumeAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: Message, player: Player, consumable: Consumable, slot: Int) { + player.startAction(ConsumeAction(consumable, player, slot)) + message.terminate() + } + } + + suspend override fun executeActionAsync() { + consumable.consume(mob, slot) + mob.playAnimation(Animation(CONSUME_ANIMATION_ID)) + wait(consumable.delay) + } + +} diff --git a/game/src/plugins/consumables/src/drinks.plugin.kts b/game/src/plugins/consumables/src/drinks.plugin.kts new file mode 100644 index 000000000..f3c8075ae --- /dev/null +++ b/game/src/plugins/consumables/src/drinks.plugin.kts @@ -0,0 +1,24 @@ +import org.apollo.plugin.consumables.drink + +//# Wine +drink(name = "jug_of_wine", id = 1993, restoration = 11) + +//# Hot Drinks +drink(name = "nettle_tea", id = 4239, restoration = 3) +drink(name = "nettle_tea", id = 4240, restoration = 3) + +//# Gnome Cocktails +drink(name = "fruit_blast", id = 2034, restoration = 9) +drink(name = "fruit_blast", id = 2084, restoration = 9) +drink(name = "pineapple_punch", id = 2036, restoration = 9) +drink(name = "pineapple_punch", id = 2048, restoration = 9) +drink(name = "wizard_blizzard", id = 2040, restoration = 5) // -4 attack, +5 strength also +drink(name = "wizard_blizzard", id = 2054, restoration = 5) // -4 attack, +5 strength also +drink(name = "short_green_guy", id = 2038, restoration = 5) // -4 attack, +5 strength also +drink(name = "short_green_guy", id = 2080, restoration = 5) // -4 attack, +5 strength also +drink(name = "drunk_dragon", id = 2032, restoration = 5) // -4 attack, +6 strength also +drink(name = "drunk_dragon", id = 2092, restoration = 5) // -4 attack, +6 strength also +drink(name = "chocolate_saturday", id = 2030, restoration = 7) // -4 attack, +6 strength also +drink(name = "chocolate_saturday", id = 2074, restoration = 7) // -4 attack, +6 strength also +drink(name = "blurberry_special", id = 2028, restoration = 7) // -4 attack, +6 strength also +drink(name = "blurberry_special", id = 2064, restoration = 7) // -4 attack, +6 strength also diff --git a/game/src/plugins/consumables/src/foods.plugin.kts b/game/src/plugins/consumables/src/foods.plugin.kts new file mode 100644 index 000000000..7762969b9 --- /dev/null +++ b/game/src/plugins/consumables/src/foods.plugin.kts @@ -0,0 +1,159 @@ +import org.apollo.plugin.consumables.food + +food(name = "anchovies", id = 319, restoration = 1) +food(name = "crab_meat", id = 7521, restoration = 2, replacement = 7523) +food(name = "crab_meat", id = 7523, restoration = 2, replacement = 7524) +food(name = "crab_meat", id = 7524, restoration = 2, replacement = 7525) +food(name = "crab_meat", id = 7525, restoration = 2, replacement = 7526) +food(name = "crab_meat", id = 7526, restoration = 2) +food(name = "shrimp", id = 315, restoration = 3) +food(name = "sardine", id = 325, restoration = 3) +food(name = "cooked_meat", id = 2142, restoration = 3) +food(name = "cooked_chicken", id = 2140, restoration = 3) +food(name = "ugthanki_meat", id = 1861, restoration = 3) +food(name = "karambwanji", id = 3151, restoration = 3) +food(name = "cooked_rabbit", id = 3228, restoration = 5) +food(name = "herring", id = 347, restoration = 6) +food(name = "trout", id = 333, restoration = 7) +food(name = "cod", id = 339, restoration = 7) +food(name = "mackeral", id = 355, restoration = 7) +food(name = "roast_rabbit", id = 7223, restoration = 7) +food(name = "pike", id = 351, restoration = 8) +food(name = "lean_snail_meat", id = 3371, restoration = 8) +food(name = "salmon", id = 329, restoration = 9) +food(name = "tuna", id = 361, restoration = 10) +food(name = "lobster", id = 379, restoration = 12) +food(name = "bass", id = 365, restoration = 13) +food(name = "swordfish", id = 373, restoration = 14) +food(name = "cooked_jubbly", id = 7568, restoration = 15) +food(name = "monkfish", id = 7946, restoration = 16) +food(name = "cooked_karambwan", id = 3144, restoration = 18, delay = 0) +food(name = "shark", id = 385, restoration = 20) +food(name = "sea_turtle", id = 397, restoration = 21) +food(name = "manta_ray", id = 391, restoration = 22) + +//# Breads/Wraps +food(name = "bread", id = 2309, restoration = 5) +food(name = "oomlie_wrap", id = 2343, restoration = 14) +food(name = "ugthanki_kebab", id = 1883, restoration = 19) + +//# Fruits +food(name = "banana", id = 1963, restoration = 2) +food(name = "sliced_banana", id = 3162, restoration = 2) +food(name = "lemon", id = 2102, restoration = 2) +food(name = "lemon_chunks", id = 2104, restoration = 2) +food(name = "lemon_slices", id = 2106, restoration = 2) +food(name = "lime", id = 2120, restoration = 2) +food(name = "lime_chunks", id = 2122, restoration = 2) +food(name = "lime_slices", id = 2124, restoration = 2) +food(name = "strawberry", id = 5504, restoration = 5) +food(name = "papaya_fruit", id = 5972, restoration = 8) +food(name = "pineapple_chunks", id = 2116, restoration = 2) +food(name = "pineapple_ring", id = 2118, restoration = 2) +food(name = "orange", id = 2108, restoration = 2) +food(name = "orange_rings", id = 2110, restoration = 2) +food(name = "orange_slices", id = 2112, restoration = 2) + +//# Pies +//# TODO: pie special effects (e.g. fish pie raises fishing level) +food(name = "redberry_pie", id = 2325, restoration = 5, replacement = 2333, delay = 1) +food(name = "redberry_pie", id = 2333, restoration = 5, delay = 1) + +food(name = "meat_pie", id = 2327, restoration = 6, replacement = 2331, delay = 1) +food(name = "meat_pie", id = 2331, restoration = 6, delay = 1) + +food(name = "apple_pie", id = 2323, restoration = 7, replacement = 2335, delay = 1) +food(name = "apple_pie", id = 2335, restoration = 7, delay = 1) + +food(name = "fish_pie", id = 7188, restoration = 6, replacement = 7190, delay = 1) +food(name = "fish_pie", id = 7190, restoration = 6, delay = 1) + +food(name = "admiral_pie", id = 7198, restoration = 8, replacement = 7200, delay = 1) +food(name = "admiral_pie", id = 7200, restoration = 8, delay = 1) + +food(name = "wild_pie", id = 7208, restoration = 11, replacement = 7210, delay = 1) +food(name = "wild_pie", id = 7210, restoration = 11, delay = 1) + +food(name = "summer_pie", id = 7218, restoration = 11, replacement = 7220, delay = 1) +food(name = "summer_pie", id = 7220, restoration = 11, delay = 1) + +//# Stews +food(name = "stew", id = 2003, restoration = 11) +food(name = "banana_stew", id = 4016, restoration = 11) +food(name = "curry", id = 2011, restoration = 19) + +//# Pizzas +food(name = "plain_pizza", id = 2289, restoration = 7, replacement = 2291) +food(name = "plain_pizza", id = 2291, restoration = 7) + +food(name = "meat_pizza", id = 2293, restoration = 8, replacement = 2295) +food(name = "meat_pizza", id = 2295, restoration = 8) + +food(name = "anchovy_pizza", id = 2297, restoration = 9, replacement = 2299) +food(name = "anchovy_pizza", id = 2299, restoration = 9) + +food(name = "pineapple_pizza", id = 2301, restoration = 11, replacement = 2303) +food(name = "pineapple_pizza", id = 2303, restoration = 11) + +//# Cakes +food(name = "fishcake", id = 7530, restoration = 11) + +food(name = "cake", id = 1891, restoration = 4, replacement = 1893) +food(name = "cake", id = 1893, restoration = 4, replacement = 1895) +food(name = "cake", id = 1895, restoration = 4) + +food(name = "chocolate_cake", id = 1897, restoration = 5, replacement = 1899) +food(name = "chocolate_cake", id = 1899, restoration = 5, replacement = 1901) +food(name = "chocolate_cake", id = 1901, restoration = 5) + +//# Vegetables +food(name = "potato", id = 1942, restoration = 1) +food(name = "spinach_roll", id = 1969, restoration = 2) +food(name = "baked_potato", id = 6701, restoration = 4) +food(name = "sweetcorn", id = 5988, restoration = 10) +food(name = "sweetcorn_bowl", id = 7088, restoration = 13) +food(name = "potato_with_butter", id = 6703, restoration = 14) +food(name = "chili_potato", id = 7054, restoration = 14) +food(name = "potato_with_cheese", id = 6705, restoration = 16) +food(name = "egg_potato", id = 7056, restoration = 16) +food(name = "mushroom_potato", id = 7058, restoration = 20) +food(name = "tuna_potato", id = 7060, restoration = 22) + +//# Dairy +food(name = "cheese", id = 1985, restoration = 2) +food(name = "pot_of_cream", id = 2130, restoration = 1) + +//# Gnome Food +food(name = "toads_legs", id = 2152, restoration = 3) + +//# Gnome Bowls +food(name = "worm_hole", id = 2191, restoration = 12) +food(name = "worm_hole", id = 2233, restoration = 12) +food(name = "vegetable_ball", id = 2195, restoration = 12) +food(name = "vegetable_ball", id = 2235, restoration = 12) +food(name = "tangled_toads_legs", id = 2187, restoration = 15) +food(name = "tangled_toads_legs", id = 2231, restoration = 15) +food(name = "chocolate_bomb", id = 2185, restoration = 15) +food(name = "chocolate_bomb", id = 2229, restoration = 15) + +//# Gnome Crunchies +food(name = "toad_crunchies", id = 2217, restoration = 7) +food(name = "toad_crunchies", id = 2243, restoration = 7) +food(name = "spicy_crunchies", id = 2213, restoration = 7) +food(name = "spicy_crunchies", id = 2241, restoration = 7) +food(name = "worm_crunchies", id = 2205, restoration = 8) +food(name = "worm_crunchies", id = 2237, restoration = 8) +food(name = "chocchip_crunchies", id = 2209, restoration = 7) +food(name = "chocchip_crunchies", id = 2239, restoration = 7) + +//# Gnome Battas +food(name = "fruit_batta", id = 2225, restoration = 11) +food(name = "fruit_batta", id = 2277, restoration = 11) +food(name = "toad_batta", id = 2221, restoration = 11) +food(name = "toad_batta", id = 2255, restoration = 11) +food(name = "worm_batta", id = 2219, restoration = 11) +food(name = "worm_batta", id = 2253, restoration = 11) +food(name = "vegetable_batta", id = 2227, restoration = 11) +food(name = "vegetable_batta", id = 2281, restoration = 11) +food(name = "cheese_tom_batta", id = 2223, restoration = 11) +food(name = "cheese_tom_batta", id = 2259, restoration = 11) diff --git a/game/src/plugins/consumables/test/FoodOrDrinkTests.kt b/game/src/plugins/consumables/test/FoodOrDrinkTests.kt new file mode 100644 index 000000000..1394e64b2 --- /dev/null +++ b/game/src/plugins/consumables/test/FoodOrDrinkTests.kt @@ -0,0 +1,86 @@ +package org.apollo.plugin.consumables + +import org.apollo.game.message.impl.ItemOptionMessage +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.testing.KotlinPluginTest +import org.apollo.game.plugin.testing.mockito.KotlinMockitoExtensions.matches +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +class FoodOrDrinkTests : KotlinPluginTest() { + + companion object { + const val TEST_FOOD_NAME = "test_food" + const val TEST_FOOD_ID = 2000 + const val TEST_FOOD_RESTORATION = 5 + + const val TEST_DRINK_NAME = "test_drink" + const val TEST_DRINK_ID = 2001 + const val TEST_DRINK_RESTORATION = 5 + + const val HP_LEVEL = 5 + const val MAX_HP_LEVEL = 10 + } + + @Before override fun setup() { + super.setup() + + val skills = player.skillSet + skills.setCurrentLevel(Skill.HITPOINTS, HP_LEVEL) + skills.setMaximumLevel(Skill.HITPOINTS, MAX_HP_LEVEL) + + food("test_food", TEST_FOOD_ID, TEST_FOOD_RESTORATION) + drink("test_drink", TEST_DRINK_ID, TEST_DRINK_RESTORATION) + } + + @Test fun `Consuming food or drink should restore the players hitpoints`() { + val expectedHpLevel = TEST_FOOD_RESTORATION + HP_LEVEL + + player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) + player.waitForActionCompletion() + + val currentHpLevel = player.skillSet.getCurrentLevel(Skill.HITPOINTS) + assertThat(currentHpLevel).isEqualTo(expectedHpLevel) + } + + @Test fun `A message should be sent notifying the player if the item restored hitpoints`() { + player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) + player.waitForActionCompletion() + + verify(player).sendMessage(matches { + assertThat(this).contains("heals some health") + }) + } + + @Test fun `A message should not be sent to the player if the item did not restore hitpoints`() { + player.skillSet.setCurrentLevel(Skill.HITPOINTS, MAX_HP_LEVEL) + player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) + player.waitForActionCompletion() + + verify(player, never()).sendMessage(matches { + assertThat(this).contains("heals some health") + }) + } + + @Test fun `A message should be sent saying the player has drank an item when consuming a drink`() { + player.notify(ItemOptionMessage(1, -1, TEST_DRINK_ID, 1)) + player.waitForActionCompletion() + + verify(player).sendMessage(matches { + assertThat(this).contains("You drink the ${TEST_DRINK_NAME}") + }) + } + + @Test fun `A message should be sent saying the player has eaten an item when consuming food`() { + player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) + player.waitForActionCompletion() + + verify(player).sendMessage(matches { + assertThat(this).contains("You eat the ${TEST_FOOD_NAME}") + }) + } + +} \ No newline at end of file From 9a8ed0d7a9099b6e17fe325e8f4d93950ecdb921 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 24 Jun 2017 17:40:08 +0100 Subject: [PATCH 040/209] Port the walkto and following plugins to Kotlin --- .../java/org/apollo/game/model/Direction.java | 2 +- .../game/model/entity/path/Heuristic.java | 2 +- .../game/plugin/kotlin/KotlinPluginScript.kt | 79 +++++++++++-------- game/src/main/kotlin/stub.kt | 10 ++- game/src/plugins/entity/following/meta.toml | 8 ++ .../plugins/entity/following/src/following.kt | 52 ++++++++++++ .../entity/following/src/following.plugin.kts | 11 +++ .../plugins/entity/player-action/meta.toml | 8 ++ .../entity/player-action/src/player_action.kt | 35 ++++++++ .../src/player_action.plugin.kts | 18 +++++ game/src/plugins/entity/walk-to/meta.toml | 4 + .../src/plugins/entity/walk-to/src/walk_to.kt | 59 ++++++++++++++ 12 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 game/src/plugins/entity/following/meta.toml create mode 100644 game/src/plugins/entity/following/src/following.kt create mode 100644 game/src/plugins/entity/following/src/following.plugin.kts create mode 100644 game/src/plugins/entity/player-action/meta.toml create mode 100644 game/src/plugins/entity/player-action/src/player_action.kt create mode 100644 game/src/plugins/entity/player-action/src/player_action.plugin.kts create mode 100644 game/src/plugins/entity/walk-to/meta.toml create mode 100644 game/src/plugins/entity/walk-to/src/walk_to.kt diff --git a/game/src/main/java/org/apollo/game/model/Direction.java b/game/src/main/java/org/apollo/game/model/Direction.java index dc03c5585..d1a13ffbd 100644 --- a/game/src/main/java/org/apollo/game/model/Direction.java +++ b/game/src/main/java/org/apollo/game/model/Direction.java @@ -85,7 +85,7 @@ public static Direction between(Position current, Position next) { int deltaX = next.getX() - current.getX(); int deltaY = next.getY() - current.getY(); - return fromDeltas(deltaX, deltaY); + return fromDeltas(Integer.signum(deltaX), Integer.signum(deltaY)); } /** diff --git a/game/src/main/java/org/apollo/game/model/entity/path/Heuristic.java b/game/src/main/java/org/apollo/game/model/entity/path/Heuristic.java index 468c65bde..45390aafe 100644 --- a/game/src/main/java/org/apollo/game/model/entity/path/Heuristic.java +++ b/game/src/main/java/org/apollo/game/model/entity/path/Heuristic.java @@ -7,7 +7,7 @@ * * @author Major */ -abstract class Heuristic { +public abstract class Heuristic { /** * Estimates the value for this heuristic. diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index e186a700e..f3b9cf3bd 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -6,6 +6,8 @@ import org.apollo.game.message.handler.MessageHandler import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.model.event.EventListener +import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message import kotlin.reflect.KClass @@ -18,19 +20,18 @@ abstract class KotlinPluginScript(private var world: World, val context: PluginC var startListener: (World) -> Unit = { _ -> }; var stopListener: (World) -> Unit = { _ -> }; - protected fun on(type: () -> KClass): KotlinMessageHandler { - return KotlinMessageHandler(world, context, type.invoke()) - } + fun on(type: () -> KClass) = KotlinMessageHandler(world, context, type.invoke()) - protected fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { - return KotlinCommandHandler(world, command, privileges) - } + fun on_player_event(type: () -> KClass) = KotlinPlayerEventHandler(world, type.invoke()) + + fun on_command(command: String, privileges: PrivilegeLevel) = KotlinCommandHandler(world, command, privileges) - protected fun start(callback: (World) -> Unit) { + + fun start(callback: (World) -> Unit) { this.startListener = callback } - protected fun stop(callback: (World) -> Unit) { + fun stop(callback: (World) -> Unit) { this.stopListener = callback } @@ -43,45 +44,59 @@ abstract class KotlinPluginScript(private var world: World, val context: PluginC } } -class KotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : MessageHandler(world) { - - override fun handle(player: Player, message: T) { - if (message.predicate()) { - message.function(player) - } - } - - var function: T.(Player) -> Unit = { _ -> } +interface KotlinPlayerHandlerProxyTrait { - var predicate: T.() -> Boolean = { true } + var callback: S.(Player) -> Unit + var predicate: S.() -> Boolean - fun where(predicate: T.() -> Boolean): KotlinMessageHandler { + fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait { this.predicate = predicate return this } - fun then(function: T.(Player) -> Unit) { - this.function = function - this.context.addMessageHandler(type.java, this) + fun then(callback: S.(Player) -> Unit) { + this.callback = callback + this.register() } + fun register() + + fun handleProxy(player: Player, subject: S) { + if (subject.predicate()) { + subject.callback(player) + } + } } -class KotlinCommandListener(val level: PrivilegeLevel, val function: Command.(Player) -> Unit) : CommandListener(level) { +class KotlinPlayerEventHandler(val world: World, val type: KClass) : + KotlinPlayerHandlerProxyTrait, EventListener { - override fun execute(player: Player, command: Command) { - function.invoke(command, player) - } + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } + + override fun handle(event: T) = handleProxy(event.player, event) + override fun register() = world.listenFor(type.java, this) } -class KotlinCommandHandler(val world : World, val command: String, val privileges: PrivilegeLevel) { +class KotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : + KotlinPlayerHandlerProxyTrait, MessageHandler(world) { - var function: Command.(Player) -> Unit = { _ -> } + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } - fun then(function: Command.(Player) -> Unit) { - this.function = function - world.commandDispatcher.register(command, KotlinCommandListener(privileges, function)) - } + override fun handle(player: Player, message: T) = handleProxy(player, message) + override fun register() = context.addMessageHandler(type.java, this) + +} + +class KotlinCommandHandler(val world: World, val command: String, privileges: PrivilegeLevel) : + KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { + + override var callback: Command.(Player) -> Unit = {} + override var predicate: Command.() -> Boolean = { true } + + override fun execute(player: Player, command: Command) = handleProxy(player, command) + override fun register() = world.commandDispatcher.register(command, this) } diff --git a/game/src/main/kotlin/stub.kt b/game/src/main/kotlin/stub.kt index a7e212c7b..70dcb9dba 100644 --- a/game/src/main/kotlin/stub.kt +++ b/game/src/main/kotlin/stub.kt @@ -6,16 +6,22 @@ * required to resolve references within plugin code. */ +import org.apollo.game.message.handler.MessageHandlerChainSet import org.apollo.game.model.World +import org.apollo.game.model.area.RegionRepository +import org.apollo.game.model.entity.* import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.kotlin.KotlinCommandHandler -import org.apollo.game.plugin.kotlin.KotlinMessageHandler +import org.apollo.game.model.event.PlayerEvent +import org.apollo.game.plugin.kotlin.* import org.apollo.net.message.Message import kotlin.reflect.KClass fun on(type: () -> KClass): KotlinMessageHandler { null!! } +fun on_player_event(type: () -> KClass): KotlinPlayerEventHandler { + null!! +} fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { null!! diff --git a/game/src/plugins/entity/following/meta.toml b/game/src/plugins/entity/following/meta.toml new file mode 100644 index 000000000..0e2e8e4dc --- /dev/null +++ b/game/src/plugins/entity/following/meta.toml @@ -0,0 +1,8 @@ +name = "following" +package = "org.apollo.game.plugin.entity" +authors = [ "Gary Tierney" ] +dependencies = [ "walkto", "command_utilities", "player_action"] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/entity/following/src/following.kt b/game/src/plugins/entity/following/src/following.kt new file mode 100644 index 000000000..e208229f2 --- /dev/null +++ b/game/src/plugins/entity/following/src/following.kt @@ -0,0 +1,52 @@ +package org.apollo.plugin.entity.following + +import org.apollo.game.action.Action +import org.apollo.game.model.Direction +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Mob +import org.apollo.game.model.entity.Player +import org.apollo.net.message.Message +import org.apollo.plugin.entity.walkto.walkBehind +import org.apollo.plugin.entity.walkto.walkTo + +class FollowAction(player: Player, val target: Player) : Action(0, true, player) { + var lastPosition: Position? = null + + companion object { + fun start(player: Player, target: Player, message: Message? = null) { + player.startAction(FollowAction(player, target)) + message?.terminate() + } + } + + override fun execute() { + if (!target.isActive) { + stop() + return + } + + mob.interactingMob = target + + if (target.position == lastPosition) { + return + } + + val distance = mob.position.getDistance(target.position) + if (distance >= 15) { + stop() + return + } + + if (mob.position == target.position) { + val directions = Direction.NESW + val directionOffset = (Math.random() * directions.size).toInt() + + mob.walkTo(target.position.step(1, directions[directionOffset])) + return + } + + mob.walkBehind(target) + lastPosition = target.position + } + +} \ No newline at end of file diff --git a/game/src/plugins/entity/following/src/following.plugin.kts b/game/src/plugins/entity/following/src/following.plugin.kts new file mode 100644 index 000000000..6037e24d3 --- /dev/null +++ b/game/src/plugins/entity/following/src/following.plugin.kts @@ -0,0 +1,11 @@ +import com.google.common.primitives.Ints +import org.apollo.game.message.impl.PlayerActionMessage +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.plugin.entity.following.FollowAction + +on_player_event { PlayerActionEvent::class } + .where { action == PlayerActionType.FOLLOW } + .then { + FollowAction.start(it, target) + terminate() + } \ No newline at end of file diff --git a/game/src/plugins/entity/player-action/meta.toml b/game/src/plugins/entity/player-action/meta.toml new file mode 100644 index 000000000..89eabaddb --- /dev/null +++ b/game/src/plugins/entity/player-action/meta.toml @@ -0,0 +1,8 @@ +name = "player_action" +package = "org.apollo.game.plugin.entity" +authors = [ "Gary Tierney" ] +dependencies = [] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/entity/player-action/src/player_action.kt b/game/src/plugins/entity/player-action/src/player_action.kt new file mode 100644 index 000000000..bfec0e6de --- /dev/null +++ b/game/src/plugins/entity/player-action/src/player_action.kt @@ -0,0 +1,35 @@ +import org.apollo.game.message.impl.SetPlayerActionMessage +import org.apollo.game.model.entity.Player +import org.apollo.game.model.event.PlayerEvent +import java.util.* + +enum class PlayerActionType(val displayName: String, val slot: Int, val primary: Boolean = true) { + ATTACK("Attack", 2), + CHALLENGE("Challenge", 2), + FOLLOW("Follow", 4), + TRADE("Trade with", 5) +} + +class PlayerActionEvent(player: Player, val target: Player, val action: PlayerActionType) : PlayerEvent(player) + +private val playerActionsMap = mutableMapOf>() +private val Player.actions: EnumSet + get() = playerActionsMap.computeIfAbsent(this, { EnumSet.noneOf(PlayerActionType::class.java) }) + +fun Player.enableAction(action: PlayerActionType) { + send(SetPlayerActionMessage(action.displayName, action.slot, action.primary)) + actions.add(action) +} + +fun Player.disableAction(action: PlayerActionType) { + send(SetPlayerActionMessage("null", action.slot, action.primary)) + actions.remove(action) +} + +fun Player.actionEnabled(action: PlayerActionType): Boolean { + return actions.contains(action) +} + +fun Player.actionAt(slot: Int): PlayerActionType? { + return actions.find { it.slot == slot } +} \ No newline at end of file diff --git a/game/src/plugins/entity/player-action/src/player_action.plugin.kts b/game/src/plugins/entity/player-action/src/player_action.plugin.kts new file mode 100644 index 000000000..c165f30aa --- /dev/null +++ b/game/src/plugins/entity/player-action/src/player_action.plugin.kts @@ -0,0 +1,18 @@ +import org.apollo.game.message.impl.PlayerActionMessage +import org.apollo.game.model.event.impl.LoginEvent + +on { PlayerActionMessage::class } + .then { + val action = it.actionAt(option) + if (action != null) { + it.world.submit(PlayerActionEvent(it, it.world.playerRepository[index], action)) + } + + terminate() + } + +on_player_event { LoginEvent::class } + .then { + it.enableAction(PlayerActionType.FOLLOW) + it.enableAction(PlayerActionType.TRADE) + } \ No newline at end of file diff --git a/game/src/plugins/entity/walk-to/meta.toml b/game/src/plugins/entity/walk-to/meta.toml new file mode 100644 index 000000000..7a7b0ff80 --- /dev/null +++ b/game/src/plugins/entity/walk-to/meta.toml @@ -0,0 +1,4 @@ +name = "walkto" +package = "org.apollo.plugin.entity.walkto" +authors = ["Gary Tierney"] +dependencies = [] \ No newline at end of file diff --git a/game/src/plugins/entity/walk-to/src/walk_to.kt b/game/src/plugins/entity/walk-to/src/walk_to.kt new file mode 100644 index 000000000..3fda1dba8 --- /dev/null +++ b/game/src/plugins/entity/walk-to/src/walk_to.kt @@ -0,0 +1,59 @@ +package org.apollo.plugin.entity.walkto + +import org.apollo.game.model.Direction +import org.apollo.game.model.Position +import org.apollo.game.model.entity.* +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.entity.path.SimplePathfindingAlgorithm + +private fun bounds(target: Entity): Pair = when (target) { + is GameObject -> { + val orientation = Direction.WNES[target.orientation] + val rotated = (orientation == Direction.WEST || orientation == Direction.EAST) + + val width = if (rotated) target.definition.length else target.definition.width + val height = if (rotated) target.definition.width else target.definition.length + + Pair(width, height) + } + is Npc -> Pair(target.definition.size, target.definition.size) + is Player -> Pair(1, 1) + else -> error("Invalid entity type") +} + +fun Mob.walkTo(target: Entity, positioningDirection: Direction? = null) { + val (sourceWidth, sourceHeight) = bounds(target) + val (targetWidth, targetHeight) = bounds(target) + + val direction = positioningDirection ?: Direction.between(position, target.position) + val dx = direction.deltaX() + val dy = direction.deltaY() + + val targetX = if (dx <= 0) target.position.x else target.position.x + targetWidth - 1 + val targetY = if (dy <= 0) target.position.y else target.position.y + targetHeight - 1 + val offsetX = if (dx < 0) -sourceWidth else if (dx > 0) 1 else 0 + val offsetY = if (dy < 0) -sourceHeight else if (dy > 0) 1 else 0 + + walkTo(Position(targetX + offsetX, targetY + offsetY, position.height)) +} + +fun Mob.walkBehind(target: Mob) { + walkTo(target, target.lastDirection.opposite()) +} + +fun Mob.walkTo(target: Position, positionPredicate: (Position) -> Boolean = { true }) { + if (position == target) { + return + } + + val pathfinder = SimplePathfindingAlgorithm(world.collisionManager) + val path = pathfinder.find(position, target) + + for (step in path) { + if (!positionPredicate.invoke(step)) { + return + } + + walkingQueue.addStep(step) + } +} \ No newline at end of file From e6052418934b431c02692bb6de76684bb49398b8 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 25 Jun 2017 02:38:56 +0100 Subject: [PATCH 041/209] Add on_button method to plugin scripts --- .../game/plugin/kotlin/KotlinPluginScript.kt | 129 ++++++++++-------- game/src/main/kotlin/stub.kt | 24 ++-- 2 files changed, 80 insertions(+), 73 deletions(-) diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index f3b9cf3bd..357b17ef3 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -3,6 +3,7 @@ package org.apollo.game.plugin.kotlin import org.apollo.game.command.Command import org.apollo.game.command.CommandListener import org.apollo.game.message.handler.MessageHandler +import org.apollo.game.message.impl.ButtonMessage import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel @@ -14,89 +15,103 @@ import kotlin.reflect.KClass import kotlin.script.templates.ScriptTemplateDefinition @ScriptTemplateDefinition( - scriptFilePattern = ".*\\.plugin\\.kts" + scriptFilePattern = ".*\\.plugin\\.kts" ) abstract class KotlinPluginScript(private var world: World, val context: PluginContext) { - var startListener: (World) -> Unit = { _ -> }; - var stopListener: (World) -> Unit = { _ -> }; - - fun on(type: () -> KClass) = KotlinMessageHandler(world, context, type.invoke()) - - fun on_player_event(type: () -> KClass) = KotlinPlayerEventHandler(world, type.invoke()) - - fun on_command(command: String, privileges: PrivilegeLevel) = KotlinCommandHandler(world, command, privileges) - - - fun start(callback: (World) -> Unit) { - this.startListener = callback - } - - fun stop(callback: (World) -> Unit) { - this.stopListener = callback - } - - fun doStart(world: World) { - this.startListener.invoke(world) - } - - fun doStop(world: World) { - this.stopListener.invoke(world) - } + var startListener: (World) -> Unit = { _ -> }; + var stopListener: (World) -> Unit = { _ -> }; + + /** + * Create a new [MessageHandler]. + */ + fun on(type: () -> KClass) = KotlinMessageHandler(world, context, type.invoke()) + + /** + * Create a new [EventListener] for a type of [PlayerEvent]. + */ + fun on_player_event(type: () -> KClass) = KotlinPlayerEventHandler(world, type.invoke()) + + /** + * Create a new [CommandHandler] for the given _command_ name, which only players with a [PrivelegeLevel] + * of _privileges_ and above can use. + */ + fun on_command(command: String, privileges: PrivilegeLevel) = KotlinCommandHandler(world, command, privileges) + + /** + * Create a new [ButtonMessage] [MessageHandler] for the given _button_ id. + */ + fun on_button(button: Int) = on { ButtonMessage::class }.where { widgetId == button } + + fun start(callback: (World) -> Unit) { + this.startListener = callback + } + + fun stop(callback: (World) -> Unit) { + this.stopListener = callback + } + + fun doStart(world: World) { + this.startListener.invoke(world) + } + + fun doStop(world: World) { + this.stopListener.invoke(world) + } } interface KotlinPlayerHandlerProxyTrait { - var callback: S.(Player) -> Unit - var predicate: S.() -> Boolean + var callback: S.(Player) -> Unit + var predicate: S.() -> Boolean - fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait { - this.predicate = predicate - return this - } + fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait { + this.predicate = predicate + return this + } - fun then(callback: S.(Player) -> Unit) { - this.callback = callback - this.register() - } + fun then(callback: S.(Player) -> Unit) { + this.callback = callback + this.register() + } - fun register() + fun register() - fun handleProxy(player: Player, subject: S) { - if (subject.predicate()) { - subject.callback(player) - } - } + fun handleProxy(player: Player, subject: S) { + if (subject.predicate()) { + subject.callback(player) + } + } } class KotlinPlayerEventHandler(val world: World, val type: KClass) : - KotlinPlayerHandlerProxyTrait, EventListener { + KotlinPlayerHandlerProxyTrait, EventListener { - override var callback: T.(Player) -> Unit = {} - override var predicate: T.() -> Boolean = { true } + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } - override fun handle(event: T) = handleProxy(event.player, event) - override fun register() = world.listenFor(type.java, this) + override fun handle(event: T) = handleProxy(event.player, event) + override fun register() = world.listenFor(type.java, this) } class KotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : - KotlinPlayerHandlerProxyTrait, MessageHandler(world) { + KotlinPlayerHandlerProxyTrait, MessageHandler(world) { - override var callback: T.(Player) -> Unit = {} - override var predicate: T.() -> Boolean = { true } + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } - override fun handle(player: Player, message: T) = handleProxy(player, message) - override fun register() = context.addMessageHandler(type.java, this) + override fun handle(player: Player, message: T) = handleProxy(player, message) + override fun register() = context.addMessageHandler(type.java, this) } class KotlinCommandHandler(val world: World, val command: String, privileges: PrivilegeLevel) : - KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { + KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { - override var callback: Command.(Player) -> Unit = {} - override var predicate: Command.() -> Boolean = { true } + override var callback: Command.(Player) -> Unit = {} + override var predicate: Command.() -> Boolean = { true } - override fun execute(player: Player, command: Command) = handleProxy(player, command) - override fun register() = world.commandDispatcher.register(command, this) + override fun execute(player: Player, command: Command) = handleProxy(player, command) + override fun register() = world.commandDispatcher.register(command, this) } diff --git a/game/src/main/kotlin/stub.kt b/game/src/main/kotlin/stub.kt index 70dcb9dba..48dd599ab 100644 --- a/game/src/main/kotlin/stub.kt +++ b/game/src/main/kotlin/stub.kt @@ -6,7 +6,9 @@ * required to resolve references within plugin code. */ +import org.apollo.game.command.Command import org.apollo.game.message.handler.MessageHandlerChainSet +import org.apollo.game.message.impl.ButtonMessage import org.apollo.game.model.World import org.apollo.game.model.area.RegionRepository import org.apollo.game.model.entity.* @@ -16,21 +18,11 @@ import org.apollo.game.plugin.kotlin.* import org.apollo.net.message.Message import kotlin.reflect.KClass -fun on(type: () -> KClass): KotlinMessageHandler { - null!! -} -fun on_player_event(type: () -> KClass): KotlinPlayerEventHandler { - null!! -} +fun on(type: () -> KClass): KotlinPlayerHandlerProxyTrait = null!! +fun on_player_event(type: () -> KClass): KotlinPlayerHandlerProxyTrait = null!! +fun on_command(command: String, privileges: PrivilegeLevel): KotlinPlayerHandlerProxyTrait = null!! +fun on_button(button: Int): KotlinPlayerHandlerProxyTrait = null!! -fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { - null!! -} +fun start(callback: (World) -> Unit) = {} +fun stop(callback: (World) -> Unit) = {} -fun start(callback: (World) -> Unit) { - -} - -fun stop(callback: (World) -> Unit) { - -} From b2f0c7e4db7537f05816119695b08dde8eb18f92 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 25 Jun 2017 02:39:46 +0100 Subject: [PATCH 042/209] Add Kotlin port of the logout plugin --- game/src/plugins/logout/meta.toml | 1 + game/src/plugins/logout/src/logout.plugin.kts | 5 +++++ game/src/plugins/logout/test/LogoutTests.kt | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 game/src/plugins/logout/meta.toml create mode 100644 game/src/plugins/logout/src/logout.plugin.kts create mode 100644 game/src/plugins/logout/test/LogoutTests.kt diff --git a/game/src/plugins/logout/meta.toml b/game/src/plugins/logout/meta.toml new file mode 100644 index 000000000..574c74b36 --- /dev/null +++ b/game/src/plugins/logout/meta.toml @@ -0,0 +1 @@ +name = "logout" \ No newline at end of file diff --git a/game/src/plugins/logout/src/logout.plugin.kts b/game/src/plugins/logout/src/logout.plugin.kts new file mode 100644 index 000000000..e3bf59ef8 --- /dev/null +++ b/game/src/plugins/logout/src/logout.plugin.kts @@ -0,0 +1,5 @@ +val LOGOUT_BUTTON_ID = 2458 + +on_button(LOGOUT_BUTTON_ID) + .where { widgetId == LOGOUT_BUTTON_ID } + .then { it.logout() } \ No newline at end of file diff --git a/game/src/plugins/logout/test/LogoutTests.kt b/game/src/plugins/logout/test/LogoutTests.kt new file mode 100644 index 000000000..e974c135a --- /dev/null +++ b/game/src/plugins/logout/test/LogoutTests.kt @@ -0,0 +1,19 @@ +import org.apollo.game.message.impl.ButtonMessage +import org.apollo.game.plugin.testing.KotlinPluginTest +import org.junit.Test +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +class LogoutTests : KotlinPluginTest() { + + companion object { + const val LOGOUT_BUTTON_ID = 2458 + } + + @Test fun `The player should be logged out when they click the logout button`() { + player.notify(ButtonMessage(LOGOUT_BUTTON_ID)) + + verify(player, times(1)).logout() + } + +} \ No newline at end of file From 8dc10e80bf373c2b70baba3d015c8bed30b17615 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 25 Jun 2017 02:44:15 +0100 Subject: [PATCH 043/209] Add kotlin port of the emote-tab plugin --- game/src/plugins/emote-tab/meta.toml | 7 +++ .../emote-tab/src/emote-tab.plugin.kts | 50 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 game/src/plugins/emote-tab/meta.toml create mode 100644 game/src/plugins/emote-tab/src/emote-tab.plugin.kts diff --git a/game/src/plugins/emote-tab/meta.toml b/game/src/plugins/emote-tab/meta.toml new file mode 100644 index 000000000..8a4891c42 --- /dev/null +++ b/game/src/plugins/emote-tab/meta.toml @@ -0,0 +1,7 @@ +name = "emote-tab" +package = "org.apollo.game.plugin.widget" +authors = [ "Gary Tierney" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/emote-tab/src/emote-tab.plugin.kts b/game/src/plugins/emote-tab/src/emote-tab.plugin.kts new file mode 100644 index 000000000..b5b886293 --- /dev/null +++ b/game/src/plugins/emote-tab/src/emote-tab.plugin.kts @@ -0,0 +1,50 @@ +import org.apollo.game.message.impl.ButtonMessage +import org.apollo.game.model.Animation + +val ANGRY_EMOTE = Animation(859) +val BECKON_EMOTE = Animation(864) +val BLOW_KISS_EMOTE = Animation(1368) +val BOW_EMOTE = Animation(858) +val CHEER_EMOTE = Animation(862) +val CLAP_EMOTE = Animation(865) +val CLIMB_ROPE_EMOTE = Animation(1130) +val CRY_EMOTE = Animation(860) +val DANCE_EMOTE = Animation(866) +val GLASS_BOX_EMOTE = Animation(1131) +val GLASS_WALL_EMOTE = Animation(1128) +val GOBLIN_BOW_EMOTE = Animation(2127) +val GOBLIN_DANCE_EMOTE = Animation(2128) +val HEAD_BANG_EMOTE = Animation(2108) +val JIG_EMOTE = Animation(2106) +val JOY_JUMP_EMOTE = Animation(2109) +val LAUGH_EMOTE = Animation(861) +val LEAN_EMOTE = Animation(1129) +val NO_EMOTE = Animation(856) +val PANIC_EMOTE = Animation(2105) +val RASPBERRY_EMOTE = Animation(2110) +val SALUTE_EMOTE = Animation(2112) +val SHRUG_EMOTE = Animation(2113) +val SPIN_EMOTE = Animation(2107) +val THINKING_EMOTE = Animation(857) +val WAVE_EMOTE = Animation(863) +val YAWN_EMOTE = Animation(2111) +val YES_EMOTE = Animation(855) + +val EMOTE_MAP = mapOf( + 162 to THINKING_EMOTE, 6_503 to CLIMB_ROPE_EMOTE, 169 to NO_EMOTE, + 164 to BOW_EMOTE, 13_384 to GOBLIN_DANCE_EMOTE, 161 to CRY_EMOTE, + 170 to LAUGH_EMOTE, 171 to CHEER_EMOTE, 163 to WAVE_EMOTE, + 167 to BECKON_EMOTE, 3_362 to PANIC_EMOTE, 172 to CLAP_EMOTE, + 166 to DANCE_EMOTE, 13_363 to JIG_EMOTE, 13_364 to SPIN_EMOTE, + 13_365 to HEAD_BANG_EMOTE, 6_506 to LEAN_EMOTE, 165 to ANGRY_EMOTE, + 13_368 to YAWN_EMOTE, 13_366 to JOY_JUMP_EMOTE, 667 to GLASS_BOX_EMOTE, + 13_367 to RASPBERRY_EMOTE, 13_369 to SALUTE_EMOTE, 13_370 to SHRUG_EMOTE, + 11_100 to BLOW_KISS_EMOTE, 666 to GLASS_WALL_EMOTE, 168 to YES_EMOTE, + 13_383 to GOBLIN_BOW_EMOTE +) + +on { ButtonMessage::class } + .where { widgetId in EMOTE_MAP } + .then { + it.playAnimation(EMOTE_MAP[widgetId]) + } \ No newline at end of file From cb14c32b71e52406faa2e8cddd3270de8a58380d Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 25 Jun 2017 02:49:58 +0100 Subject: [PATCH 044/209] Add kotlin port of the walk/run toggle plugin --- game/src/plugins/run/meta.toml | 1 + game/src/plugins/run/src/run.plugin.kts | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 game/src/plugins/run/meta.toml create mode 100644 game/src/plugins/run/src/run.plugin.kts diff --git a/game/src/plugins/run/meta.toml b/game/src/plugins/run/meta.toml new file mode 100644 index 000000000..fd05752f8 --- /dev/null +++ b/game/src/plugins/run/meta.toml @@ -0,0 +1 @@ +name = "run" \ No newline at end of file diff --git a/game/src/plugins/run/src/run.plugin.kts b/game/src/plugins/run/src/run.plugin.kts new file mode 100644 index 000000000..00c6a4705 --- /dev/null +++ b/game/src/plugins/run/src/run.plugin.kts @@ -0,0 +1,10 @@ +import org.apollo.game.message.impl.ButtonMessage + +val WALK_BUTTON_ID = 152 +val RUN_BUTTON_ID = 153 + +on { ButtonMessage::class } + .where { widgetId == WALK_BUTTON_ID || widgetId == RUN_BUTTON_ID } + .then { + it.toggleRunning() + } \ No newline at end of file From b32b98eb86c69e5e21f52c0e811e85e4be3d088d Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 02:39:34 +0100 Subject: [PATCH 045/209] Share kotlin version config between buildSrc and project (#353) * Share kotlin version config between buildSrc and project * Use built-in Kotlin MessageCollector --- build.gradle | 4 +-- buildSrc/build.gradle | 4 +-- .../build/compile/KotlinScriptCompiler.kt | 35 +++++++------------ .../build/tasks/KotlinScriptCompileTask.kt | 10 ++++-- .../plugins/entity/spawn/src/spawn.plugin.kts | 2 +- properties.gradle | 3 ++ 6 files changed, 25 insertions(+), 33 deletions(-) create mode 100644 properties.gradle diff --git a/build.gradle b/build.gradle index f482903b9..333ae83c5 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,7 @@ allprojects { version = '0.0.1' } -ext { - kotlinVersion = '1.1.2-4' -} +apply from: 'properties.gradle' subprojects { apply plugin: 'java' diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index b559f2239..4a399fda5 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,9 +1,7 @@ apply plugin: 'kotlin' buildscript { - ext { - kotlinVersion = '1.1.2-4' - } + apply from: '../properties.gradle' repositories { mavenCentral() diff --git a/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt b/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt index 9384f16e0..eaebdeb8a 100644 --- a/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt +++ b/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt @@ -1,39 +1,28 @@ package org.apollo.build.compile import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.messages.* -import org.jetbrains.kotlin.cli.jvm.compiler.* +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot import org.jetbrains.kotlin.codegen.CompilationException import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer -import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.addKotlinSourceRoot import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate import java.io.File import java.lang.management.ManagementFactory import java.net.URISyntaxException import java.net.URLClassLoader -import java.nio.file.* +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardOpenOption import java.util.* -class KotlinMessageCollector : MessageCollector { - - override fun clear() { - } - - override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { - if (severity.isError) { - println("${location.path}:${location.line}-${location.column}: $message") - println(">>> ${location.lineContent}") - } - } - - override fun hasErrors(): Boolean { - return false - } - -} - data class KotlinCompilerResult(val fqName: String, val outputPath: Path) class KotlinScriptCompiler { @@ -87,7 +76,7 @@ class KotlinScriptCompiler { configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.map { JvmClasspathRoot(it) }) configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) - configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, KotlinMessageCollector()) + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) configuration.copy() return configuration diff --git a/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt b/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt index 373e64784..2e7cc5edf 100644 --- a/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt +++ b/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt @@ -1,11 +1,14 @@ package org.apollo.build.tasks -import org.apollo.build.compile.KotlinMessageCollector import org.apollo.build.compile.KotlinScriptCompiler import org.gradle.api.DefaultTask import org.gradle.api.file.FileCollection -import org.gradle.api.tasks.* +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.incremental.IncrementalTaskInputs +import org.jetbrains.kotlin.cli.common.messages.MessageRenderer +import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector import java.io.File open class KotlinScriptCompileTask : DefaultTask() { @@ -29,7 +32,8 @@ open class KotlinScriptCompileTask : DefaultTask() { } val classpath = compileClasspath!!.files - val compiler = KotlinScriptCompiler(scriptDefinitionClass!!, classpath, KotlinMessageCollector()) + val messageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, true); + val compiler = KotlinScriptCompiler(scriptDefinitionClass!!, classpath, messageCollector) inputs.outOfDate { removeBinariesFor(it.file) diff --git a/game/src/plugins/entity/spawn/src/spawn.plugin.kts b/game/src/plugins/entity/spawn/src/spawn.plugin.kts index cb65aacec..37625df2a 100644 --- a/game/src/plugins/entity/spawn/src/spawn.plugin.kts +++ b/game/src/plugins/entity/spawn/src/spawn.plugin.kts @@ -3,7 +3,7 @@ import org.apollo.game.model.entity.Npc start { world -> Spawns.list.forEach { - val definition = if (it.id != null) NpcDefinition.lookup(it.id) else lookup_npc(it.name) + val definition = if (it.id != null) NpcDefinition.lookup(it.id!!) else lookup_npc(it.name) if (definition == null) { throw IllegalArgumentException("Invalid NPC name or ID ${it.name}, ${it.id}") } diff --git a/properties.gradle b/properties.gradle new file mode 100644 index 000000000..e19e24a28 --- /dev/null +++ b/properties.gradle @@ -0,0 +1,3 @@ +ext { + kotlinVersion = '1.1.4-3' +} \ No newline at end of file From d323bcd69c8c9da411472b721462da809eb68dd3 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 03:04:20 +0100 Subject: [PATCH 046/209] Fix plugin test runner --- game/plugins.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/plugins.gradle b/game/plugins.gradle index 47a1f793a..c2ab058f7 100644 --- a/game/plugins.gradle +++ b/game/plugins.gradle @@ -85,7 +85,7 @@ def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSourc def testsTask = task("test${taskName}", type: Test) { group = "plugin-verification" - testClassesDir = testSources.output.classesDir + testClassesDirs = testSources.output.classesDirs classpath = testSources.runtimeClasspath + mainSources.runtimeClasspath binResultsDir = file("$buildDir/plugin-test-results/binary/$name") From 36282cf81e9ec777b3f272a4709286147cb733f9 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 18:49:06 +0100 Subject: [PATCH 047/209] Remove plugins.gradle and factor into common extension --- build.gradle | 1 + buildSrc/build.gradle | 1 + .../apollo/build/plugin/ApolloPlugin.groovy | 12 + .../build/plugin/ApolloPluginExtension.groovy | 101 +++++++++ .../KotlinCompilerConfigurationFactory.groovy | 61 +++++ .../plugin/compiler/KotlinScriptBinary.groovy | 13 ++ .../compiler/KotlinScriptCompiler.groovy | 75 +++++++ .../KotlinScriptCompilerException.groovy | 11 + .../tasks/ApolloScriptCompileTask.groovy | 59 +++++ .../build/compile/KotlinScriptCompiler.kt | 128 ----------- .../build/tasks/KotlinScriptCompileTask.kt | 58 ----- .../gradle-plugins/apollo-plugin.properties | 1 + game/build.gradle | 17 +- game/plugin-testing/build.gradle | 6 + .../game/plugin/testing/KotlinPluginTest.kt | 0 .../plugin/testing/KotlinPluginTestHelpers.kt | 0 .../testing/fakes/FakePluginContextFactory.kt | 0 .../testing/mockito/KotlinArgMatcher.kt | 0 .../mockito/KotlinMockitoExtensions.kt | 0 game/plugin/bank/build.gradle | 7 + game/{src/plugins => plugin}/bank/meta.toml | 0 .../bank/src/bank.plugin.kts | 0 .../bank/test/OpenBankTest.kt | 0 game/plugin/build.gradle | 74 ++++++ .../chat/private-messaging/build.gradle | 3 + .../chat/private-messaging/meta.toml | 0 .../private-messaging/src/friends.plugin.kts | 0 .../private-messaging/src/ignores.plugin.kts | 0 .../src/messaging.plugin.kts | 0 game/plugin/cmd/build.gradle | 13 ++ game/{src/plugins => plugin}/cmd/meta.toml | 0 .../cmd/src/animate-cmd.plugin.kts | 0 .../cmd/src/bank-cmd.plugin.kts | 0 .../cmd/src/item-cmd.plugin.kts | 0 .../cmd/src/lookup.plugin.kts | 0 .../cmd/src/messaging-cmd.plugin.kts | 0 .../cmd/src/punish-cmd.plugin.kts | 0 .../cmd/src/skill-cmd.plugin.kts | 0 .../cmd/src/spawn-cmd.plugin.kts | 0 .../cmd/src/teleport-cmd.plugin.kts | 0 game/plugin/consumables/build.gradle | 7 + .../plugins => plugin}/consumables/meta.toml | 0 .../consumables/src/consumables.kt | 0 .../consumables/src/consumables.plugin.kts | 0 .../consumables/src/drinks.plugin.kts | 0 .../consumables/src/foods.plugin.kts | 0 .../consumables/test/FoodOrDrinkTests.kt | 0 game/plugin/dummy/build.gradle | 7 + game/{src/plugins => plugin}/dummy/meta.toml | 0 .../dummy/src/dummy.plugin.kts | 0 .../dummy/test/TrainingDummyTest.kt | 0 game/plugin/emote-tab/build.gradle | 7 + .../plugins => plugin}/emote-tab/meta.toml | 0 .../emote-tab/src/emote-tab.plugin.kts | 0 game/plugin/entity/following/build.gradle | 12 + .../entity/following/meta.toml | 0 .../entity/following/src/following.kt | 0 .../entity/following/src/following.plugin.kts | 0 game/plugin/entity/player-action/build.gradle | 7 + .../entity/player-action/meta.toml | 0 .../entity/player-action/src/player_action.kt | 0 .../src/player_action.plugin.kts | 0 game/plugin/entity/spawn/build.gradle | 10 + .../plugins => plugin}/entity/spawn/meta.toml | 0 .../entity/spawn/src/spawn.kt | 0 .../entity/spawn/src/spawn.plugin.kts | 0 game/plugin/entity/walk-to/build.gradle | 7 + .../entity/walk-to/meta.toml | 0 .../entity/walk-to/src/walk_to.kt | 0 game/plugin/locations/al-kharid/build.gradle | 10 + .../locations/al-kharid/meta.toml | 0 .../al-kharid/src/al-kharid-npcs.plugin.kts | 0 game/plugin/locations/edgeville/build.gradle | 10 + .../locations/edgeville/meta.toml | 0 .../edgeville/src/edgeville-npcs.plugin.kts | 0 game/plugin/locations/falador/build.gradle | 10 + .../locations/falador/meta.toml | 0 .../falador/src/falador-npcs.plugin.kts | 0 game/plugin/locations/lumbridge/build.gradle | 10 + .../locations/lumbridge/meta.toml | 0 .../lumbridge/src/lumbridge-npcs.plugin.kts | 0 .../locations/tutorial-island/build.gradle | 10 + .../locations/tutorial-island/meta.toml | 0 .../src/tutorial-island-npcs.plugin.kts | 0 game/plugin/locations/varrock/build.gradle | 10 + .../locations/varrock/meta.toml | 0 .../varrock/src/varrock-npcs.plugin.kts | 0 game/plugin/logout/build.gradle | 3 + game/{src/plugins => plugin}/logout/meta.toml | 0 .../logout/src/logout.plugin.kts | 0 .../logout/test/LogoutTests.kt | 0 game/plugin/run/build.gradle | 3 + game/{src/plugins => plugin}/run/meta.toml | 0 .../plugins => plugin}/run/src/run.plugin.kts | 0 game/plugin/util/command/build.gradle | 4 + .../plugins => plugin}/util/command/meta.toml | 0 .../util/command/src/command.kt | 0 game/plugin/util/lookup/build.gradle | 4 + .../plugins => plugin}/util/lookup/meta.toml | 0 .../util/lookup/src/lookup.kt | 0 .../util/lookup/test/LookupTests.kt | 0 game/plugins.gradle | 210 ------------------ game/src/main/kotlin/stub.kt | 2 +- settings.gradle | 32 +++ 104 files changed, 608 insertions(+), 408 deletions(-) create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy delete mode 100644 buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt delete mode 100644 buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt create mode 100644 buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties create mode 100644 game/plugin-testing/build.gradle rename game/{src/pluginTesting => plugin-testing/src/test}/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt (100%) rename game/{src/pluginTesting => plugin-testing/src/test}/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt (100%) rename game/{src/pluginTesting => plugin-testing/src/test}/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt (100%) rename game/{src/pluginTesting => plugin-testing/src/test}/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt (100%) rename game/{src/pluginTesting => plugin-testing/src/test}/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt (100%) create mode 100644 game/plugin/bank/build.gradle rename game/{src/plugins => plugin}/bank/meta.toml (100%) rename game/{src/plugins => plugin}/bank/src/bank.plugin.kts (100%) rename game/{src/plugins => plugin}/bank/test/OpenBankTest.kt (100%) create mode 100644 game/plugin/build.gradle create mode 100644 game/plugin/chat/private-messaging/build.gradle rename game/{src/plugins => plugin}/chat/private-messaging/meta.toml (100%) rename game/{src/plugins => plugin}/chat/private-messaging/src/friends.plugin.kts (100%) rename game/{src/plugins => plugin}/chat/private-messaging/src/ignores.plugin.kts (100%) rename game/{src/plugins => plugin}/chat/private-messaging/src/messaging.plugin.kts (100%) create mode 100644 game/plugin/cmd/build.gradle rename game/{src/plugins => plugin}/cmd/meta.toml (100%) rename game/{src/plugins => plugin}/cmd/src/animate-cmd.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/bank-cmd.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/item-cmd.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/lookup.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/messaging-cmd.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/punish-cmd.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/skill-cmd.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/spawn-cmd.plugin.kts (100%) rename game/{src/plugins => plugin}/cmd/src/teleport-cmd.plugin.kts (100%) create mode 100644 game/plugin/consumables/build.gradle rename game/{src/plugins => plugin}/consumables/meta.toml (100%) rename game/{src/plugins => plugin}/consumables/src/consumables.kt (100%) rename game/{src/plugins => plugin}/consumables/src/consumables.plugin.kts (100%) rename game/{src/plugins => plugin}/consumables/src/drinks.plugin.kts (100%) rename game/{src/plugins => plugin}/consumables/src/foods.plugin.kts (100%) rename game/{src/plugins => plugin}/consumables/test/FoodOrDrinkTests.kt (100%) create mode 100644 game/plugin/dummy/build.gradle rename game/{src/plugins => plugin}/dummy/meta.toml (100%) rename game/{src/plugins => plugin}/dummy/src/dummy.plugin.kts (100%) rename game/{src/plugins => plugin}/dummy/test/TrainingDummyTest.kt (100%) create mode 100644 game/plugin/emote-tab/build.gradle rename game/{src/plugins => plugin}/emote-tab/meta.toml (100%) rename game/{src/plugins => plugin}/emote-tab/src/emote-tab.plugin.kts (100%) create mode 100644 game/plugin/entity/following/build.gradle rename game/{src/plugins => plugin}/entity/following/meta.toml (100%) rename game/{src/plugins => plugin}/entity/following/src/following.kt (100%) rename game/{src/plugins => plugin}/entity/following/src/following.plugin.kts (100%) create mode 100644 game/plugin/entity/player-action/build.gradle rename game/{src/plugins => plugin}/entity/player-action/meta.toml (100%) rename game/{src/plugins => plugin}/entity/player-action/src/player_action.kt (100%) rename game/{src/plugins => plugin}/entity/player-action/src/player_action.plugin.kts (100%) create mode 100644 game/plugin/entity/spawn/build.gradle rename game/{src/plugins => plugin}/entity/spawn/meta.toml (100%) rename game/{src/plugins => plugin}/entity/spawn/src/spawn.kt (100%) rename game/{src/plugins => plugin}/entity/spawn/src/spawn.plugin.kts (100%) create mode 100644 game/plugin/entity/walk-to/build.gradle rename game/{src/plugins => plugin}/entity/walk-to/meta.toml (100%) rename game/{src/plugins => plugin}/entity/walk-to/src/walk_to.kt (100%) create mode 100644 game/plugin/locations/al-kharid/build.gradle rename game/{src/plugins => plugin}/locations/al-kharid/meta.toml (100%) rename game/{src/plugins => plugin}/locations/al-kharid/src/al-kharid-npcs.plugin.kts (100%) create mode 100644 game/plugin/locations/edgeville/build.gradle rename game/{src/plugins => plugin}/locations/edgeville/meta.toml (100%) rename game/{src/plugins => plugin}/locations/edgeville/src/edgeville-npcs.plugin.kts (100%) create mode 100644 game/plugin/locations/falador/build.gradle rename game/{src/plugins => plugin}/locations/falador/meta.toml (100%) rename game/{src/plugins => plugin}/locations/falador/src/falador-npcs.plugin.kts (100%) create mode 100644 game/plugin/locations/lumbridge/build.gradle rename game/{src/plugins => plugin}/locations/lumbridge/meta.toml (100%) rename game/{src/plugins => plugin}/locations/lumbridge/src/lumbridge-npcs.plugin.kts (100%) create mode 100644 game/plugin/locations/tutorial-island/build.gradle rename game/{src/plugins => plugin}/locations/tutorial-island/meta.toml (100%) rename game/{src/plugins => plugin}/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts (100%) create mode 100644 game/plugin/locations/varrock/build.gradle rename game/{src/plugins => plugin}/locations/varrock/meta.toml (100%) rename game/{src/plugins => plugin}/locations/varrock/src/varrock-npcs.plugin.kts (100%) create mode 100644 game/plugin/logout/build.gradle rename game/{src/plugins => plugin}/logout/meta.toml (100%) rename game/{src/plugins => plugin}/logout/src/logout.plugin.kts (100%) rename game/{src/plugins => plugin}/logout/test/LogoutTests.kt (100%) create mode 100644 game/plugin/run/build.gradle rename game/{src/plugins => plugin}/run/meta.toml (100%) rename game/{src/plugins => plugin}/run/src/run.plugin.kts (100%) create mode 100644 game/plugin/util/command/build.gradle rename game/{src/plugins => plugin}/util/command/meta.toml (100%) rename game/{src/plugins => plugin}/util/command/src/command.kt (100%) create mode 100644 game/plugin/util/lookup/build.gradle rename game/{src/plugins => plugin}/util/lookup/meta.toml (100%) rename game/{src/plugins => plugin}/util/lookup/src/lookup.kt (100%) rename game/{src/plugins => plugin}/util/lookup/test/LookupTests.kt (100%) delete mode 100644 game/plugins.gradle diff --git a/build.gradle b/build.gradle index 333ae83c5..5ce4fad5e 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,7 @@ subprojects { repositories { mavenLocal() maven { url "https://repo.maven.apache.org/maven2" } + maven { url "https://dl.bintray.com/kotlin/kotlinx/" } } dependencies { diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 4a399fda5..fe67c4349 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'kotlin' +apply plugin: 'groovy' buildscript { apply from: '../properties.gradle' diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy new file mode 100644 index 000000000..e312c143b --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy @@ -0,0 +1,12 @@ +package org.apollo.build.plugin + +import org.gradle.api.Plugin +import org.gradle.api.Project + +class ApolloPlugin implements Plugin { + + @Override + void apply(Project project) { + project.extensions.create('apolloPlugin', ApolloPluginExtension, project) + } +} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy new file mode 100644 index 000000000..00743dcf7 --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -0,0 +1,101 @@ +package org.apollo.build.plugin + +import org.apollo.build.plugin.tasks.ApolloScriptCompileTask +import org.gradle.api.Project +import org.gradle.api.file.FileTree + +class ApolloPluginExtension { + private Project project + + /** + * The name of this plugin (defaults to the project name). + */ + String name + + /** + * The package that plugin scripts (.kts files) will be packaged under for this plugin. + */ + String packageName = "org.apollo.game.plugins" + + /** + * An optional description of this plugin. + */ + String description = "Empty description" + + /** + * A list of other {@link ApolloPlugin}s that this plugin depends on. + */ + List dependencies = [] + + /** + * A list of others who contributed to this plugin. + */ + List authors = [] + + /** + * The directory that library files and script files are found under. + */ + final String srcDir = "src/" + + /** + * The directory that tests are found under. + */ + final String testDir = "test/" + + ApolloPluginExtension(Project project) { + this.project = project + this.name = project.name + + init() + } + + /** + * Setup the {@link Project} with the correct dependencies and tasks required to build the plugin + * and its scripts. + */ + def init() { + def gameProject = project.findProject(":game") + def pluginTestingProject = project.findProject(':game:plugin-testing') + + project.plugins.apply('kotlin') + project.sourceSets { + main { + kotlin { + srcDir this.srcDir + exclude '*.kts' + } + } + + test { + kotlin { + srcDir this.testDir + } + } + } + + project.dependencies.add('compile', gameProject) + project.dependencies.add('testCompile', pluginTestingProject.sourceSets.test.output) + + dependencies.each { + project.dependencies.add('compile', project.findProject(":game:plugin:$it")) + } + + project.tasks.create('compileScripts', ApolloScriptCompileTask) { + def mainSources = project.sourceSets.main + def outputDir = mainSources.output.classesDir + + FileTree filtered = project.fileTree(srcDir).matching { + include '*.kts' + } + + inputs.files filtered.files + outputsDir = outputDir + + compileClasspath = mainSources.compileClasspath + + mainSources.runtimeClasspath + + scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript" + mustRunAfter project.tasks['classes'] + } + } +} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy new file mode 100644 index 000000000..2be6e28b6 --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy @@ -0,0 +1,61 @@ +package org.apollo.build.plugin.compiler + +import kotlin.jvm.JvmClassMappingKt +import kotlin.reflect.KClass +import kotlin.reflect.full.KClasses +import kotlin.reflect.jvm.internal.KClassImpl +import kotlin.script.templates.ScriptTemplateDefinition +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate + +import java.lang.management.ManagementFactory + +class KotlinCompilerConfigurationFactory { + + static CompilerConfiguration create(String scriptDefinitionClassName, Collection classpath, MessageCollector messageCollector) { + def parentClassLoader = (URLClassLoader) Thread.currentThread().contextClassLoader + if (parentClassLoader == null) { + throw new RuntimeException("Unable to find current classloader") + } + + URL[] classpathUrls = parentClassLoader.getURLs() + + for (classpathUrl in classpathUrls) { + try { + classpath.add(new File(classpathUrl.toURI())) + } catch (ex) { + throw new RuntimeException("URL returned by ClassLoader is invalid", ex) + } + + } + + def runtimeBean = ManagementFactory.getRuntimeMXBean() + if (!runtimeBean.bootClassPathSupported) { + println("Warning! Boot class path is not supported, must be supplied on the command line") + } else { + def bootClasspath = runtimeBean.bootClassPath + classpath.addAll(bootClasspath.split(File.pathSeparatorChar.toString()).collect { new File(it) }) + } + + + def classLoader = new URLClassLoader(classpath.collect { it.toURL() }.toArray(new URL[classpath.size()])) + def configuration = new CompilerConfiguration() + def scriptDefinitionClass = classLoader.loadClass(scriptDefinitionClassName) + def classpathFiles = classpath.collect { it } + + def scriptDefinition = new KotlinScriptDefinitionFromAnnotatedTemplate(JvmClassMappingKt.getKotlinClass(scriptDefinitionClass), + null, null, null, classpathFiles) + + configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.collect { new JvmClasspathRoot(it) }) + configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) + configuration.copy() + + return configuration + } +} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy new file mode 100644 index 000000000..e4df437d3 --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy @@ -0,0 +1,13 @@ +package org.apollo.build.plugin.compiler + +import java.nio.file.Path + +class KotlinScriptBinary { + final String fullyQualifiedName + final Path output + + KotlinScriptBinary(String fullyQualifiedName, Path output) { + this.output = output + this.fullyQualifiedName = fullyQualifiedName + } +} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy new file mode 100644 index 000000000..20f510d26 --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy @@ -0,0 +1,75 @@ +package org.apollo.build.plugin.compiler + +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler +import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.KotlinSourceRoot + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardOpenOption + +class KotlinScriptCompiler { + private String scriptDefinitionClass + private Collection classpath + private MessageCollector messageCollector + + KotlinScriptCompiler(String scriptDefinitionClass, Collection classpath, MessageCollector messageCollector) { + this.scriptDefinitionClass = scriptDefinitionClass + this.classpath = classpath + this.messageCollector = messageCollector + } + + KotlinScriptBinary compile(Path input, Path output) { + def compilerConfiguration = KotlinCompilerConfigurationFactory.create( + scriptDefinitionClass, + classpath, + messageCollector + ) + + def rootDisposable = Disposer.newDisposable() + def configuration = compilerConfiguration.copy() + + output.toFile().mkdirs() + + configuration.put(CommonConfigurationKeys.MODULE_NAME, input.toString()) + configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, new KotlinSourceRoot(input.toAbsolutePath().toString())) + + def configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES + def environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, configFiles) + + try { + def generationState = KotlinToJVMBytecodeCompiler.INSTANCE.analyzeAndGenerate(environment) + if (generationState == null) { + throw new KotlinScriptCompilerException("Failed to generate bytecode for kotlin script") + } + + def sourceFiles = environment.getSourceFiles() + def script = sourceFiles[0].script + if (script == null) { + throw new KotlinScriptCompilerException("Main source file is not a script") + } + + def scriptFilePath = script.fqName.asString().replace('.', '/') + ".class" + def scriptFileClass = generationState.factory.get(scriptFilePath) + + if (scriptFileClass == null) { + throw new KotlinScriptCompilerException("Unable to find compiled plugin class file $scriptFilePath") + } + + generationState.factory.asList().forEach { + Files.write(output.resolve(it.relativePath), it.asByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING) + } + + return new KotlinScriptBinary(script.fqName.asString(), output.resolve(scriptFileClass.relativePath)) + } catch (ex) { + throw new KotlinScriptCompilerException("Compilation failed", ex) + } finally { + Disposer.dispose(rootDisposable) + } + } +} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy new file mode 100644 index 000000000..ae899f487 --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy @@ -0,0 +1,11 @@ +package org.apollo.build.plugin.compiler + +class KotlinScriptCompilerException extends Exception { + KotlinScriptCompilerException(String message) { + super(message) + } + + KotlinScriptCompilerException(String message, Throwable cause) { + super(message, cause) + } +} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy new file mode 100644 index 000000000..2846531b9 --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy @@ -0,0 +1,59 @@ +package org.apollo.build.plugin.tasks + +import org.apollo.build.plugin.compiler.KotlinScriptCompiler +import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.incremental.IncrementalTaskInputs +import org.jetbrains.kotlin.cli.common.messages.MessageRenderer +import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector + +class ApolloScriptCompileTask extends DefaultTask { + File outputsDir + + @Input + FileCollection compileClasspath + + @Input + String scriptDefinitionClass + + @TaskAction + def execute(IncrementalTaskInputs inputs) { + if (scriptDefinitionClass == null) { + throw new Exception("No script definition class given") + } + + if (compileClasspath == null) { + throw new Exception("No compile classpath given") + } + + def classpath = compileClasspath.files + def messageCollector = new PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, true); + def compiler = new KotlinScriptCompiler(scriptDefinitionClass, classpath, messageCollector) + + inputs.outOfDate { + removeBinariesFor(it.file) + compiler.compile(it.file.toPath(), outputsDir.toPath()) + } + + inputs.removed { + removeBinariesFor(it.file) + } + } + + def removeBinariesFor(File file) { + def normalizedFilename = file.name.replace("[^A-Z_]", "_") + def normalizedPrefix = normalizedFilename.subSequence(0, normalizedFilename.lastIndexOf('.')) + + FileFilter filter = { + it.name.startsWith(normalizedPrefix) + } + + def binaries = outputsDir.listFiles FileFilter { dir, name -> name.startsWith(normalizedPrefix) } + + binaries.forEach { + it.delete() + } + } +} diff --git a/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt b/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt deleted file mode 100644 index eaebdeb8a..000000000 --- a/buildSrc/src/main/kotlin/org/apollo/build/compile/KotlinScriptCompiler.kt +++ /dev/null @@ -1,128 +0,0 @@ -package org.apollo.build.compile - -import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler -import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot -import org.jetbrains.kotlin.codegen.CompilationException -import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.addKotlinSourceRoot -import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate -import java.io.File -import java.lang.management.ManagementFactory -import java.net.URISyntaxException -import java.net.URLClassLoader -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption -import java.util.* - - -data class KotlinCompilerResult(val fqName: String, val outputPath: Path) - -class KotlinScriptCompiler { - - val classpath: List - val messageCollector: MessageCollector - val compilerConfiguration: CompilerConfiguration - - constructor(scriptDefinitionClassName: String, classpath: Collection, messageCollector: MessageCollector) { - this.classpath = classpath + currentClasspath() - this.messageCollector = messageCollector - this.compilerConfiguration = createCompilerConfiguration(scriptDefinitionClassName) - } - - companion object { - - fun currentClasspath(): List { - val classLoader = Thread.currentThread().contextClassLoader as? URLClassLoader ?: - throw RuntimeException("Unable to resolve classpath for current ClassLoader") - - val classpathUrls = classLoader.urLs - val classpath = ArrayList() - - for (classpathUrl in classpathUrls) { - try { - classpath.add(File(classpathUrl.toURI())) - } catch (e: URISyntaxException) { - throw RuntimeException("URL returned by ClassLoader is invalid") - } - - } - - val runtimeBean = ManagementFactory.getRuntimeMXBean() - if (!runtimeBean.isBootClassPathSupported) { - println("Warning! Boot class path is not supported, must be supplied on the command line") - } else { - val bootClasspath = runtimeBean.bootClassPath - classpath.addAll(bootClasspath.split(File.pathSeparatorChar).map { File(it) }) - } - - return classpath - } - } - - private fun createCompilerConfiguration(scriptDefinitionClassName: String): CompilerConfiguration { - val classLoader = URLClassLoader(classpath.map { it.toURL() }.toTypedArray()) - val configuration = CompilerConfiguration() - val scriptDefinitionClass = classLoader.loadClass(scriptDefinitionClassName) - val scriptDefinition = KotlinScriptDefinitionFromAnnotatedTemplate(scriptDefinitionClass.kotlin) - - configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) - configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.map { JvmClasspathRoot(it) }) - configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) - configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) - configuration.copy() - - return configuration - } - - @Throws(KotlinPluginCompilerException::class) - fun compile(inputPath: Path, outputPath: Path): KotlinCompilerResult { - val rootDisposable = Disposer.newDisposable() - val configuration = compilerConfiguration.copy() - - configuration.put(CommonConfigurationKeys.MODULE_NAME, inputPath.toString()) - configuration.addKotlinSourceRoot(inputPath.toAbsolutePath().toString()) - - val configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES - val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, configFiles) - - try { - val generationState = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(environment) - if (generationState == null) { - throw KotlinPluginCompilerException("Failed to generate bytecode for kotlin script") - } - - val sourceFiles = environment.getSourceFiles() - val script = sourceFiles[0].script ?: throw KotlinPluginCompilerException("Main script file isnt a script") - - val scriptFilePath = script.fqName.asString().replace('.', '/') + ".class" - val scriptFileClass = generationState.factory.get(scriptFilePath) - - if (scriptFileClass == null) { - throw KotlinPluginCompilerException("Unable to find compiled plugin class file $scriptFilePath") - } - - generationState.factory.asList().forEach { - Files.write(outputPath.resolve(it.relativePath), it.asByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING) - } - - return KotlinCompilerResult(script.fqName.asString(), outputPath.resolve(scriptFileClass.relativePath)) - } catch (e: CompilationException) { - throw KotlinPluginCompilerException("Compilation failed", e) - } finally { - Disposer.dispose(rootDisposable) - } - } - -} - -class KotlinPluginCompilerException(message: String, cause: Throwable? = null) : Exception(message, cause) { - -} diff --git a/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt b/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt deleted file mode 100644 index 2e7cc5edf..000000000 --- a/buildSrc/src/main/kotlin/org/apollo/build/tasks/KotlinScriptCompileTask.kt +++ /dev/null @@ -1,58 +0,0 @@ -package org.apollo.build.tasks - -import org.apollo.build.compile.KotlinScriptCompiler -import org.gradle.api.DefaultTask -import org.gradle.api.file.FileCollection -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.incremental.IncrementalTaskInputs -import org.jetbrains.kotlin.cli.common.messages.MessageRenderer -import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector -import java.io.File - -open class KotlinScriptCompileTask : DefaultTask() { - @OutputDirectory - var outputsDir: File? = null - - @Input - var compileClasspath: FileCollection? = null - - @Input - var scriptDefinitionClass: String? = null - - @TaskAction - fun execute(inputs: IncrementalTaskInputs) { - if (scriptDefinitionClass == null) { - throw Exception("No script definition class given") - } - - if (compileClasspath == null) { - throw Exception("No compile classpath given") - } - - val classpath = compileClasspath!!.files - val messageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, true); - val compiler = KotlinScriptCompiler(scriptDefinitionClass!!, classpath, messageCollector) - - inputs.outOfDate { - removeBinariesFor(it.file) - compiler.compile(it.file.toPath(), outputsDir!!.toPath()) - } - - inputs.removed { - removeBinariesFor(it.file) - } - } - - private fun removeBinariesFor(file: File) { - val normalizedFilename = file.name.replace("[^A-Z_]", "_") - val normalizedPrefix = normalizedFilename.subSequence(0, normalizedFilename.lastIndexOf('.')) - - val binaries = outputsDir!!.listFiles { dir, name -> name.startsWith(normalizedPrefix) } - - binaries.forEach { - it.delete() - } - } -} diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties new file mode 100644 index 000000000..5b546ceb9 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties @@ -0,0 +1 @@ +implementation-class=org.apollo.build.plugin.ApolloPlugin \ No newline at end of file diff --git a/game/build.gradle b/game/build.gradle index b4441d4a0..d1d4bab3d 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -6,15 +6,11 @@ buildscript { } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - classpath group: 'com.moandjiezana.toml', name: 'toml4j', version: '0.7.1' + classpath group: 'org.jetbrains.kotlin', name: 'kotlin-gradle-plugin', version: "$kotlinVersion" } } -ext.pluginsDir = "$projectDir/src/plugins" - apply plugin: 'kotlin' -apply from: 'plugins.gradle' sourceSets { main { @@ -24,12 +20,6 @@ sourceSets { } } -repositories { - maven { - url { 'https://dl.bintray.com/kotlin/kotlinx/' } - } -} - dependencies { compile project(':cache') compile project(':net') @@ -41,6 +31,11 @@ dependencies { compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-jdk8', version: '0.16' compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '0.16' + project(":game:plugin").subprojects.each { plugin -> + println(plugin) + runtime plugin + } + testCompile group: 'org.assertj', name: 'assertj-core', version: '3.8.0' } diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle new file mode 100644 index 000000000..2c0f85472 --- /dev/null +++ b/game/plugin-testing/build.gradle @@ -0,0 +1,6 @@ +apply plugin: 'kotlin' + + +dependencies { + compile project(':game') +} \ No newline at end of file diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt b/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt similarity index 100% rename from game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt rename to game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt b/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt similarity index 100% rename from game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt rename to game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt b/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt similarity index 100% rename from game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt rename to game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt b/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt similarity index 100% rename from game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt rename to game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt diff --git a/game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt b/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt similarity index 100% rename from game/src/pluginTesting/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt rename to game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt diff --git a/game/plugin/bank/build.gradle b/game/plugin/bank/build.gradle new file mode 100644 index 000000000..b128b5e02 --- /dev/null +++ b/game/plugin/bank/build.gradle @@ -0,0 +1,7 @@ +apolloPlugin { + name = "Banking" + packageName = "org.apollo.game.plugin.banking" + authors = [ + "Major", + ] +} \ No newline at end of file diff --git a/game/src/plugins/bank/meta.toml b/game/plugin/bank/meta.toml similarity index 100% rename from game/src/plugins/bank/meta.toml rename to game/plugin/bank/meta.toml diff --git a/game/src/plugins/bank/src/bank.plugin.kts b/game/plugin/bank/src/bank.plugin.kts similarity index 100% rename from game/src/plugins/bank/src/bank.plugin.kts rename to game/plugin/bank/src/bank.plugin.kts diff --git a/game/src/plugins/bank/test/OpenBankTest.kt b/game/plugin/bank/test/OpenBankTest.kt similarity index 100% rename from game/src/plugins/bank/test/OpenBankTest.kt rename to game/plugin/bank/test/OpenBankTest.kt diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle new file mode 100644 index 000000000..7635586be --- /dev/null +++ b/game/plugin/build.gradle @@ -0,0 +1,74 @@ +import com.moandjiezana.toml.Toml + +import java.nio.file.Paths + +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath group: 'com.moandjiezana.toml', name: 'toml4j', version: '0.7.1' + } +} + +subprojects { + if (it.buildFile.exists()) { + apply plugin: 'apollo-plugin' + + repositories { + mavenCentral() + maven { + url { 'https://dl.bintray.com/kotlin/kotlinx/' } + } + } + } +} + +task("convertPluginTomlToGradle") { + def pluginTree = fileTree(dir: "${project.rootDir}/game/src/plugins/") + def pluginDefinitions = pluginTree.matching { + include "**/*.toml" + } + + pluginDefinitions.each { file -> + def meta = new Toml() + meta.read(file.absoluteFile) + + def pluginFolder = Paths.get(file.parentFile.absolutePath) + def name = meta.getString("name", pluginFolder.getFileName().toString()) + def normalizedName = name.replaceAll("[^a-zA-Z0-9_]", '_').toLowerCase() + def description = meta.getString("description", "") + def packageName = meta.getString("package", "org.apollo.game.plugin") + def authors = meta.getList("authors", new ArrayList()) + def dependencies = meta.getList("dependencies", new ArrayList()) + + def buildFile = new File(pluginFolder.toFile(), 'build.gradle') + buildFile.withWriter('UTF-8') { writer -> + writer.write("apolloPlugin {\n") + writer.write(" name = \"$normalizedName\"\n") + + if (packageName != "org.apollo.game.plugin") { + writer.write(" packageName = \"$packageName\"\n") + } + + if (description.length() > 0) { + writer.write(" description = \"$description\"\n") + } + + if (authors.size > 0) { + writer.write(" authors = [\n") + authors.each { writer.write(" \"$it\",\n") } + writer.write(" ]\n") + } + + if (dependencies.size > 0) { + writer.write(" dependencies = [\n") + dependencies.each { writer.write(" \"$it\",\n") } + writer.write(" ]\n") + } + + writer.write("}") + } + } +} \ No newline at end of file diff --git a/game/plugin/chat/private-messaging/build.gradle b/game/plugin/chat/private-messaging/build.gradle new file mode 100644 index 000000000..f1f464072 --- /dev/null +++ b/game/plugin/chat/private-messaging/build.gradle @@ -0,0 +1,3 @@ +apolloPlugin { + name = "private-messaging" +} \ No newline at end of file diff --git a/game/src/plugins/chat/private-messaging/meta.toml b/game/plugin/chat/private-messaging/meta.toml similarity index 100% rename from game/src/plugins/chat/private-messaging/meta.toml rename to game/plugin/chat/private-messaging/meta.toml diff --git a/game/src/plugins/chat/private-messaging/src/friends.plugin.kts b/game/plugin/chat/private-messaging/src/friends.plugin.kts similarity index 100% rename from game/src/plugins/chat/private-messaging/src/friends.plugin.kts rename to game/plugin/chat/private-messaging/src/friends.plugin.kts diff --git a/game/src/plugins/chat/private-messaging/src/ignores.plugin.kts b/game/plugin/chat/private-messaging/src/ignores.plugin.kts similarity index 100% rename from game/src/plugins/chat/private-messaging/src/ignores.plugin.kts rename to game/plugin/chat/private-messaging/src/ignores.plugin.kts diff --git a/game/src/plugins/chat/private-messaging/src/messaging.plugin.kts b/game/plugin/chat/private-messaging/src/messaging.plugin.kts similarity index 100% rename from game/src/plugins/chat/private-messaging/src/messaging.plugin.kts rename to game/plugin/chat/private-messaging/src/messaging.plugin.kts diff --git a/game/plugin/cmd/build.gradle b/game/plugin/cmd/build.gradle new file mode 100644 index 000000000..ecb98912f --- /dev/null +++ b/game/plugin/cmd/build.gradle @@ -0,0 +1,13 @@ +apolloPlugin { + name = "Chat commands" + packageName = "org.apollo.game.plugin.cmd" + authors = [ + "Graham", + "Major", + "lare96", + "cubeee", + ] + dependencies = [ + "util:command", + ] +} \ No newline at end of file diff --git a/game/src/plugins/cmd/meta.toml b/game/plugin/cmd/meta.toml similarity index 100% rename from game/src/plugins/cmd/meta.toml rename to game/plugin/cmd/meta.toml diff --git a/game/src/plugins/cmd/src/animate-cmd.plugin.kts b/game/plugin/cmd/src/animate-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/animate-cmd.plugin.kts rename to game/plugin/cmd/src/animate-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/bank-cmd.plugin.kts b/game/plugin/cmd/src/bank-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/bank-cmd.plugin.kts rename to game/plugin/cmd/src/bank-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/item-cmd.plugin.kts b/game/plugin/cmd/src/item-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/item-cmd.plugin.kts rename to game/plugin/cmd/src/item-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/lookup.plugin.kts b/game/plugin/cmd/src/lookup.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/lookup.plugin.kts rename to game/plugin/cmd/src/lookup.plugin.kts diff --git a/game/src/plugins/cmd/src/messaging-cmd.plugin.kts b/game/plugin/cmd/src/messaging-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/messaging-cmd.plugin.kts rename to game/plugin/cmd/src/messaging-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/punish-cmd.plugin.kts b/game/plugin/cmd/src/punish-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/punish-cmd.plugin.kts rename to game/plugin/cmd/src/punish-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/skill-cmd.plugin.kts b/game/plugin/cmd/src/skill-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/skill-cmd.plugin.kts rename to game/plugin/cmd/src/skill-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/spawn-cmd.plugin.kts b/game/plugin/cmd/src/spawn-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/spawn-cmd.plugin.kts rename to game/plugin/cmd/src/spawn-cmd.plugin.kts diff --git a/game/src/plugins/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts similarity index 100% rename from game/src/plugins/cmd/src/teleport-cmd.plugin.kts rename to game/plugin/cmd/src/teleport-cmd.plugin.kts diff --git a/game/plugin/consumables/build.gradle b/game/plugin/consumables/build.gradle new file mode 100644 index 000000000..84c3ff795 --- /dev/null +++ b/game/plugin/consumables/build.gradle @@ -0,0 +1,7 @@ +apolloPlugin { + name = "consumables" + packageName = "org.apollo.game.plugin.consumables" + authors = [ + "Gary Tierney", + ] +} \ No newline at end of file diff --git a/game/src/plugins/consumables/meta.toml b/game/plugin/consumables/meta.toml similarity index 100% rename from game/src/plugins/consumables/meta.toml rename to game/plugin/consumables/meta.toml diff --git a/game/src/plugins/consumables/src/consumables.kt b/game/plugin/consumables/src/consumables.kt similarity index 100% rename from game/src/plugins/consumables/src/consumables.kt rename to game/plugin/consumables/src/consumables.kt diff --git a/game/src/plugins/consumables/src/consumables.plugin.kts b/game/plugin/consumables/src/consumables.plugin.kts similarity index 100% rename from game/src/plugins/consumables/src/consumables.plugin.kts rename to game/plugin/consumables/src/consumables.plugin.kts diff --git a/game/src/plugins/consumables/src/drinks.plugin.kts b/game/plugin/consumables/src/drinks.plugin.kts similarity index 100% rename from game/src/plugins/consumables/src/drinks.plugin.kts rename to game/plugin/consumables/src/drinks.plugin.kts diff --git a/game/src/plugins/consumables/src/foods.plugin.kts b/game/plugin/consumables/src/foods.plugin.kts similarity index 100% rename from game/src/plugins/consumables/src/foods.plugin.kts rename to game/plugin/consumables/src/foods.plugin.kts diff --git a/game/src/plugins/consumables/test/FoodOrDrinkTests.kt b/game/plugin/consumables/test/FoodOrDrinkTests.kt similarity index 100% rename from game/src/plugins/consumables/test/FoodOrDrinkTests.kt rename to game/plugin/consumables/test/FoodOrDrinkTests.kt diff --git a/game/plugin/dummy/build.gradle b/game/plugin/dummy/build.gradle new file mode 100644 index 000000000..c76482a9a --- /dev/null +++ b/game/plugin/dummy/build.gradle @@ -0,0 +1,7 @@ +apolloPlugin { + name = "training-dummy" + packageName = "org.apollo.game.plugin.entity" + authors = [ + "Gary Tierney", + ] +} \ No newline at end of file diff --git a/game/src/plugins/dummy/meta.toml b/game/plugin/dummy/meta.toml similarity index 100% rename from game/src/plugins/dummy/meta.toml rename to game/plugin/dummy/meta.toml diff --git a/game/src/plugins/dummy/src/dummy.plugin.kts b/game/plugin/dummy/src/dummy.plugin.kts similarity index 100% rename from game/src/plugins/dummy/src/dummy.plugin.kts rename to game/plugin/dummy/src/dummy.plugin.kts diff --git a/game/src/plugins/dummy/test/TrainingDummyTest.kt b/game/plugin/dummy/test/TrainingDummyTest.kt similarity index 100% rename from game/src/plugins/dummy/test/TrainingDummyTest.kt rename to game/plugin/dummy/test/TrainingDummyTest.kt diff --git a/game/plugin/emote-tab/build.gradle b/game/plugin/emote-tab/build.gradle new file mode 100644 index 000000000..64d546aab --- /dev/null +++ b/game/plugin/emote-tab/build.gradle @@ -0,0 +1,7 @@ +apolloPlugin { + name = "emote-tab" + packageName = "org.apollo.game.plugin.widget" + authors = [ + "Gary Tierney", + ] +} \ No newline at end of file diff --git a/game/src/plugins/emote-tab/meta.toml b/game/plugin/emote-tab/meta.toml similarity index 100% rename from game/src/plugins/emote-tab/meta.toml rename to game/plugin/emote-tab/meta.toml diff --git a/game/src/plugins/emote-tab/src/emote-tab.plugin.kts b/game/plugin/emote-tab/src/emote-tab.plugin.kts similarity index 100% rename from game/src/plugins/emote-tab/src/emote-tab.plugin.kts rename to game/plugin/emote-tab/src/emote-tab.plugin.kts diff --git a/game/plugin/entity/following/build.gradle b/game/plugin/entity/following/build.gradle new file mode 100644 index 000000000..cca1aa0ab --- /dev/null +++ b/game/plugin/entity/following/build.gradle @@ -0,0 +1,12 @@ +apolloPlugin { + name = "following" + packageName = "org.apollo.game.plugin.entity" + authors = [ + "Gary Tierney", + ] + dependencies = [ + "walkto", + "command_utilities", + "player_action", + ] +} \ No newline at end of file diff --git a/game/src/plugins/entity/following/meta.toml b/game/plugin/entity/following/meta.toml similarity index 100% rename from game/src/plugins/entity/following/meta.toml rename to game/plugin/entity/following/meta.toml diff --git a/game/src/plugins/entity/following/src/following.kt b/game/plugin/entity/following/src/following.kt similarity index 100% rename from game/src/plugins/entity/following/src/following.kt rename to game/plugin/entity/following/src/following.kt diff --git a/game/src/plugins/entity/following/src/following.plugin.kts b/game/plugin/entity/following/src/following.plugin.kts similarity index 100% rename from game/src/plugins/entity/following/src/following.plugin.kts rename to game/plugin/entity/following/src/following.plugin.kts diff --git a/game/plugin/entity/player-action/build.gradle b/game/plugin/entity/player-action/build.gradle new file mode 100644 index 000000000..c85b336d2 --- /dev/null +++ b/game/plugin/entity/player-action/build.gradle @@ -0,0 +1,7 @@ +apolloPlugin { + name = "player_action" + packageName = "org.apollo.game.plugin.entity" + authors = [ + "Gary Tierney", + ] +} \ No newline at end of file diff --git a/game/src/plugins/entity/player-action/meta.toml b/game/plugin/entity/player-action/meta.toml similarity index 100% rename from game/src/plugins/entity/player-action/meta.toml rename to game/plugin/entity/player-action/meta.toml diff --git a/game/src/plugins/entity/player-action/src/player_action.kt b/game/plugin/entity/player-action/src/player_action.kt similarity index 100% rename from game/src/plugins/entity/player-action/src/player_action.kt rename to game/plugin/entity/player-action/src/player_action.kt diff --git a/game/src/plugins/entity/player-action/src/player_action.plugin.kts b/game/plugin/entity/player-action/src/player_action.plugin.kts similarity index 100% rename from game/src/plugins/entity/player-action/src/player_action.plugin.kts rename to game/plugin/entity/player-action/src/player_action.plugin.kts diff --git a/game/plugin/entity/spawn/build.gradle b/game/plugin/entity/spawn/build.gradle new file mode 100644 index 000000000..48d810a70 --- /dev/null +++ b/game/plugin/entity/spawn/build.gradle @@ -0,0 +1,10 @@ +apolloPlugin { + name = "spawning" + packageName = "org.apollo.game.plugin.entity" + authors = [ + "Gary Tierney", + ] + dependencies = [ + "entity_lookup", + ] +} \ No newline at end of file diff --git a/game/src/plugins/entity/spawn/meta.toml b/game/plugin/entity/spawn/meta.toml similarity index 100% rename from game/src/plugins/entity/spawn/meta.toml rename to game/plugin/entity/spawn/meta.toml diff --git a/game/src/plugins/entity/spawn/src/spawn.kt b/game/plugin/entity/spawn/src/spawn.kt similarity index 100% rename from game/src/plugins/entity/spawn/src/spawn.kt rename to game/plugin/entity/spawn/src/spawn.kt diff --git a/game/src/plugins/entity/spawn/src/spawn.plugin.kts b/game/plugin/entity/spawn/src/spawn.plugin.kts similarity index 100% rename from game/src/plugins/entity/spawn/src/spawn.plugin.kts rename to game/plugin/entity/spawn/src/spawn.plugin.kts diff --git a/game/plugin/entity/walk-to/build.gradle b/game/plugin/entity/walk-to/build.gradle new file mode 100644 index 000000000..7102d6202 --- /dev/null +++ b/game/plugin/entity/walk-to/build.gradle @@ -0,0 +1,7 @@ +apolloPlugin { + name = "walkto" + packageName = "org.apollo.plugin.entity.walkto" + authors = [ + "Gary Tierney", + ] +} \ No newline at end of file diff --git a/game/src/plugins/entity/walk-to/meta.toml b/game/plugin/entity/walk-to/meta.toml similarity index 100% rename from game/src/plugins/entity/walk-to/meta.toml rename to game/plugin/entity/walk-to/meta.toml diff --git a/game/src/plugins/entity/walk-to/src/walk_to.kt b/game/plugin/entity/walk-to/src/walk_to.kt similarity index 100% rename from game/src/plugins/entity/walk-to/src/walk_to.kt rename to game/plugin/entity/walk-to/src/walk_to.kt diff --git a/game/plugin/locations/al-kharid/build.gradle b/game/plugin/locations/al-kharid/build.gradle new file mode 100644 index 000000000..64a4c5272 --- /dev/null +++ b/game/plugin/locations/al-kharid/build.gradle @@ -0,0 +1,10 @@ +apolloPlugin { + name = "al-kharid npc spawns" + packageName = "org.apollo.game.plugin.locations" + authors = [ + "Jesse W", + ] + dependencies = [ + "spawning", + ] +} \ No newline at end of file diff --git a/game/src/plugins/locations/al-kharid/meta.toml b/game/plugin/locations/al-kharid/meta.toml similarity index 100% rename from game/src/plugins/locations/al-kharid/meta.toml rename to game/plugin/locations/al-kharid/meta.toml diff --git a/game/src/plugins/locations/al-kharid/src/al-kharid-npcs.plugin.kts b/game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts similarity index 100% rename from game/src/plugins/locations/al-kharid/src/al-kharid-npcs.plugin.kts rename to game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts diff --git a/game/plugin/locations/edgeville/build.gradle b/game/plugin/locations/edgeville/build.gradle new file mode 100644 index 000000000..e7262e2f6 --- /dev/null +++ b/game/plugin/locations/edgeville/build.gradle @@ -0,0 +1,10 @@ +apolloPlugin { + name = "edgeville npc spawns" + packageName = "org.apollo.game.plugin.locations" + authors = [ + "Jesse W", + ] + dependencies = [ + "spawning", + ] +} \ No newline at end of file diff --git a/game/src/plugins/locations/edgeville/meta.toml b/game/plugin/locations/edgeville/meta.toml similarity index 100% rename from game/src/plugins/locations/edgeville/meta.toml rename to game/plugin/locations/edgeville/meta.toml diff --git a/game/src/plugins/locations/edgeville/src/edgeville-npcs.plugin.kts b/game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts similarity index 100% rename from game/src/plugins/locations/edgeville/src/edgeville-npcs.plugin.kts rename to game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts diff --git a/game/plugin/locations/falador/build.gradle b/game/plugin/locations/falador/build.gradle new file mode 100644 index 000000000..47f2171ea --- /dev/null +++ b/game/plugin/locations/falador/build.gradle @@ -0,0 +1,10 @@ +apolloPlugin { + name = "falador npc spawns" + packageName = "org.apollo.game.plugin.locations" + authors = [ + "Jesse W", + ] + dependencies = [ + "spawning", + ] +} \ No newline at end of file diff --git a/game/src/plugins/locations/falador/meta.toml b/game/plugin/locations/falador/meta.toml similarity index 100% rename from game/src/plugins/locations/falador/meta.toml rename to game/plugin/locations/falador/meta.toml diff --git a/game/src/plugins/locations/falador/src/falador-npcs.plugin.kts b/game/plugin/locations/falador/src/falador-npcs.plugin.kts similarity index 100% rename from game/src/plugins/locations/falador/src/falador-npcs.plugin.kts rename to game/plugin/locations/falador/src/falador-npcs.plugin.kts diff --git a/game/plugin/locations/lumbridge/build.gradle b/game/plugin/locations/lumbridge/build.gradle new file mode 100644 index 000000000..6a47562c3 --- /dev/null +++ b/game/plugin/locations/lumbridge/build.gradle @@ -0,0 +1,10 @@ +apolloPlugin { + name = "lumbridge npc spawns" + packageName = "org.apollo.game.plugin.locations" + authors = [ + "Gary Tierney", + ] + dependencies = [ + "spawning", + ] +} \ No newline at end of file diff --git a/game/src/plugins/locations/lumbridge/meta.toml b/game/plugin/locations/lumbridge/meta.toml similarity index 100% rename from game/src/plugins/locations/lumbridge/meta.toml rename to game/plugin/locations/lumbridge/meta.toml diff --git a/game/src/plugins/locations/lumbridge/src/lumbridge-npcs.plugin.kts b/game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts similarity index 100% rename from game/src/plugins/locations/lumbridge/src/lumbridge-npcs.plugin.kts rename to game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts diff --git a/game/plugin/locations/tutorial-island/build.gradle b/game/plugin/locations/tutorial-island/build.gradle new file mode 100644 index 000000000..0b184b507 --- /dev/null +++ b/game/plugin/locations/tutorial-island/build.gradle @@ -0,0 +1,10 @@ +apolloPlugin { + name = "tutorial island npc spawns" + packageName = "org.apollo.game.plugin.locations" + authors = [ + "Jesse W", + ] + dependencies = [ + "spawning", + ] +} \ No newline at end of file diff --git a/game/src/plugins/locations/tutorial-island/meta.toml b/game/plugin/locations/tutorial-island/meta.toml similarity index 100% rename from game/src/plugins/locations/tutorial-island/meta.toml rename to game/plugin/locations/tutorial-island/meta.toml diff --git a/game/src/plugins/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts b/game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts similarity index 100% rename from game/src/plugins/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts rename to game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts diff --git a/game/plugin/locations/varrock/build.gradle b/game/plugin/locations/varrock/build.gradle new file mode 100644 index 000000000..02061ca69 --- /dev/null +++ b/game/plugin/locations/varrock/build.gradle @@ -0,0 +1,10 @@ +apolloPlugin { + name = "varrock npc spawns" + packageName = "org.apollo.game.plugin.locations" + authors = [ + "Jesse W", + ] + dependencies = [ + "spawning", + ] +} \ No newline at end of file diff --git a/game/src/plugins/locations/varrock/meta.toml b/game/plugin/locations/varrock/meta.toml similarity index 100% rename from game/src/plugins/locations/varrock/meta.toml rename to game/plugin/locations/varrock/meta.toml diff --git a/game/src/plugins/locations/varrock/src/varrock-npcs.plugin.kts b/game/plugin/locations/varrock/src/varrock-npcs.plugin.kts similarity index 100% rename from game/src/plugins/locations/varrock/src/varrock-npcs.plugin.kts rename to game/plugin/locations/varrock/src/varrock-npcs.plugin.kts diff --git a/game/plugin/logout/build.gradle b/game/plugin/logout/build.gradle new file mode 100644 index 000000000..341b83a74 --- /dev/null +++ b/game/plugin/logout/build.gradle @@ -0,0 +1,3 @@ +apolloPlugin { + name = "logout" +} \ No newline at end of file diff --git a/game/src/plugins/logout/meta.toml b/game/plugin/logout/meta.toml similarity index 100% rename from game/src/plugins/logout/meta.toml rename to game/plugin/logout/meta.toml diff --git a/game/src/plugins/logout/src/logout.plugin.kts b/game/plugin/logout/src/logout.plugin.kts similarity index 100% rename from game/src/plugins/logout/src/logout.plugin.kts rename to game/plugin/logout/src/logout.plugin.kts diff --git a/game/src/plugins/logout/test/LogoutTests.kt b/game/plugin/logout/test/LogoutTests.kt similarity index 100% rename from game/src/plugins/logout/test/LogoutTests.kt rename to game/plugin/logout/test/LogoutTests.kt diff --git a/game/plugin/run/build.gradle b/game/plugin/run/build.gradle new file mode 100644 index 000000000..cb2a34086 --- /dev/null +++ b/game/plugin/run/build.gradle @@ -0,0 +1,3 @@ +apolloPlugin { + name = "run" +} \ No newline at end of file diff --git a/game/src/plugins/run/meta.toml b/game/plugin/run/meta.toml similarity index 100% rename from game/src/plugins/run/meta.toml rename to game/plugin/run/meta.toml diff --git a/game/src/plugins/run/src/run.plugin.kts b/game/plugin/run/src/run.plugin.kts similarity index 100% rename from game/src/plugins/run/src/run.plugin.kts rename to game/plugin/run/src/run.plugin.kts diff --git a/game/plugin/util/command/build.gradle b/game/plugin/util/command/build.gradle new file mode 100644 index 000000000..df15b2d00 --- /dev/null +++ b/game/plugin/util/command/build.gradle @@ -0,0 +1,4 @@ +apolloPlugin { + name = "command utilities" + packageName = "org.apollo.game.plugins.util" +} \ No newline at end of file diff --git a/game/src/plugins/util/command/meta.toml b/game/plugin/util/command/meta.toml similarity index 100% rename from game/src/plugins/util/command/meta.toml rename to game/plugin/util/command/meta.toml diff --git a/game/src/plugins/util/command/src/command.kt b/game/plugin/util/command/src/command.kt similarity index 100% rename from game/src/plugins/util/command/src/command.kt rename to game/plugin/util/command/src/command.kt diff --git a/game/plugin/util/lookup/build.gradle b/game/plugin/util/lookup/build.gradle new file mode 100644 index 000000000..613965248 --- /dev/null +++ b/game/plugin/util/lookup/build.gradle @@ -0,0 +1,4 @@ +apolloPlugin { + name = "entity lookup" + packageName = "org.apollo.game.plugins.util" +} \ No newline at end of file diff --git a/game/src/plugins/util/lookup/meta.toml b/game/plugin/util/lookup/meta.toml similarity index 100% rename from game/src/plugins/util/lookup/meta.toml rename to game/plugin/util/lookup/meta.toml diff --git a/game/src/plugins/util/lookup/src/lookup.kt b/game/plugin/util/lookup/src/lookup.kt similarity index 100% rename from game/src/plugins/util/lookup/src/lookup.kt rename to game/plugin/util/lookup/src/lookup.kt diff --git a/game/src/plugins/util/lookup/test/LookupTests.kt b/game/plugin/util/lookup/test/LookupTests.kt similarity index 100% rename from game/src/plugins/util/lookup/test/LookupTests.kt rename to game/plugin/util/lookup/test/LookupTests.kt diff --git a/game/plugins.gradle b/game/plugins.gradle deleted file mode 100644 index c2ab058f7..000000000 --- a/game/plugins.gradle +++ /dev/null @@ -1,210 +0,0 @@ -import com.moandjiezana.toml.Toml -import org.apollo.build.tasks.KotlinScriptCompileTask - -import java.nio.file.Paths - -def PLUGIN_VERIFICATION_GROUP = "plugin-verification" -def PLUGIN_BUILD_GROUP = "plugin-build" - -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath group: 'com.moandjiezana.toml', name: 'toml4j', version: '0.7.1' - } -} - -task testPlugins { - -} - -sourceSets { - pluginTesting { - kotlin { - srcDir 'src/pluginTesting/kotlin' - } - } -} - -dependencies { - pluginTestingCompile sourceSets.test.output - pluginTestingCompile sourceSets.test.compileClasspath -} - -check.dependsOn testPlugins - -class PluginBuildData { - PluginBuildData(String normalizedName, SourceSet mainSources, SourceSet testSources, - FileCollection scriptFiles, List dependencyNames) { - this.normalizedName = normalizedName - this.mainSources = mainSources - this.testSources = testSources - this.scriptFiles = scriptFiles - this.dependencyNames = dependencyNames - } - - String normalizedName - SourceSet mainSources - SourceSet testSources - FileCollection scriptFiles - List dependencyNames -} - -Map pluginMap = new HashMap<>() - -def configurePluginDependencies(SourceSet mainSources, SourceSet testSources, - List pluginDependencies) { - - def testConfiguration = testSources.compileConfigurationName - def mainConfiguration = mainSources.compileConfigurationName - - // Add this plugin as a runtime dependency to the main game project - dependencies.add(configurations.runtime.name, mainSources.output) - - pluginDependencies.each { - dependencies.add(mainConfiguration, it.mainSources.output) - dependencies.add(testConfiguration, it.testSources.output) - } - - dependencies.add(mainConfiguration, configurations.compile) - dependencies.add(mainConfiguration, sourceSets.main.output) - - dependencies.add(testConfiguration, mainSources.output) - dependencies.add(testConfiguration, configurations.testCompile) - dependencies.add(testConfiguration, sourceSets.test.output) - dependencies.add(testConfiguration, sourceSets.test.compileClasspath) - dependencies.add(testConfiguration, sourceSets.pluginTesting.output) -} - -def configurePluginTasks(String name, SourceSet mainSources, SourceSet testSources, - FileCollection scriptFiles, List pluginDependencies) { - def taskName = name.split("_").collect { it.capitalize() }.join("") - - def testsTask = task("test${taskName}", type: Test) { - group = "plugin-verification" - - testClassesDirs = testSources.output.classesDirs - classpath = testSources.runtimeClasspath + mainSources.runtimeClasspath - - binResultsDir = file("$buildDir/plugin-test-results/binary/$name") - - reports { - junitXml.destination = "$buildDir/plugin-tests/$name" - } - - testLogging { - events "passed", "skipped", "failed" - } - } - - testPlugins.dependsOn testsTask - - if (!scriptFiles.empty) { - def compileScriptsTask = task("compile${taskName}Scripts", type: KotlinScriptCompileTask) { - group = "plugin-compile" - - def outputDir = mainSources.output.classesDir - - inputs.files scriptFiles - outputsDir = outputDir - - compileClasspath = sourceSets.main.compileClasspath + - sourceSets.main.runtimeClasspath + - mainSources.compileClasspath + - mainSources.runtimeClasspath - - scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript" - mustRunAfter tasks[mainSources.classesTaskName] - } - - testPlugins.dependsOn compileScriptsTask - tasks[mainSources.classesTaskName].finalizedBy compileScriptsTask - } -} - -def pluginTree = fileTree(dir: "$pluginsDir") -def pluginDefinitions = pluginTree.matching { - include '**/meta.toml' -} - -class PluginScriptFile { - def scriptFileName - def pluginDir - - PluginScriptFile(scriptFileName, pluginDir) { - this.scriptFileName = scriptFileName - this.pluginDir = pluginDir - } -} - -def pluginFiles = new ArrayList() - -pluginDefinitions.each { file -> - def meta = new Toml() - meta.read(file.absoluteFile) - - def pluginFolder = Paths.get(file.parentFile.absolutePath) - def name = meta.getString("name", pluginFolder.getFileName().toString()) - def normalizedName = name.replaceAll("[^a-zA-Z0-9_]", '_').toLowerCase() - def displayNameArray = normalizedName.split("_").collect { it.capitalize() }.join("").toCharArray() - displayNameArray[0] = displayNameArray[0].toLowerCase() - - def sourceSetName = new String(displayNameArray) - - def packageName = meta.getString("package", "org.apollo.game.plugin") - def authors = meta.getList("authors", new ArrayList()) - def dependencies = meta.getList("dependencies", new ArrayList()) - - def scripts = fileTree(file.parentFile) { - include '**/*.plugin.kts' - exclude '*.kt' - } - - def srcsDir = meta.getString("config.src", "src/") - def testDir = meta.getString("config.test", "test/") - - def mainSources = sourceSets.create("${sourceSetName}Main") { - kotlin { - srcDir pluginFolder.resolve(srcsDir).toString() - exclude '*.kts' - } - } - - def testSources = sourceSets.create("${sourceSetName}Test") { - kotlin { - srcDir pluginFolder.resolve(testDir).toString() - } - } - - scripts.files.forEach { - def scriptFileName = it.getName() - - //@todo - also compare package - def existingFile = pluginFiles.find { it.scriptFileName == scriptFileName } - if (existingFile != null) { - throw new GradleException("Duplicate script file found named ${scriptFileName} in ${pluginFolder}, " + - "also exists in ${existingFile.pluginDir}") - } - - pluginFiles.add(new PluginScriptFile(scriptFileName, pluginFolder)) - } - - def pluginData = new PluginBuildData(normalizedName, mainSources, testSources, scripts, dependencies) - pluginMap.put(normalizedName, pluginData) -} - -pluginMap.values().each { - def dependencies = it.dependencyNames.collect { name -> pluginMap.get(name) } - - configurePluginDependencies(it.mainSources, it.testSources, dependencies) - configurePluginTasks(it.normalizedName, it.mainSources, it.testSources, it.scriptFiles, dependencies) -} - -task testPluginsReport(type: TestReport) { - destinationDir = file("$buildDir/reports/plugin-tests") - reportOn tasks.findAll { it.group.equals("plugin-verification"); } -} - -testPlugins.finalizedBy testPluginsReport \ No newline at end of file diff --git a/game/src/main/kotlin/stub.kt b/game/src/main/kotlin/stub.kt index 48dd599ab..c236c3a37 100644 --- a/game/src/main/kotlin/stub.kt +++ b/game/src/main/kotlin/stub.kt @@ -23,6 +23,6 @@ fun on_player_event(type: () -> KClass): KotlinPlayerHandle fun on_command(command: String, privileges: PrivilegeLevel): KotlinPlayerHandlerProxyTrait = null!! fun on_button(button: Int): KotlinPlayerHandlerProxyTrait = null!! -fun start(callback: (World) -> Unit) = {} +fun start(callback: (World) -> Unit) {} fun stop(callback: (World) -> Unit) = {} diff --git a/settings.gradle b/settings.gradle index 2bde76af5..8747757d5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,37 @@ +import java.nio.file.Paths +import java.nio.file.Path + rootProject.name = 'org.apollo' include ':cache' include ':game' +include ':game:plugin' +include ':game:plugin-testing' include ':net' include ':util' + +def pluginDirs = [ + rootProject.projectDir.toPath().resolve("game/plugin"), +] + +def processPluginDir(Path pluginDir) { + if (pluginDir.toFile().exists()) { + def pluginFileFinder = new FileNameFinder(); + def pluginFiles = pluginFileFinder.getFileNames(pluginDir.toString(), "**/*.gradle"); + + pluginFiles.each { filename -> + def path = Paths.get(filename) + def parentPath = path.parent + + if (parentPath == pluginDir) { + return + } + + def relativePath = pluginDir.relativize(parentPath) + def pluginName = relativePath.toString().replaceAll("/", ":") + + include ":game:plugin:$pluginName" + } + } +} + +pluginDirs.each { processPluginDir(it) } \ No newline at end of file From edcb72b4746f39d29e21aff95212a6168c9c0fad Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 20:40:17 +0100 Subject: [PATCH 048/209] Fix plugin test running with new gradle modules --- .gitignore | 1 + .../apollo/build/plugin/ApolloPlugin.groovy | 2 +- .../build/plugin/ApolloPluginExtension.groovy | 41 +++++++++--- .../tasks/ApolloScriptCompileTask.groovy | 8 +-- game/build.gradle | 1 - game/plugin-testing/build.gradle | 12 +++- .../game/plugin/testing/KotlinPluginTest.kt | 0 .../plugin/testing/KotlinPluginTestHelpers.kt | 0 .../testing/fakes/FakePluginContextFactory.kt | 0 .../testing/mockito/KotlinArgMatcher.kt | 0 .../mockito/KotlinMockitoExtensions.kt | 0 game/plugin/bank/build.gradle | 4 +- game/plugin/build.gradle | 62 ------------------- .../chat/private-messaging/build.gradle | 4 +- game/plugin/cmd/build.gradle | 4 +- game/plugin/consumables/build.gradle | 2 +- .../consumables/test/FoodOrDrinkTests.kt | 1 - game/plugin/dummy/build.gradle | 4 +- game/plugin/emote-tab/build.gradle | 4 +- game/plugin/entity/following/build.gradle | 8 +-- game/plugin/entity/player-action/build.gradle | 2 +- game/plugin/entity/spawn/build.gradle | 4 +- game/plugin/entity/walk-to/build.gradle | 2 +- game/plugin/locations/al-kharid/build.gradle | 6 +- game/plugin/locations/al-kharid/meta.toml | 2 +- game/plugin/locations/edgeville/build.gradle | 6 +- game/plugin/locations/edgeville/meta.toml | 2 +- game/plugin/locations/falador/build.gradle | 6 +- game/plugin/locations/falador/meta.toml | 2 +- game/plugin/locations/lumbridge/build.gradle | 6 +- game/plugin/locations/lumbridge/meta.toml | 2 +- .../locations/tutorial-island/build.gradle | 6 +- .../locations/tutorial-island/meta.toml | 2 +- game/plugin/locations/varrock/build.gradle | 6 +- game/plugin/locations/varrock/meta.toml | 2 +- game/plugin/logout/build.gradle | 2 +- game/plugin/run/build.gradle | 2 +- game/plugin/util/command/build.gradle | 4 +- game/plugin/util/lookup/build.gradle | 4 +- 39 files changed, 97 insertions(+), 129 deletions(-) rename game/plugin-testing/src/{test => main}/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt (100%) rename game/plugin-testing/src/{test => main}/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt (100%) rename game/plugin-testing/src/{test => main}/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt (100%) rename game/plugin-testing/src/{test => main}/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt (100%) rename game/plugin-testing/src/{test => main}/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt (100%) diff --git a/.gitignore b/.gitignore index 1b37aca00..8de8fb066 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ /lib/ */target/ */build/ +**/build/ \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy index e312c143b..f8f4459bb 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy @@ -7,6 +7,6 @@ class ApolloPlugin implements Plugin { @Override void apply(Project project) { - project.extensions.create('apolloPlugin', ApolloPluginExtension, project) + project.extensions.create('plugin', ApolloPluginExtension, project) } } diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy index 00743dcf7..67fa83445 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -3,9 +3,10 @@ package org.apollo.build.plugin import org.apollo.build.plugin.tasks.ApolloScriptCompileTask import org.gradle.api.Project import org.gradle.api.file.FileTree +import org.gradle.api.tasks.testing.Test class ApolloPluginExtension { - private Project project + final Project project /** * The name of this plugin (defaults to the project name). @@ -73,29 +74,49 @@ class ApolloPluginExtension { } } - project.dependencies.add('compile', gameProject) - project.dependencies.add('testCompile', pluginTestingProject.sourceSets.test.output) + def mainSources = project.sourceSets.main + def gameCompileConfiguration = gameProject.configurations.getByName("compile") + def gameSources = gameProject.sourceSets.main + def gameDependencies = gameCompileConfiguration.dependencies - dependencies.each { - project.dependencies.add('compile', project.findProject(":game:plugin:$it")) + gameDependencies.each { + project.dependencies.add('compile', it) } - project.tasks.create('compileScripts', ApolloScriptCompileTask) { - def mainSources = project.sourceSets.main - def outputDir = mainSources.output.classesDir + project.dependencies.add('compile', gameSources.output) + project.dependencies.add('testCompile', pluginTestingProject) + project.dependencies.add('testCompile', project.sourceSets.main.output) + + def kotlinCompileTask = project.tasks['compileKotlin'] + project.tasks.create('compileScripts', ApolloScriptCompileTask) { FileTree filtered = project.fileTree(srcDir).matching { include '*.kts' } inputs.files filtered.files - outputsDir = outputDir + outputsDir = new File("${project.buildDir}/classes/main") compileClasspath = mainSources.compileClasspath + mainSources.runtimeClasspath scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript" - mustRunAfter project.tasks['classes'] + mustRunAfter kotlinCompileTask } + + kotlinCompileTask.finalizedBy project.tasks['compileScripts'] + } + + def getDependencies() { + return dependencies } + + def setDependencies(List dependencies) { + dependencies.each { + project.dependencies.add('compile', project.findProject(":game:plugin:$it")) + } + + this.dependencies = dependencies + } + } diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy index 2846531b9..7189dc572 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector class ApolloScriptCompileTask extends DefaultTask { + @Input File outputsDir @Input @@ -47,12 +48,11 @@ class ApolloScriptCompileTask extends DefaultTask { def normalizedPrefix = normalizedFilename.subSequence(0, normalizedFilename.lastIndexOf('.')) FileFilter filter = { - it.name.startsWith(normalizedPrefix) + return it.name.startsWith(normalizedPrefix) } - def binaries = outputsDir.listFiles FileFilter { dir, name -> name.startsWith(normalizedPrefix) } - - binaries.forEach { + def binaries = outputsDir.listFiles(filter) + binaries.each { it.delete() } } diff --git a/game/build.gradle b/game/build.gradle index d1d4bab3d..cb8af5e78 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -32,7 +32,6 @@ dependencies { compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '0.16' project(":game:plugin").subprojects.each { plugin -> - println(plugin) runtime plugin } diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index 2c0f85472..534eabbf9 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -2,5 +2,15 @@ apply plugin: 'kotlin' dependencies { - compile project(':game') + def gameProject = project(':game') + + compile gameProject.sourceSets.main.output + compile group: 'org.assertj', name: 'assertj-core', version: '3.8.0' + + def gameTestConfiguration = gameProject.configurations.testCompileOnly + def gameTestDependencies = gameTestConfiguration.dependencies + + gameTestDependencies.each { + compile it + } } \ No newline at end of file diff --git a/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt similarity index 100% rename from game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt rename to game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt diff --git a/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt similarity index 100% rename from game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt rename to game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt diff --git a/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt similarity index 100% rename from game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt rename to game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt diff --git a/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt similarity index 100% rename from game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt rename to game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt diff --git a/game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt similarity index 100% rename from game/plugin-testing/src/test/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt rename to game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt diff --git a/game/plugin/bank/build.gradle b/game/plugin/bank/build.gradle index b128b5e02..ba8a32fae 100644 --- a/game/plugin/bank/build.gradle +++ b/game/plugin/bank/build.gradle @@ -1,5 +1,5 @@ -apolloPlugin { - name = "Banking" +plugin { + name = "banking" packageName = "org.apollo.game.plugin.banking" authors = [ "Major", diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index 7635586be..7cb4bb8df 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,17 +1,3 @@ -import com.moandjiezana.toml.Toml - -import java.nio.file.Paths - -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath group: 'com.moandjiezana.toml', name: 'toml4j', version: '0.7.1' - } -} - subprojects { if (it.buildFile.exists()) { apply plugin: 'apollo-plugin' @@ -24,51 +10,3 @@ subprojects { } } } - -task("convertPluginTomlToGradle") { - def pluginTree = fileTree(dir: "${project.rootDir}/game/src/plugins/") - def pluginDefinitions = pluginTree.matching { - include "**/*.toml" - } - - pluginDefinitions.each { file -> - def meta = new Toml() - meta.read(file.absoluteFile) - - def pluginFolder = Paths.get(file.parentFile.absolutePath) - def name = meta.getString("name", pluginFolder.getFileName().toString()) - def normalizedName = name.replaceAll("[^a-zA-Z0-9_]", '_').toLowerCase() - def description = meta.getString("description", "") - def packageName = meta.getString("package", "org.apollo.game.plugin") - def authors = meta.getList("authors", new ArrayList()) - def dependencies = meta.getList("dependencies", new ArrayList()) - - def buildFile = new File(pluginFolder.toFile(), 'build.gradle') - buildFile.withWriter('UTF-8') { writer -> - writer.write("apolloPlugin {\n") - writer.write(" name = \"$normalizedName\"\n") - - if (packageName != "org.apollo.game.plugin") { - writer.write(" packageName = \"$packageName\"\n") - } - - if (description.length() > 0) { - writer.write(" description = \"$description\"\n") - } - - if (authors.size > 0) { - writer.write(" authors = [\n") - authors.each { writer.write(" \"$it\",\n") } - writer.write(" ]\n") - } - - if (dependencies.size > 0) { - writer.write(" dependencies = [\n") - dependencies.each { writer.write(" \"$it\",\n") } - writer.write(" ]\n") - } - - writer.write("}") - } - } -} \ No newline at end of file diff --git a/game/plugin/chat/private-messaging/build.gradle b/game/plugin/chat/private-messaging/build.gradle index f1f464072..4bd4ef678 100644 --- a/game/plugin/chat/private-messaging/build.gradle +++ b/game/plugin/chat/private-messaging/build.gradle @@ -1,3 +1,3 @@ -apolloPlugin { - name = "private-messaging" +plugin { + name = "private_messaging" } \ No newline at end of file diff --git a/game/plugin/cmd/build.gradle b/game/plugin/cmd/build.gradle index ecb98912f..d7520c630 100644 --- a/game/plugin/cmd/build.gradle +++ b/game/plugin/cmd/build.gradle @@ -1,5 +1,5 @@ -apolloPlugin { - name = "Chat commands" +plugin { + name = "chat_commands" packageName = "org.apollo.game.plugin.cmd" authors = [ "Graham", diff --git a/game/plugin/consumables/build.gradle b/game/plugin/consumables/build.gradle index 84c3ff795..97834d7fc 100644 --- a/game/plugin/consumables/build.gradle +++ b/game/plugin/consumables/build.gradle @@ -1,4 +1,4 @@ -apolloPlugin { +plugin { name = "consumables" packageName = "org.apollo.game.plugin.consumables" authors = [ diff --git a/game/plugin/consumables/test/FoodOrDrinkTests.kt b/game/plugin/consumables/test/FoodOrDrinkTests.kt index 1394e64b2..45457925e 100644 --- a/game/plugin/consumables/test/FoodOrDrinkTests.kt +++ b/game/plugin/consumables/test/FoodOrDrinkTests.kt @@ -4,7 +4,6 @@ import org.apollo.game.message.impl.ItemOptionMessage import org.apollo.game.model.entity.Skill import org.apollo.game.plugin.testing.KotlinPluginTest import org.apollo.game.plugin.testing.mockito.KotlinMockitoExtensions.matches -import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.mockito.Mockito.never diff --git a/game/plugin/dummy/build.gradle b/game/plugin/dummy/build.gradle index c76482a9a..23142dcad 100644 --- a/game/plugin/dummy/build.gradle +++ b/game/plugin/dummy/build.gradle @@ -1,5 +1,5 @@ -apolloPlugin { - name = "training-dummy" +plugin { + name = "training_dummy" packageName = "org.apollo.game.plugin.entity" authors = [ "Gary Tierney", diff --git a/game/plugin/emote-tab/build.gradle b/game/plugin/emote-tab/build.gradle index 64d546aab..d54c23e57 100644 --- a/game/plugin/emote-tab/build.gradle +++ b/game/plugin/emote-tab/build.gradle @@ -1,5 +1,5 @@ -apolloPlugin { - name = "emote-tab" +plugin { + name = "emote_tab" packageName = "org.apollo.game.plugin.widget" authors = [ "Gary Tierney", diff --git a/game/plugin/entity/following/build.gradle b/game/plugin/entity/following/build.gradle index cca1aa0ab..da73a832f 100644 --- a/game/plugin/entity/following/build.gradle +++ b/game/plugin/entity/following/build.gradle @@ -1,12 +1,12 @@ -apolloPlugin { +plugin { name = "following" packageName = "org.apollo.game.plugin.entity" authors = [ "Gary Tierney", ] dependencies = [ - "walkto", - "command_utilities", - "player_action", + "entity:walk-to", + "util:command", + "entity:player-action", ] } \ No newline at end of file diff --git a/game/plugin/entity/player-action/build.gradle b/game/plugin/entity/player-action/build.gradle index c85b336d2..264d895f3 100644 --- a/game/plugin/entity/player-action/build.gradle +++ b/game/plugin/entity/player-action/build.gradle @@ -1,4 +1,4 @@ -apolloPlugin { +plugin { name = "player_action" packageName = "org.apollo.game.plugin.entity" authors = [ diff --git a/game/plugin/entity/spawn/build.gradle b/game/plugin/entity/spawn/build.gradle index 48d810a70..e417db46d 100644 --- a/game/plugin/entity/spawn/build.gradle +++ b/game/plugin/entity/spawn/build.gradle @@ -1,10 +1,10 @@ -apolloPlugin { +plugin { name = "spawning" packageName = "org.apollo.game.plugin.entity" authors = [ "Gary Tierney", ] dependencies = [ - "entity_lookup", + "util:lookup", ] } \ No newline at end of file diff --git a/game/plugin/entity/walk-to/build.gradle b/game/plugin/entity/walk-to/build.gradle index 7102d6202..4f14b86f0 100644 --- a/game/plugin/entity/walk-to/build.gradle +++ b/game/plugin/entity/walk-to/build.gradle @@ -1,4 +1,4 @@ -apolloPlugin { +plugin { name = "walkto" packageName = "org.apollo.plugin.entity.walkto" authors = [ diff --git a/game/plugin/locations/al-kharid/build.gradle b/game/plugin/locations/al-kharid/build.gradle index 64a4c5272..8eb8ee02b 100644 --- a/game/plugin/locations/al-kharid/build.gradle +++ b/game/plugin/locations/al-kharid/build.gradle @@ -1,10 +1,10 @@ -apolloPlugin { - name = "al-kharid npc spawns" +plugin { + name = "al_kharid_npc_spawns" packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] dependencies = [ - "spawning", + "entity:spawn", ] } \ No newline at end of file diff --git a/game/plugin/locations/al-kharid/meta.toml b/game/plugin/locations/al-kharid/meta.toml index 4e0d3dc68..8c1835929 100644 --- a/game/plugin/locations/al-kharid/meta.toml +++ b/game/plugin/locations/al-kharid/meta.toml @@ -1,7 +1,7 @@ name = "al-kharid npc spawns" package = "org.apollo.game.plugin.locations" authors = [ "Jesse W" ] -dependencies = [ "spawning" ] +dependencies = [ "entity:spawn" ] [config] srcDir = "src/" diff --git a/game/plugin/locations/edgeville/build.gradle b/game/plugin/locations/edgeville/build.gradle index e7262e2f6..663066a87 100644 --- a/game/plugin/locations/edgeville/build.gradle +++ b/game/plugin/locations/edgeville/build.gradle @@ -1,10 +1,10 @@ -apolloPlugin { - name = "edgeville npc spawns" +plugin { + name = "edgeville_npc_spawns" packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] dependencies = [ - "spawning", + "entity:spawn", ] } \ No newline at end of file diff --git a/game/plugin/locations/edgeville/meta.toml b/game/plugin/locations/edgeville/meta.toml index 01a8dc336..469f40714 100644 --- a/game/plugin/locations/edgeville/meta.toml +++ b/game/plugin/locations/edgeville/meta.toml @@ -1,7 +1,7 @@ name = "edgeville npc spawns" package = "org.apollo.game.plugin.locations" authors = [ "Jesse W" ] -dependencies = [ "spawning" ] +dependencies = [ "entity:spawn" ] [config] srcDir = "src/" diff --git a/game/plugin/locations/falador/build.gradle b/game/plugin/locations/falador/build.gradle index 47f2171ea..ffff3f044 100644 --- a/game/plugin/locations/falador/build.gradle +++ b/game/plugin/locations/falador/build.gradle @@ -1,10 +1,10 @@ -apolloPlugin { - name = "falador npc spawns" +plugin { + name = "falador_npc_spawns" packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] dependencies = [ - "spawning", + "entity:spawn", ] } \ No newline at end of file diff --git a/game/plugin/locations/falador/meta.toml b/game/plugin/locations/falador/meta.toml index 6ba11a574..49c9aa26a 100644 --- a/game/plugin/locations/falador/meta.toml +++ b/game/plugin/locations/falador/meta.toml @@ -1,7 +1,7 @@ name = "falador npc spawns" package = "org.apollo.game.plugin.locations" authors = [ "Jesse W" ] -dependencies = [ "spawning" ] +dependencies = [ "entity:spawn" ] [config] srcDir = "src/" diff --git a/game/plugin/locations/lumbridge/build.gradle b/game/plugin/locations/lumbridge/build.gradle index 6a47562c3..a85c254ad 100644 --- a/game/plugin/locations/lumbridge/build.gradle +++ b/game/plugin/locations/lumbridge/build.gradle @@ -1,10 +1,10 @@ -apolloPlugin { - name = "lumbridge npc spawns" +plugin { + name = "lumbridge_npc_spawns" packageName = "org.apollo.game.plugin.locations" authors = [ "Gary Tierney", ] dependencies = [ - "spawning", + "entity:spawn", ] } \ No newline at end of file diff --git a/game/plugin/locations/lumbridge/meta.toml b/game/plugin/locations/lumbridge/meta.toml index 17ab1025b..098197b37 100644 --- a/game/plugin/locations/lumbridge/meta.toml +++ b/game/plugin/locations/lumbridge/meta.toml @@ -1,7 +1,7 @@ name = "lumbridge npc spawns" package = "org.apollo.game.plugin.locations" authors = [ "Gary Tierney" ] -dependencies = [ "spawning" ] +dependencies = [ "entity:spawn" ] [config] srcDir = "src/" diff --git a/game/plugin/locations/tutorial-island/build.gradle b/game/plugin/locations/tutorial-island/build.gradle index 0b184b507..44c5e1a51 100644 --- a/game/plugin/locations/tutorial-island/build.gradle +++ b/game/plugin/locations/tutorial-island/build.gradle @@ -1,10 +1,10 @@ -apolloPlugin { - name = "tutorial island npc spawns" +plugin { + name = "tutorial_island_npc_spawns" packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] dependencies = [ - "spawning", + "entity:spawn", ] } \ No newline at end of file diff --git a/game/plugin/locations/tutorial-island/meta.toml b/game/plugin/locations/tutorial-island/meta.toml index 837b3c9ac..eff5223f0 100644 --- a/game/plugin/locations/tutorial-island/meta.toml +++ b/game/plugin/locations/tutorial-island/meta.toml @@ -1,7 +1,7 @@ name = "tutorial island npc spawns" package = "org.apollo.game.plugin.locations" authors = [ "Jesse W" ] -dependencies = [ "spawning" ] +dependencies = [ "entity:spawn" ] [config] srcDir = "src/" diff --git a/game/plugin/locations/varrock/build.gradle b/game/plugin/locations/varrock/build.gradle index 02061ca69..54a1418cc 100644 --- a/game/plugin/locations/varrock/build.gradle +++ b/game/plugin/locations/varrock/build.gradle @@ -1,10 +1,10 @@ -apolloPlugin { - name = "varrock npc spawns" +plugin { + name = "varrock_npc_spawns" packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] dependencies = [ - "spawning", + "entity:spawn", ] } \ No newline at end of file diff --git a/game/plugin/locations/varrock/meta.toml b/game/plugin/locations/varrock/meta.toml index d56f16d58..1a8b3d577 100644 --- a/game/plugin/locations/varrock/meta.toml +++ b/game/plugin/locations/varrock/meta.toml @@ -1,7 +1,7 @@ name = "varrock npc spawns" package = "org.apollo.game.plugin.locations" authors = [ "Jesse W" ] -dependencies = [ "spawning" ] +dependencies = [ "entity:spawn" ] [config] srcDir = "src/" diff --git a/game/plugin/logout/build.gradle b/game/plugin/logout/build.gradle index 341b83a74..ae0395e62 100644 --- a/game/plugin/logout/build.gradle +++ b/game/plugin/logout/build.gradle @@ -1,3 +1,3 @@ -apolloPlugin { +plugin { name = "logout" } \ No newline at end of file diff --git a/game/plugin/run/build.gradle b/game/plugin/run/build.gradle index cb2a34086..1e335cc47 100644 --- a/game/plugin/run/build.gradle +++ b/game/plugin/run/build.gradle @@ -1,3 +1,3 @@ -apolloPlugin { +plugin { name = "run" } \ No newline at end of file diff --git a/game/plugin/util/command/build.gradle b/game/plugin/util/command/build.gradle index df15b2d00..58e59401e 100644 --- a/game/plugin/util/command/build.gradle +++ b/game/plugin/util/command/build.gradle @@ -1,4 +1,4 @@ -apolloPlugin { - name = "command utilities" +plugin { + name = "command_utilities" packageName = "org.apollo.game.plugins.util" } \ No newline at end of file diff --git a/game/plugin/util/lookup/build.gradle b/game/plugin/util/lookup/build.gradle index 613965248..e910e2fad 100644 --- a/game/plugin/util/lookup/build.gradle +++ b/game/plugin/util/lookup/build.gradle @@ -1,4 +1,4 @@ -apolloPlugin { - name = "entity lookup" +plugin { + name = "entity_lookup" packageName = "org.apollo.game.plugins.util" } \ No newline at end of file From b4d951c7cc04e5a2b91396c5038aca8a4baaf347 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 21:49:45 +0100 Subject: [PATCH 049/209] Fix incremental script compilation --- .../build/plugin/ApolloPluginExtension.groovy | 49 +++++++++++-------- .../tasks/ApolloScriptCompileTask.groovy | 3 +- game/plugin-testing/build.gradle | 7 +-- .../consumables/test/FoodOrDrinkTests.kt | 1 + 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy index 67fa83445..5771aac5e 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -2,6 +2,7 @@ package org.apollo.build.plugin import org.apollo.build.plugin.tasks.ApolloScriptCompileTask import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.file.FileTree import org.gradle.api.tasks.testing.Test @@ -50,6 +51,21 @@ class ApolloPluginExtension { init() } + private def addDependencyOn(Project other, String configuration, boolean includeProject) { + def compileConfiguration = other.configurations.getByName("compile") + def sources = other.sourceSets.main + def deps = compileConfiguration.dependencies + + deps.each { + project.dependencies.add(configuration, it) + } + + project.dependencies.add(configuration, sources.output) + if (includeProject) { + project.dependencies.add(configuration, other) + } + } + /** * Setup the {@link Project} with the correct dependencies and tasks required to build the plugin * and its scripts. @@ -75,36 +91,29 @@ class ApolloPluginExtension { } def mainSources = project.sourceSets.main - def gameCompileConfiguration = gameProject.configurations.getByName("compile") - def gameSources = gameProject.sourceSets.main - def gameDependencies = gameCompileConfiguration.dependencies - gameDependencies.each { - project.dependencies.add('compile', it) - } + addDependencyOn(gameProject, "compile", false) + addDependencyOn(pluginTestingProject, "testCompile", true) - project.dependencies.add('compile', gameSources.output) - project.dependencies.add('testCompile', pluginTestingProject) - project.dependencies.add('testCompile', project.sourceSets.main.output) + def buildTask = project.tasks['classes'] - def kotlinCompileTask = project.tasks['compileKotlin'] + FileTree scripts = project.fileTree(srcDir).matching { + include '*.kts' + } project.tasks.create('compileScripts', ApolloScriptCompileTask) { - FileTree filtered = project.fileTree(srcDir).matching { - include '*.kts' - } + def outputDir = new File("${project.buildDir}/classes/main") - inputs.files filtered.files - outputsDir = new File("${project.buildDir}/classes/main") - - compileClasspath = mainSources.compileClasspath + - mainSources.runtimeClasspath + inputs.files scripts.files + outputsDir = outputDir + compileClasspath = mainSources.compileClasspath + mainSources.runtimeClasspath + mainSources.output scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript" - mustRunAfter kotlinCompileTask + + mustRunAfter buildTask } - kotlinCompileTask.finalizedBy project.tasks['compileScripts'] + buildTask.finalizedBy(project.tasks['compileScripts']) } def getDependencies() { diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy index 7189dc572..0092fa060 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy @@ -4,13 +4,14 @@ import org.apollo.build.plugin.compiler.KotlinScriptCompiler import org.gradle.api.DefaultTask import org.gradle.api.file.FileCollection import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector class ApolloScriptCompileTask extends DefaultTask { - @Input + @OutputDirectory File outputsDir @Input diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index 534eabbf9..b9735b373 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -1,13 +1,10 @@ apply plugin: 'kotlin' - dependencies { - def gameProject = project(':game') - - compile gameProject.sourceSets.main.output + compileOnly project(':game') compile group: 'org.assertj', name: 'assertj-core', version: '3.8.0' - def gameTestConfiguration = gameProject.configurations.testCompileOnly + def gameTestConfiguration = project(':game').configurations.testCompile def gameTestDependencies = gameTestConfiguration.dependencies gameTestDependencies.each { diff --git a/game/plugin/consumables/test/FoodOrDrinkTests.kt b/game/plugin/consumables/test/FoodOrDrinkTests.kt index 45457925e..1394e64b2 100644 --- a/game/plugin/consumables/test/FoodOrDrinkTests.kt +++ b/game/plugin/consumables/test/FoodOrDrinkTests.kt @@ -4,6 +4,7 @@ import org.apollo.game.message.impl.ItemOptionMessage import org.apollo.game.model.entity.Skill import org.apollo.game.plugin.testing.KotlinPluginTest import org.apollo.game.plugin.testing.mockito.KotlinMockitoExtensions.matches +import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.mockito.Mockito.never From a60cc82650abc4b3d33c370a92566936522c1032 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 21:54:57 +0100 Subject: [PATCH 050/209] Use main sourcset output dir for scripts --- .../groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy index 5771aac5e..796534cc3 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -102,7 +102,7 @@ class ApolloPluginExtension { } project.tasks.create('compileScripts', ApolloScriptCompileTask) { - def outputDir = new File("${project.buildDir}/classes/main") + def outputDir = mainSources.output.classesDir inputs.files scripts.files outputsDir = outputDir From 68710cae4766c3ce99f7608664257924897db2cf Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 22:13:12 +0100 Subject: [PATCH 051/209] Use File.separator in settings.gradle --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 8747757d5..39b150434 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,7 +27,7 @@ def processPluginDir(Path pluginDir) { } def relativePath = pluginDir.relativize(parentPath) - def pluginName = relativePath.toString().replaceAll("/", ":") + def pluginName = relativePath.toString().replaceAll(File.separator, ":") include ":game:plugin:$pluginName" } From f23114d511ab152e2f3040c5840908001f81100a Mon Sep 17 00:00:00 2001 From: Major- Date: Sat, 16 Sep 2017 23:11:22 +0100 Subject: [PATCH 052/209] Fix plugin processing on windows --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 39b150434..25f8e47f0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,7 +27,7 @@ def processPluginDir(Path pluginDir) { } def relativePath = pluginDir.relativize(parentPath) - def pluginName = relativePath.toString().replaceAll(File.separator, ":") + def pluginName = relativePath.toString().replace(File.separator, ":") include ":game:plugin:$pluginName" } From 445c4712832dccbb13ce976dca2e115df61aeeb8 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 17 Sep 2017 03:11:00 +0100 Subject: [PATCH 053/209] Add kotlin to .editorconfig Uses the recommended conventions. --- .editorconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 69f4250be..4430bd40f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,10 @@ insert_final_newline = false indent_style=tab tab_width=4 +[*.{kt, kts}] +indent_style=space +tab_width=4 + [*.rb] indent_style=space -indent_size=2 \ No newline at end of file +indent_size=2 From 3a9e4351898fc1f4f9093a0887aa4f07d57cc732 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 16 Sep 2017 22:34:24 +0100 Subject: [PATCH 054/209] Add an await function to the AsyncActionRunner trait --- game/plugin/api/build.gradle | 4 +++ .../apollo/game/plugins/api/definitions.kt | 19 ++++++++++++++ .../src/org/apollo/game/plugins/api/player.kt | 26 +++++++++++++++++++ .../apollo/game/action/AsyncActionRunner.kt | 17 +++++++++--- 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 game/plugin/api/build.gradle create mode 100644 game/plugin/api/src/org/apollo/game/plugins/api/definitions.kt create mode 100644 game/plugin/api/src/org/apollo/game/plugins/api/player.kt diff --git a/game/plugin/api/build.gradle b/game/plugin/api/build.gradle new file mode 100644 index 000000000..fb25c053e --- /dev/null +++ b/game/plugin/api/build.gradle @@ -0,0 +1,4 @@ +plugin { + name = "Apollo Plugin API" + description = "Helpers and API for common plugin usecases" +} \ No newline at end of file diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/definitions.kt b/game/plugin/api/src/org/apollo/game/plugins/api/definitions.kt new file mode 100644 index 000000000..3de58a113 --- /dev/null +++ b/game/plugin/api/src/org/apollo/game/plugins/api/definitions.kt @@ -0,0 +1,19 @@ +package org.apollo.game.plugins.api + +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition + +object Definitions { + fun item(id: Int): ItemDefinition? { + return ItemDefinition.lookup(id) + } + + fun obj(id: Int): ObjectDefinition? { + return ObjectDefinition.lookup(id) + } + + fun npc(id: Int): NpcDefinition? { + return NpcDefinition.lookup(id) + } +} \ No newline at end of file diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/player.kt b/game/plugin/api/src/org/apollo/game/plugins/api/player.kt new file mode 100644 index 000000000..d6b46151a --- /dev/null +++ b/game/plugin/api/src/org/apollo/game/plugins/api/player.kt @@ -0,0 +1,26 @@ +package org.apollo.game.plugins.api + +import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.SkillSet + +val SkillSet.attack: Skill get() = getSkill(Skill.ATTACK) +val SkillSet.defence: Skill get() = getSkill(Skill.DEFENCE) +val SkillSet.strength: Skill get() = getSkill(Skill.STRENGTH) +val SkillSet.hitpoints: Skill get() = getSkill(Skill.HITPOINTS) +val SkillSet.ranged: Skill get() = getSkill(Skill.RANGED) +val SkillSet.prayer: Skill get() = getSkill(Skill.PRAYER) +val SkillSet.magic: Skill get() = getSkill(Skill.MAGIC) +val SkillSet.cooking: Skill get() = getSkill(Skill.COOKING) +val SkillSet.woodcutting: Skill get() = getSkill(Skill.WOODCUTTING) +val SkillSet.fletching: Skill get() = getSkill(Skill.FLETCHING) +val SkillSet.fishing: Skill get() = getSkill(Skill.FISHING) +val SkillSet.firemaking: Skill get() = getSkill(Skill.FIREMAKING) +val SkillSet.crafting: Skill get() = getSkill(Skill.CRAFTING) +val SkillSet.smithing: Skill get() = getSkill(Skill.SMITHING) +val SkillSet.mining: Skill get() = getSkill(Skill.MINING) +val SkillSet.herblore: Skill get() = getSkill(Skill.HERBLORE) +val SkillSet.agility: Skill get() = getSkill(Skill.AGILITY) +val SkillSet.thieving: Skill get() = getSkill(Skill.THIEVING) +val SkillSet.slayer: Skill get() = getSkill(Skill.SLAYER) +val SkillSet.farming: Skill get() = getSkill(Skill.FARMING) +val SkillSet.runecraft: Skill get() = getSkill(Skill.RUNECRAFT) \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt index 366af4e20..e4d3ab5fb 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt @@ -1,10 +1,10 @@ package org.apollo.game.action -import kotlinx.coroutines.experimental.* +import kotlinx.coroutines.experimental.CommonPool +import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.channels.Channel +import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.selects.select -import org.apollo.game.model.entity.Mob -import java.util.function.Supplier class AsyncActionRunner(val actionSupplier: () -> Action<*>, val callback: suspend () -> Unit) { var job: Job? = null @@ -53,4 +53,15 @@ class AsyncActionRunner(val actionSupplier: () -> Action<*>, val callback: suspe remainingPulses -= numPulses } } + + suspend fun await(condition: () -> Boolean, timeout: Int = 15) { + var remainingPulsesBeforeTimeout = timeout + + while (!condition.invoke()) { + remainingPulsesBeforeTimeout -= pulseChannel.receive() + if (remainingPulsesBeforeTimeout <= 0) { + break + } + } + } } \ No newline at end of file From cf0e3331e0fec57169f0fa0a6dd7be110e4e694f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 03:09:47 +0100 Subject: [PATCH 055/209] Add API plugin with common functionality --- .../src/org/apollo/game/plugins/api/player.kt | 2 + .../src/org/apollo/game/plugins/api/util.kt | 7 +++ .../src/org/apollo/game/plugins/api/world.kt | 61 +++++++++++++++++++ .../org/apollo/game/model/area/Region.java | 16 ++++- .../apollo/game/action/AsyncActionRunner.kt | 12 ++-- .../apollo/game/action/AsyncActionTrait.kt | 4 +- .../game/action/AsyncDistancedAction.kt | 6 ++ 7 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 game/plugin/api/src/org/apollo/game/plugins/api/util.kt create mode 100644 game/plugin/api/src/org/apollo/game/plugins/api/world.kt diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/player.kt b/game/plugin/api/src/org/apollo/game/plugins/api/player.kt index d6b46151a..87881bdd8 100644 --- a/game/plugin/api/src/org/apollo/game/plugins/api/player.kt +++ b/game/plugin/api/src/org/apollo/game/plugins/api/player.kt @@ -1,8 +1,10 @@ package org.apollo.game.plugins.api +import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.SkillSet +val Player.skills: SkillSet get() = skillSet val SkillSet.attack: Skill get() = getSkill(Skill.ATTACK) val SkillSet.defence: Skill get() = getSkill(Skill.DEFENCE) val SkillSet.strength: Skill get() = getSkill(Skill.STRENGTH) diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/util.kt b/game/plugin/api/src/org/apollo/game/plugins/api/util.kt new file mode 100644 index 000000000..377af6c8c --- /dev/null +++ b/game/plugin/api/src/org/apollo/game/plugins/api/util.kt @@ -0,0 +1,7 @@ +import java.util.* + +val RAND = Random() + +fun rand(bounds: Int): Int { + return RAND.nextInt(bounds) +} \ No newline at end of file diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/world.kt b/game/plugin/api/src/org/apollo/game/plugins/api/world.kt new file mode 100644 index 000000000..5a550879f --- /dev/null +++ b/game/plugin/api/src/org/apollo/game/plugins/api/world.kt @@ -0,0 +1,61 @@ +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.area.Region +import org.apollo.game.model.entity.Entity +import org.apollo.game.model.entity.EntityType +import org.apollo.game.model.entity.EntityType.DYNAMIC_OBJECT +import org.apollo.game.model.entity.EntityType.STATIC_OBJECT +import org.apollo.game.model.entity.obj.DynamicGameObject +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.entity.obj.StaticGameObject +import org.apollo.game.scheduling.ScheduledTask +import java.lang.IllegalArgumentException +import java.util.* +import java.util.stream.Stream + +fun Region.find(position: Position, pred: (T) -> Boolean, vararg types: EntityType): Stream { + val result = this.getEntities(position, *types) + + return result.stream() + .filter(pred::invoke) +} + +fun Region.findObjects(position: Position, id: Int): Stream { + return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) +} + +fun Region.findObject(position: Position, id: Int): Optional { + return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) + .findFirst() +} + +class ExpireObjectTask( + val world: World, + val obj: GameObject, + val replacement: GameObject, + val respawnDelay: Int +) : ScheduledTask(0, true) { + + private var respawning: Boolean = false + + override fun execute() { + val region = world.regionRepository.fromPosition(obj.position) + + if (!respawning) { + world.spawn(replacement) + respawning = true + setDelay(respawnDelay) + } else { + region.removeEntity(replacement, false) + world.spawn(obj) + stop() + } + } +} + +fun World.expireObject(obj: GameObject, replacement: Int, respawnDelay: Int) { + val replacementObj = DynamicGameObject.createPublic(this, replacement, obj.position, obj.type, obj.orientation) + val respawnedObj = DynamicGameObject.createPublic(this, obj.id, obj.position, obj.type, obj.orientation) + + schedule(ExpireObjectTask(this, obj, replacementObj, respawnDelay)) +} diff --git a/game/src/main/java/org/apollo/game/model/area/Region.java b/game/src/main/java/org/apollo/game/model/area/Region.java index 7eafb952c..e5150d45b 100644 --- a/game/src/main/java/org/apollo/game/model/area/Region.java +++ b/game/src/main/java/org/apollo/game/model/area/Region.java @@ -335,12 +335,22 @@ public void notifyListeners(Entity entity, EntityUpdateType type) { } /** - * Removes an {@link Entity} from this Region. + * Removes an {@link Entity} from this Region and notifies listeners. * * @param entity The Entity. * @throws IllegalArgumentException If the Entity does not belong in this Region, or if it was never added. */ public void removeEntity(Entity entity) { + removeEntity(entity, true); + } + + /** + * Removes an {@link Entity} from this Region. + * + * @param entity The Entity. + * @throws IllegalArgumentException If the Entity does not belong in this Region, or if it was never added. + */ + public void removeEntity(Entity entity, boolean notifyListeners) { EntityType type = entity.getEntityType(); if (type.isTransient()) { throw new IllegalArgumentException("Tried to remove a transient Entity (" + entity + ") from " + @@ -356,7 +366,9 @@ public void removeEntity(Entity entity) { throw new IllegalArgumentException("Entity (" + entity + ") belongs in (" + this + ") but does not exist."); } - notifyListeners(entity, EntityUpdateType.REMOVE); + if (notifyListeners) { + notifyListeners(entity, EntityUpdateType.REMOVE); + } } @Override diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt index e4d3ab5fb..5288abc27 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt @@ -4,7 +4,7 @@ import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.launch -import kotlinx.coroutines.experimental.selects.select +import kotlinx.coroutines.experimental.runBlocking class AsyncActionRunner(val actionSupplier: () -> Action<*>, val callback: suspend () -> Unit) { var job: Job? = null @@ -27,10 +27,10 @@ class AsyncActionRunner(val actionSupplier: () -> Action<*>, val callback: suspe val action = actionSupplier.invoke() job = launch(CommonPool) { - select { - pulseChannel.onReceive { + run { + while (action.isRunning) { + pulseChannel.receive() callback() - action.stop() } } } @@ -45,12 +45,14 @@ class AsyncActionRunner(val actionSupplier: () -> Action<*>, val callback: suspe pulseChannel.close() } - suspend fun wait(pulses: Int = 1) { + suspend fun wait(pulses: Int = 1, pulseCallback: (() -> Unit)? = null) { var remainingPulses = pulses while (remainingPulses > 0) { val numPulses = pulseChannel.receive() remainingPulses -= numPulses + + pulseCallback?.invoke() } } diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt index f398c5f9e..7ad1a973c 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt @@ -3,7 +3,7 @@ package org.apollo.game.action interface AsyncActionTrait { val runner: AsyncActionRunner - suspend fun wait(pulses: Int = 1) { - runner.wait(pulses) + suspend fun wait(pulses: Int = 1, pulseCallback: (() -> Unit)? = null) { + runner.wait(pulses, pulseCallback) } } \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt index e947f8e4a..343b2fd3a 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt @@ -15,12 +15,18 @@ abstract class AsyncDistancedAction : DistancedAction, AsyncActionTr abstract suspend fun executeActionAsync() + open protected fun start() { + + } + override fun stop() { super.stop() runner.stop() } override fun executeAction() { + start() + if (!runner.started()) { runner.start() } From e61f4ef95a2a00bc09a2eb514f1458e41d83b715 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Thu, 17 Aug 2017 19:47:07 -0800 Subject: [PATCH 056/209] Adding support for mining skill --- game/src/plugins/skills/mining/meta.toml | 14 ++ game/src/plugins/skills/mining/src/gem.kt | 10 ++ .../skills/mining/src/mining.plugin.kts | 5 + game/src/plugins/skills/mining/src/ore.kt | 144 ++++++++++++++++++ game/src/plugins/skills/mining/src/pickaxe.kt | 21 +++ .../src/plugins/skills/mining/src/respawn.kts | 6 + 6 files changed, 200 insertions(+) create mode 100644 game/src/plugins/skills/mining/meta.toml create mode 100644 game/src/plugins/skills/mining/src/gem.kt create mode 100644 game/src/plugins/skills/mining/src/mining.plugin.kts create mode 100644 game/src/plugins/skills/mining/src/ore.kt create mode 100644 game/src/plugins/skills/mining/src/pickaxe.kt create mode 100644 game/src/plugins/skills/mining/src/respawn.kts diff --git a/game/src/plugins/skills/mining/meta.toml b/game/src/plugins/skills/mining/meta.toml new file mode 100644 index 000000000..162162ac9 --- /dev/null +++ b/game/src/plugins/skills/mining/meta.toml @@ -0,0 +1,14 @@ +name = "Mining Skill" +package = "org.apollo.game.plugin.skills.mining" +authors = [ + "Graham", + "Mikey`", + "WH:II:DOW", + "Requa", + "Clifton", + "tlf30" + ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/src/plugins/skills/mining/src/gem.kt b/game/src/plugins/skills/mining/src/gem.kt new file mode 100644 index 000000000..e3b0de561 --- /dev/null +++ b/game/src/plugins/skills/mining/src/gem.kt @@ -0,0 +1,10 @@ + + +data class Gem(id: Int, chance: Int) + +val GEMS = Array( + Gem(1623, 0), // uncut sapphire + Gem(1605, 0), // uncut emerald + Gem(1619, 0), // uncut ruby + Gem(1617, 0) // uncut diamond +) \ No newline at end of file diff --git a/game/src/plugins/skills/mining/src/mining.plugin.kts b/game/src/plugins/skills/mining/src/mining.plugin.kts new file mode 100644 index 000000000..3a71de22b --- /dev/null +++ b/game/src/plugins/skills/mining/src/mining.plugin.kts @@ -0,0 +1,5 @@ +import org.apollo.game.action.DistancedAction +import org.apollo.game.model.entity.EquipmentConstants +import org.apollo.game.model.entity.Skill + + diff --git a/game/src/plugins/skills/mining/src/ore.kt b/game/src/plugins/skills/mining/src/ore.kt new file mode 100644 index 000000000..35b05a4ff --- /dev/null +++ b/game/src/plugins/skills/mining/src/ore.kt @@ -0,0 +1,144 @@ + + +/* +Thanks to Mikey` for helping +to find some of the item/object IDs, minimum levels and experiences. +Thanks to Clifton for helping +to find some of the expired object IDs. + */ + +data class Ore(id: Int, objects: Map, level: Int, exp: Float, respawn: Int) + +val ORE_OBJECTS = Array( + Ore(434, CLAY_OBJECTS, 1, 5, 3), // clay + Ore(436, COPPER_OBJECTS, 1, 17.5, 6), // copper + Ore(438, TIN_OBJECTS, 1, 17.5, 6), // tin + Ore(440, IRON_OBJECTS, 15, 35, 16), // iron + Ore(453, COAL_OBJECTS, 30, 50, 100), // coal + Ore(444, GOLD_OBJECTS, 40, 65, 200), // gold + Ore(442, SILVER_OBJECTS, 20, 40, 200), // silver + Ore(447, MITHRIL_OBJECTS, 55, 80, 400), // mithril + Ore(449, ADAMANT_OBJECTS, 70, 95, 800), // adamant + Ore(451, RUNITE_OBJECTS, 85, 125, 2500) // runite +) + +val ORES = asMap() +val EXPIRED_ORES = asMap() + +for (ore in ORE_OBJECTS) { + for (key in ore.objects.keys) { + ORES.put(key, ore) + EXPIRED_ORES.put(ore.objects.(get), true) + } +} + +val CLAY_OBJECTS = mapOf( + 2180 to 450, + 2109 to 451, + 14904 to 14896, + 14905 to 14897 +) + +val COPPER_OBJECTS = mapOf( + 11960 to 11555, + 11961 to 11556, + 11962 to 11557, + 11936 to 11552, + 11937 to 11553, + 11938 to 11554, + 2090 to 450, + 2091 to 451, + 14906 to 14898, + 14907 to 14899, + 14856 to 14832, + 14857 to 14833, + 14858 to 14834 +) + +val TIN_OBJECTS = mapOf( + 11597 to 11555, + 11958 to 11556, + 11959 to 11557, + 11933 to 11552, + 11934 to 11553, + 11935 to 11554, + 2094 to 450, + 2095 to 451, + 14092 to 14894, + 14903 to 14895 +) + +val IRON_OBJECTS = mapOf( + 11954 to 11555, + 11955 to 11556, + 11956 to 11557, + 2092 to 450, + 2093 to 451, + 14900 to 14892, + 14901 to 14893, + 14913 to 14915, + 14914 to 14916 +) + +val COAL_OBJECTS = mapOf( + 11963 to 11555, + 11964 to 11556, + 11965 to 11557, + 11930 to 11552, + 11931 to 11553, + 11932 to 11554, + 2096 to 450, + 2097 to 451, + 14850 to 14832, + 14851 to 14833, + 14852 to 14834 +) + +val SILVER_OBJECTS = mapOf ( + 11948 to 11555, + 11949 to 11556, + 11950 to 11557, + 2100 to 450, + 2101 to 451 +) + +val GOLD_OBJECTS = mapOf( + 11951 to 11555, + 11952 to 11556, + 11953 to 11557, + 2098 to 450, + 2099 to 451 +) + +val MITHRIL_OBJECTS = mapOf( + 11945 to 11555, + 11946 to 11556, + 11947 to 11557, + 11942 to 11552, + 11943 to 11553, + 11944 to 11554, + 2102 to 450, + 2103 to 451, + 14853 to 14832, + 14854 to 14833, + 14855 to 14834 +) + +val ADAMANT_OBJECTS = mapOf( + 11939 to 11552, + 11940 to 11553, + 11941 to 11554, + 2104 to 450, + 2105 to 451, + 14862 to 14832, + 14863 to 14833, + 14864 to 14834 +) + +val RUNITE_OBJECTS = mapOf( + 2106 to 450, + 2107 to 451, + 14859 to 14832, + 14860 to 14833, + 14861 to 14834 +) \ No newline at end of file diff --git a/game/src/plugins/skills/mining/src/pickaxe.kt b/game/src/plugins/skills/mining/src/pickaxe.kt new file mode 100644 index 000000000..dccf2caf6 --- /dev/null +++ b/game/src/plugins/skills/mining/src/pickaxe.kt @@ -0,0 +1,21 @@ +import org.apollo.game.model.Animation; + +data class Pickaxe(id: Int, level: Int, animation: Animation, pulses: Int) + +val PICKAXES = Array( + Pickaxe(1265, 1, 625, 8), // bronze + Pickaxe(1267, 1, 626, 7), // iron + Pickaxe(1269, 1, 627, 6), // steel + Pickaxe(1273, 21, 629, 5), // mithril + Pickaxe(1271, 31, 628, 4), // adamant + Pickaxe(1275, 41, 624, 3) // rune +) + +val PICKAXE_IDS: IntArray = intArrayOf( + 1275, // rune + 1271 // adamant + 1273, // mithril + 1269, // steel + 1267, // iron + 1265, // bronze +) \ No newline at end of file diff --git a/game/src/plugins/skills/mining/src/respawn.kts b/game/src/plugins/skills/mining/src/respawn.kts new file mode 100644 index 000000000..5ff371040 --- /dev/null +++ b/game/src/plugins/skills/mining/src/respawn.kts @@ -0,0 +1,6 @@ + + + +fun respawn_pulses(base: Int, players: Int) { + return base - players * base / (world.playerRepository.size() * 2); +} \ No newline at end of file From a54485e2637127070507802fdf6a5b45c8646e61 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Thu, 17 Aug 2017 21:29:15 -0800 Subject: [PATCH 057/209] Finish up porting mining plugin to Kotlin --- game/src/plugins/skills/mining/meta.toml | 4 +- game/src/plugins/skills/mining/src/gem.kt | 16 +- .../skills/mining/src/mining.plugin.kts | 195 ++++++++++++++++++ game/src/plugins/skills/mining/src/ore.kt | 55 +++-- game/src/plugins/skills/mining/src/pickaxe.kt | 40 ++-- .../src/plugins/skills/mining/src/respawn.kts | 6 - 6 files changed, 260 insertions(+), 56 deletions(-) delete mode 100644 game/src/plugins/skills/mining/src/respawn.kts diff --git a/game/src/plugins/skills/mining/meta.toml b/game/src/plugins/skills/mining/meta.toml index 162162ac9..0cf7d9ae4 100644 --- a/game/src/plugins/skills/mining/meta.toml +++ b/game/src/plugins/skills/mining/meta.toml @@ -1,4 +1,4 @@ -name = "Mining Skill" +name = "mining-skill" package = "org.apollo.game.plugin.skills.mining" authors = [ "Graham", @@ -11,4 +11,4 @@ authors = [ [config] srcDir = "src/" -testDir = "test/" \ No newline at end of file +testDir = "test/" diff --git a/game/src/plugins/skills/mining/src/gem.kt b/game/src/plugins/skills/mining/src/gem.kt index e3b0de561..6414bfe61 100644 --- a/game/src/plugins/skills/mining/src/gem.kt +++ b/game/src/plugins/skills/mining/src/gem.kt @@ -1,10 +1,12 @@ +package org.apollo.game.plugin.skills.mining +enum class Gem(val id: Int, val chance: Int) { + UNCUT_SAPPHIRE(1623, 0), + UNCUT_EMERALD(1605, 0), + UNCUT_RUBY(1619, 0), + UNCUT_DIAMOND(1617, 0) +} -data class Gem(id: Int, chance: Int) +val GEMS = Gem.values() -val GEMS = Array( - Gem(1623, 0), // uncut sapphire - Gem(1605, 0), // uncut emerald - Gem(1619, 0), // uncut ruby - Gem(1617, 0) // uncut diamond -) \ No newline at end of file +fun lookupGem(id: Int): Gem? = GEMS.find { it.id == id } diff --git a/game/src/plugins/skills/mining/src/mining.plugin.kts b/game/src/plugins/skills/mining/src/mining.plugin.kts index 3a71de22b..a0cd3e402 100644 --- a/game/src/plugins/skills/mining/src/mining.plugin.kts +++ b/game/src/plugins/skills/mining/src/mining.plugin.kts @@ -1,5 +1,200 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.ObjectDefinition import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Animation +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Entity import org.apollo.game.model.entity.EquipmentConstants +import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.obj.StaticGameObject +import org.apollo.game.plugin.skills.mining.* +import org.apollo.game.scheduling.ScheduledTask +import org.apollo.game.scheduling.Scheduler +import java.util.* +import kotlin.properties.Delegates +class MiningAction(val player: Player, val objectID: Int, val p: Position, val ore: Ore) : DistancedAction(PULSES, true, player, p, ORE_SIZE) { + companion object { + private val PULSES = 0 + private val ORE_SIZE = 1; + } + + private var counter: Int = 0 + private var started: Boolean = false + private val rand: Random = Random() + + override fun executeAction() { + val level = mob.skillSet.getSkill(Skill.MINING).currentLevel + val pickaxe = findPickaxe() + + + //check that our pick can mine the ore + if (pickaxe == null || level < pickaxe.level) { + mob.sendMessage("You do not have a pickaxe for which you have the level to use.") + stop() + return + } + + //check that we can mine the ore + if (level < ore.level) { + mob.sendMessage("You do not have the required level to mine this rock.") + stop() + return + } + + //start the process of mining + if (started) { + if (counter == 0) { + if (!miningSuccessful(ore.chance, ore.chanceOffset, level)) { + mine(pickaxe) + return //We did not mine the ore... Keep going + } + //Check inv capacity + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + stop() + return + } + if (mob.inventory.add(ore.id)) { + //TODO: Use lookup from utils once it has a lookup function for IDs + val oreName = ItemDefinition.lookup(ore.id).name.toLowerCase(); + mob.sendMessage("You managed to mine some " + oreName + ".") + mob.skillSet.addExperience(Skill.MINING, ore.exp) + //Expire ore + var rockEntity: StaticGameObject? = null + val region = mob.world.regionRepository.fromPosition(position) + val entities = region.getEntities(position) + for (entity: Entity in entities) { + if (entity is StaticGameObject) { + if (entity.id == objectID) { + rockEntity = entity + } + } + } + if (rockEntity == null) { //Mining entity not found at location... + stop() + return + } + //Get ID of exipred ore + val expiredObjectID = ore.objects.get(objectID); + val expiredRockEntity = StaticGameObject(mob.world, expiredObjectID!!, position, rockEntity!!.type, rockEntity!!.orientation) + //add task to remove normal ore and replace with depleted + mob.world.schedule(object: ScheduledTask(0, true) { + override fun execute() { + //Replace normal ore with expired ore + region.removeEntity(rockEntity); + region.addEntity(expiredRockEntity) + this.stop() //Makes task run once + } + }) + //add task to respawn normal ore + mob.world.schedule(object: ScheduledTask(ore.respawn, false) { + override fun execute() { + //Replace expired ore with normal ore + region.removeEntity(expiredRockEntity) + region.addEntity(rockEntity); + this.stop() //Makes task run once + } + }) + } //If we did not add to inv, the action will still stop + stop(); //Force this action to stop after we are done + } + counter -= 1 + } else { + started = true + mine(pickaxe) + } + } + + private fun findPickaxe(): Pickaxe? { + for (pick in getPickaxes()) { + if (pick!!.level > mob.skillSet.getSkill(Skill.MINING).currentLevel) { + continue; + } + val weaponSlot = mob.equipment.get(EquipmentConstants.WEAPON) + if (weaponSlot != null && weaponSlot.id == pick.id) { + return pick; + } else if (mob.inventory.contains(pick.id)) { + return pick; + } + } + return null; + } + + private fun mine(pickaxe: Pickaxe) { + mob.sendMessage("You swing your pick at the rock.") + mob.playAnimation(pickaxe.animation) + counter = pickaxe.pulses + mob.turnTo(position) + } + + /** + * Returns the chance of mining being successful. + * Algorithm comes from: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula + */ + private fun miningSuccessful(oreChance: Double, oreChanceOffset: Boolean, playerLevel: Int): Boolean { + val percent: Double + if (oreChanceOffset) { + percent = (oreChance * playerLevel + 1) * 100 + } else { + percent = (oreChance * playerLevel) * 100 + } + return rand.nextInt(100) < percent; + } +} + +class ExpiredProspectingAction : DistancedAction { + + constructor(mob: Player, position: Position) : super(PROSPECT_PULSES, true, mob, position, ORE_SIZE) + + companion object { + private val PROSPECT_PULSES = 0 + private val ORE_SIZE = 1; + } + + override fun executeAction() { + mob.sendMessage("There is currently no ore available in this rock.") + stop(); + } +} + +class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : DistancedAction(PROSPECT_PULSES, true, m, p, ORE_SIZE) { + + companion object { + private val PROSPECT_PULSES = 3 + private val ORE_SIZE = 1; + } + + var started = false; + + override fun executeAction() { + if (started) { + val oreName = ItemDefinition.lookup(ore.id).name.toLowerCase() + mob.sendMessage("This rock contains " + oreName + ".") + stop(); + } else { + started = true + mob.sendMessage("You examine the rock for ores...") + mob.turnTo(position) + } + } +} + +on {ObjectActionMessage::class} + .where {option == 1} + .then { + if (lookupOreRock(id) != null) { + it.startAction(MiningAction(it, id, this.position, lookupOreRock(id)!!)) + } + } + +on {ObjectActionMessage::class} + .where {option == 2} + .then { + if (lookupOreRock(id) != null) { + it.startAction(ProspectingAction(it, this.position, lookupOreRock(id)!!)) + } + } diff --git a/game/src/plugins/skills/mining/src/ore.kt b/game/src/plugins/skills/mining/src/ore.kt index 35b05a4ff..8a67cd80b 100644 --- a/game/src/plugins/skills/mining/src/ore.kt +++ b/game/src/plugins/skills/mining/src/ore.kt @@ -1,4 +1,6 @@ +package org.apollo.game.plugin.skills.mining +import com.google.common.collect.Maps.asMap /* Thanks to Mikey` for helping @@ -7,33 +9,41 @@ Thanks to Clifton for helping to find some of the expired object IDs. */ -data class Ore(id: Int, objects: Map, level: Int, exp: Float, respawn: Int) - -val ORE_OBJECTS = Array( - Ore(434, CLAY_OBJECTS, 1, 5, 3), // clay - Ore(436, COPPER_OBJECTS, 1, 17.5, 6), // copper - Ore(438, TIN_OBJECTS, 1, 17.5, 6), // tin - Ore(440, IRON_OBJECTS, 15, 35, 16), // iron - Ore(453, COAL_OBJECTS, 30, 50, 100), // coal - Ore(444, GOLD_OBJECTS, 40, 65, 200), // gold - Ore(442, SILVER_OBJECTS, 20, 40, 200), // silver - Ore(447, MITHRIL_OBJECTS, 55, 80, 400), // mithril - Ore(449, ADAMANT_OBJECTS, 70, 95, 800), // adamant - Ore(451, RUNITE_OBJECTS, 85, 125, 2500) // runite -) -val ORES = asMap() -val EXPIRED_ORES = asMap() +/** + * Chance values thanks to: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula + * Respawn times and xp thanks to: http://oldschoolrunescape.wikia.com/wiki/ + */ +enum class Ore(val id: Int, val objects: Map, val level: Int, val exp: Double, val respawn: Int, val chance: Double, val chanceOffset: Boolean) { + CLAY(434, CLAY_OBJECTS, 1, 5.0, 1, 0.0085, true), + COPPER(436, COPPER_OBJECTS, 1, 17.5, 4, 0.0085, true), + TIN(438, TIN_OBJECTS, 1, 17.5, 4, 0.0085, true), + IRON(440, IRON_OBJECTS, 15, 35.0, 9, 0.0085, true), + COAL(453, COAL_OBJECTS, 30, 50.0, 50, 0.004, false), + GOLD(444, GOLD_OBJECTS, 40, 65.0, 100, 0.003, false), + SILVER(442, SILVER_OBJECTS, 20, 40.0, 100, 0.0085, false), + MITHRIL(447, MITHRIL_OBJECTS, 55, 80.0, 200, 0.002, false), + ADAMANT(449, ADAMANT_OBJECTS, 70, 95.0, 800, 0.001, false), + RUNITE(451, RUNITE_OBJECTS, 85, 125.0, 1200, 0.0008, false) +} + +val ORES = Ore.values() -for (ore in ORE_OBJECTS) { - for (key in ore.objects.keys) { - ORES.put(key, ore) - EXPIRED_ORES.put(ore.objects.(get), true) +fun lookupOre(id: Int): Ore? = ORES.find { it.id == id } + +fun lookupOreRock(id: Int): Ore? { + for (ore in ORES) { + for (rock in ore.objects) { + if (rock.key == id) { + return ore + } + } } + return null } val CLAY_OBJECTS = mapOf( - 2180 to 450, + 2108 to 450, 2109 to 451, 14904 to 14896, 14905 to 14897 @@ -141,4 +151,5 @@ val RUNITE_OBJECTS = mapOf( 14859 to 14832, 14860 to 14833, 14861 to 14834 -) \ No newline at end of file +) + diff --git a/game/src/plugins/skills/mining/src/pickaxe.kt b/game/src/plugins/skills/mining/src/pickaxe.kt index dccf2caf6..4b5f0faa1 100644 --- a/game/src/plugins/skills/mining/src/pickaxe.kt +++ b/game/src/plugins/skills/mining/src/pickaxe.kt @@ -1,21 +1,23 @@ +package org.apollo.game.plugin.skills.mining + import org.apollo.game.model.Animation; -data class Pickaxe(id: Int, level: Int, animation: Animation, pulses: Int) - -val PICKAXES = Array( - Pickaxe(1265, 1, 625, 8), // bronze - Pickaxe(1267, 1, 626, 7), // iron - Pickaxe(1269, 1, 627, 6), // steel - Pickaxe(1273, 21, 629, 5), // mithril - Pickaxe(1271, 31, 628, 4), // adamant - Pickaxe(1275, 41, 624, 3) // rune -) - -val PICKAXE_IDS: IntArray = intArrayOf( - 1275, // rune - 1271 // adamant - 1273, // mithril - 1269, // steel - 1267, // iron - 1265, // bronze -) \ No newline at end of file +enum class Pickaxe(val id: Int, val level: Int, val animation: Animation, val pulses: Int) { + RUNE(1275, 41, Animation(624), 3), + ADAMANT(1271, 31, Animation(628), 4), + MITHRIL(1273, 21, Animation(629), 5), + STEEL(1269, 1, Animation(627), 6), + ITRON(1267, 1, Animation(626), 7), + BRONZE(1265, 1, Animation(625), 8) +} + +val PICKAXES = Pickaxe.values() + + + +fun getPickaxes(): Array { + return PICKAXES +} + +fun lookupPickaxe(id: Int): Pickaxe? = PICKAXES.find { it.id == id } + diff --git a/game/src/plugins/skills/mining/src/respawn.kts b/game/src/plugins/skills/mining/src/respawn.kts deleted file mode 100644 index 5ff371040..000000000 --- a/game/src/plugins/skills/mining/src/respawn.kts +++ /dev/null @@ -1,6 +0,0 @@ - - - -fun respawn_pulses(base: Int, players: Int) { - return base - players * base / (world.playerRepository.size() * 2); -} \ No newline at end of file From 0dc6879bdcce692af49cb8beeb5c48586beea37c Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 03:10:15 +0100 Subject: [PATCH 058/209] Refactor mining to use async actions --- game/plugin/skills/mining/build.gradle | 14 ++ .../skills/mining/meta.toml | 0 .../skills/mining/src/gem.kt | 0 .../skills/mining/src/mining.plugin.kts | 174 +++++++++++++++ .../skills/mining/src/ore.kt | 66 +++--- .../skills/mining/src/pickaxe.kt | 0 .../skills/mining/src/mining.plugin.kts | 200 ------------------ 7 files changed, 221 insertions(+), 233 deletions(-) create mode 100644 game/plugin/skills/mining/build.gradle rename game/{src/plugins => plugin}/skills/mining/meta.toml (100%) rename game/{src/plugins => plugin}/skills/mining/src/gem.kt (100%) create mode 100644 game/plugin/skills/mining/src/mining.plugin.kts rename game/{src/plugins => plugin}/skills/mining/src/ore.kt (98%) rename game/{src/plugins => plugin}/skills/mining/src/pickaxe.kt (100%) delete mode 100644 game/src/plugins/skills/mining/src/mining.plugin.kts diff --git a/game/plugin/skills/mining/build.gradle b/game/plugin/skills/mining/build.gradle new file mode 100644 index 000000000..00a165376 --- /dev/null +++ b/game/plugin/skills/mining/build.gradle @@ -0,0 +1,14 @@ +plugin { + name = "mining-skill" + packageName = "org.apollo.game.plugin.skills.mining" + authors = [ + "Graham", + "Mikey`", + "WH:II:DOW", + "Requa", + "Clifton", + "tlf30" + ] + + dependencies = ["api"] +} \ No newline at end of file diff --git a/game/src/plugins/skills/mining/meta.toml b/game/plugin/skills/mining/meta.toml similarity index 100% rename from game/src/plugins/skills/mining/meta.toml rename to game/plugin/skills/mining/meta.toml diff --git a/game/src/plugins/skills/mining/src/gem.kt b/game/plugin/skills/mining/src/gem.kt similarity index 100% rename from game/src/plugins/skills/mining/src/gem.kt rename to game/plugin/skills/mining/src/gem.kt diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts new file mode 100644 index 000000000..f44020b96 --- /dev/null +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -0,0 +1,174 @@ +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.skills.mining.Ore +import org.apollo.game.plugin.skills.mining.PICKAXES +import org.apollo.game.plugin.skills.mining.Pickaxe +import org.apollo.game.plugin.skills.mining.lookupOreRock +import org.apollo.game.plugins.api.Definitions +import org.apollo.game.plugins.api.mining +import org.apollo.game.plugins.api.skills +import org.apollo.net.message.Message +import java.util.* + +class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { + fun getObject(world: World): Optional { + val region = world.regionRepository.fromPosition(position) + val obj = region.findObject(position, objectId) + + return obj + } + + fun isSuccessful(mob: Player): Boolean { + val offset = if (ore.chanceOffset) 1 else 0 + val percent = (ore.chance * mob.skills.mining.currentLevel + offset) * 100 + + return rand(100) < percent; + } +} + +class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) : AsyncDistancedAction( + PULSES, + true, + player, + target.position, + ORE_SIZE +) { + + companion object { + private val PULSES = 0 + private val ORE_SIZE = 1; + + fun pickaxeFor(player: Player): Pickaxe? { + return PICKAXES + .filter { it.level <= player.skills.mining.currentLevel } + .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } + .sortedByDescending { it.level } + .firstOrNull() + } + + /** + * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player, ore: Ore) { + val pickaxe = pickaxeFor(player) + if (pickaxe != null) { + val action = MiningAction(player, pickaxe, MiningTarget(message.id, message.position, ore)) + player.startAction(action) + } else { + player.sendMessage("You do not have a pickaxe for which you have the level to use.") + } + + message.terminate() + } + } + + override fun start() { + mob.turnTo(position) + + val level = mob.skills.mining.currentLevel + + if (level < target.ore.level) { + mob.sendMessage("You do not have the required level to mine this rock.") + stop() + } + } + + override suspend fun executeActionAsync() { + mob.sendMessage("You swing your pick at the rock.") + mob.playAnimation(tool.animation) + + wait(tool.pulses) + + val obj = target.getObject(mob.world) + if (!obj.isPresent) { + stop() + return + } + + if (target.isSuccessful(mob)) { + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + stop() + return + } + + if (mob.inventory.add(target.ore.id)) { + val oreName = Definitions.item(target.ore.id)?.name?.toLowerCase() + mob.sendMessage("You manage to mine some $oreName") + + mob.skills.addExperience(Skill.MINING, target.ore.exp) + mob.world.expireObject(obj.get(), target.ore.objects[target.objectId]!!, target.ore.respawn) + stop() + return + } + } + } +} + +class ExpiredProspectingAction : DistancedAction { + + constructor(mob: Player, position: Position) : super(PROSPECT_PULSES, true, mob, position, ORE_SIZE) + + companion object { + private val PROSPECT_PULSES = 0 + private val ORE_SIZE = 1; + } + + override fun executeAction() { + mob.sendMessage("There is currently no ore available in this rock.") + stop(); + } +} + +class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : AsyncDistancedAction(PROSPECT_PULSES, true, m, p, ORE_SIZE) { + companion object { + private val PROSPECT_PULSES = 3 + private val ORE_SIZE = 1; + + /** + * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player, ore: Ore) { + val action = ProspectingAction(player, message.position, ore) + player.startAction(action) + + message.terminate() + } + } + + suspend override fun executeActionAsync() { + mob.sendMessage("You examine the rock for ores...") + mob.turnTo(position) + + wait() + + val oreName = Definitions.item(ore.id)?.name?.toLowerCase() + mob.sendMessage("This rock contains $oreName") + + stop() + } +} + +on { ObjectActionMessage::class } + .where { option == 1 } + .then { + val ore = lookupOreRock(id) + if (ore != null) { + MiningAction.start(this, it, ore) + } + } + +on { ObjectActionMessage::class } + .where { option == 2 } + .then { + var ore = lookupOreRock(id) + if (ore != null) { + ProspectingAction.start(this, it, ore) + } + } diff --git a/game/src/plugins/skills/mining/src/ore.kt b/game/plugin/skills/mining/src/ore.kt similarity index 98% rename from game/src/plugins/skills/mining/src/ore.kt rename to game/plugin/skills/mining/src/ore.kt index 8a67cd80b..90001fdcc 100644 --- a/game/src/plugins/skills/mining/src/ore.kt +++ b/game/plugin/skills/mining/src/ore.kt @@ -9,39 +9,6 @@ Thanks to Clifton for helping to find some of the expired object IDs. */ - -/** - * Chance values thanks to: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula - * Respawn times and xp thanks to: http://oldschoolrunescape.wikia.com/wiki/ - */ -enum class Ore(val id: Int, val objects: Map, val level: Int, val exp: Double, val respawn: Int, val chance: Double, val chanceOffset: Boolean) { - CLAY(434, CLAY_OBJECTS, 1, 5.0, 1, 0.0085, true), - COPPER(436, COPPER_OBJECTS, 1, 17.5, 4, 0.0085, true), - TIN(438, TIN_OBJECTS, 1, 17.5, 4, 0.0085, true), - IRON(440, IRON_OBJECTS, 15, 35.0, 9, 0.0085, true), - COAL(453, COAL_OBJECTS, 30, 50.0, 50, 0.004, false), - GOLD(444, GOLD_OBJECTS, 40, 65.0, 100, 0.003, false), - SILVER(442, SILVER_OBJECTS, 20, 40.0, 100, 0.0085, false), - MITHRIL(447, MITHRIL_OBJECTS, 55, 80.0, 200, 0.002, false), - ADAMANT(449, ADAMANT_OBJECTS, 70, 95.0, 800, 0.001, false), - RUNITE(451, RUNITE_OBJECTS, 85, 125.0, 1200, 0.0008, false) -} - -val ORES = Ore.values() - -fun lookupOre(id: Int): Ore? = ORES.find { it.id == id } - -fun lookupOreRock(id: Int): Ore? { - for (ore in ORES) { - for (rock in ore.objects) { - if (rock.key == id) { - return ore - } - } - } - return null -} - val CLAY_OBJECTS = mapOf( 2108 to 450, 2109 to 451, @@ -153,3 +120,36 @@ val RUNITE_OBJECTS = mapOf( 14861 to 14834 ) + +/** + * Chance values thanks to: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula + * Respawn times and xp thanks to: http://oldschoolrunescape.wikia.com/wiki/ + */ +enum class Ore(val id: Int, val objects: Map, val level: Int, val exp: Double, val respawn: Int, val chance: Double, val chanceOffset: Boolean) { + CLAY(434, CLAY_OBJECTS, 1, 5.0, 1, 0.0085, true), + COPPER(436, COPPER_OBJECTS, 1, 17.5, 4, 0.0085, true), + TIN(438, TIN_OBJECTS, 1, 17.5, 4, 0.0085, true), + IRON(440, IRON_OBJECTS, 15, 35.0, 9, 0.0085, true), + COAL(453, COAL_OBJECTS, 30, 50.0, 50, 0.004, false), + GOLD(444, GOLD_OBJECTS, 40, 65.0, 100, 0.003, false), + SILVER(442, SILVER_OBJECTS, 20, 40.0, 100, 0.0085, false), + MITHRIL(447, MITHRIL_OBJECTS, 55, 80.0, 200, 0.002, false), + ADAMANT(449, ADAMANT_OBJECTS, 70, 95.0, 800, 0.001, false), + RUNITE(451, RUNITE_OBJECTS, 85, 125.0, 1200, 0.0008, false) +} + +val ORES = enumValues() + +fun lookupOre(id: Int): Ore? = ORES.find { it.id == id } + +fun lookupOreRock(id: Int): Ore? { + for (ore in enumValues()) { + for (rock in ore.objects) { + if (rock.key == id) { + return ore + } + } + } + return null +} + diff --git a/game/src/plugins/skills/mining/src/pickaxe.kt b/game/plugin/skills/mining/src/pickaxe.kt similarity index 100% rename from game/src/plugins/skills/mining/src/pickaxe.kt rename to game/plugin/skills/mining/src/pickaxe.kt diff --git a/game/src/plugins/skills/mining/src/mining.plugin.kts b/game/src/plugins/skills/mining/src/mining.plugin.kts deleted file mode 100644 index a0cd3e402..000000000 --- a/game/src/plugins/skills/mining/src/mining.plugin.kts +++ /dev/null @@ -1,200 +0,0 @@ -import org.apollo.cache.def.ItemDefinition -import org.apollo.cache.def.ObjectDefinition -import org.apollo.game.action.DistancedAction -import org.apollo.game.message.impl.ObjectActionMessage -import org.apollo.game.model.Animation -import org.apollo.game.model.Position -import org.apollo.game.model.entity.Entity -import org.apollo.game.model.entity.EquipmentConstants -import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.Skill -import org.apollo.game.model.entity.obj.StaticGameObject -import org.apollo.game.plugin.skills.mining.* -import org.apollo.game.scheduling.ScheduledTask -import org.apollo.game.scheduling.Scheduler -import java.util.* -import kotlin.properties.Delegates - -class MiningAction(val player: Player, val objectID: Int, val p: Position, val ore: Ore) : DistancedAction(PULSES, true, player, p, ORE_SIZE) { - - companion object { - private val PULSES = 0 - private val ORE_SIZE = 1; - } - - private var counter: Int = 0 - private var started: Boolean = false - private val rand: Random = Random() - - override fun executeAction() { - val level = mob.skillSet.getSkill(Skill.MINING).currentLevel - val pickaxe = findPickaxe() - - - //check that our pick can mine the ore - if (pickaxe == null || level < pickaxe.level) { - mob.sendMessage("You do not have a pickaxe for which you have the level to use.") - stop() - return - } - - //check that we can mine the ore - if (level < ore.level) { - mob.sendMessage("You do not have the required level to mine this rock.") - stop() - return - } - - //start the process of mining - if (started) { - if (counter == 0) { - if (!miningSuccessful(ore.chance, ore.chanceOffset, level)) { - mine(pickaxe) - return //We did not mine the ore... Keep going - } - //Check inv capacity - if (mob.inventory.freeSlots() == 0) { - mob.inventory.forceCapacityExceeded() - stop() - return - } - if (mob.inventory.add(ore.id)) { - //TODO: Use lookup from utils once it has a lookup function for IDs - val oreName = ItemDefinition.lookup(ore.id).name.toLowerCase(); - mob.sendMessage("You managed to mine some " + oreName + ".") - mob.skillSet.addExperience(Skill.MINING, ore.exp) - //Expire ore - var rockEntity: StaticGameObject? = null - val region = mob.world.regionRepository.fromPosition(position) - val entities = region.getEntities(position) - for (entity: Entity in entities) { - if (entity is StaticGameObject) { - if (entity.id == objectID) { - rockEntity = entity - } - } - } - if (rockEntity == null) { //Mining entity not found at location... - stop() - return - } - //Get ID of exipred ore - val expiredObjectID = ore.objects.get(objectID); - val expiredRockEntity = StaticGameObject(mob.world, expiredObjectID!!, position, rockEntity!!.type, rockEntity!!.orientation) - //add task to remove normal ore and replace with depleted - mob.world.schedule(object: ScheduledTask(0, true) { - override fun execute() { - //Replace normal ore with expired ore - region.removeEntity(rockEntity); - region.addEntity(expiredRockEntity) - this.stop() //Makes task run once - } - }) - //add task to respawn normal ore - mob.world.schedule(object: ScheduledTask(ore.respawn, false) { - override fun execute() { - //Replace expired ore with normal ore - region.removeEntity(expiredRockEntity) - region.addEntity(rockEntity); - this.stop() //Makes task run once - } - }) - } //If we did not add to inv, the action will still stop - stop(); //Force this action to stop after we are done - } - counter -= 1 - } else { - started = true - mine(pickaxe) - } - } - - private fun findPickaxe(): Pickaxe? { - for (pick in getPickaxes()) { - if (pick!!.level > mob.skillSet.getSkill(Skill.MINING).currentLevel) { - continue; - } - val weaponSlot = mob.equipment.get(EquipmentConstants.WEAPON) - if (weaponSlot != null && weaponSlot.id == pick.id) { - return pick; - } else if (mob.inventory.contains(pick.id)) { - return pick; - } - } - return null; - } - - private fun mine(pickaxe: Pickaxe) { - mob.sendMessage("You swing your pick at the rock.") - mob.playAnimation(pickaxe.animation) - counter = pickaxe.pulses - mob.turnTo(position) - } - - /** - * Returns the chance of mining being successful. - * Algorithm comes from: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula - */ - private fun miningSuccessful(oreChance: Double, oreChanceOffset: Boolean, playerLevel: Int): Boolean { - val percent: Double - if (oreChanceOffset) { - percent = (oreChance * playerLevel + 1) * 100 - } else { - percent = (oreChance * playerLevel) * 100 - } - return rand.nextInt(100) < percent; - } -} - -class ExpiredProspectingAction : DistancedAction { - - constructor(mob: Player, position: Position) : super(PROSPECT_PULSES, true, mob, position, ORE_SIZE) - - companion object { - private val PROSPECT_PULSES = 0 - private val ORE_SIZE = 1; - } - - override fun executeAction() { - mob.sendMessage("There is currently no ore available in this rock.") - stop(); - } -} - -class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : DistancedAction(PROSPECT_PULSES, true, m, p, ORE_SIZE) { - - companion object { - private val PROSPECT_PULSES = 3 - private val ORE_SIZE = 1; - } - - var started = false; - - override fun executeAction() { - if (started) { - val oreName = ItemDefinition.lookup(ore.id).name.toLowerCase() - mob.sendMessage("This rock contains " + oreName + ".") - stop(); - } else { - started = true - mob.sendMessage("You examine the rock for ores...") - mob.turnTo(position) - } - } -} - -on {ObjectActionMessage::class} - .where {option == 1} - .then { - if (lookupOreRock(id) != null) { - it.startAction(MiningAction(it, id, this.position, lookupOreRock(id)!!)) - } - } - -on {ObjectActionMessage::class} - .where {option == 2} - .then { - if (lookupOreRock(id) != null) { - it.startAction(ProspectingAction(it, this.position, lookupOreRock(id)!!)) - } - } From 40095d65e54355b2ba2d338981bdd938ad64cbd1 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 03:24:59 +0100 Subject: [PATCH 059/209] Add explicit stop() to async actions --- game/plugin/consumables/src/consumables.plugin.kts | 1 + game/plugin/dummy/src/dummy.plugin.kts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/game/plugin/consumables/src/consumables.plugin.kts b/game/plugin/consumables/src/consumables.plugin.kts index 49c64312d..4624be019 100644 --- a/game/plugin/consumables/src/consumables.plugin.kts +++ b/game/plugin/consumables/src/consumables.plugin.kts @@ -31,6 +31,7 @@ class ConsumeAction(val consumable: Consumable, player: Player, val slot: Int) : consumable.consume(mob, slot) mob.playAnimation(Animation(CONSUME_ANIMATION_ID)) wait(consumable.delay) + stop() } } diff --git a/game/plugin/dummy/src/dummy.plugin.kts b/game/plugin/dummy/src/dummy.plugin.kts index ac7e90795..1730ff809 100644 --- a/game/plugin/dummy/src/dummy.plugin.kts +++ b/game/plugin/dummy/src/dummy.plugin.kts @@ -66,6 +66,8 @@ class DummyAction(val player: Player, position: Position) : AsyncDistancedAction } else { skills.addExperience(Skill.ATTACK, EXP_PER_HIT) } + + stop() } } From 112b8aab5708b7c33d18692d9b53c03ef8766d9b Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 04:26:19 +0100 Subject: [PATCH 060/209] Add basic detekt configuration --- game/plugin/build.gradle | 42 ++++- game/plugin/detekt.yml | 325 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 game/plugin/detekt.yml diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index 7cb4bb8df..74cfb889a 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,6 +1,35 @@ -subprojects { - if (it.buildFile.exists()) { +buildscript { + repositories { + jcenter() + mavenCentral() + + maven { url "https://plugins.gradle.org/m2/" } + } + + dependencies { + classpath "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0.RC4-3" + } +} + +def detektConfig = "${project.projectDir}/detekt.yml" + +subprojects { subproj -> + if (subproj.buildFile.exists()) { apply plugin: 'apollo-plugin' + apply plugin: 'io.gitlab.arturbosch.detekt' + + buildscript { + repositories { + jcenter() + mavenCentral() + + maven { url "https://plugins.gradle.org/m2/" } + } + + dependencies { + classpath "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0.RC4-3" + } + } repositories { mavenCentral() @@ -8,5 +37,14 @@ subprojects { url { 'https://dl.bintray.com/kotlin/kotlinx/' } } } + + detekt { + version = "1.0.0.RC4-3" + + profile("main") { + input = "${subproj.projectDir}/src" + config = detektConfig + } + } } } diff --git a/game/plugin/detekt.yml b/game/plugin/detekt.yml new file mode 100644 index 000000000..0872ae9dc --- /dev/null +++ b/game/plugin/detekt.yml @@ -0,0 +1,325 @@ +autoCorrect: true +failFast: false + +build: + warningThreshold: 5 + failThreshold: 10 + weights: + complexity: 2 + formatting: 1 + LongParameterList: 1 + comments: 1 + +processors: + active: true + exclude: + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ClassCountProcessor' + # - 'PackageCountProcessor' + # - 'KtFileCountProcessor' + +console-reports: + active: true + exclude: + # - 'ProjectStatisticsReport' + # - 'ComplexityReport' + # - 'NotificationReport' + # - 'FindingsReport' + # - 'BuildFailureReport' + +output-reports: + active: true + exclude: + # - 'PlainOutputReport' + # - 'XmlOutputReport' + +potential-bugs: + active: true + DuplicateCaseInWhenExpression: + active: true + EqualsAlwaysReturnsTrueOrFalse: + active: false + EqualsWithHashCodeExist: + active: true + WrongEqualsTypeParameter: + active: false + ExplicitGarbageCollectionCall: + active: true + UnreachableCode: + active: true + LateinitUsage: + active: false + UnsafeCallOnNullableType: + active: false + UnsafeCast: + active: false + UselessPostfixExpression: + active: false + +performance: + active: true + ForEachOnRange: + active: true + SpreadOperator: + active: true + UnnecessaryTemporaryInstantiation: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: false + methodNames: 'toString,hashCode,equals,finalize' + SwallowedException: + active: false + TooGenericExceptionCaught: + active: true + exceptions: + - ArrayIndexOutOfBoundsException + - Error + - Exception + - IllegalMonitorStateException + - IndexOutOfBoundsException + - InterruptedException + - NullPointerException + - RuntimeException + TooGenericExceptionThrown: + active: true + exceptions: + - Throwable + - ThrowError + - ThrowException + - ThrowNullPointerException + - ThrowRuntimeException + - ThrowThrowable + InstanceOfCheckForException: + active: false + IteratorNotThrowingNoSuchElementException: + active: false + PrintExceptionStackTrace: + active: false + RethrowCaughtException: + active: false + ReturnFromFinally: + active: false + ThrowingExceptionFromFinally: + active: false + ThrowingExceptionInMain: + active: false + ThrowingNewInstanceOfSameException: + active: false + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptySecondaryConstructor: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +complexity: + active: true + LongMethod: + threshold: 20 + LongParameterList: + threshold: 5 + LargeClass: + threshold: 150 + ComplexMethod: + threshold: 10 + TooManyFunctions: + threshold: 10 + ComplexCondition: + threshold: 3 + LabeledExpression: + active: false + StringLiteralDuplication: + active: false + threshold: 2 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + +code-smell: + active: true + FeatureEnvy: + threshold: 0.5 + weight: 0.45 + base: 0.5 + +formatting: + active: true + useTabs: true + Indentation: + active: false + indentSize: 4 + ConsecutiveBlankLines: + active: true + autoCorrect: true + MultipleSpaces: + active: true + autoCorrect: true + SpacingAfterComma: + active: true + autoCorrect: true + SpacingAfterKeyword: + active: true + autoCorrect: true + SpacingAroundColon: + active: true + autoCorrect: true + SpacingAroundCurlyBraces: + active: true + autoCorrect: true + SpacingAroundOperator: + active: true + autoCorrect: true + TrailingSpaces: + active: true + autoCorrect: true + UnusedImports: + active: true + autoCorrect: true + OptionalSemicolon: + active: true + autoCorrect: true + OptionalUnit: + active: true + autoCorrect: true + ExpressionBodySyntax: + active: false + autoCorrect: false + ExpressionBodySyntaxLineBreaks: + active: false + autoCorrect: false + OptionalReturnKeyword: + active: true + autoCorrect: false + +style: + active: true + ReturnCount: + active: true + max: 2 + NewLineAtEndOfFile: + active: true + OptionalAbstractKeyword: + active: true + OptionalWhenBraces: + active: false + EqualsNullCall: + active: false + ForbiddenComment: + active: true + values: 'TODO:,FIXME:,STOPSHIP:' + ForbiddenImport: + active: false + imports: '' + PackageDeclarationStyle: + active: false + ModifierOrder: + active: true + MagicNumber: + active: true + ignoreNumbers: '-1,0,1,2' + ignoreHashCodeFunction: false + ignorePropertyDeclaration: false + ignoreAnnotation: false + WildcardImport: + active: true + SafeCast: + active: true + MaxLineLength: + active: true + maxLineLength: 120 + excludePackageStatements: false + excludeImportStatements: false + PackageNaming: + active: true + packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$' + ClassNaming: + active: true + classPattern: '[A-Z$][a-zA-Z$]*' + EnumNaming: + active: true + enumEntryPattern: '^[A-Z$][a-zA-Z_$]*$' + FunctionNaming: + active: true + functionPattern: '^[a-z$][a-zA-Z$0-9]*$' + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + VariableNaming: + active: true + variablePattern: '^(_)?[a-z$][a-zA-Z$0-9]*$' + ConstantNaming: + active: true + constantPattern: '^([A-Z_]*|serialVersionUID)$' + VariableMaxLength: + active: false + maximumVariableNameLength: 30 + VariableMinLength: + active: false + minimumVariableNameLength: 3 + ForbiddenClassName: + active: false + forbiddenName: '' + ProtectedMemberInFinalClass: + active: false + UnnecessaryParentheses: + active: false + DataClassContainsFunctions: + active: false + UseDataClass: + active: false + UnnecessaryAbstractClass: + active: false + +comments: + active: true + CommentOverPrivateMethod: + active: true + CommentOverPrivateProperty: + active: true + UndocumentedPublicClass: + active: false + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + UndocumentedPublicFunction: + active: false + +# *experimental feature* +# Migration rules can be defined in the same config file or a new one +migration: + active: true + imports: + # your.package.Class: new.package.or.Class + # for example: + # io.gitlab.arturbosch.detekt.api.Rule: io.gitlab.arturbosch.detekt.rule.Rule From 89516dab636f40fca5cba7be349a839aa3c91ba4 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 18:42:19 +0100 Subject: [PATCH 061/209] Rewrite package names in compiled script files --- buildSrc/build.gradle | 1 + .../build/plugin/ApolloPluginExtension.groovy | 1 - .../KotlinCompilerConfigurationFactory.groovy | 5 +-- .../plugin/compiler/KotlinScriptBinary.groovy | 20 +++++++--- .../KotlinScriptBinaryArtifactRemapper.groovy | 39 +++++++++++++++++++ .../compiler/KotlinScriptCompiler.groovy | 14 +++---- .../tasks/ApolloScriptCompileTask.groovy | 26 ++++++++++++- 7 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index fe67c4349..404e3214c 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -20,6 +20,7 @@ repositories { dependencies { compile gradleApi() + compile group: 'org.ow2.asm', name: 'asm-all', version: '5.0.3' compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" } \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy index 796534cc3..ea4c910e4 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -109,7 +109,6 @@ class ApolloPluginExtension { compileClasspath = mainSources.compileClasspath + mainSources.runtimeClasspath + mainSources.output scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript" - mustRunAfter buildTask } diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy index 2be6e28b6..04ce01789 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy @@ -41,11 +41,10 @@ class KotlinCompilerConfigurationFactory { classpath.addAll(bootClasspath.split(File.pathSeparatorChar.toString()).collect { new File(it) }) } - - def classLoader = new URLClassLoader(classpath.collect { it.toURL() }.toArray(new URL[classpath.size()])) + def classpathFiles = classpath.findAll { it.exists() } + def classLoader = new URLClassLoader(classpathFiles.collect { it.toURL() }.toArray(new URL[classpath.size()])) def configuration = new CompilerConfiguration() def scriptDefinitionClass = classLoader.loadClass(scriptDefinitionClassName) - def classpathFiles = classpath.collect { it } def scriptDefinition = new KotlinScriptDefinitionFromAnnotatedTemplate(JvmClassMappingKt.getKotlinClass(scriptDefinitionClass), null, null, null, classpathFiles) diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy index e4df437d3..398ed251b 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy @@ -2,12 +2,22 @@ package org.apollo.build.plugin.compiler import java.nio.file.Path +class KotlinScriptBinaryArtifact { + final String relativePath + final byte[] data + + KotlinScriptBinaryArtifact(String relativePath, byte[] data) { + this.relativePath = relativePath + this.data = data + } +} + class KotlinScriptBinary { - final String fullyQualifiedName - final Path output + final String mainClassName + final List artifacts - KotlinScriptBinary(String fullyQualifiedName, Path output) { - this.output = output - this.fullyQualifiedName = fullyQualifiedName + KotlinScriptBinary(String mainClassName, List artifacts) { + this.mainClassName = mainClassName + this.artifacts = artifacts } } diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy new file mode 100644 index 000000000..7216c1ba0 --- /dev/null +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy @@ -0,0 +1,39 @@ +package org.apollo.build.plugin.compiler + +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.commons.Remapper +import org.objectweb.asm.commons.RemappingClassAdapter + +class KotlinScriptBinaryArtifactRemapper { + String mainClassName + + KotlinScriptBinaryArtifactRemapper(String mainClassName) { + this.mainClassName = mainClassName + } + + KotlinScriptBinaryArtifact remapToPackage(KotlinScriptBinaryArtifact artifact, String packageName) { + def reader = new ClassReader(new ByteArrayInputStream(artifact.data)) + def writer = new ClassWriter(0) + def normalizedPackageName = packageName.replace('.', '/') + def oldClassName = reader.getClassName() + def newClassName = artifact.relativePath.replace(oldClassName, "$normalizedPackageName/$oldClassName") + + def remapper = new Remapper() { + @Override + String map(String typeName) { + if (typeName.equals(mainClassName) || typeName.startsWith("$mainClassName\$")) { + return "$normalizedPackageName/$typeName" + } + + return super.map(typeName); + } + } + + def remappingAdapter = new RemappingClassAdapter(writer, remapper) + reader.accept(remappingAdapter, ClassReader.EXPAND_FRAMES) + writer.visitEnd() + + return new KotlinScriptBinaryArtifact(newClassName, writer.toByteArray()) + } +} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy index 20f510d26..98a1716c9 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy @@ -5,13 +5,12 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer +import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.java.PsiPackageStatementImpl import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.KotlinSourceRoot -import java.nio.file.Files import java.nio.file.Path -import java.nio.file.StandardOpenOption class KotlinScriptCompiler { private String scriptDefinitionClass @@ -24,7 +23,7 @@ class KotlinScriptCompiler { this.messageCollector = messageCollector } - KotlinScriptBinary compile(Path input, Path output) { + KotlinScriptBinary compile(Path input) { def compilerConfiguration = KotlinCompilerConfigurationFactory.create( scriptDefinitionClass, classpath, @@ -34,7 +33,6 @@ class KotlinScriptCompiler { def rootDisposable = Disposer.newDisposable() def configuration = compilerConfiguration.copy() - output.toFile().mkdirs() configuration.put(CommonConfigurationKeys.MODULE_NAME, input.toString()) configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, new KotlinSourceRoot(input.toAbsolutePath().toString())) @@ -50,6 +48,7 @@ class KotlinScriptCompiler { def sourceFiles = environment.getSourceFiles() def script = sourceFiles[0].script + if (script == null) { throw new KotlinScriptCompilerException("Main source file is not a script") } @@ -61,11 +60,10 @@ class KotlinScriptCompiler { throw new KotlinScriptCompilerException("Unable to find compiled plugin class file $scriptFilePath") } - generationState.factory.asList().forEach { - Files.write(output.resolve(it.relativePath), it.asByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING) - } + def outputs = generationState.factory.asList() + def artifacts = outputs.collect { new KotlinScriptBinaryArtifact(it.relativePath, it.asByteArray()) } - return new KotlinScriptBinary(script.fqName.asString(), output.resolve(scriptFileClass.relativePath)) + return new KotlinScriptBinary(script.fqName.asString(), artifacts) } catch (ex) { throw new KotlinScriptCompilerException("Compilation failed", ex) } finally { diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy index 0092fa060..d1e06c122 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy @@ -1,5 +1,7 @@ package org.apollo.build.plugin.tasks +import org.apollo.build.plugin.ApolloPluginExtension +import org.apollo.build.plugin.compiler.KotlinScriptBinaryArtifactRemapper import org.apollo.build.plugin.compiler.KotlinScriptCompiler import org.gradle.api.DefaultTask import org.gradle.api.file.FileCollection @@ -10,6 +12,9 @@ import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector +import java.nio.file.Files +import java.nio.file.StandardOpenOption + class ApolloScriptCompileTask extends DefaultTask { @OutputDirectory File outputsDir @@ -22,6 +27,9 @@ class ApolloScriptCompileTask extends DefaultTask { @TaskAction def execute(IncrementalTaskInputs inputs) { + def extension = getProject().getExtensions().getByType(ApolloPluginExtension.class); + def packageName = extension.packageName + if (scriptDefinitionClass == null) { throw new Exception("No script definition class given") } @@ -34,9 +42,25 @@ class ApolloScriptCompileTask extends DefaultTask { def messageCollector = new PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, true); def compiler = new KotlinScriptCompiler(scriptDefinitionClass, classpath, messageCollector) + outputsDir.mkdirs() + inputs.outOfDate { removeBinariesFor(it.file) - compiler.compile(it.file.toPath(), outputsDir.toPath()) + + def binary = compiler.compile(it.file.toPath()) + def binaryArtifactRemapper = new KotlinScriptBinaryArtifactRemapper(binary.mainClassName) + def artifacts = binary.artifacts.collect { binaryArtifactRemapper.remapToPackage(it, packageName) } + + artifacts.each { + def artifactOutput = outputsDir.toPath().resolve(it.relativePath) + + Files.createDirectories(artifactOutput.getParent()) + Files.write(artifactOutput, it.data, + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.TRUNCATE_EXISTING + ) + } } inputs.removed { From 1f33619ac686f9b81772576d3954276498ecce79 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 19:36:58 +0100 Subject: [PATCH 062/209] Add source information to remapped scripts --- .../KotlinCompilerConfigurationFactory.groovy | 7 +++---- .../KotlinScriptBinaryArtifactRemapper.groovy | 15 +++++++++++---- .../plugin/tasks/ApolloScriptCompileTask.groovy | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy index 04ce01789..3da38f157 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy @@ -41,17 +41,16 @@ class KotlinCompilerConfigurationFactory { classpath.addAll(bootClasspath.split(File.pathSeparatorChar.toString()).collect { new File(it) }) } - def classpathFiles = classpath.findAll { it.exists() } - def classLoader = new URLClassLoader(classpathFiles.collect { it.toURL() }.toArray(new URL[classpath.size()])) + def classLoader = new URLClassLoader(classpath.collect { it.toURL() }.toArray(new URL[classpath.size()])) def configuration = new CompilerConfiguration() def scriptDefinitionClass = classLoader.loadClass(scriptDefinitionClassName) def scriptDefinition = new KotlinScriptDefinitionFromAnnotatedTemplate(JvmClassMappingKt.getKotlinClass(scriptDefinitionClass), - null, null, null, classpathFiles) + null, null, null, classpath.collect()) configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.collect { new JvmClasspathRoot(it) }) - configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) + configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false) configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) configuration.copy() diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy index 7216c1ba0..ffaae9519 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy @@ -4,17 +4,23 @@ import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter import org.objectweb.asm.commons.Remapper import org.objectweb.asm.commons.RemappingClassAdapter +import org.objectweb.asm.tree.ClassNode class KotlinScriptBinaryArtifactRemapper { - String mainClassName + final String originalSourceFileName + final String mainClassName - KotlinScriptBinaryArtifactRemapper(String mainClassName) { + KotlinScriptBinaryArtifactRemapper(String originalSourceFileName, String mainClassName) { + this.originalSourceFileName = originalSourceFileName this.mainClassName = mainClassName } KotlinScriptBinaryArtifact remapToPackage(KotlinScriptBinaryArtifact artifact, String packageName) { - def reader = new ClassReader(new ByteArrayInputStream(artifact.data)) + def node = new ClassNode() def writer = new ClassWriter(0) + def reader = new ClassReader(new ByteArrayInputStream(artifact.data)) + reader.accept(node, ClassReader.EXPAND_FRAMES) + def normalizedPackageName = packageName.replace('.', '/') def oldClassName = reader.getClassName() def newClassName = artifact.relativePath.replace(oldClassName, "$normalizedPackageName/$oldClassName") @@ -31,7 +37,8 @@ class KotlinScriptBinaryArtifactRemapper { } def remappingAdapter = new RemappingClassAdapter(writer, remapper) - reader.accept(remappingAdapter, ClassReader.EXPAND_FRAMES) + node.accept(remappingAdapter) + writer.visitSource(originalSourceFileName, null) writer.visitEnd() return new KotlinScriptBinaryArtifact(newClassName, writer.toByteArray()) diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy index d1e06c122..df5904101 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy @@ -48,7 +48,7 @@ class ApolloScriptCompileTask extends DefaultTask { removeBinariesFor(it.file) def binary = compiler.compile(it.file.toPath()) - def binaryArtifactRemapper = new KotlinScriptBinaryArtifactRemapper(binary.mainClassName) + def binaryArtifactRemapper = new KotlinScriptBinaryArtifactRemapper(it.file.name, binary.mainClassName) def artifacts = binary.artifacts.collect { binaryArtifactRemapper.remapToPackage(it, packageName) } artifacts.each { From 8a3decfc54af1ec8d2c9ce77e2c401c161981ff8 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 19:37:14 +0100 Subject: [PATCH 063/209] Enable experimental coroutines for all kotlin projects --- game/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/game/build.gradle b/game/build.gradle index cb8af5e78..eae4f98ff 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -20,6 +20,12 @@ sourceSets { } } +allprojects { + it.plugins.withId('kotlin') { + kotlin { experimental { coroutines 'enable' } } + } +} + dependencies { compile project(':cache') compile project(':net') From 169d89ffc0e3c3589730c1d051c38157854434fd Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 17 Sep 2017 20:27:50 +0100 Subject: [PATCH 064/209] Clear static object REMOVE messages when re-adding --- .../src/org/apollo/game/plugins/api/world.kt | 2 +- .../org/apollo/game/model/area/Region.java | 20 +++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/world.kt b/game/plugin/api/src/org/apollo/game/plugins/api/world.kt index 5a550879f..8d77ce1ca 100644 --- a/game/plugin/api/src/org/apollo/game/plugins/api/world.kt +++ b/game/plugin/api/src/org/apollo/game/plugins/api/world.kt @@ -46,7 +46,7 @@ class ExpireObjectTask( respawning = true setDelay(respawnDelay) } else { - region.removeEntity(replacement, false) + region.removeEntity(replacement) world.spawn(obj) stop() } diff --git a/game/src/main/java/org/apollo/game/model/area/Region.java b/game/src/main/java/org/apollo/game/model/area/Region.java index e5150d45b..df7a9a170 100644 --- a/game/src/main/java/org/apollo/game/model/area/Region.java +++ b/game/src/main/java/org/apollo/game/model/area/Region.java @@ -334,23 +334,13 @@ public void notifyListeners(Entity entity, EntityUpdateType type) { listeners.forEach(listener -> listener.execute(this, entity, type)); } - /** - * Removes an {@link Entity} from this Region and notifies listeners. - * - * @param entity The Entity. - * @throws IllegalArgumentException If the Entity does not belong in this Region, or if it was never added. - */ - public void removeEntity(Entity entity) { - removeEntity(entity, true); - } - /** * Removes an {@link Entity} from this Region. * * @param entity The Entity. * @throws IllegalArgumentException If the Entity does not belong in this Region, or if it was never added. */ - public void removeEntity(Entity entity, boolean notifyListeners) { + public void removeEntity(Entity entity) { EntityType type = entity.getEntityType(); if (type.isTransient()) { throw new IllegalArgumentException("Tried to remove a transient Entity (" + entity + ") from " + @@ -366,9 +356,7 @@ public void removeEntity(Entity entity, boolean notifyListeners) { throw new IllegalArgumentException("Entity (" + entity + ") belongs in (" + this + ") but does not exist."); } - if (notifyListeners) { - notifyListeners(entity, EntityUpdateType.REMOVE); - } + notifyListeners(entity, EntityUpdateType.REMOVE); } @Override @@ -425,7 +413,9 @@ private void record(T entity, EntityUpdateT } else { // TODO should this really be possible? removedObjects.get(height).remove(inverse); } - } else if (update == EntityUpdateType.REMOVE && !type.isTransient()) { + } + + if (update == EntityUpdateType.REMOVE && !type.isTransient()) { updates.remove(inverse); } From 76dd8ba192b2ed8293a868429634635aafe10c53 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 19 Sep 2017 01:52:10 +0100 Subject: [PATCH 065/209] Refactor asynchronous actions to avoid thread usage Adds custom coroutines specifically for use within Actions. This implements all features of the previous system, however, does not rely on a separate executor to wake up continuations. Note: since Actions are still ran by an executor and a small chance of overlap exists the ActionCoroutine implementation uses atomic counters and references. --- .../consumables/src/consumables.plugin.kts | 3 +- game/plugin/dummy/src/dummy.plugin.kts | 7 +- .../skills/mining/src/mining.plugin.kts | 11 +- .../org/apollo/game/action/ActionCoroutine.kt | 139 ++++++++++++++++++ .../org/apollo/game/action/AsyncAction.kt | 18 +-- .../apollo/game/action/AsyncActionRunner.kt | 69 --------- .../apollo/game/action/AsyncActionTrait.kt | 26 +++- .../game/action/AsyncDistancedAction.kt | 30 +--- .../apollo/game/action/ActionCoroutineTest.kt | 39 +++++ 9 files changed, 220 insertions(+), 122 deletions(-) create mode 100644 game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt delete mode 100644 game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt create mode 100644 game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt diff --git a/game/plugin/consumables/src/consumables.plugin.kts b/game/plugin/consumables/src/consumables.plugin.kts index 4624be019..c633e9002 100644 --- a/game/plugin/consumables/src/consumables.plugin.kts +++ b/game/plugin/consumables/src/consumables.plugin.kts @@ -1,3 +1,4 @@ +import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncAction import org.apollo.game.message.impl.ItemOptionMessage import org.apollo.game.model.Animation @@ -27,7 +28,7 @@ class ConsumeAction(val consumable: Consumable, player: Player, val slot: Int) : } } - suspend override fun executeActionAsync() { + override fun action(): ActionBlock = { consumable.consume(mob, slot) mob.playAnimation(Animation(CONSUME_ANIMATION_ID)) wait(consumable.delay) diff --git a/game/plugin/dummy/src/dummy.plugin.kts b/game/plugin/dummy/src/dummy.plugin.kts index 1730ff809..f02507b12 100644 --- a/game/plugin/dummy/src/dummy.plugin.kts +++ b/game/plugin/dummy/src/dummy.plugin.kts @@ -1,6 +1,7 @@ import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.selects.select +import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.action.DistancedAction import org.apollo.game.message.impl.ObjectActionMessage @@ -53,9 +54,9 @@ class DummyAction(val player: Player, position: Position) : AsyncDistancedAction } - override suspend fun executeActionAsync() { + override fun action(): ActionBlock = { mob.sendMessage("You hit the dummy.") - mob.turnTo(this.position) + mob.turnTo(position) mob.playAnimation(PUNCH_ANIMATION) wait() @@ -66,8 +67,6 @@ class DummyAction(val player: Player, position: Position) : AsyncDistancedAction } else { skills.addExperience(Skill.ATTACK, EXP_PER_HIT) } - - stop() } } diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index f44020b96..22c9652ca 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -1,3 +1,4 @@ +import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.action.DistancedAction import org.apollo.game.message.impl.ObjectActionMessage @@ -68,18 +69,15 @@ class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) } } - override fun start() { + override fun action() : ActionBlock = { mob.turnTo(position) val level = mob.skills.mining.currentLevel - if (level < target.ore.level) { mob.sendMessage("You do not have the required level to mine this rock.") stop() } - } - override suspend fun executeActionAsync() { mob.sendMessage("You swing your pick at the rock.") mob.playAnimation(tool.animation) @@ -88,14 +86,12 @@ class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) val obj = target.getObject(mob.world) if (!obj.isPresent) { stop() - return } if (target.isSuccessful(mob)) { if (mob.inventory.freeSlots() == 0) { mob.inventory.forceCapacityExceeded() stop() - return } if (mob.inventory.add(target.ore.id)) { @@ -105,7 +101,6 @@ class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) mob.skills.addExperience(Skill.MINING, target.ore.exp) mob.world.expireObject(obj.get(), target.ore.objects[target.objectId]!!, target.ore.respawn) stop() - return } } } @@ -142,7 +137,7 @@ class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : AsyncDis } } - suspend override fun executeActionAsync() { + override fun action() : ActionBlock = { mob.sendMessage("You examine the rock for ores...") mob.turnTo(position) diff --git a/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt new file mode 100644 index 000000000..1087142b7 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt @@ -0,0 +1,139 @@ +package org.apollo.game.action + +import kotlinx.coroutines.experimental.suspendCancellableCoroutine +import java.util.concurrent.CancellationException +import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.atomic.AtomicReference +import kotlin.coroutines.experimental.Continuation +import kotlin.coroutines.experimental.CoroutineContext +import kotlin.coroutines.experimental.EmptyCoroutineContext +import kotlin.coroutines.experimental.RestrictsSuspension +import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED +import kotlin.coroutines.experimental.intrinsics.createCoroutineUnchecked +import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn + +typealias ActionPredicate = () -> Boolean +typealias ActionBlock = suspend ActionCoroutine.() -> Unit + +interface ActionCoroutineCondition { + /** + * Called once every tick to check if `Continuation` associated with this condition should be resumed. + */ + fun resume(): Boolean +} + +/** + * A continuation condition that waits on a given number of pulses. + */ +class AwaitPulses(pulses: Int) : ActionCoroutineCondition { + val remainingPulses: AtomicInteger = AtomicInteger(pulses) + + override fun resume(): Boolean { + return remainingPulses.decrementAndGet() <= 0 + } +} + +/** + * A continuation condition that waits until a predicate is fufilled. + */ +class AwaitPredicate(val predicate: ActionPredicate) : ActionCoroutineCondition { + override fun resume(): Boolean { + return predicate.invoke() + } +} + +/** + * A suspend point in an `ActionCoroutine` that has its `continuation` resumed whenever the `condition` evaluates + * to `true`. + */ +data class ActionCoroutineStep(val condition: ActionCoroutineCondition, internal val continuation: Continuation) + +@RestrictsSuspension +class ActionCoroutine : Continuation { + companion object { + /** + * Create a new `ActionCoroutine` and immediately execute the given `block`, returning a continuation that + * can be resumed. + */ + fun start(block: ActionBlock) : ActionCoroutine { + val coroutine = ActionCoroutine() + val continuation = block.createCoroutineUnchecked(coroutine, coroutine) + + coroutine.resumeContinuation(continuation) + + return coroutine + } + } + + override val context: CoroutineContext = EmptyCoroutineContext + override fun resume(value: Unit) {} + override fun resumeWithException(exception: Throwable) = throw exception + + private fun resumeContinuation(continuation: Continuation, allowCancellation: Boolean = true) { + try { + continuation.resume(Unit) + } catch (ex: CancellationException) { + if (!allowCancellation) { + throw ex + } + } + } + + /** + * The next `step` in this `ActionCoroutine` saved as a resume point. + */ + private var next = AtomicReference() + + /** + * Check if this continuation has no more steps to execute. + */ + fun stopped(): Boolean { + return next.get() == null + } + + /** + * Update this continuation and check if the condition for the next step to be resumed is satisfied. + */ + fun pulse() { + val nextStep = next.getAndSet(null) + if (nextStep == null) { + return + } + + val condition = nextStep.condition + val continuation = nextStep.continuation + + if (condition.resume()) { + resumeContinuation(continuation) + } else { + next.compareAndSet(null, nextStep) + } + } + + private suspend fun awaitCondition(condition: ActionCoroutineCondition) { + return suspendCoroutineOrReturn { cont -> + next.compareAndSet(null, ActionCoroutineStep(condition, cont)) + COROUTINE_SUSPENDED + } + } + + /** + * Stop execution of this continuation. + */ + suspend fun stop() { + return suspendCancellableCoroutine(true) { cont -> + next.set(null) + cont.cancel() + } + } + + /** + * Wait `pulses` game updates before resuming this continuation. + */ + suspend fun wait(pulses: Int = 1) = awaitCondition(AwaitPulses(pulses)) + + /** + * Wait until the `predicate` returns `true` before resuming this continuation. + */ + suspend fun wait(predicate: ActionPredicate) = awaitCondition(AwaitPredicate(predicate)) +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt index abf85dc8c..e8df401d2 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncAction.kt @@ -3,24 +3,14 @@ package org.apollo.game.action import org.apollo.game.model.entity.Mob abstract class AsyncAction : Action, AsyncActionTrait { - override val runner: AsyncActionRunner - constructor(delay: Int, immediate: Boolean, mob: T) : super(delay, immediate, mob) { - this.runner = AsyncActionRunner({ this }, { executeActionAsync() }) - } + override var continuation: ActionCoroutine? = null - abstract suspend fun executeActionAsync() + constructor(delay: Int, immediate: Boolean, mob: T) : super(delay, immediate, mob) override fun execute() { - if (!runner.started()) { - runner.start() + if (update()) { + stop() } - - runner.pulse() - } - - override fun stop() { - super.stop() - runner.stop() } } \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt deleted file mode 100644 index 5288abc27..000000000 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncActionRunner.kt +++ /dev/null @@ -1,69 +0,0 @@ -package org.apollo.game.action - -import kotlinx.coroutines.experimental.CommonPool -import kotlinx.coroutines.experimental.Job -import kotlinx.coroutines.experimental.channels.Channel -import kotlinx.coroutines.experimental.launch -import kotlinx.coroutines.experimental.runBlocking - -class AsyncActionRunner(val actionSupplier: () -> Action<*>, val callback: suspend () -> Unit) { - var job: Job? = null - var pulseChannel = Channel(1) - var unsentPulses = 0 - - fun pulse() { - if (pulseChannel.offer(unsentPulses + 1)) { - unsentPulses = 0 - } else { - unsentPulses++ - } - } - - fun start() { - if (job != null) { - return - } - - val action = actionSupplier.invoke() - - job = launch(CommonPool) { - run { - while (action.isRunning) { - pulseChannel.receive() - callback() - } - } - } - } - - fun started(): Boolean { - return job != null - } - - fun stop() { - job?.cancel() - pulseChannel.close() - } - - suspend fun wait(pulses: Int = 1, pulseCallback: (() -> Unit)? = null) { - var remainingPulses = pulses - - while (remainingPulses > 0) { - val numPulses = pulseChannel.receive() - remainingPulses -= numPulses - - pulseCallback?.invoke() - } - } - - suspend fun await(condition: () -> Boolean, timeout: Int = 15) { - var remainingPulsesBeforeTimeout = timeout - - while (!condition.invoke()) { - remainingPulsesBeforeTimeout -= pulseChannel.receive() - if (remainingPulsesBeforeTimeout <= 0) { - break - } - } - } -} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt index 7ad1a973c..55a02aefd 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt @@ -1,9 +1,29 @@ package org.apollo.game.action interface AsyncActionTrait { - val runner: AsyncActionRunner + /** + * The continuation that this `Action` is executing. May be `null` if this action hasn't started yet. + */ + abstract var continuation: ActionCoroutine? - suspend fun wait(pulses: Int = 1, pulseCallback: (() -> Unit)? = null) { - runner.wait(pulses, pulseCallback) + /** + * Update this action, initializing the continuation if not already initialized. + * + * @return `true` if this `Action` has completed execution. + */ + fun update(): Boolean { + val continuation = this.continuation + if (continuation == null) { + this.continuation = ActionCoroutine.start(action()) + return false + } + + continuation.pulse() + return continuation.stopped() } + + /** + * Create a new `ActionBlock` to execute. + */ + fun action() : ActionBlock } \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt index 343b2fd3a..761714d00 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt @@ -3,36 +3,20 @@ package org.apollo.game.action import org.apollo.game.model.Position import org.apollo.game.model.entity.Mob +/** + * A `DistancedAction` that uses `ActionCoroutine`s to run asynchronously. + */ abstract class AsyncDistancedAction : DistancedAction, AsyncActionTrait { - override val runner: AsyncActionRunner + override var continuation: ActionCoroutine? = null constructor(delay: Int, immediate: Boolean, mob: T, position: Position, distance: Int) : - super(delay, immediate, mob, position, distance) { - - this.runner = AsyncActionRunner({ this }, { executeActionAsync() }) - } - - abstract suspend fun executeActionAsync() - - open protected fun start() { - - } - - override fun stop() { - super.stop() - runner.stop() - } + super(delay, immediate, mob, position, distance) override fun executeAction() { - start() - - if (!runner.started()) { - runner.start() + if (update()) { + stop() } - - runner.pulse() } - } diff --git a/game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt b/game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt new file mode 100644 index 000000000..4b6df03d7 --- /dev/null +++ b/game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt @@ -0,0 +1,39 @@ +package org.apollo.game.action + +import org.apollo.game.action.ActionCoroutine +import org.junit.Assert.* +import org.junit.Test + +class ActionCoroutineTest { + @Test + fun `Coroutine execution resumes after a pulse() call`() { + val coroutine = ActionCoroutine.start { + wait(1) + } + + coroutine.pulse() + assertTrue(coroutine.stopped()) + } + + @Test + fun `Coroutine suspends on wait() calls`() { + val coroutine = ActionCoroutine.start { + wait(1) + } + + // Check that the continuation is still waiting on a pulse. + assertFalse(coroutine.stopped()) + } + + @Test + fun `Coroutine cancels on stop() calls`() { + val coroutine = ActionCoroutine.start { + stop() + wait(1) + } + + assertTrue(coroutine.stopped()) + coroutine.pulse() + assertTrue(coroutine.stopped()) + } +} \ No newline at end of file From 3e6415f0d23543e3ac5ec23c2d5a2802f90fecc6 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Sat, 16 Sep 2017 20:31:53 -0700 Subject: [PATCH 066/209] Initial commit on new woodcutting branch --- game/plugin/skills/woodcutting/build.gradle | 7 + game/plugin/skills/woodcutting/meta.toml | 9 + game/plugin/skills/woodcutting/src/axe.kt | 23 +++ game/plugin/skills/woodcutting/src/wood.kt | 85 +++++++++ .../woodcutting/src/woodcutting.plugin.kts | 163 ++++++++++++++++++ 5 files changed, 287 insertions(+) create mode 100644 game/plugin/skills/woodcutting/build.gradle create mode 100644 game/plugin/skills/woodcutting/meta.toml create mode 100644 game/plugin/skills/woodcutting/src/axe.kt create mode 100644 game/plugin/skills/woodcutting/src/wood.kt create mode 100644 game/plugin/skills/woodcutting/src/woodcutting.plugin.kts diff --git a/game/plugin/skills/woodcutting/build.gradle b/game/plugin/skills/woodcutting/build.gradle new file mode 100644 index 000000000..886112d70 --- /dev/null +++ b/game/plugin/skills/woodcutting/build.gradle @@ -0,0 +1,7 @@ +plugin { + name = "woodcutting_skill" + packageName = "org.apollo.game.plugin.skills.woodcutting" + authors = [ + "tlf30" + ] +} \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/meta.toml b/game/plugin/skills/woodcutting/meta.toml new file mode 100644 index 000000000..c490c7118 --- /dev/null +++ b/game/plugin/skills/woodcutting/meta.toml @@ -0,0 +1,9 @@ +name = "woodcutting-skill" +package = "org.apollo.game.plugin.skills.woodcutting" +authors = [ + "tlf30" + ] + +[config] +srcDir = "src/" +testDir = "test/" diff --git a/game/plugin/skills/woodcutting/src/axe.kt b/game/plugin/skills/woodcutting/src/axe.kt new file mode 100644 index 000000000..ae3e11a7b --- /dev/null +++ b/game/plugin/skills/woodcutting/src/axe.kt @@ -0,0 +1,23 @@ +package org.apollo.game.plugin.skills.mining + +import org.apollo.game.model.Animation; + +//Animation IDs: https://www.rune-server.ee/runescape-development/rs2-client/configuration/272373-emote-gfx-id-list.html +enum class Axe(val id: Int, val level: Int, val animation: Animation, val pulses: Int) { + RUNE(1359, 41, Animation(867), 3), + ADAMANT(1357, 31, Animation(869), 4), + MITHRIL(1355, 21, Animation(871), 5), + BLACK(1361, 11, Animation(873), 6), + STEEL(1353, 6, Animation(875), 6), + IRON(1349, 1, Animation(877), 7), + BRONZE(1351, 1, Animation(879), 8) +} + +val AXES = Axe.values() + +fun getAxes(): Array { + return AXES +} + +fun lookupPickaxe(id: Int): Axe? = AXES.find { it.id == id } + diff --git a/game/plugin/skills/woodcutting/src/wood.kt b/game/plugin/skills/woodcutting/src/wood.kt new file mode 100644 index 000000000..6201d8cd8 --- /dev/null +++ b/game/plugin/skills/woodcutting/src/wood.kt @@ -0,0 +1,85 @@ +package org.apollo.game.plugin.skills.mining + + +/** + * values thanks to: http://oldschoolrunescape.wikia.com/wiki/Woodcutting + */ +enum class Wood(val id: Int, val objects: IntArray, val stump: Int, val level: Int, val exp: Double, val chance: Double) { + NORMAL(1511, NORMAL_OBJECTS, NORMAL_STUMP, 1, 25.0, 100.0), + ACHEY(2862, ACHEY_OBJECTS, ACHEY_STUMP, 1, 25.0, 100.0), + OAK(1521, OAK_OBJECTS, OAK_STUMP, 15, 37.5, 0.125), + WILLOW(1519, WILLOW_OBJECTS, WILLOW_STUMP, 30, 67.5, 0.125), + TEAK(6333, TEAK_OBJECTS, TEAK_STUMP, 35, 85.0, 0.125), + MAPLE(1517, MAPLE_OBJECTS, MAPLE_STUMP, 45, 100.0, 0.125), + MAHOGANY(6332, MAHOGANY_OBJECTS, MAHOGANY_STUMP, 50, 125.0,0.125), + YEW(1515, YEW_OBJECTS, YEW_STUMP, 60, 175.0, 0.125), + MAGIC(1513, MAGIC_OBJECTS, MAGIC_STUMP, 75, 250.0, 0.125), +} + +val WOOD = Wood.values() + +fun lookupWood(id: Int): Wood? =WOOD.find { it.id == id } + +fun lookupTree(id: Int): Wood? { + for (wood in WOOD) { + for (tree in wood.objects) { + if (tree == id) { + return wood + } + } + } + return null +} + +val NORMAL_STUMP = 1342 +val ACHEY_STUMP = 3371 +val OAK_STUMP = 1342 +val WILLOW_STUMP = 1342 +val TEAK_STUMP = 1342 +val MAPLE_STUMP = 1342 +val MAHOGANY_STUMP = 1342 +val YEW_STUMP = 1342 +val MAGIC_STUMP = 1324 + +val NORMAL_OBJECTS = intArrayOf( + 1276, 1277, 1278, 1279, 1280, 1282, 1283, 1284, 1285, 1285, 1286, 1289, 1290, 1291, 1315, + 1316, 1318, 1330, 1331, 1332, 1365, 1383, 1384, 2409, 3033, 3034, 3035, 3036, 3881, 3882, + 3883, 5902, 5903, 5904, 10041 +) + +val ACHEY_OBJECTS = intArrayOf( + 2023 +) + +val OAK_OBJECTS = intArrayOf( + 1281, 3037 +) + +val WILLOW_OBJECTS = intArrayOf( + 5551, 5552, 5553 +) + +val TEAK_OBJECTS = intArrayOf( + 9036 +) + + +val MAPLE_OBJECTS = intArrayOf( + 1307, 4674 +) + +val MAHOGANY_OBJECTS = intArrayOf( + 9034 +) + + +val YEW_OBJECTS = intArrayOf( + 1309 +) + +val MAGIC_OBJECTS = intArrayOf( + 1292, 1306 +) + + + diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts new file mode 100644 index 000000000..8b5d0a48f --- /dev/null +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -0,0 +1,163 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Entity +import org.apollo.game.model.entity.EquipmentConstants +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.obj.StaticGameObject +import org.apollo.game.plugin.skills.mining.* +import org.apollo.game.scheduling.ScheduledTask +import java.util.* + +class WoodcuttingAction(val player: Player, val objectID: Int, val p: Position, val wood: Wood) : DistancedAction(PULSES, true, player, p, TREE_SIZE) { + + companion object { + private val PULSES = 0 + private val TREE_SIZE = 1; + } + + private var counter: Int = 0 + private var started: Boolean = false + private val rand: Random = Random() + + override fun executeAction() { + System.out.println("Cutting " + wood.id + " @ " + p) + val level = mob.skillSet.getSkill(Skill.WOODCUTTING).currentLevel + val axe = findAxe() + + + //check that our pick can mine the wood + if (axe == null || level < axe.level) { + mob.sendMessage("You do not have a axe for which you have the level to use.") + stop() + return + } + + //check that we can mine the wood + if (level < wood.level) { + mob.sendMessage("You do not have the required level to mine this rock.") + stop() + return + } + + //start the process of cutting + if (started) { + if (counter == 0) { + //Check inv capacity + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + stop() + return + } + if (mob.inventory.add(wood.id)) { + //TODO: Use lookup from utils once it has a lookup function for IDs + val woodName = ItemDefinition.lookup(wood.id).name.toLowerCase(); + mob.sendMessage("You managed to cut some " + woodName + ".") + mob.skillSet.addExperience(Skill.WOODCUTTING, wood.exp) + + } else { + System.out.println("Failed to add wood to inv"); + stop(); + return; + } + + if (!cuttingSuccessful(wood.chance)) { + System.out.println("Chopping...") + cut(axe) + return //We did not cut down the tree... Keep going + } else { + //We cut down the tree + var treeEntity: StaticGameObject? = null + val region = mob.world.regionRepository.fromPosition(position) + val entities = region.getEntities(position) + for (entity: Entity in entities) { + if (entity is StaticGameObject) { + System.out.println("Entity at cutting location: " + entity.id + " with type: " + entity.entityType) + if (entity.id == objectID) { + treeEntity = entity + } + } + } + if (treeEntity == null) { //tree entity not found at location... + System.out.println("WARNING: Invalid cutting condition on tree"); + stop() + return + } + //Get ID of exipred wood + val expiredObjectID = wood.stump; + val expiredRockEntity = StaticGameObject(mob.world, expiredObjectID!!, position, treeEntity!!.type, treeEntity!!.orientation) + //Remove normal wood and replace with expired + System.out.println("Removing " + objectID + " addding " + expiredObjectID) + System.out.println("Adding tasks") + //add task to remove normal wood and replace with depleted + mob.world.schedule(object: ScheduledTask(0, true) { + override fun execute() { + System.out.println("running deplete task") + //Replace normal wood with expired wood + region.removeEntity(treeEntity); + region.addEntity(expiredRockEntity) + this.stop() //Makes task run once + } + }) + //add task to respawn normal wood + //respawn time: http://runescape.wikia.com/wiki/Trees + val respawn = ((30 * 1000) / 600) + ((rand.nextInt(150) * 1000) / 600) // between 30 sec and 3 min respawm + mob.world.schedule(object: ScheduledTask(respawn, false) { + override fun execute() { + System.out.println("running wood task") + //Replace expired wood with normal wood + region.removeEntity(expiredRockEntity) + region.addEntity(treeEntity); + this.stop() //Makes task run once + } + }) + stop() + return + } + } + counter -= 1 + } else { + started = true + cut(axe) + } + } + + private fun findAxe(): Axe? { + for (axe in getAxes()) { + if (axe!!.level > mob.skillSet.getSkill(Skill.WOODCUTTING).currentLevel) { + continue; + } + val weponSlot = mob.equipment.get(EquipmentConstants.WEAPON) + if (weponSlot != null && weponSlot.id == axe.id) { + return axe; + } else if (mob.inventory.contains(axe.id)) { + return axe; + } + } + return null; + } + + private fun cut(axe: Axe) { + mob.sendMessage("You swing your axe at the tree.") + mob.playAnimation(axe.animation) + counter = axe.pulses + mob.turnTo(position) + } + + private fun cuttingSuccessful(woodChance: Double): Boolean { + return rand.nextInt(100) <= woodChance * 100; + } +} + + +on {ObjectActionMessage::class} + .where {option == 1} + .then { + if (lookupTree(id) != null) { + it.startAction(WoodcuttingAction(it, id, this.position, lookupTree(id)!!)) + } else { + System.out.println("Unknown wood: " + id) + } + } From da7c7e10b45ca32557b4d699ec851ecc22f9c4b0 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Sat, 16 Sep 2017 21:26:29 -0700 Subject: [PATCH 067/209] Woodcutting now uses Async Action --- game/plugin/skills/woodcutting/build.gradle | 1 + game/plugin/skills/woodcutting/src/axe.kt | 2 +- game/plugin/skills/woodcutting/src/wood.kt | 2 +- .../woodcutting/src/woodcutting.plugin.kts | 210 +++++++----------- 4 files changed, 83 insertions(+), 132 deletions(-) diff --git a/game/plugin/skills/woodcutting/build.gradle b/game/plugin/skills/woodcutting/build.gradle index 886112d70..d52d61ca1 100644 --- a/game/plugin/skills/woodcutting/build.gradle +++ b/game/plugin/skills/woodcutting/build.gradle @@ -4,4 +4,5 @@ plugin { authors = [ "tlf30" ] + dependencies = ["api"] } \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/src/axe.kt b/game/plugin/skills/woodcutting/src/axe.kt index ae3e11a7b..02ad7d36e 100644 --- a/game/plugin/skills/woodcutting/src/axe.kt +++ b/game/plugin/skills/woodcutting/src/axe.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.skills.mining +package org.apollo.game.plugin.skills.woodcutting import org.apollo.game.model.Animation; diff --git a/game/plugin/skills/woodcutting/src/wood.kt b/game/plugin/skills/woodcutting/src/wood.kt index 6201d8cd8..550b98ca1 100644 --- a/game/plugin/skills/woodcutting/src/wood.kt +++ b/game/plugin/skills/woodcutting/src/wood.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.skills.mining +package org.apollo.game.plugin.skills.woodcutting /** diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index 8b5d0a48f..9facda64d 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -1,163 +1,113 @@ import org.apollo.cache.def.ItemDefinition -import org.apollo.game.action.DistancedAction +import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position -import org.apollo.game.model.entity.Entity -import org.apollo.game.model.entity.EquipmentConstants +import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill -import org.apollo.game.model.entity.obj.StaticGameObject -import org.apollo.game.plugin.skills.mining.* +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.skills.woodcutting.* +import org.apollo.game.plugins.api.Definitions +import org.apollo.game.plugins.api.woodcutting +import org.apollo.game.plugins.api.skills import org.apollo.game.scheduling.ScheduledTask import java.util.* -class WoodcuttingAction(val player: Player, val objectID: Int, val p: Position, val wood: Wood) : DistancedAction(PULSES, true, player, p, TREE_SIZE) { +class WoodcuttingTarget(val objectId: Int, val position: Position, val wood: Wood) { + + fun getObject(world: World): Optional { + val region = world.regionRepository.fromPosition(position) + val obj = region.findObject(position, objectId) + + return obj + } + + fun isSuccessful(mob: Player): Boolean { + return rand(100) <= wood.chance * 100 + } +} + +class WoodcuttingAction(val player: Player, val tool: Axe, val target: WoodcuttingTarget) : AsyncDistancedAction(PULSES, true, player, target.position, TREE_SIZE) { companion object { private val PULSES = 0 private val TREE_SIZE = 1; + + fun axeFor(player: Player): Axe? { + return AXES + .filter { it.level <= player.skills.woodcutting.currentLevel } + .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } + .sortedByDescending { it.level } + .firstOrNull() + } + + /** + * Starts a [WoodcuttingAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player, wood: Wood) { + val axe = axeFor(player) + if (axe != null) { + val action = WoodcuttingAction(player, axe, WoodcuttingTarget(message.id, message.position, wood)) + player.startAction(action) + } else { + player.sendMessage("You do not have a axe for which you have the level to use.") + } + + message.terminate() + } } - private var counter: Int = 0 - private var started: Boolean = false - private val rand: Random = Random() - override fun executeAction() { - System.out.println("Cutting " + wood.id + " @ " + p) - val level = mob.skillSet.getSkill(Skill.WOODCUTTING).currentLevel - val axe = findAxe() + override fun start() { + mob.turnTo(position) + + val level = mob.skills.woodcutting.currentLevel - //check that our pick can mine the wood - if (axe == null || level < axe.level) { - mob.sendMessage("You do not have a axe for which you have the level to use.") + if (level < target.wood.level) { + mob.sendMessage("You do not have the required level to cut down this tree.") stop() - return } + } - //check that we can mine the wood - if (level < wood.level) { - mob.sendMessage("You do not have the required level to mine this rock.") + override suspend fun executeActionAsync() { + mob.sendMessage("You swing your axe at the tree.") + mob.playAnimation(tool.animation) + + wait(tool.pulses) + // + + val obj = target.getObject(mob.world) + if (!obj.isPresent) { stop() return } - //start the process of cutting - if (started) { - if (counter == 0) { - //Check inv capacity - if (mob.inventory.freeSlots() == 0) { - mob.inventory.forceCapacityExceeded() - stop() - return - } - if (mob.inventory.add(wood.id)) { - //TODO: Use lookup from utils once it has a lookup function for IDs - val woodName = ItemDefinition.lookup(wood.id).name.toLowerCase(); - mob.sendMessage("You managed to cut some " + woodName + ".") - mob.skillSet.addExperience(Skill.WOODCUTTING, wood.exp) - - } else { - System.out.println("Failed to add wood to inv"); - stop(); - return; - } - - if (!cuttingSuccessful(wood.chance)) { - System.out.println("Chopping...") - cut(axe) - return //We did not cut down the tree... Keep going - } else { - //We cut down the tree - var treeEntity: StaticGameObject? = null - val region = mob.world.regionRepository.fromPosition(position) - val entities = region.getEntities(position) - for (entity: Entity in entities) { - if (entity is StaticGameObject) { - System.out.println("Entity at cutting location: " + entity.id + " with type: " + entity.entityType) - if (entity.id == objectID) { - treeEntity = entity - } - } - } - if (treeEntity == null) { //tree entity not found at location... - System.out.println("WARNING: Invalid cutting condition on tree"); - stop() - return - } - //Get ID of exipred wood - val expiredObjectID = wood.stump; - val expiredRockEntity = StaticGameObject(mob.world, expiredObjectID!!, position, treeEntity!!.type, treeEntity!!.orientation) - //Remove normal wood and replace with expired - System.out.println("Removing " + objectID + " addding " + expiredObjectID) - System.out.println("Adding tasks") - //add task to remove normal wood and replace with depleted - mob.world.schedule(object: ScheduledTask(0, true) { - override fun execute() { - System.out.println("running deplete task") - //Replace normal wood with expired wood - region.removeEntity(treeEntity); - region.addEntity(expiredRockEntity) - this.stop() //Makes task run once - } - }) - //add task to respawn normal wood - //respawn time: http://runescape.wikia.com/wiki/Trees - val respawn = ((30 * 1000) / 600) + ((rand.nextInt(150) * 1000) / 600) // between 30 sec and 3 min respawm - mob.world.schedule(object: ScheduledTask(respawn, false) { - override fun execute() { - System.out.println("running wood task") - //Replace expired wood with normal wood - region.removeEntity(expiredRockEntity) - region.addEntity(treeEntity); - this.stop() //Makes task run once - } - }) - stop() - return - } - } - counter -= 1 - } else { - started = true - cut(axe) + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + stop() + return } - } - - private fun findAxe(): Axe? { - for (axe in getAxes()) { - if (axe!!.level > mob.skillSet.getSkill(Skill.WOODCUTTING).currentLevel) { - continue; - } - val weponSlot = mob.equipment.get(EquipmentConstants.WEAPON) - if (weponSlot != null && weponSlot.id == axe.id) { - return axe; - } else if (mob.inventory.contains(axe.id)) { - return axe; - } + if (mob.inventory.add(target.wood.id)) { + //TODO: Use lookup from utils once it has a lookup function for IDs + val woodName = ItemDefinition.lookup(target.wood.id).name.toLowerCase(); + mob.sendMessage("You managed to cut some $woodName.") + mob.skillSet.addExperience(Skill.WOODCUTTING, target.wood.exp) } - return null; - } - private fun cut(axe: Axe) { - mob.sendMessage("You swing your axe at the tree.") - mob.playAnimation(axe.animation) - counter = axe.pulses - mob.turnTo(position) - } - - private fun cuttingSuccessful(woodChance: Double): Boolean { - return rand.nextInt(100) <= woodChance * 100; + if (target.isSuccessful(mob)) { + //respawn time: http://runescape.wikia.com/wiki/Trees + val respawn = ((30 * 1000) / 600) + ((rand(150) * 1000) / 600) // between 30 sec and 3 min respawm + mob.world.expireObject(obj.get(), target.wood.stump, respawn) + } } } - -on {ObjectActionMessage::class} - .where {option == 1} +on { ObjectActionMessage::class } + .where { option == 1 } .then { - if (lookupTree(id) != null) { - it.startAction(WoodcuttingAction(it, id, this.position, lookupTree(id)!!)) - } else { - System.out.println("Unknown wood: " + id) + val wood = lookupTree(id) + if (wood != null) { + WoodcuttingAction.start(this, it, wood) } } From 75a9b828b25a18e6c027330a9c3c748174f64ba9 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Sat, 16 Sep 2017 21:48:45 -0700 Subject: [PATCH 068/209] Fix all issues. Wood cutting now works. --- game/plugin/skills/woodcutting/build.gradle | 2 +- game/plugin/skills/woodcutting/meta.toml | 9 -- game/plugin/skills/woodcutting/src/axe.kt | 16 ++-- game/plugin/skills/woodcutting/src/wood.kt | 89 ++++++++----------- .../woodcutting/src/woodcutting.plugin.kts | 82 +++++++++-------- 5 files changed, 92 insertions(+), 106 deletions(-) delete mode 100644 game/plugin/skills/woodcutting/meta.toml diff --git a/game/plugin/skills/woodcutting/build.gradle b/game/plugin/skills/woodcutting/build.gradle index d52d61ca1..0c154fb3f 100644 --- a/game/plugin/skills/woodcutting/build.gradle +++ b/game/plugin/skills/woodcutting/build.gradle @@ -2,7 +2,7 @@ plugin { name = "woodcutting_skill" packageName = "org.apollo.game.plugin.skills.woodcutting" authors = [ - "tlf30" + "tlf30" ] dependencies = ["api"] } \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/meta.toml b/game/plugin/skills/woodcutting/meta.toml deleted file mode 100644 index c490c7118..000000000 --- a/game/plugin/skills/woodcutting/meta.toml +++ /dev/null @@ -1,9 +0,0 @@ -name = "woodcutting-skill" -package = "org.apollo.game.plugin.skills.woodcutting" -authors = [ - "tlf30" - ] - -[config] -srcDir = "src/" -testDir = "test/" diff --git a/game/plugin/skills/woodcutting/src/axe.kt b/game/plugin/skills/woodcutting/src/axe.kt index 02ad7d36e..d7d23e818 100644 --- a/game/plugin/skills/woodcutting/src/axe.kt +++ b/game/plugin/skills/woodcutting/src/axe.kt @@ -2,7 +2,7 @@ package org.apollo.game.plugin.skills.woodcutting import org.apollo.game.model.Animation; -//Animation IDs: https://www.rune-server.ee/runescape-development/rs2-client/configuration/272373-emote-gfx-id-list.html +//Animation IDs thanks to Deadly A G S at rune-server.ee enum class Axe(val id: Int, val level: Int, val animation: Animation, val pulses: Int) { RUNE(1359, 41, Animation(867), 3), ADAMANT(1357, 31, Animation(869), 4), @@ -10,14 +10,14 @@ enum class Axe(val id: Int, val level: Int, val animation: Animation, val pulses BLACK(1361, 11, Animation(873), 6), STEEL(1353, 6, Animation(875), 6), IRON(1349, 1, Animation(877), 7), - BRONZE(1351, 1, Animation(879), 8) -} - -val AXES = Axe.values() + BRONZE(1351, 1, Animation(879), 8); -fun getAxes(): Array { - return AXES + companion object { + private val AXES = Axe.values() + fun getAxes(): Array { + return AXES + } + } } -fun lookupPickaxe(id: Int): Axe? = AXES.find { it.id == id } diff --git a/game/plugin/skills/woodcutting/src/wood.kt b/game/plugin/skills/woodcutting/src/wood.kt index 550b98ca1..71c910ad6 100644 --- a/game/plugin/skills/woodcutting/src/wood.kt +++ b/game/plugin/skills/woodcutting/src/wood.kt @@ -1,85 +1,72 @@ package org.apollo.game.plugin.skills.woodcutting - -/** - * values thanks to: http://oldschoolrunescape.wikia.com/wiki/Woodcutting - */ -enum class Wood(val id: Int, val objects: IntArray, val stump: Int, val level: Int, val exp: Double, val chance: Double) { - NORMAL(1511, NORMAL_OBJECTS, NORMAL_STUMP, 1, 25.0, 100.0), - ACHEY(2862, ACHEY_OBJECTS, ACHEY_STUMP, 1, 25.0, 100.0), - OAK(1521, OAK_OBJECTS, OAK_STUMP, 15, 37.5, 0.125), - WILLOW(1519, WILLOW_OBJECTS, WILLOW_STUMP, 30, 67.5, 0.125), - TEAK(6333, TEAK_OBJECTS, TEAK_STUMP, 35, 85.0, 0.125), - MAPLE(1517, MAPLE_OBJECTS, MAPLE_STUMP, 45, 100.0, 0.125), - MAHOGANY(6332, MAHOGANY_OBJECTS, MAHOGANY_STUMP, 50, 125.0,0.125), - YEW(1515, YEW_OBJECTS, YEW_STUMP, 60, 175.0, 0.125), - MAGIC(1513, MAGIC_OBJECTS, MAGIC_STUMP, 75, 250.0, 0.125), -} - -val WOOD = Wood.values() - -fun lookupWood(id: Int): Wood? =WOOD.find { it.id == id } - -fun lookupTree(id: Int): Wood? { - for (wood in WOOD) { - for (tree in wood.objects) { - if (tree == id) { - return wood - } - } - } - return null -} - -val NORMAL_STUMP = 1342 -val ACHEY_STUMP = 3371 -val OAK_STUMP = 1342 -val WILLOW_STUMP = 1342 -val TEAK_STUMP = 1342 -val MAPLE_STUMP = 1342 -val MAHOGANY_STUMP = 1342 -val YEW_STUMP = 1342 -val MAGIC_STUMP = 1324 - -val NORMAL_OBJECTS = intArrayOf( +private val NORMAL_STUMP = 1342 +private val ACHEY_STUMP = 3371 +private val OAK_STUMP = 1342 +private val WILLOW_STUMP = 1342 +private val TEAK_STUMP = 1342 +private val MAPLE_STUMP = 1342 +private val MAHOGANY_STUMP = 1342 +private val YEW_STUMP = 1342 +private val MAGIC_STUMP = 1324 + +private val NORMAL_OBJECTS = hashSetOf( 1276, 1277, 1278, 1279, 1280, 1282, 1283, 1284, 1285, 1285, 1286, 1289, 1290, 1291, 1315, 1316, 1318, 1330, 1331, 1332, 1365, 1383, 1384, 2409, 3033, 3034, 3035, 3036, 3881, 3882, 3883, 5902, 5903, 5904, 10041 ) -val ACHEY_OBJECTS = intArrayOf( +private val ACHEY_OBJECTS = hashSetOf( 2023 ) -val OAK_OBJECTS = intArrayOf( +private val OAK_OBJECTS = hashSetOf( 1281, 3037 ) -val WILLOW_OBJECTS = intArrayOf( +private val WILLOW_OBJECTS = hashSetOf( 5551, 5552, 5553 ) -val TEAK_OBJECTS = intArrayOf( +private val TEAK_OBJECTS = hashSetOf( 9036 ) -val MAPLE_OBJECTS = intArrayOf( +private val MAPLE_OBJECTS = hashSetOf( 1307, 4674 ) -val MAHOGANY_OBJECTS = intArrayOf( +private val MAHOGANY_OBJECTS = hashSetOf( 9034 ) - -val YEW_OBJECTS = intArrayOf( +private val YEW_OBJECTS = hashSetOf( 1309 ) -val MAGIC_OBJECTS = intArrayOf( +private val MAGIC_OBJECTS = hashSetOf( 1292, 1306 ) +/** + * values thanks to: http://oldschoolrunescape.wikia.com/wiki/Woodcutting + */ +enum class Tree(val id: Int, val objects: HashSet, val stump: Int, val level: Int, val exp: Double, val chance: Double) { + NORMAL(1511, NORMAL_OBJECTS, NORMAL_STUMP, 1, 25.0, 100.0), + ACHEY(2862, ACHEY_OBJECTS, ACHEY_STUMP, 1, 25.0, 100.0), + OAK(1521, OAK_OBJECTS, OAK_STUMP, 15, 37.5, 0.125), + WILLOW(1519, WILLOW_OBJECTS, WILLOW_STUMP, 30, 67.5, 0.125), + TEAK(6333, TEAK_OBJECTS, TEAK_STUMP, 35, 85.0, 0.125), + MAPLE(1517, MAPLE_OBJECTS, MAPLE_STUMP, 45, 100.0, 0.125), + MAHOGANY(6332, MAHOGANY_OBJECTS, MAHOGANY_STUMP, 50, 125.0, 0.125), + YEW(1515, YEW_OBJECTS, YEW_STUMP, 60, 175.0, 0.125), + MAGIC(1513, MAGIC_OBJECTS, MAGIC_STUMP, 75, 250.0, 0.125); + + companion object { + private val TREES = Tree.values().flatMap { tree -> tree.objects.map { Pair(it, tree) } }.toMap() + fun lookup(id: Int): Tree? = TREES[id] + } +} diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index 9facda64d..ab8aee862 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -1,4 +1,5 @@ import org.apollo.cache.def.ItemDefinition +import org.apollo.game.GameConstants import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position @@ -7,34 +8,41 @@ import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.plugin.skills.woodcutting.* -import org.apollo.game.plugins.api.Definitions import org.apollo.game.plugins.api.woodcutting import org.apollo.game.plugins.api.skills -import org.apollo.game.scheduling.ScheduledTask import java.util.* +import java.util.concurrent.TimeUnit -class WoodcuttingTarget(val objectId: Int, val position: Position, val wood: Wood) { +class WoodcuttingTarget(val objectId: Int, val position: Position, val tree: Tree) { + /** + * Get the tree object in the world + */ fun getObject(world: World): Optional { val region = world.regionRepository.fromPosition(position) - val obj = region.findObject(position, objectId) - - return obj + return region.findObject(position, objectId) } - fun isSuccessful(mob: Player): Boolean { - return rand(100) <= wood.chance * 100 + /** + * Check if the tree was cut down + */ + fun isCutDown(mob: Player): Boolean { + return rand(100) <= tree.chance * 100 } } -class WoodcuttingAction(val player: Player, val tool: Axe, val target: WoodcuttingTarget) : AsyncDistancedAction(PULSES, true, player, target.position, TREE_SIZE) { +class WoodcuttingAction(val player: Player, val tool: Axe, val target: WoodcuttingTarget) : AsyncDistancedAction(DELAY, true, player, target.position, TREE_SIZE) { companion object { - private val PULSES = 0 - private val TREE_SIZE = 1; + private val DELAY = 0 + private val TREE_SIZE = 2 + private val MINIMUM_RESPAWN_TIME = 30L //In seconds - fun axeFor(player: Player): Axe? { - return AXES + /** + * Find the highest level axe the player has + */ + private fun axeFor(player: Player): Axe? { + return getAxes() .filter { it.level <= player.skills.woodcutting.currentLevel } .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } .sortedByDescending { it.level } @@ -44,27 +52,30 @@ class WoodcuttingAction(val player: Player, val tool: Axe, val target: Woodcutti /** * Starts a [WoodcuttingAction] for the specified [Player], terminating the [Message] that triggered it. */ - fun start(message: ObjectActionMessage, player: Player, wood: Wood) { + fun start(message: ObjectActionMessage, player: Player, wood: Tree) { val axe = axeFor(player) if (axe != null) { + //Check that the player had room in their inventory + if (player.inventory.freeSlots() == 0) { + player.inventory.forceCapacityExceeded() + return + } val action = WoodcuttingAction(player, axe, WoodcuttingTarget(message.id, message.position, wood)) player.startAction(action) } else { - player.sendMessage("You do not have a axe for which you have the level to use.") + player.sendMessage("You do not have an axe for which you have the level to use.") } message.terminate() } } - - override fun start() { mob.turnTo(position) val level = mob.skills.woodcutting.currentLevel - if (level < target.wood.level) { + if (level < target.tree.level) { mob.sendMessage("You do not have the required level to cut down this tree.") stop() } @@ -75,39 +86,36 @@ class WoodcuttingAction(val player: Player, val tool: Axe, val target: Woodcutti mob.playAnimation(tool.animation) wait(tool.pulses) - // + //Check that the object exists in the world val obj = target.getObject(mob.world) if (!obj.isPresent) { stop() return } - if (mob.inventory.freeSlots() == 0) { - mob.inventory.forceCapacityExceeded() - stop() - return - } - if (mob.inventory.add(target.wood.id)) { + if (mob.inventory.add(target.tree.id)) { //TODO: Use lookup from utils once it has a lookup function for IDs - val woodName = ItemDefinition.lookup(target.wood.id).name.toLowerCase(); - mob.sendMessage("You managed to cut some $woodName.") - mob.skillSet.addExperience(Skill.WOODCUTTING, target.wood.exp) + val logName = ItemDefinition.lookup(target.tree.id).name.toLowerCase(); + mob.sendMessage("You managed to cut some $logName.") + mob.skillSet.addExperience(Skill.WOODCUTTING, target.tree.exp) } - if (target.isSuccessful(mob)) { + //Check if the tree was cut down. If it was, we stop the task. + if (target.isCutDown(mob)) { //respawn time: http://runescape.wikia.com/wiki/Trees - val respawn = ((30 * 1000) / 600) + ((rand(150) * 1000) / 600) // between 30 sec and 3 min respawm - mob.world.expireObject(obj.get(), target.wood.stump, respawn) + val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY + mob.world.expireObject(obj.get(), target.tree.stump, respawn.toInt()) + stop() } } } on { ObjectActionMessage::class } - .where { option == 1 } - .then { - val wood = lookupTree(id) - if (wood != null) { - WoodcuttingAction.start(this, it, wood) - } + .where { option == 1 } + .then { + val tree = Tree.lookup(id) + if (tree != null) { + WoodcuttingAction.start(this, it, tree) } + } From 2cd160feb3c2cbed73e0226f5f457e6204427c8e Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 19 Sep 2017 19:01:30 +0100 Subject: [PATCH 069/209] Refactor woodcutting to use coroutines --- .../woodcutting/src/woodcutting.plugin.kts | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index ab8aee862..eb769d492 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -1,5 +1,6 @@ import org.apollo.cache.def.ItemDefinition import org.apollo.game.GameConstants +import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position @@ -8,8 +9,7 @@ import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.plugin.skills.woodcutting.* -import org.apollo.game.plugins.api.woodcutting -import org.apollo.game.plugins.api.skills +import org.apollo.game.plugins.api.* import java.util.* import java.util.concurrent.TimeUnit @@ -42,7 +42,7 @@ class WoodcuttingAction(val player: Player, val tool: Axe, val target: Woodcutti * Find the highest level axe the player has */ private fun axeFor(player: Player): Axe? { - return getAxes() + return Axe.getAxes() .filter { it.level <= player.skills.woodcutting.currentLevel } .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } .sortedByDescending { it.level } @@ -55,11 +55,11 @@ class WoodcuttingAction(val player: Player, val tool: Axe, val target: Woodcutti fun start(message: ObjectActionMessage, player: Player, wood: Tree) { val axe = axeFor(player) if (axe != null) { - //Check that the player had room in their inventory if (player.inventory.freeSlots() == 0) { player.inventory.forceCapacityExceeded() return } + val action = WoodcuttingAction(player, axe, WoodcuttingTarget(message.id, message.position, wood)) player.startAction(action) } else { @@ -70,43 +70,39 @@ class WoodcuttingAction(val player: Player, val tool: Axe, val target: Woodcutti } } - override fun start() { + override fun action(): ActionBlock = { mob.turnTo(position) val level = mob.skills.woodcutting.currentLevel - if (level < target.tree.level) { mob.sendMessage("You do not have the required level to cut down this tree.") stop() } - } - override suspend fun executeActionAsync() { - mob.sendMessage("You swing your axe at the tree.") - mob.playAnimation(tool.animation) + while (isRunning) { + mob.sendMessage("You swing your axe at the tree.") + mob.playAnimation(tool.animation) - wait(tool.pulses) + wait(tool.pulses) - //Check that the object exists in the world - val obj = target.getObject(mob.world) - if (!obj.isPresent) { - stop() - return - } + //Check that the object exists in the world + val obj = target.getObject(mob.world) + if (!obj.isPresent) { + stop() + } - if (mob.inventory.add(target.tree.id)) { - //TODO: Use lookup from utils once it has a lookup function for IDs - val logName = ItemDefinition.lookup(target.tree.id).name.toLowerCase(); - mob.sendMessage("You managed to cut some $logName.") - mob.skillSet.addExperience(Skill.WOODCUTTING, target.tree.exp) - } + if (mob.inventory.add(target.tree.id)) { + val logName = Definitions.item(target.tree.id)?.name?.toLowerCase(); + mob.sendMessage("You managed to cut some $logName.") + mob.skills.addExperience(Skill.WOODCUTTING, target.tree.exp) + } - //Check if the tree was cut down. If it was, we stop the task. - if (target.isCutDown(mob)) { - //respawn time: http://runescape.wikia.com/wiki/Trees - val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY - mob.world.expireObject(obj.get(), target.tree.stump, respawn.toInt()) - stop() + if (target.isCutDown(mob)) { + //respawn time: http://runescape.wikia.com/wiki/Trees + val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY + mob.world.expireObject(obj.get(), target.tree.stump, respawn.toInt()) + stop() + } } } } From 1c8bc3a009661665f932a1b239983803c7ad3ac0 Mon Sep 17 00:00:00 2001 From: Arin Date: Wed, 20 Sep 2017 03:29:36 -0700 Subject: [PATCH 070/209] Add door support in Kotlin (#356) Adds support for doors as a Kotlin plugin, based on the previous ruby plugin by shiver. --- .gitignore | 3 +- game/plugin/navigation/door/build.gradle | 9 + game/plugin/navigation/door/src/door.kt | 165 ++++++++++++++++++ .../navigation/door/src/door.plugin.kts | 16 ++ 4 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 game/plugin/navigation/door/build.gradle create mode 100644 game/plugin/navigation/door/src/door.kt create mode 100644 game/plugin/navigation/door/src/door.plugin.kts diff --git a/.gitignore b/.gitignore index 8de8fb066..c852a9f9b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ /lib/ */target/ */build/ -**/build/ \ No newline at end of file +**/build/ +**/out/ \ No newline at end of file diff --git a/game/plugin/navigation/door/build.gradle b/game/plugin/navigation/door/build.gradle new file mode 100644 index 000000000..2d62d81fa --- /dev/null +++ b/game/plugin/navigation/door/build.gradle @@ -0,0 +1,9 @@ +plugin { + name = "door" + packageName = "org.apollo.game.plugin.navigation.door" + dependencies = ["api"] + authors = [ + "Shiver", + "Arin" + ] +} \ No newline at end of file diff --git a/game/plugin/navigation/door/src/door.kt b/game/plugin/navigation/door/src/door.kt new file mode 100644 index 000000000..b3369cadb --- /dev/null +++ b/game/plugin/navigation/door/src/door.kt @@ -0,0 +1,165 @@ +package org.apollo.plugin.navigation.door + +import org.apollo.game.action.DistancedAction +import org.apollo.game.model.Direction +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.DynamicGameObject +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.event.PlayerEvent +import org.apollo.net.message.Message +import java.util.Objects +import findObject + +enum class DoorType { + LEFT, RIGHT, NOT_SUPPORTED +} + +class Door(private val gameObject: GameObject) { + + companion object { + + val LEFT_HINGE_ORIENTATION: HashMap = hashMapOf( + Direction.NORTH to Direction.WEST, + Direction.SOUTH to Direction.EAST, + Direction.WEST to Direction.SOUTH, + Direction.EAST to Direction.NORTH + ) + + val RIGHT_HINGE_ORIENTATION: HashMap = hashMapOf( + Direction.NORTH to Direction.EAST, + Direction.SOUTH to Direction.WEST, + Direction.WEST to Direction.NORTH, + Direction.EAST to Direction.SOUTH + ) + + val toggledDoors: HashMap = hashMapOf() + + val LEFT_HINGED = setOf(1516, 1536, 1533) + + val RIGHT_HINGED = setOf(1519, 1530, 4465, 4467, 3014, 3017, 3018, 3019) + + /** + * Find a given door in the world + * @param world The [World] the door lives in + * @param position The [Position] of the door + * @param objectId The [GameObject] id of the door + */ + fun find(world: World, position: Position, objectId: Int): Door? { + val region = world.regionRepository.fromPosition(position) + val gameObject = region.findObject(position, objectId).orElseGet(null) + return if (gameObject == null) { + null + } else { + Door(gameObject) + } + } + } + + /** + * Returns the supported doors by the system + * See [DoorType] + */ + fun supported(): Boolean { + return type() !== DoorType.NOT_SUPPORTED + } + + + /** + * Computes the given door type by which id exists in + * the supported left and right hinged doors + */ + fun type(): DoorType { + return when { + gameObject.id in LEFT_HINGED -> DoorType.LEFT + gameObject.id in RIGHT_HINGED -> DoorType.RIGHT + else -> DoorType.NOT_SUPPORTED + } + } + + /** + * Toggles a given [GameObject] orientation and position + * Stores the door state in toggleDoors class variable + */ + fun toggle() { + val world = gameObject.world + val regionRepository = world.regionRepository + + regionRepository.fromPosition(gameObject.position).removeEntity(gameObject) + + val originalDoor: GameObject? = toggledDoors[gameObject] + + if (originalDoor == null) { + val position = movePosition() + val orientation: Int = translateDirection()?.toOrientationInteger() ?: gameObject.orientation + + val toggledDoor = DynamicGameObject.createPublic(world, gameObject.id, position, gameObject.type, orientation) + + regionRepository.fromPosition(position).addEntity(toggledDoor) + toggledDoors.put(toggledDoor, gameObject) + } else { + toggledDoors.remove(gameObject) + regionRepository.fromPosition(originalDoor.position).addEntity(originalDoor) + } + + } + + /** + * Calculates the position to move the door based on orientation + */ + private fun movePosition(): Position { + return gameObject.position.step(1, Direction.WNES[gameObject.orientation]) + } + + /** + * Calculates the orientation of the door based on + * if it is right or left hinged door + */ + private fun translateDirection(): Direction? { + val direction = Direction.WNES[gameObject.orientation] + return when(type()) { + DoorType.LEFT -> LEFT_HINGE_ORIENTATION[direction] + DoorType.RIGHT -> RIGHT_HINGE_ORIENTATION[direction] + DoorType.NOT_SUPPORTED -> null + } + } + +} + +class OpenDoorAction(private val player: Player, private val door: Door, position: Position) : DistancedAction(0, true, player, position, DISTANCE) { + + companion object { + + /** + * The distance threshold that must be reached before the door is opened. + */ + const val DISTANCE = 1 + + /** + * Starts a [OpenDoorAction] for the specified [Player], terminating the [Message] that triggered. + */ + fun start(message: Message, player: Player, door: Door, position: Position) { + player.startAction(OpenDoorAction(player, door, position)) + message.terminate() + } + + } + + override fun executeAction() { + if (player.world.submit(OpenDoorEvent(player))) { + player.turnTo(position) + door.toggle() + } + stop() + } + + override fun equals(other: Any?): Boolean { + return other is OpenDoorAction && position == other.position && player == other.player + } + + override fun hashCode(): Int = Objects.hash(position, player) + +} + +class OpenDoorEvent(player: Player) : PlayerEvent(player) diff --git a/game/plugin/navigation/door/src/door.plugin.kts b/game/plugin/navigation/door/src/door.plugin.kts new file mode 100644 index 000000000..d91ceee9a --- /dev/null +++ b/game/plugin/navigation/door/src/door.plugin.kts @@ -0,0 +1,16 @@ + +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.plugin.navigation.door.Door +import org.apollo.plugin.navigation.door.OpenDoorAction + +/** + * Hook into the [ObjectActionMessage] and listens for a supported door [GameObject] + */ +on { ObjectActionMessage::class } + .where { option == 1 } + .then { + val door = Door.find(it.world, position, id) ?: return@then + if (door.supported()) { + OpenDoorAction.start(this, it, door, position) + } + } \ No newline at end of file From 6d202abbc2ef012a02adbfd7870abb3d52e6ae3f Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 23 Sep 2017 04:11:44 +0100 Subject: [PATCH 071/209] Support lookup_x inputs with the id at the end --- game/plugin/util/lookup/src/lookup.kt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/game/plugin/util/lookup/src/lookup.kt b/game/plugin/util/lookup/src/lookup.kt index 637f4fab6..a789b17d9 100644 --- a/game/plugin/util/lookup/src/lookup.kt +++ b/game/plugin/util/lookup/src/lookup.kt @@ -1,4 +1,6 @@ -import org.apollo.cache.def.* +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition fun lookup_object(name: String): ObjectDefinition? { return find_entity(ObjectDefinition::getDefinitions, ObjectDefinition::getName, name) @@ -12,13 +14,22 @@ fun lookup_item(name: String): ItemDefinition? { return find_entity(ItemDefinition::getDefinitions, ItemDefinition::getName, name) } +/** + * The [Regex] used to match 'names' that have an id attached to the end. + */ +private val ID_REGEX = Regex(".+_[0-9]+$") + private fun find_entity(definitionsProvider: () -> Array, nameSupplier: T.() -> String, name: String): T? { + val definitions = definitionsProvider.invoke() + + if (ID_REGEX matches name) { + val id = name.substring(name.lastIndexOf('_') + 1, name.length).toInt() + return definitions.getOrNull(id) + } val normalizedName = name.replace('_', ' ') - val definitions = definitionsProvider.invoke(); - val matcher: (T) -> Boolean = { it.nameSupplier().equals(normalizedName, true) } - return definitions.filter(matcher).firstOrNull() + return definitions.firstOrNull { it.nameSupplier().equals(normalizedName, true) } } \ No newline at end of file From 52c25946b930783d422393d0d5451b07d6b8911a Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 23 Sep 2017 04:12:08 +0100 Subject: [PATCH 072/209] Add shops plugin Thanks to tlf30 for a lot of work on this. --- game/plugin/shops/build.gradle | 12 + game/plugin/shops/src/action.kt | 66 ++++ game/plugin/shops/src/dls.kt | 350 ++++++++++++++++++ game/plugin/shops/src/shop.kt | 333 +++++++++++++++++ game/plugin/shops/src/shop.plugin.kts | 46 +++ .../handler/ItemVerificationHandler.java | 2 +- 6 files changed, 808 insertions(+), 1 deletion(-) create mode 100644 game/plugin/shops/build.gradle create mode 100644 game/plugin/shops/src/action.kt create mode 100644 game/plugin/shops/src/dls.kt create mode 100644 game/plugin/shops/src/shop.kt create mode 100644 game/plugin/shops/src/shop.plugin.kts diff --git a/game/plugin/shops/build.gradle b/game/plugin/shops/build.gradle new file mode 100644 index 000000000..1147de622 --- /dev/null +++ b/game/plugin/shops/build.gradle @@ -0,0 +1,12 @@ +plugin { + name = "shops" + packageName = "org.apollo.game.plugin.shops" + authors = [ + "Stuart", + "Major", + "tlf30" + ] + dependencies = [ + "util:lookup", + ] +} diff --git a/game/plugin/shops/src/action.kt b/game/plugin/shops/src/action.kt new file mode 100644 index 000000000..db9561e46 --- /dev/null +++ b/game/plugin/shops/src/action.kt @@ -0,0 +1,66 @@ +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.handler.ItemVerificationHandler.InventorySupplier +import org.apollo.game.message.impl.SetWidgetTextMessage +import org.apollo.game.model.entity.Mob +import org.apollo.game.model.entity.Player +import org.apollo.game.model.inter.InterfaceListener +import org.apollo.game.model.inv.Inventory +import org.apollo.game.model.inv.SynchronizationInventoryListener + +/** + * A [DistancedAction] that opens a [Shop]. + */ +class OpenShopAction( + player: Player, + private val shop: Shop, + val npc: Mob +) : DistancedAction(0, true, player, npc.position, 1) { // TODO this needs to follow the NPC if they move + + override fun executeAction() { + mob.interactingMob = npc + + val closeListener = addInventoryListeners(mob, shop.inventory) + mob.send(SetWidgetTextMessage(Interfaces.SHOP_NAME, shop.name)) + + mob.interfaceSet.openWindowWithSidebar(closeListener, Interfaces.SHOP_WINDOW, Interfaces.INVENTORY_SIDEBAR) + stop() + } + + /** + * Adds [SynchronizationInventoryListener]s to the [Player] and [Shop] [Inventories][Inventory], returning an + * [InterfaceListener] that removes them when the interface is closed. + */ + private fun addInventoryListeners(player: Player, shop: Inventory): InterfaceListener { + val invListener = SynchronizationInventoryListener(player, Interfaces.INVENTORY_CONTAINER) + val shopListener = SynchronizationInventoryListener(player, Interfaces.SHOP_CONTAINER) + + player.inventory.addListener(invListener) + player.inventory.forceRefresh() + + shop.addListener(shopListener) + shop.forceRefresh() + + return InterfaceListener { + mob.interfaceSet.close() + mob.resetInteractingMob() + + mob.inventory.removeListener(invListener) + shop.removeListener(shopListener) + } + } + +} + +/** + * An [InventorySupplier] that returns a [Player]'s [Inventory] if they are browsing a shop. + */ +class PlayerInventorySupplier : InventorySupplier { + + override fun getInventory(player: Player): Inventory? { + return when { + player.interfaceSet.contains(Interfaces.SHOP_WINDOW) -> player.inventory + else -> null + } + } + +} \ No newline at end of file diff --git a/game/plugin/shops/src/dls.kt b/game/plugin/shops/src/dls.kt new file mode 100644 index 000000000..19100bbda --- /dev/null +++ b/game/plugin/shops/src/dls.kt @@ -0,0 +1,350 @@ +import CategoryWrapper.Affix +import org.apollo.cache.def.NpcDefinition +import org.jetbrains.kotlin.utils.keysToMap + +/** + * Creates a [Shop]. + * + * @param name The name of the shop. + */ +fun shop(name: String, builder: ShopBuilder.() -> Unit) { + val shop = ShopBuilder(name) + builder(shop) + + val built = shop.build() + val operators = shop.operators().keysToMap { built } + + SHOPS.putAll(operators) +} + +/** + * A [DslMarker] for the shop DSL. + */ +@DslMarker +annotation class ShopDslMarker + +/** + * A builder for a [Shop]. + */ +@ShopDslMarker +class ShopBuilder(val name: String) { + + /** + * Overloads function invokation on strings to map `"ambiguous_npc_name"(id)` to a [Pair]. + */ + operator fun String.invoke(id: Int): Pair = Pair(this, id) + + /** + * Adds a sequence of items to this Shop, grouped together (in the DSL) for convenience. Items will be displayed + * in the same order they are provided. + * + * @param name The name of the category. + * @param affix The method of affixation between the item and category name (see [Affix]). + * @param depluralise Whether or not the category name should have the "s". + * @param builder The builder used to add items to the category. + */ + fun category(name: String, affix: Affix = Affix.Suffix, depluralise: Boolean = true, + builder: CategoryWrapper.() -> Unit) { + val items = mutableListOf>() + builder.invoke(CategoryWrapper(items)) + + val category = when { + depluralise -> name.removeSuffix("s") + else -> name + } + + val affixed = items.map { (name, amount) -> Pair(affix.join(name, category), amount) } + sold.addAll(affixed) + } + + /** + * Creates a [SellBuilder] with the specified [amount]. + */ + fun sell(amount: Int): SellBuilder = SellBuilder(amount, sold) + + /** + * The id on the operator npc's action menu used to open the shop. + */ + val action = ActionBuilder() + + /** + * The type of [Currency] the [Shop] makes exchanges with. + */ + var trades = CurrencyBuilder() + + /** + * The [Shop]'s policy towards purchasing items from players. + */ + var buys = PurchasesBuilder() + + /** + * Redundant variable used only to complete the [PurchasesBuilder] (e.g. `buys no items`). + */ + val items = Unit + + /** + * Places the category name before the item name (inserting a space between the names). + */ + val prefix = Affix.Prefix + + /** + * Prevents the category name from being joined to the item name in any way. + */ + val nothing = Affix.None + + /** + * The [OperatorBuilder] used to collate the [Shop]'s operators. + */ + val operated = OperatorBuilder() + + /** + * The [List] of items sold by the shop, as (name, amount) [Pair]s. + */ + private val sold = mutableListOf>() + + /** + * Converts this builder into a [Shop]. + */ + internal fun build(): Shop { + val items = sold.associateBy({ (first) -> lookup_item(first)!!.id }, Pair::second) + val npc = NpcDefinition.lookup(operators().first()) + + return Shop(name, action.action(npc), items, trades.currency, buys.policy) + } + + /** + * Gets the [List] of shop operator ids. + */ + internal fun operators(): MutableList = operated.operators + +} + +@ShopDslMarker +class CategoryWrapper(private val items: MutableList>) { + + /** + * The method of joining the item and category name. + */ + sealed class Affix(private val joiner: (item: String, category: String) -> String) { + + /** + * Appends the category after the item name (with a space between). + */ + object Suffix : Affix({ item, affix -> "$item $affix" }) + + /** + * Prepends the category before the item name (with a space between). + */ + object Prefix : Affix({ item, affix -> "$affix $item" }) + + /** + * Does not join the category at all (i.e. only returns the item name). + */ + object None : Affix({ item, _ -> item }) + + /** + * Joins the item and category name in the expected manner. + */ + fun join(item: String, category: String): String = joiner(item, category) + + } + + /** + * Creates a [SellBuilder] with the specified [amount]. + */ + fun sell(amount: Int): SellBuilder = SellBuilder(amount, items) + +} + +/** + * A builder to provide the list of shop operators - the npcs that can be interacted with to access the shop. + */ +@ShopDslMarker +class OperatorBuilder internal constructor() { + + /** + * The [List] of shop operators. + */ + val operators: MutableList = mutableListOf() + + /** + * Adds a shop operator, using the specified [name] to resolve the npc id. + */ + infix fun by(name: String): OperatorBuilder { + operators.add(lookup_npc(name)!!.id) + return this + } + + /** + * Adds a shop operator, using the specified [name] to resolve the npc id. + */ + infix fun and(name: String): OperatorBuilder = by(name) + + /** + * Adds a shop operator, using the specified [name] to resolve the npc id. + */ + operator fun plus(name: String): OperatorBuilder = and(name) + + /** + * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation + * operator, solely to disambiguate between npcs with the same name (e.g. + * `"Shopkeeper"(500) vs `"Shopkeeper"(501)`). Use [by(String][by] if the npc name is unambiguous. + */ + infix fun by(pair: Pair): OperatorBuilder { + operators.add(pair.second) + return this + } + + /** + * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation + * operator, solely to disambiguate between npcs with the same name (e.g. + * `"Shopkeeper"(500) vs `"Shopkeeper"(501)`). Use [by(String][by] if the npc name is unambiguous. + */ + infix fun and(pair: Pair): OperatorBuilder = by(pair) + + /** + * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation + * operator, solely to disambiguate between npcs with the same name (e.g. + * `"Shopkeeper"(500) vs `"Shopkeeper"(501)`). Use [by(String][by] if the npc name is unambiguous. + */ + operator fun plus(pair: Pair): OperatorBuilder = by(pair) + +} + +/** + * A builder to provide the action id used to open the shop. + */ +@ShopDslMarker +class ActionBuilder { + + private var action: String = "Trade" + + private var actionId: Int? = null + + /** + * Sets the name or id of the action used to open the shop interface with an npc. Defaults to "Trade". + * + * If specifying an id it must account for hidden npc menu actions (if any exist) - if "Open Shop" is the first + * action displayed when the npc is right-clicked, it does not necessarily mean that the action id is `1`. + * + * @param action The `name` (as a [String]) or `id` (as an `Int`) of the npc's action menu, to open the shop. + * @throws IllegalArgumentException If `action` is not a [String] or [Int]. + */ + override fun equals(@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") action: Any?): Boolean { + if (action is String) { + this.action = action + return true + } else if (action is Int) { + actionId = action + return true + } + + throw IllegalArgumentException("The Npc option must be provided as a String (the option name) or the ") + } + + /** + * Returns the open shop action slot. + * + * @throws IllegalArgumentException If the action id or name is invalid. + */ + internal fun action(npc: NpcDefinition): Int { + actionId?.let { action -> + if (npc.hasInteraction(action - 1)) { // ActionMessages are 1-based + return action + } + + throw IllegalArgumentException("Npc ${npc.name} does not have an an action $action.") + } + + val index = npc.interactions.indexOf(action) + when (index) { + -1 -> throw IllegalArgumentException("Npc ${npc.name} does not have an an action $action.") + else -> return index + 1 // ActionMessages are 1-based + } + } + + /** + * Throws [UnsupportedOperationException]. + */ + override fun hashCode(): Int = throw UnsupportedOperationException("ActionBuilder is a utility class for a DSL " + + "and improperly implements equals() - it should not be used anywhere outside of the DSL.") + +} + +/** + * A builder to provide the currency used by the [Shop]. + */ +@ShopDslMarker +class CurrencyBuilder { + + internal var currency = Currency.COINS + + /** + * Overloads the `in` operator on [Currency] to achieve e.g. `trades in tokkul`. + */ + operator fun Currency.contains(builder: CurrencyBuilder): Boolean { + builder.currency = this + return true + } + +} + +/** + * A builder to provide the [Shop.PurchasePolicy]. + */ +@ShopDslMarker +class PurchasesBuilder { + + internal var policy = Shop.PurchasePolicy.OWNED + + /** + * Instructs the shop to purchase no items, regardless of whether or not it sells it. + */ + infix fun no(@Suppress("UNUSED_PARAMETER") items: Unit) { + policy = Shop.PurchasePolicy.NOTHING + } + + /** + * Instructs the shop to purchase any tradeable item. + */ + infix fun any(@Suppress("UNUSED_PARAMETER") items: Unit) { + policy = Shop.PurchasePolicy.ANY + } + +} + +/** + * A builder to provide the items to sell. + * + * @param amount The amount to sell (of each item). + * @param items The [MutableList] to insert the given items into. + */ +@ShopDslMarker +class SellBuilder(val amount: Int, val items: MutableList>) { + + infix fun of(lambda: SellBuilder.() -> Unit) = lambda.invoke(this) + + /** + * Provides an item with the specified name. + * + * @name The item name. Must be unambiguous. + */ + infix fun of(name: String) = items.add(Pair(name, amount)) + + /** + * Overloads unary minus on Strings so that item names can be listed. + */ + operator fun String.unaryMinus() = items.add(Pair(this, amount)) + + /** + * Overloads the unary minus on Pairs so that name+id pairs can be listed. Only intended to be used with the + * overloaded String invokation operator. + */ // ShopBuilder uses the lookup plugin, which can operate on _ids tacked on the end + operator fun Pair.unaryMinus() = items.add(Pair("{$this.first}_${this.second}", amount)) + + /** + * Overloads function invokation on Strings to map `"ambiguous_npc_name"(id)` to a [Pair]. + */ + operator fun String.invoke(id: Int): Pair = Pair(this, id) + +} diff --git a/game/plugin/shops/src/shop.kt b/game/plugin/shops/src/shop.kt new file mode 100644 index 000000000..90e81086c --- /dev/null +++ b/game/plugin/shops/src/shop.kt @@ -0,0 +1,333 @@ +import Shop.Companion.ExchangeType.BUYING +import Shop.Companion.ExchangeType.SELLING +import Shop.PurchasePolicy.ANY +import Shop.PurchasePolicy.NOTHING +import Shop.PurchasePolicy.OWNED +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.Item +import org.apollo.game.model.entity.Player +import org.apollo.game.model.inv.Inventory +import org.apollo.game.model.inv.Inventory.StackMode.STACK_ALWAYS + +/** + * Contains shop-related interface ids. + */ +object Interfaces { + + /** + * The container interface id for the player's inventory. + */ + const val INVENTORY_CONTAINER = 3823 + + /** + * The sidebar id for the inventory, when a Shop window is open. + */ + const val INVENTORY_SIDEBAR = 3822 + + /** + * The shop window interface id. + */ + const val SHOP_WINDOW = 3824 + + /** + * The container interface id for the shop's inventory. + */ + const val SHOP_CONTAINER = 3900 + + /** + * The id of the text widget that displays a shop's name. + */ + const val SHOP_NAME = 3901 + +} + +/** + * The [Map] from npc ids to [Shop]s. + */ +val SHOPS = mutableMapOf() + +/** + * A [Shop]'s method of payment. + * + * @param id The item id of the currency. + * @param plural Whether or not the name of this currency is plural. + */ +data class Currency(val id: Int, val plural: Boolean = false) { + + companion object { + val COINS = Currency(995, plural = true) + } + + val name: String = ItemDefinition.lookup(id).name?.toLowerCase() + ?: throw IllegalArgumentException("Currencies must have a name.") + + fun name(amount: Int): String { + return when { + amount == 1 && plural -> name.removeSuffix("s") + else -> name + } + } + +} + +/** + * An in-game shop, operated by one or more npcs. + * + * @param name The name of the shop. + * @param action The id of the NpcActionMessage sent (by the client) when a player opens this shop. + * @param sells The [Map] from item id to amount sold. + * @param currency The [Currency] used when making exchanges with this [Shop]. + * @param purchases This [Shop]'s attitude towards purchasing items from players. + */ +class Shop( + val name: String, + val action: Int, + private val sells: Map, + private val currency: Currency = Currency.COINS, + private val purchases: PurchasePolicy = OWNED +) { + + companion object { + + /** + * The amount of pulses between shop inventory restocking. + */ + const val RESTOCK_INTERVAL = 100 + + /** + * The capacity of a [Shop]. + */ + private const val CAPACITY = 30 + + /** + * The type of exchange occurring between the [Player] and [Shop]. + */ + private enum class ExchangeType { BUYING, SELLING } + + /** + * The option id for item valuation. + */ + private const val VALUATION_OPTION = 1 + + /** + * Returns the amount that a player tried to buy or sell. + * + * @param option The id of the option the player selected. + */ + private fun amount(option: Int): Int { + return when (option) { + 2 -> 1 + 3 -> 5 + 4 -> 10 + else -> throw IllegalArgumentException("Option must be 1-4") + } + } + + } + + /** + * The [Shop]s policy regarding purchasing items from players. + */ + enum class PurchasePolicy { + + /** + * Never purchase anything from players. + */ + NOTHING, + + /** + * Only purchase items that this Shop sells by default. + */ + OWNED, + + /** + * Purchase any tradeable items. + */ + ANY + } + + /** + * The [Inventory] containing this [Shop]'s current items. + */ + val inventory = Inventory(CAPACITY, STACK_ALWAYS) + + init { + sells.forEach { (id, amount) -> inventory.add(id, amount) } + } + + /** + * Restocks this [Shop], adding and removing items as necessary to move the stock closer to its initial state. + */ + fun restock() { + for (item in inventory.items.filterNotNull()) { + val id = item.id + + if (!sells(id) || item.amount > sells[id]!!) { + inventory.remove(id) + } else if (item.amount < sells[id]!!) { + inventory.add(id) + } + } + } + + /** + * Sells an item to a [Player]. + */ + fun sell(player: Player, slot: Int, option: Int) { + val item = inventory.get(slot) + val id = item.id + val itemCost = value(id, SELLING) + + if (option == VALUATION_OPTION) { + val itemId = ItemDefinition.lookup(id).name + player.sendMessage("$itemId: currently costs $itemCost ${currency.name(itemCost)}.") + return + } + + var buying: Int = amount(option) + var unavailable = false + + val amount = item.amount + if (buying > amount) { + buying = amount + unavailable = true + } + + val stackable = item.definition.isStackable + val slotsRequired = when { + stackable && player.inventory.contains(id) -> 0 + !stackable -> buying + else -> 1 + } + + val freeSlots = player.inventory.freeSlots() + var full = false + + if (slotsRequired > freeSlots) { + buying = freeSlots + full = true + } + + val totalCost = buying * itemCost + val totalCurrency = player.inventory.getAmount(currency.id) + var unaffordable = false + + if (totalCost > totalCurrency) { + buying = totalCurrency / itemCost + unaffordable = true + } + + if (buying > 0) { + player.inventory.remove(currency.id, totalCost) + val remaining = player.inventory.add(id, buying) + + if (remaining > 0) { + player.inventory.add(currency.id, remaining * itemCost) + } + + if (buying >= amount && sells(id)) { + // If the item is from the shop's main stock, set its amount to zero so it can be restocked over time. + inventory.set(slot, Item(id, 0)) + } else { + inventory.remove(id, buying - remaining) + } + } + + val message = when { + unaffordable -> "You don't have enough ${currency.name}." + full -> "You don't have enough inventory space." + unavailable -> "The shop has run out of stock." + else -> return + } + + player.sendMessage(message) + } + + /** + * Purchases the item from the specified [Player]. + */ + fun buy(seller: Player, slot: Int, option: Int) { + val player = seller.inventory + val id = player.get(slot).id + + if (!verifyPurchase(seller, id)) { + return + } + + val value = value(id, BUYING) + if (option == VALUATION_OPTION) { + seller.sendMessage("${ItemDefinition.lookup(id).name}: shop will buy for $value ${currency.name(value)}.") + return + } + + val amount = Math.min(player.getAmount(id), amount(option)) + + player.remove(id, amount) + inventory.add(id, amount) + + if (value != 0) { + player.add(currency.id, value * amount) + } + } + + /** + * Returns the value of the item with the specified id. + * + * @param method The [ExchangeType]. + */ + private fun value(item: Int, method: ExchangeType): Int { + val value = ItemDefinition.lookup(item).value + + return when (method) { + BUYING -> when (purchases) { + NOTHING -> throw UnsupportedOperationException("Cannot get sell value in shop that doesn't buy.") + OWNED -> (value * 0.6).toInt() + ANY -> (value * 0.4).toInt() + } + SELLING -> when (purchases) { + ANY -> Math.ceil(value * 0.8).toInt() + else -> value + } + } + } + + /** + * Verifies that the [Player] can actually sell an item with the given id to this [Shop]. + * + * @param id The id of the [Item] to sell. + */ + private fun verifyPurchase(player: Player, id: Int): Boolean { + val item = ItemDefinition.lookup(id) + + if (!purchases(id) || item.isMembersOnly && !player.isMembers || item.value == 0) { + player.sendMessage("You can't sell this item to this shop.") + return false + } else if (inventory.freeSlots() == 0 && !inventory.contains(id)) { + player.sendMessage("The shop is currently full at the moment.") + return false + } + + return true + } + + /** + * Returns whether or not this [Shop] will purchase an item with the given id. + * + * @param id The id of the [Item] purchase buy. + */ + private fun purchases(id: Int): Boolean { + return id != currency.id && when (purchases) { + NOTHING -> false + OWNED -> sells.containsKey(id) + ANY -> true + } + } + + /** + * Returns whether or not this [Shop] sells the item with the given id. + * + * @param id The id of the [Item] to sell. + */ + private fun sells(id: Int): Boolean = sells.containsKey(id) + +} \ No newline at end of file diff --git a/game/plugin/shops/src/shop.plugin.kts b/game/plugin/shops/src/shop.plugin.kts new file mode 100644 index 000000000..8dd974a8b --- /dev/null +++ b/game/plugin/shops/src/shop.plugin.kts @@ -0,0 +1,46 @@ + +import org.apollo.game.message.handler.ItemVerificationHandler +import org.apollo.game.message.impl.ItemActionMessage +import org.apollo.game.message.impl.NpcActionMessage +import org.apollo.game.model.entity.Mob +import org.apollo.game.scheduling.ScheduledTask + +fun Mob.shop(): Shop? = SHOPS[definition.id] + +start { + ItemVerificationHandler.addInventory(Interfaces.SHOP_CONTAINER) { it.interactingMob?.shop()?.inventory } + ItemVerificationHandler.addInventory(Interfaces.INVENTORY_CONTAINER, PlayerInventorySupplier()) + + it.schedule(object : ScheduledTask(Shop.RESTOCK_INTERVAL, false) { + override fun execute() = SHOPS.values.distinct().forEach(Shop::restock) + }) +} + +on { NpcActionMessage::class } + .then { + val npc = it.world.npcRepository.get(index) + val shop = npc.shop() ?: return@then + + if (shop.action == option) { + it.startAction(OpenShopAction(it, shop, npc)) + terminate() + } + } + + +on { ItemActionMessage::class } + .where { interfaceId == Interfaces.SHOP_CONTAINER || interfaceId == Interfaces.INVENTORY_CONTAINER } + .then { + if (!it.interfaceSet.contains(Interfaces.SHOP_WINDOW)) { + return@then + } + + val shop = it.interactingMob?.shop() ?: return@then + when (interfaceId) { + Interfaces.INVENTORY_CONTAINER -> shop.buy(it, slot, option) + Interfaces.SHOP_CONTAINER -> shop.sell(it, slot, option) + else -> throw IllegalStateException("Supposedly unreacheable case.") + } + + terminate() + } \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/message/handler/ItemVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/ItemVerificationHandler.java index 5f61d8043..a6e96c9c2 100644 --- a/game/src/main/java/org/apollo/game/message/handler/ItemVerificationHandler.java +++ b/game/src/main/java/org/apollo/game/message/handler/ItemVerificationHandler.java @@ -31,7 +31,7 @@ public interface InventorySupplier { * Gets the appropriate {@link Inventory}. * * @param player The {@link Player} who prompted the verification call. - * @return The inventory. Must not be {@code null}. + * @return The inventory, or {@code null} to immediately fail verification. */ Inventory getInventory(Player player); From 22df59500e44730fa443f4ece75739e1b825c947 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Sat, 23 Sep 2017 04:13:47 +0100 Subject: [PATCH 073/209] Add varrock shops --- game/plugin/locations/varrock/build.gradle | 8 +- .../locations/varrock/src/shops.plugin.kts | 172 ++++++++++++++++++ 2 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 game/plugin/locations/varrock/src/shops.plugin.kts diff --git a/game/plugin/locations/varrock/build.gradle b/game/plugin/locations/varrock/build.gradle index 54a1418cc..86896a7c7 100644 --- a/game/plugin/locations/varrock/build.gradle +++ b/game/plugin/locations/varrock/build.gradle @@ -1,10 +1,12 @@ plugin { - name = "varrock_npc_spawns" + name = "varrock" packageName = "org.apollo.game.plugin.locations" authors = [ - "Jesse W", + "Jesse W", + "Major", + "tlf30", ] dependencies = [ - "entity:spawn", + "entity:spawn", "shops" ] } \ No newline at end of file diff --git a/game/plugin/locations/varrock/src/shops.plugin.kts b/game/plugin/locations/varrock/src/shops.plugin.kts new file mode 100644 index 000000000..d48e15e6e --- /dev/null +++ b/game/plugin/locations/varrock/src/shops.plugin.kts @@ -0,0 +1,172 @@ +shop("Aubury's Rune Shop.") { + operated by "Aubury" + + category("runes") { + sell(5000) of { + -"Earth" + -"Water" + -"Fire" + -"Air" + -"Mind" + -"Body" + } + + sell(250) of { + -"Chaos" + -"Death" + } + } +} + +shop("Lowe's Archery Emporium.") { + operated by "Lowe" + + category("arrows") { + sell(2000) of "Bronze" + sell(1500) of "Iron" + sell(1000) of "Steel" + sell(800) of "Mithril" + sell(600) of "Adamant" + } + + category("normal weapons", affix = nothing) { + sell(4) of "Shortbow" + sell(4) of "Longbow" + sell(2) of "Crossbow" + } + + category("shortbows") { + sell(3) of "Oak" + sell(2) of "Willow" + sell(1) of "Maple" + } + + category("longbows") { + sell(3) of "Oak" + sell(2) of "Willow" + sell(1) of "Maple" + } +} + +shop("Horvik's Armour Shop.") { + operated by "Horvik" + + category("chainbody") { + sell(5) of "Bronze" + sell(3) of "Iron" + sell(3) of "Steel" + sell(1) of "Mithril" + } + + category("platebody") { + sell(3) of "Bronze" + + sell(1) of { + -"Iron" + -"Steel" + -"Black" + -"Mithril" + } + } + + sell(1) of { + -"Iron platelegs" + -"Studded body" + -"Studded chaps" + } +} + +shop("Thessalia's Fine Clothes.") { + operated by "Thessalia" + + category("apron") { + sell(3) of "White" + sell(1) of "Brown" + } + + category("leather", affix = prefix) { + sell(12) of "Body" + sell(10) of "Gloves" + sell(10) of "Boots" + } + + category("skirt") { + sell(5) of "Pink" + sell(3) of "Black" + sell(2) of "Blue" + } + + sell(4) of "Cape" + sell(5) of "Silk" + + sell(3) of { + -"Priest gown"(426) + -"Priest gown"(428) + } +} + +shop("Varrock General Store.") { + operated by "Shopkeeper"(522) and "Shop assistant"(523) + buys any items + + sell(5) of "Pot" + sell(2) of "Jug" + sell(2) of "Shears" + sell(3) of "Bucket" + sell(2) of "Bowl" + sell(2) of "Cake tin" + sell(2) of "Tinderbox" + sell(2) of "Chisel" + sell(5) of "Hammer" + sell(5) of "Newcomer map" +} + +shop("Varrock Swordshop.") { + operated by "Shopkeeper"(551) and "Shop assistant"(552) + + category("swords") { + sell(5) of "Bronze" + sell(4) of "Iron" + sell(4) of "Steel" + sell(3) of "Black" + sell(3) of "Mithril" + sell(2) of "Adamant" + } + + category("longswords") { + sell(4) of "Bronze" + sell(3) of "Iron" + sell(3) of "Steel" + sell(2) of "Black" + sell(2) of "Mithril" + sell(1) of "Adamant" + } + + category("daggers") { + sell(10) of "Bronze" + sell(6) of "Iron" + sell(5) of "Steel" + sell(4) of "Black" + sell(3) of "Mithril" + sell(2) of "Adamant" + } +} + +shop("Zaff's Superior Staffs!") { + operated by "Zaff" + + category("staves", affix = nothing) { + sell(5) of { + -"Battlestaff" + -"Staff" + -"Magic staff" + } + + sell(2) of { + -"Staff of air" + -"Staff of water" + -"Staff of earth" + -"Staff of fire" + } + } +} From 53521e7e0d267922391b4254206c34218128b145 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 23 Sep 2017 13:30:13 +0100 Subject: [PATCH 074/209] Update varrock plugin package name --- game/plugin/locations/varrock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/plugin/locations/varrock/build.gradle b/game/plugin/locations/varrock/build.gradle index 86896a7c7..1443d085b 100644 --- a/game/plugin/locations/varrock/build.gradle +++ b/game/plugin/locations/varrock/build.gradle @@ -1,6 +1,6 @@ plugin { name = "varrock" - packageName = "org.apollo.game.plugin.locations" + packageName = "org.apollo.game.plugin.locations.varrock" authors = [ "Jesse W", "Major", From 64ee653423ac63e26023d97236d2012cc7236480 Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 23 Sep 2017 19:37:31 +0100 Subject: [PATCH 075/209] Rename dls.kt to dsl.kt --- game/plugin/shops/src/{dls.kt => dsl.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename game/plugin/shops/src/{dls.kt => dsl.kt} (100%) diff --git a/game/plugin/shops/src/dls.kt b/game/plugin/shops/src/dsl.kt similarity index 100% rename from game/plugin/shops/src/dls.kt rename to game/plugin/shops/src/dsl.kt From 01f2bdda58d7a3e4e7c47d63b033382f85d9850a Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Sat, 23 Sep 2017 18:00:38 -0700 Subject: [PATCH 076/209] Port Fishing plugin to kotlin (#347) This also fixes a bunch of bugs. --- game/plugin/skills/fishing/build.gradle | 12 ++ game/plugin/skills/fishing/src/fishing.kt | 170 ++++++++++++++++ .../skills/fishing/src/fishing.plugin.kts | 137 +++++++++++++ game/plugin/skills/fishing/src/spots.kts | 187 ++++++++++++++++++ 4 files changed, 506 insertions(+) create mode 100644 game/plugin/skills/fishing/build.gradle create mode 100644 game/plugin/skills/fishing/src/fishing.kt create mode 100644 game/plugin/skills/fishing/src/fishing.plugin.kts create mode 100644 game/plugin/skills/fishing/src/spots.kts diff --git a/game/plugin/skills/fishing/build.gradle b/game/plugin/skills/fishing/build.gradle new file mode 100644 index 000000000..4e13f4397 --- /dev/null +++ b/game/plugin/skills/fishing/build.gradle @@ -0,0 +1,12 @@ +plugin { + name = "fishing_skill" + packageName = "org.apollo.game.plugin.skills.fishing" + authors = [ + "Linux", + "Major", + "tlf30" + ] + dependencies = [ + "util:lookup", "entity:spawn", "api" + ] +} diff --git a/game/plugin/skills/fishing/src/fishing.kt b/game/plugin/skills/fishing/src/fishing.kt new file mode 100644 index 000000000..e045a445b --- /dev/null +++ b/game/plugin/skills/fishing/src/fishing.kt @@ -0,0 +1,170 @@ +package org.apollo.game.plugin.skills.fishing + +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.Animation +import org.apollo.game.plugin.skills.fishing.Fish.* +import org.apollo.game.plugin.skills.fishing.FishingTool.* +import java.util.Random + +/** + * A fish that can be gathered using the fishing skill. + */ +enum class Fish(val id: Int, val level: Int, val experience: Double) { + SHRIMP(317, 1, 10.0), + SARDINE(327, 5, 20.0), + MACKEREL(353, 16, 20.0), + HERRING(345, 10, 30.0), + ANCHOVY(321, 15, 40.0), + TROUT(335, 20, 50.0), + COD(341, 23, 45.0), + PIKE(349, 25, 60.0), + SALMON(331, 30, 70.0), + TUNA(359, 35, 80.0), + LOBSTER(377, 40, 90.0), + BASS(363, 46, 100.0), + SWORDFISH(371, 50, 100.0), + SHARK(383, 76, 110.0); + + /** + * The name of this fish, formatted so it can be inserted into a message. + */ + val formattedName = ItemDefinition.lookup(id).name.toLowerCase() + +} + +/** + * A tool used to gather [Fish] from a [FishingSpot]. + */ +enum class FishingTool(val id: Int, animation: Int, val message: String, val bait: Int, val baitName: String?) { + LOBSTER_CAGE(301, 619, "You attempt to catch a lobster..."), + SMALL_NET(303, 620, "You cast out your net..."), + BIG_NET(305, 620, "You cast out your net..."), + HARPOON(311, 618, "You start harpooning fish..."), + FISHING_ROD(307, 622, "You attempt to catch a fish...", 313, "feathers"), + FLY_FISHING_ROD(309, 622, "You attempt to catch a fish...", 314, "fishing bait"); + + @Suppress("unused") // IntelliJ bug, doesn't detect that this constructor is used + constructor(id: Int, animation: Int, message: String) : this(id, animation, message, -1, null) + + /** + * The [Animation] played when fishing with this tool. + */ + val animation: Animation = Animation(animation) + + /** + * The name of this tool, formatted so it can be inserted into a message. + */ + val formattedName = ItemDefinition.lookup(id).name.toLowerCase() + +} + +/** + * A spot that can be fished from. + */ +enum class FishingSpot(val npc: Int, private val first: Option, private val second: Option) { + ROD(309, Option.of(FLY_FISHING_ROD, TROUT, SALMON), Option.of(FISHING_ROD, PIKE)), + CAGE_HARPOON(312, Option.of(LOBSTER_CAGE, LOBSTER), Option.of(HARPOON, TUNA, SWORDFISH)), + NET_HARPOON(313, Option.of(BIG_NET, MACKEREL, COD), Option.of(HARPOON, BASS, SHARK)), + NET_ROD(316, Option.of(SMALL_NET, SHRIMP, ANCHOVY), Option.of(FISHING_ROD, SARDINE, HERRING)); + + companion object { + + private val FISHING_SPOTS = FishingSpot.values().associateBy({ it.npc }, { it }) + + /** + * Returns the [FishingSpot] with the specified [id], or `null` if the spot does not exist. + */ + fun lookup(id: Int): FishingSpot? = FISHING_SPOTS[id] + + } + + /** + * Returns the [FishingSpot.Option] associated with the specified action id. + */ + fun option(action: Int): Option { + return when (action) { + 1 -> first + 3 -> second + else -> throw UnsupportedOperationException("Unexpected fishing spot option $action.") + } + } + + /** + * An option at a [FishingSpot] (e.g. either "rod fishing" or "net fishing"). + */ + sealed class Option { + + companion object { + + fun of(tool: FishingTool, primary: Fish): Option = Single(tool, primary) + + fun of(tool: FishingTool, primary: Fish, secondary: Fish): Option { + return when { + primary.level < secondary.level -> Pair(tool, primary, secondary) + else -> Pair(tool, secondary, primary) + } + } + + } + + /** + * The tool used to obtain fish + */ + abstract val tool: FishingTool + + /** + * The minimum level required to obtain fish. + */ + abstract val level: Int + + /** + * Samples a [Fish], randomly (with weighting) returning one (that can be fished by the player). + * + * @param level The fishing level of the player. + */ + abstract fun sample(level: Int): Fish + + /** + * A [FishingSpot] [Option] that can only provide a single type of fish. + */ + private data class Single(override val tool: FishingTool, val primary: Fish) : Option() { + override val level = primary.level + + override fun sample(level: Int): Fish = primary + + } + + /** + * A [FishingSpot] [Option] that can provide a two different types of fish. + */ + private data class Pair(override val tool: FishingTool, val primary: Fish, val secondary: Fish) : Option() { + + companion object { + + val random = Random() + + /** + * The weighting factor that causes the lower-level fish to be returned more frequently. + */ + const val WEIGHTING = 70 + + } + + override val level = Math.min(primary.level, secondary.level) + + override fun sample(level: Int): Fish { + if (secondary.level > level) { + return primary + } + + return when { + random.nextInt(100) < WEIGHTING -> primary + else -> secondary + } + } + + } + + } + +} diff --git a/game/plugin/skills/fishing/src/fishing.plugin.kts b/game/plugin/skills/fishing/src/fishing.plugin.kts new file mode 100644 index 000000000..cc53c99ce --- /dev/null +++ b/game/plugin/skills/fishing/src/fishing.plugin.kts @@ -0,0 +1,137 @@ +import Fishing_plugin.FishingAction +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.message.impl.NpcActionMessage +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.skills.fishing.FishingSpot +import org.apollo.game.plugin.skills.fishing.FishingTool +import org.apollo.game.plugins.api.fishing +import org.apollo.game.plugins.api.skills +import java.util.Objects +import java.util.Random + +// TODO: moving fishing spots, seaweed and caskets, evil bob + +class FishingAction(player: Player, position: Position, val option: FishingSpot.Option) : + AsyncDistancedAction(0, true, player, position, SPOT_DISTANCE) { + + companion object { + private const val SPOT_DISTANCE = 1 + private const val FISHING_DELAY = 4 + + /** + * The random number generator used by the fishing plugin. + */ + private val random = Random() + + /** + * Returns whether or not the catch was successful. + * TODO: We need to identify the correct algorithm for this + */ + private fun successfulCatch(level: Int, req: Int): Boolean = minOf(level - req + 5, 40) > random.nextInt(100) + + /** + * Returns whether or not the [Player] has (or does not need) bait. + */ + private fun hasBait(player: Player, bait: Int): Boolean = bait == -1 || player.inventory.contains(bait) + + /** + * @return if the player has the needed tool to fish at the spot. + */ + private fun hasTool(player: Player, tool: FishingTool): Boolean = player.equipment.contains(tool.id) || + player.inventory.contains(tool.id) + + } + + /** + * The [FishingTool] used for the fishing spot. + */ + private val tool = option.tool + + override fun action(): ActionBlock = { + if (!verify()) { + stop() + } + + mob.turnTo(position) + mob.sendMessage(tool.message) + + while (isRunning) { + mob.playAnimation(tool.animation) + wait(FISHING_DELAY) + + val level = mob.skills.fishing.currentLevel + val fish = option.sample(level) + + if (successfulCatch(level, fish.level)) { + if (tool.bait != -1) { + mob.inventory.remove(tool.bait) + } + + mob.inventory.add(fish.id) + mob.sendMessage("You catch a ${fish.formattedName}.") + mob.skills.addExperience(Skill.FISHING, fish.experience) + + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + mob.stopAnimation() + stop() + } else if (!hasBait(mob, tool.bait)) { + mob.sendMessage("You need more ${tool.baitName} to fish at this spot.") + mob.stopAnimation() + stop() + } + } + } + } + + /** + * Verifies that the player can gather fish from the [FishingSpot] they clicked. + */ + private fun verify(): Boolean { + if (mob.skills.fishing.currentLevel < option.level) { + mob.sendMessage("You need a fishing level of ${option.level} to fish at this spot.") + return false + } else if (!hasTool(mob, tool)) { + mob.sendMessage("You need a ${tool.formattedName} to fish at this spot.") + return false + } else if (!hasBait(mob, tool.bait)) { + mob.sendMessage("You need some ${tool.baitName} to fish at this spot.") + return false + } else if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + return false + } + + return true + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FishingAction + + return option == other.option && position == other.position && mob == other.mob + } + + override fun hashCode(): Int = Objects.hash(option, position, mob) + +} + +/** + * Intercepts the [NpcActionMessage] and starts a [FishingAction] if the npc + */ +on { NpcActionMessage::class } + .where { option == 1 || option == 3 } + .then { + val entity = it.world.npcRepository[index] + val spot = FishingSpot.lookup(entity.id) ?: return@then + + val option = spot.option(option) + it.startAction(FishingAction(it, entity.position, option)) + + terminate() + } diff --git a/game/plugin/skills/fishing/src/spots.kts b/game/plugin/skills/fishing/src/spots.kts new file mode 100644 index 000000000..83080e29f --- /dev/null +++ b/game/plugin/skills/fishing/src/spots.kts @@ -0,0 +1,187 @@ + +import org.apollo.game.model.Direction +import org.apollo.game.model.Position +import org.apollo.game.plugin.skills.fishing.FishingSpot +import org.apollo.game.plugin.skills.fishing.FishingSpot.CAGE_HARPOON +import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_HARPOON +import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_ROD +import org.apollo.game.plugin.skills.fishing.FishingSpot.ROD + +// Al-Kharid +register(NET_ROD, x = 3267, y = 3148) +register(NET_ROD, x = 3268, y = 3147) +register(NET_ROD, x = 3277, y = 3139) +register(CAGE_HARPOON, x = 3350, y = 3817) +register(CAGE_HARPOON, x = 3347, y = 3814) +register(CAGE_HARPOON, x = 3363, y = 3816) +register(CAGE_HARPOON, x = 3368, y = 3811) + +// Ardougne +register(ROD, x = 2561, y = 3374) +register(ROD, x = 2562, y = 3374) +register(ROD, x = 2568, y = 3365) + +// Bandit camp +register(NET_ROD, x = 3047, y = 3703) +register(NET_ROD, x = 3045, y = 3702) + +// Baxtorian falls +register(ROD, x = 2527, y = 3412) +register(ROD, x = 2530, y = 3412) +register(ROD, x = 2533, y = 3410) + +// Burgh de Rott +register(NET_HARPOON, x = 3497, y = 3175) +register(NET_HARPOON, x = 3496, y = 3178) +register(NET_HARPOON, x = 3499, y = 3178) +register(NET_HARPOON, x = 3489, y = 3184) +register(NET_HARPOON, x = 3496, y = 3176) +register(NET_HARPOON, x = 3486, y = 3184) +register(NET_HARPOON, x = 3479, y = 3189) +register(NET_HARPOON, x = 3476, y = 3191) +register(NET_HARPOON, x = 3472, y = 3196) +register(NET_HARPOON, x = 3496, y = 3180) +register(NET_HARPOON, x = 3512, y = 3178) +register(NET_HARPOON, x = 3515, y = 3180) +register(NET_HARPOON, x = 3518, y = 3177) +register(NET_HARPOON, x = 3528, y = 3172) +register(NET_HARPOON, x = 3531, y = 3169) +register(NET_HARPOON, x = 3531, y = 3172) +register(NET_HARPOON, x = 3531, y = 3167) + +// Camelot +register(ROD, x = 2726, y = 3524) +register(ROD, x = 2727, y = 3524) + +// Castle wars +register(ROD, x = 2461, y = 3151) +register(ROD, x = 2461, y = 3150) +register(ROD, x = 2462, y = 3145) +register(ROD, x = 2472, y = 3156) + +// Catherby 1 +register(NET_ROD, x = 2838, y = 3431) +register(CAGE_HARPOON, x = 2837, y = 3431) +register(CAGE_HARPOON, x = 2836, y = 3431) +register(NET_ROD, x = 2846, y = 3429) +register(NET_ROD, x = 2844, y = 3429) +register(CAGE_HARPOON, x = 2845, y = 3429) +register(NET_HARPOON, x = 2853, y = 3423) +register(NET_HARPOON, x = 2855, y = 3423) +register(NET_HARPOON, x = 2859, y = 3426) + +// Draynor village +register(NET_ROD, x = 3085, y = 3230) +register(NET_ROD, x = 3085, y = 3231) +register(NET_ROD, x = 3086, y = 3227) + +// Elf camp +register(ROD, x = 2210, y = 3243) +register(ROD, x = 2216, y = 3236) +register(ROD, x = 2222, y = 3241) + +// Entrana +register(NET_ROD, x = 2843, y = 3359) +register(NET_ROD, x = 2842, y = 3359) +register(NET_ROD, x = 2847, y = 3361) +register(NET_ROD, x = 2848, y = 3361) +register(NET_ROD, x = 2840, y = 3356) +register(NET_ROD, x = 2845, y = 3356) +register(NET_ROD, x = 2875, y = 3342) +register(NET_ROD, x = 2876, y = 3342) +register(NET_ROD, x = 2877, y = 3342) + +// Fishing guild +register(CAGE_HARPOON, x = 2612, y = 3411) +register(CAGE_HARPOON, x = 2607, y = 3410) +register(NET_HARPOON, x = 2612, y = 3414) +register(NET_HARPOON, x = 2612, y = 3415) +register(NET_HARPOON, x = 2609, y = 3416) +register(CAGE_HARPOON, x = 2604, y = 3417) +register(NET_HARPOON, x = 2605, y = 3416) +register(NET_HARPOON, x = 2602, y = 3411) +register(NET_HARPOON, x = 2602, y = 3412) +register(CAGE_HARPOON, x = 2602, y = 3414) +register(NET_HARPOON, x = 2603, y = 3417) +register(NET_HARPOON, x = 2599, y = 3419) +register(NET_HARPOON, x = 2601, y = 3422) +register(NET_HARPOON, x = 2605, y = 3421) +register(CAGE_HARPOON, x = 2602, y = 3426) +register(NET_HARPOON, x = 2604, y = 3426) +register(CAGE_HARPOON, x = 2605, y = 3425) + +// Fishing platform +register(NET_ROD, x = 2791, y = 3279) +register(NET_ROD, x = 2795, y = 3279) +register(NET_ROD, x = 2790, y = 3273) + +// Grand Tree +register(ROD, x = 2393, y = 3419) +register(ROD, x = 2391, y = 3421) +register(ROD, x = 2389, y = 3423) +register(ROD, x = 2388, y = 3423) +register(ROD, x = 2385, y = 3422) +register(ROD, x = 2384, y = 3419) +register(ROD, x = 2383, y = 3417) + +// Gunnarsgrunn +register(ROD, x = 3101, y = 3092) +register(ROD, x = 3103, y = 3092) + +// Karamja +register(NET_ROD, x = 2921, y = 3178) +register(CAGE_HARPOON, x = 2923, y = 3179) +register(CAGE_HARPOON, x = 2923, y = 3180) +register(NET_ROD, x = 2924, y = 3181) +register(NET_ROD, x = 2926, y = 3180) +register(CAGE_HARPOON, x = 2926, y = 3179) + +// Lumbridge +register(ROD, x = 3239, y = 3244) +register(NET_ROD, x = 3238, y = 3252) + +// Miscellenia +register(CAGE_HARPOON, x = 2580, y = 3851) +register(CAGE_HARPOON, x = 2581, y = 3851) +register(CAGE_HARPOON, x = 2582, y = 3851) +register(CAGE_HARPOON, x = 2583, y = 3852) +register(CAGE_HARPOON, x = 2583, y = 3853) + +// Rellekka +register(NET_ROD, x = 2633, y = 3691) +register(NET_ROD, x = 2633, y = 3689) +register(CAGE_HARPOON, x = 2639, y = 3698) +register(CAGE_HARPOON, x = 2639, y = 3697) +register(CAGE_HARPOON, x = 2639, y = 3695) +register(NET_HARPOON, x = 2642, y = 3694) +register(NET_HARPOON, x = 2642, y = 3697) +register(NET_HARPOON, x = 2644, y = 3709) + +// Rimmington +register(NET_ROD, x = 2990, y = 3169) +register(NET_ROD, x = 2986, y = 3176) + +// Shilo Village + +register(ROD, x = 2855, y = 2974) +register(ROD, x = 2865, y = 2972) +register(ROD, x = 2860, y = 2972) +register(ROD, x = 2835, y = 2974) +register(ROD, x = 2859, y = 2976) + +// Tirannwn +register(ROD, x = 2266, y = 3253) +register(ROD, x = 2265, y = 3258) +register(ROD, x = 2264, y = 3258) + +// Tutorial island +register(NET_ROD, x = 3101, y = 3092) +register(NET_ROD, x = 3103, y = 3092) + +/** + * Registers the [FishingSpot] at the specified position. + */ +fun register(spot: FishingSpot, x: Int, y: Int, z: Int = 0) { + val position = Position(x, y, z) + Spawns.list.add(Spawn(spot.npc, "", position, Direction.NORTH)) +} \ No newline at end of file From 8c2f086ae5b4dbab29980202f44ef730e017827b Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 24 Sep 2017 02:40:33 +0100 Subject: [PATCH 077/209] Remove meta.toml files Since plugins were moved to gradle they aren't used anyway. --- game/plugin/bank/meta.toml | 7 ------- game/plugin/chat/private-messaging/meta.toml | 0 game/plugin/cmd/meta.toml | 13 ------------- game/plugin/consumables/meta.toml | 8 -------- game/plugin/dummy/meta.toml | 7 ------- game/plugin/emote-tab/meta.toml | 7 ------- game/plugin/entity/following/meta.toml | 8 -------- game/plugin/entity/player-action/meta.toml | 8 -------- game/plugin/entity/spawn/meta.toml | 8 -------- game/plugin/entity/walk-to/meta.toml | 4 ---- game/plugin/locations/al-kharid/meta.toml | 8 -------- game/plugin/locations/edgeville/meta.toml | 8 -------- game/plugin/locations/falador/meta.toml | 8 -------- game/plugin/locations/lumbridge/meta.toml | 8 -------- game/plugin/locations/tutorial-island/meta.toml | 8 -------- game/plugin/locations/varrock/meta.toml | 8 -------- game/plugin/logout/meta.toml | 1 - game/plugin/run/meta.toml | 1 - game/plugin/skills/mining/meta.toml | 14 -------------- game/plugin/util/command/meta.toml | 5 ----- game/plugin/util/lookup/meta.toml | 2 -- 21 files changed, 141 deletions(-) delete mode 100644 game/plugin/bank/meta.toml delete mode 100644 game/plugin/chat/private-messaging/meta.toml delete mode 100644 game/plugin/cmd/meta.toml delete mode 100644 game/plugin/consumables/meta.toml delete mode 100644 game/plugin/dummy/meta.toml delete mode 100644 game/plugin/emote-tab/meta.toml delete mode 100644 game/plugin/entity/following/meta.toml delete mode 100644 game/plugin/entity/player-action/meta.toml delete mode 100644 game/plugin/entity/spawn/meta.toml delete mode 100644 game/plugin/entity/walk-to/meta.toml delete mode 100644 game/plugin/locations/al-kharid/meta.toml delete mode 100644 game/plugin/locations/edgeville/meta.toml delete mode 100644 game/plugin/locations/falador/meta.toml delete mode 100644 game/plugin/locations/lumbridge/meta.toml delete mode 100644 game/plugin/locations/tutorial-island/meta.toml delete mode 100644 game/plugin/locations/varrock/meta.toml delete mode 100644 game/plugin/logout/meta.toml delete mode 100644 game/plugin/run/meta.toml delete mode 100644 game/plugin/skills/mining/meta.toml delete mode 100644 game/plugin/util/command/meta.toml delete mode 100644 game/plugin/util/lookup/meta.toml diff --git a/game/plugin/bank/meta.toml b/game/plugin/bank/meta.toml deleted file mode 100644 index e7895a9e1..000000000 --- a/game/plugin/bank/meta.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "Banking" -package = "org.apollo.game.plugin.banking" -authors = [ "Major" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/chat/private-messaging/meta.toml b/game/plugin/chat/private-messaging/meta.toml deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/plugin/cmd/meta.toml b/game/plugin/cmd/meta.toml deleted file mode 100644 index 7a255f397..000000000 --- a/game/plugin/cmd/meta.toml +++ /dev/null @@ -1,13 +0,0 @@ -name = "Chat commands" -package = "org.apollo.game.plugin.cmd" -dependencies = [ "command_utilities" ] -authors = [ - "Graham", - "Major", - "lare96", - "cubeee" -] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/consumables/meta.toml b/game/plugin/consumables/meta.toml deleted file mode 100644 index e31a38c37..000000000 --- a/game/plugin/consumables/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "consumables" -package = "org.apollo.game.plugin.consumables" -authors = [ "Gary Tierney" ] -dependencies = [] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/dummy/meta.toml b/game/plugin/dummy/meta.toml deleted file mode 100644 index 46c61366d..000000000 --- a/game/plugin/dummy/meta.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "training-dummy" -package = "org.apollo.game.plugin.entity" -authors = [ "Gary Tierney" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/emote-tab/meta.toml b/game/plugin/emote-tab/meta.toml deleted file mode 100644 index 8a4891c42..000000000 --- a/game/plugin/emote-tab/meta.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "emote-tab" -package = "org.apollo.game.plugin.widget" -authors = [ "Gary Tierney" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/entity/following/meta.toml b/game/plugin/entity/following/meta.toml deleted file mode 100644 index 0e2e8e4dc..000000000 --- a/game/plugin/entity/following/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "following" -package = "org.apollo.game.plugin.entity" -authors = [ "Gary Tierney" ] -dependencies = [ "walkto", "command_utilities", "player_action"] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/entity/player-action/meta.toml b/game/plugin/entity/player-action/meta.toml deleted file mode 100644 index 89eabaddb..000000000 --- a/game/plugin/entity/player-action/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "player_action" -package = "org.apollo.game.plugin.entity" -authors = [ "Gary Tierney" ] -dependencies = [] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/entity/spawn/meta.toml b/game/plugin/entity/spawn/meta.toml deleted file mode 100644 index 3551199da..000000000 --- a/game/plugin/entity/spawn/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "spawning" -package = "org.apollo.game.plugin.entity" -authors = [ "Gary Tierney" ] -dependencies = [ "entity_lookup" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/entity/walk-to/meta.toml b/game/plugin/entity/walk-to/meta.toml deleted file mode 100644 index 7a7b0ff80..000000000 --- a/game/plugin/entity/walk-to/meta.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "walkto" -package = "org.apollo.plugin.entity.walkto" -authors = ["Gary Tierney"] -dependencies = [] \ No newline at end of file diff --git a/game/plugin/locations/al-kharid/meta.toml b/game/plugin/locations/al-kharid/meta.toml deleted file mode 100644 index 8c1835929..000000000 --- a/game/plugin/locations/al-kharid/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "al-kharid npc spawns" -package = "org.apollo.game.plugin.locations" -authors = [ "Jesse W" ] -dependencies = [ "entity:spawn" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/locations/edgeville/meta.toml b/game/plugin/locations/edgeville/meta.toml deleted file mode 100644 index 469f40714..000000000 --- a/game/plugin/locations/edgeville/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "edgeville npc spawns" -package = "org.apollo.game.plugin.locations" -authors = [ "Jesse W" ] -dependencies = [ "entity:spawn" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/locations/falador/meta.toml b/game/plugin/locations/falador/meta.toml deleted file mode 100644 index 49c9aa26a..000000000 --- a/game/plugin/locations/falador/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "falador npc spawns" -package = "org.apollo.game.plugin.locations" -authors = [ "Jesse W" ] -dependencies = [ "entity:spawn" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/locations/lumbridge/meta.toml b/game/plugin/locations/lumbridge/meta.toml deleted file mode 100644 index 098197b37..000000000 --- a/game/plugin/locations/lumbridge/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "lumbridge npc spawns" -package = "org.apollo.game.plugin.locations" -authors = [ "Gary Tierney" ] -dependencies = [ "entity:spawn" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/locations/tutorial-island/meta.toml b/game/plugin/locations/tutorial-island/meta.toml deleted file mode 100644 index eff5223f0..000000000 --- a/game/plugin/locations/tutorial-island/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "tutorial island npc spawns" -package = "org.apollo.game.plugin.locations" -authors = [ "Jesse W" ] -dependencies = [ "entity:spawn" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/locations/varrock/meta.toml b/game/plugin/locations/varrock/meta.toml deleted file mode 100644 index 1a8b3d577..000000000 --- a/game/plugin/locations/varrock/meta.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "varrock npc spawns" -package = "org.apollo.game.plugin.locations" -authors = [ "Jesse W" ] -dependencies = [ "entity:spawn" ] - -[config] -srcDir = "src/" -testDir = "test/" \ No newline at end of file diff --git a/game/plugin/logout/meta.toml b/game/plugin/logout/meta.toml deleted file mode 100644 index 574c74b36..000000000 --- a/game/plugin/logout/meta.toml +++ /dev/null @@ -1 +0,0 @@ -name = "logout" \ No newline at end of file diff --git a/game/plugin/run/meta.toml b/game/plugin/run/meta.toml deleted file mode 100644 index fd05752f8..000000000 --- a/game/plugin/run/meta.toml +++ /dev/null @@ -1 +0,0 @@ -name = "run" \ No newline at end of file diff --git a/game/plugin/skills/mining/meta.toml b/game/plugin/skills/mining/meta.toml deleted file mode 100644 index 0cf7d9ae4..000000000 --- a/game/plugin/skills/mining/meta.toml +++ /dev/null @@ -1,14 +0,0 @@ -name = "mining-skill" -package = "org.apollo.game.plugin.skills.mining" -authors = [ - "Graham", - "Mikey`", - "WH:II:DOW", - "Requa", - "Clifton", - "tlf30" - ] - -[config] -srcDir = "src/" -testDir = "test/" diff --git a/game/plugin/util/command/meta.toml b/game/plugin/util/command/meta.toml deleted file mode 100644 index 2d962919d..000000000 --- a/game/plugin/util/command/meta.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "command utilities" -package = "org.apollo.game.plugins.util" - -[config] -srcDir = "src/" \ No newline at end of file diff --git a/game/plugin/util/lookup/meta.toml b/game/plugin/util/lookup/meta.toml deleted file mode 100644 index 91b1757be..000000000 --- a/game/plugin/util/lookup/meta.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "entity lookup" -package = "org.apollo.game.plugins.util" From ae3d3c7ce2276ee222fbb12fe90236d0225395d0 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 24 Sep 2017 03:48:55 +0100 Subject: [PATCH 078/209] Add destructuring operators for Position --- .../api/src/org/apollo/game/plugins/api/position.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 game/plugin/api/src/org/apollo/game/plugins/api/position.kt diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/position.kt b/game/plugin/api/src/org/apollo/game/plugins/api/position.kt new file mode 100644 index 000000000..ffd3534d1 --- /dev/null +++ b/game/plugin/api/src/org/apollo/game/plugins/api/position.kt @@ -0,0 +1,9 @@ +package org.apollo.game.plugins.api + +import org.apollo.game.model.Position + +// Support destructuring a Position into its components. + +operator fun Position.component1(): Int = x +operator fun Position.component2(): Int = y +operator fun Position.component3(): Int = height From cb9e6f353d66229201626ccaafbefa6523f66999 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 24 Sep 2017 18:13:17 +0100 Subject: [PATCH 079/209] Let plugins intercept Events Support for PlayerEvents already exists, but general event support wasn't included in the original KotlinPluginScript. --- .../game/plugin/kotlin/KotlinPluginScript.kt | 191 +++++++++++------- game/src/main/kotlin/stub.kt | 8 +- 2 files changed, 124 insertions(+), 75 deletions(-) diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index 357b17ef3..a1b551513 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -7,6 +7,7 @@ import org.apollo.game.message.impl.ButtonMessage import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.model.event.Event import org.apollo.game.model.event.EventListener import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.PluginContext @@ -15,103 +16,151 @@ import kotlin.reflect.KClass import kotlin.script.templates.ScriptTemplateDefinition @ScriptTemplateDefinition( - scriptFilePattern = ".*\\.plugin\\.kts" + scriptFilePattern = ".*\\.plugin\\.kts" ) abstract class KotlinPluginScript(private var world: World, val context: PluginContext) { - var startListener: (World) -> Unit = { _ -> }; - var stopListener: (World) -> Unit = { _ -> }; - - /** - * Create a new [MessageHandler]. - */ - fun on(type: () -> KClass) = KotlinMessageHandler(world, context, type.invoke()) - - /** - * Create a new [EventListener] for a type of [PlayerEvent]. - */ - fun on_player_event(type: () -> KClass) = KotlinPlayerEventHandler(world, type.invoke()) - - /** - * Create a new [CommandHandler] for the given _command_ name, which only players with a [PrivelegeLevel] - * of _privileges_ and above can use. - */ - fun on_command(command: String, privileges: PrivilegeLevel) = KotlinCommandHandler(world, command, privileges) - - /** - * Create a new [ButtonMessage] [MessageHandler] for the given _button_ id. - */ - fun on_button(button: Int) = on { ButtonMessage::class }.where { widgetId == button } - - fun start(callback: (World) -> Unit) { - this.startListener = callback - } - - fun stop(callback: (World) -> Unit) { - this.stopListener = callback - } - - fun doStart(world: World) { - this.startListener.invoke(world) - } - - fun doStop(world: World) { - this.stopListener.invoke(world) - } + var startListener: (World) -> Unit = { _ -> } + var stopListener: (World) -> Unit = { _ -> } + + /** + * Creates a [MessageHandler]. + */ + fun on(type: () -> KClass) = KotlinMessageHandler(world, context, type.invoke()) + + /** + * Create an [EventListener] for a [PlayerEvent]. + */ + fun on_player_event(type: () -> KClass) = KotlinPlayerEventHandler(world, type.invoke()) + + /** + * Create an [EventListener] for an [Event]. + */ + fun on_event(type: () -> KClass) = KotlinEventHandler(world, type.invoke()) + + /** + * Create a [CommandListener] for the given [command] name, which only players with a [PrivilegeLevel] + * of [privileges] and above can use. + */ + fun on_command(command: String, privileges: PrivilegeLevel) = KotlinCommandHandler(world, command, privileges) + + /** + * Create a [ButtonMessage] [MessageHandler] for the given [id]. + */ + fun on_button(id: Int) = on { ButtonMessage::class }.where { widgetId == id } + + fun start(callback: (World) -> Unit) { + this.startListener = callback + } + + fun stop(callback: (World) -> Unit) { + this.stopListener = callback + } + + fun doStart(world: World) { + this.startListener.invoke(world) + } + + fun doStop(world: World) { + this.stopListener.invoke(world) + } + } +/** + * A proxy interface for any handler that operates on [Player]s. + */ interface KotlinPlayerHandlerProxyTrait { - var callback: S.(Player) -> Unit - var predicate: S.() -> Boolean + var callback: S.(Player) -> Unit + var predicate: S.() -> Boolean + + fun register() + + fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait { + this.predicate = predicate + return this + } - fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait { - this.predicate = predicate - return this - } + fun then(callback: S.(Player) -> Unit) { + this.callback = callback + this.register() + } - fun then(callback: S.(Player) -> Unit) { - this.callback = callback - this.register() - } - fun register() + fun handleProxy(player: Player, subject: S) { + if (subject.predicate()) { + subject.callback(player) + } + } - fun handleProxy(player: Player, subject: S) { - if (subject.predicate()) { - subject.callback(player) - } - } } +/** + * A handler for [PlayerEvent]s. + */ class KotlinPlayerEventHandler(val world: World, val type: KClass) : - KotlinPlayerHandlerProxyTrait, EventListener { + KotlinPlayerHandlerProxyTrait, EventListener { + + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } + + override fun handle(event: T) = handleProxy(event.player, event) + override fun register() = world.listenFor(type.java, this) + +} + +/** + * A handler for [Event]s. + */ +class KotlinEventHandler(val world: World, val type: KClass) : EventListener { + + private var callback: S.() -> Unit = {} + private var predicate: S.() -> Boolean = { true } + + fun where(predicate: S.() -> Boolean): KotlinEventHandler { + this.predicate = predicate + return this + } + + fun then(callback: S.() -> Unit) { + this.callback = callback + this.register() + } - override var callback: T.(Player) -> Unit = {} - override var predicate: T.() -> Boolean = { true } + override fun handle(event: S) { + if (event.predicate()) { + event.callback() + } + } - override fun handle(event: T) = handleProxy(event.player, event) - override fun register() = world.listenFor(type.java, this) + fun register() = world.listenFor(type.java, this) } +/** + * A handler for [Message]s. + */ class KotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : - KotlinPlayerHandlerProxyTrait, MessageHandler(world) { + KotlinPlayerHandlerProxyTrait, MessageHandler(world) { - override var callback: T.(Player) -> Unit = {} - override var predicate: T.() -> Boolean = { true } + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } - override fun handle(player: Player, message: T) = handleProxy(player, message) - override fun register() = context.addMessageHandler(type.java, this) + override fun handle(player: Player, message: T) = handleProxy(player, message) + override fun register() = context.addMessageHandler(type.java, this) } +/** + * A handler for [Command]s. + */ class KotlinCommandHandler(val world: World, val command: String, privileges: PrivilegeLevel) : - KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { + KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { - override var callback: Command.(Player) -> Unit = {} - override var predicate: Command.() -> Boolean = { true } + override var callback: Command.(Player) -> Unit = {} + override var predicate: Command.() -> Boolean = { true } - override fun execute(player: Player, command: Command) = handleProxy(player, command) - override fun register() = world.commandDispatcher.register(command, this) + override fun execute(player: Player, command: Command) = handleProxy(player, command) + override fun register() = world.commandDispatcher.register(command, this) } diff --git a/game/src/main/kotlin/stub.kt b/game/src/main/kotlin/stub.kt index c236c3a37..0f49676b1 100644 --- a/game/src/main/kotlin/stub.kt +++ b/game/src/main/kotlin/stub.kt @@ -7,19 +7,19 @@ */ import org.apollo.game.command.Command -import org.apollo.game.message.handler.MessageHandlerChainSet import org.apollo.game.message.impl.ButtonMessage import org.apollo.game.model.World -import org.apollo.game.model.area.RegionRepository -import org.apollo.game.model.entity.* import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.model.event.Event import org.apollo.game.model.event.PlayerEvent -import org.apollo.game.plugin.kotlin.* +import org.apollo.game.plugin.kotlin.KotlinEventHandler +import org.apollo.game.plugin.kotlin.KotlinPlayerHandlerProxyTrait import org.apollo.net.message.Message import kotlin.reflect.KClass fun on(type: () -> KClass): KotlinPlayerHandlerProxyTrait = null!! fun on_player_event(type: () -> KClass): KotlinPlayerHandlerProxyTrait = null!! +fun on_event(type: () -> KClass): KotlinEventHandler = null!! fun on_command(command: String, privileges: PrivilegeLevel): KotlinPlayerHandlerProxyTrait = null!! fun on_button(button: Int): KotlinPlayerHandlerProxyTrait = null!! From ce1bcba893f36cfd793a3f9c9f0a9380bb8107e2 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 24 Sep 2017 18:42:06 +0100 Subject: [PATCH 080/209] Port Area plugin to Kotlin --- game/plugin/areas/build.gradle | 6 ++ game/plugin/areas/src/action.kt | 18 +++++ game/plugin/areas/src/area.kt | 94 ++++++++++++++++++++++++++ game/plugin/areas/src/areas.plugin.kts | 23 +++++++ 4 files changed, 141 insertions(+) create mode 100644 game/plugin/areas/build.gradle create mode 100644 game/plugin/areas/src/action.kt create mode 100644 game/plugin/areas/src/area.kt create mode 100644 game/plugin/areas/src/areas.plugin.kts diff --git a/game/plugin/areas/build.gradle b/game/plugin/areas/build.gradle new file mode 100644 index 000000000..4a0d8ff96 --- /dev/null +++ b/game/plugin/areas/build.gradle @@ -0,0 +1,6 @@ +plugin { + name = "Area listeners" + description = "Enables plugins to listen on mobs entering, moving inside of, or leaving a rectangular area." + authors = ["Major"] + dependencies = ["api"] +} \ No newline at end of file diff --git a/game/plugin/areas/src/action.kt b/game/plugin/areas/src/action.kt new file mode 100644 index 000000000..5b965603a --- /dev/null +++ b/game/plugin/areas/src/action.kt @@ -0,0 +1,18 @@ +package org.apollo.game.plugins.area + +/** + * Defines an area action using the DSL. + */ +fun action(@Suppress("UNUSED_PARAMETER") name: String, builder: ActionBuilder.() -> Unit) { + val listener = ActionBuilder() + builder(listener) + + actions.add(listener.build()) +} + +/** + * The [Set] of ([Area], [AreaAction]) [Pair]s. + */ +val actions = mutableSetOf>() + +class AreaAction(val entrance: AreaListener, val inside: AreaListener, val exit: AreaListener) \ No newline at end of file diff --git a/game/plugin/areas/src/area.kt b/game/plugin/areas/src/area.kt new file mode 100644 index 000000000..3c53fb1cc --- /dev/null +++ b/game/plugin/areas/src/area.kt @@ -0,0 +1,94 @@ +package org.apollo.game.plugins.area + +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.plugins.api.component1 +import org.apollo.game.plugins.api.component2 +import org.apollo.game.plugins.api.component3 + +/** + * An area in the game world. + */ +interface Area { + + /** + * Returns whether or not the specified [Position] is inside this [Area]. + */ + operator fun contains(position: Position): Boolean + +} + +private class RectangularArea(val x: IntRange, val y: IntRange, val height: Int) : Area { + + override operator fun contains(position: Position): Boolean { + val (x, y, z) = position + return x in this.x && y in this.y && z == height + } + +} + +/** + * A typealias for a function that is invoked when a player enters, moves inside of, or exits an [Area]. + */ +internal typealias AreaListener = Player.(Position) -> Unit + +/** + * A builder for ([Area], [AreaAction]) [Pair]s. + */ +class ActionBuilder { + + private var area: Area? = null + + private var entrance: AreaListener = { } + + private var inside: AreaListener = { } + + private var exit: AreaListener = { } + + /** + * Places the contents of this builder into an ([Area], [AreaAction]) [Pair]. + */ + fun build(): Pair { + val area = area ?: throw UnsupportedOperationException("Area must be specified.") + return Pair(area, AreaAction(entrance, inside, exit)) + } + + /** + * Sets the [Area] to listen for movement in. + */ + fun area(contains: (Position) -> Boolean) { + this.area = object : Area { + override fun contains(position: Position): Boolean = contains.invoke(position) + } + } + + /** + * Sets the [Area] to listen for movement in. Note that [IntRange]s are (inclusive, _exclusive_), i.e. the upper + * bound is exclusive. + */ + fun area(x: IntRange, y: IntRange, height: Int = 0) { + this.area = RectangularArea(x, y, height) + } + + /** + * Executes the specified [listener] when a player enters the related [Area]. + */ + fun entrance(listener: AreaListener) { + this.entrance = listener + } + + /** + * Executes the specified [listener] when a player moves around inside the related [Area]. + */ + fun inside(listener: AreaListener) { + this.inside = listener + } + + /** + * Executes the specified [listener] when a player moves exits the related [Area]. + */ + fun exit(listener: AreaListener) { + this.exit = listener + } + +} \ No newline at end of file diff --git a/game/plugin/areas/src/areas.plugin.kts b/game/plugin/areas/src/areas.plugin.kts new file mode 100644 index 000000000..e029b1999 --- /dev/null +++ b/game/plugin/areas/src/areas.plugin.kts @@ -0,0 +1,23 @@ + +import org.apollo.game.model.entity.Player +import org.apollo.game.model.event.impl.MobPositionUpdateEvent +import org.apollo.game.plugins.area.actions + +/** + * Intercepts the [MobPositionUpdateEvent] and invokes area actions if necessary. + */ +on_event { MobPositionUpdateEvent::class } + .where { mob is Player } + .then { + for ((area, action) in actions) { + if (mob.position in area) { + if (next in area) { + action.inside(mob as Player, next) + } else { + action.exit(mob as Player, next) + } + } else if (next in area) { + action.entrance(mob as Player, next) + } + } + } From b4e8a7136b3a8b6ae1d7f4fab153c49c26b39d09 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 24 Sep 2017 19:44:17 +0100 Subject: [PATCH 081/209] Add skill extension properties --- .../src/org/apollo/game/plugins/api/player.kt | 28 ------ game/plugin/api/src/player.kt | 81 ++++++++++++++++ .../skills/fishing/src/fishing.plugin.kts | 12 +-- .../skills/mining/src/mining.plugin.kts | 94 ++++++++++--------- .../woodcutting/src/woodcutting.plugin.kts | 49 +++++----- 5 files changed, 161 insertions(+), 103 deletions(-) delete mode 100644 game/plugin/api/src/org/apollo/game/plugins/api/player.kt create mode 100644 game/plugin/api/src/player.kt diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/player.kt b/game/plugin/api/src/org/apollo/game/plugins/api/player.kt deleted file mode 100644 index 87881bdd8..000000000 --- a/game/plugin/api/src/org/apollo/game/plugins/api/player.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.apollo.game.plugins.api - -import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.Skill -import org.apollo.game.model.entity.SkillSet - -val Player.skills: SkillSet get() = skillSet -val SkillSet.attack: Skill get() = getSkill(Skill.ATTACK) -val SkillSet.defence: Skill get() = getSkill(Skill.DEFENCE) -val SkillSet.strength: Skill get() = getSkill(Skill.STRENGTH) -val SkillSet.hitpoints: Skill get() = getSkill(Skill.HITPOINTS) -val SkillSet.ranged: Skill get() = getSkill(Skill.RANGED) -val SkillSet.prayer: Skill get() = getSkill(Skill.PRAYER) -val SkillSet.magic: Skill get() = getSkill(Skill.MAGIC) -val SkillSet.cooking: Skill get() = getSkill(Skill.COOKING) -val SkillSet.woodcutting: Skill get() = getSkill(Skill.WOODCUTTING) -val SkillSet.fletching: Skill get() = getSkill(Skill.FLETCHING) -val SkillSet.fishing: Skill get() = getSkill(Skill.FISHING) -val SkillSet.firemaking: Skill get() = getSkill(Skill.FIREMAKING) -val SkillSet.crafting: Skill get() = getSkill(Skill.CRAFTING) -val SkillSet.smithing: Skill get() = getSkill(Skill.SMITHING) -val SkillSet.mining: Skill get() = getSkill(Skill.MINING) -val SkillSet.herblore: Skill get() = getSkill(Skill.HERBLORE) -val SkillSet.agility: Skill get() = getSkill(Skill.AGILITY) -val SkillSet.thieving: Skill get() = getSkill(Skill.THIEVING) -val SkillSet.slayer: Skill get() = getSkill(Skill.SLAYER) -val SkillSet.farming: Skill get() = getSkill(Skill.FARMING) -val SkillSet.runecraft: Skill get() = getSkill(Skill.RUNECRAFT) \ No newline at end of file diff --git a/game/plugin/api/src/player.kt b/game/plugin/api/src/player.kt new file mode 100644 index 000000000..473b13f61 --- /dev/null +++ b/game/plugin/api/src/player.kt @@ -0,0 +1,81 @@ +package org.apollo.game.plugin.api + +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.SkillSet + +val Player.attack: SkillProxy get() = SkillProxy(skillSet, Skill.ATTACK) +val Player.defence: SkillProxy get() = SkillProxy(skillSet, Skill.DEFENCE) +val Player.strength: SkillProxy get() = SkillProxy(skillSet, Skill.STRENGTH) +val Player.hitpoints: SkillProxy get() = SkillProxy(skillSet, Skill.HITPOINTS) +val Player.ranged: SkillProxy get() = SkillProxy(skillSet, Skill.RANGED) +val Player.prayer: SkillProxy get() = SkillProxy(skillSet, Skill.PRAYER) +val Player.magic: SkillProxy get() = SkillProxy(skillSet, Skill.MAGIC) +val Player.cooking: SkillProxy get() = SkillProxy(skillSet, Skill.COOKING) +val Player.woodcutting: SkillProxy get() = SkillProxy(skillSet, Skill.WOODCUTTING) +val Player.fletching: SkillProxy get() = SkillProxy(skillSet, Skill.FLETCHING) +val Player.fishing: SkillProxy get() = SkillProxy(skillSet, Skill.FISHING) +val Player.firemaking: SkillProxy get() = SkillProxy(skillSet, Skill.FIREMAKING) +val Player.crafting: SkillProxy get() = SkillProxy(skillSet, Skill.CRAFTING) +val Player.smithing: SkillProxy get() = SkillProxy(skillSet, Skill.SMITHING) +val Player.mining: SkillProxy get() = SkillProxy(skillSet, Skill.MINING) +val Player.herblore: SkillProxy get() = SkillProxy(skillSet, Skill.HERBLORE) +val Player.agility: SkillProxy get() = SkillProxy(skillSet, Skill.AGILITY) +val Player.thieving: SkillProxy get() = SkillProxy(skillSet, Skill.THIEVING) +val Player.slayer: SkillProxy get() = SkillProxy(skillSet, Skill.SLAYER) +val Player.farming: SkillProxy get() = SkillProxy(skillSet, Skill.FARMING) +val Player.runecraft: SkillProxy get() = SkillProxy(skillSet, Skill.RUNECRAFT) + +/** + * A proxy class to allow + */ +class SkillProxy(val skills: SkillSet, val skill: Int) { + + /** + * The maximum level of this skill. + */ + val maximum = skills.getMaximumLevel(skill) + + /** + * The current level of this skill. + */ + val current = skills.getCurrentLevel(skill) + + val experience = ExperienceProxy() + + /** + * A proxy class to make [experience] (effectively) write-only. + */ + inner class ExperienceProxy { + + operator fun plusAssign(amount: Int) = skills.addExperience(skill, amount.toDouble()) + + operator fun plusAssign(amount: Double) = skills.addExperience(skill, amount) + + } + + /** + * Boosts the current level of this skill by [amount], if possible (i.e. if `current + amount <= maximum + amount`). + */ + fun boost(amount: Int) { + val new = Math.min(current + amount, maximum + amount) + skills.setCurrentLevel(skill, new) + } + + /** + * Drains the current level of this skill by [amount], if possible (i.e. if `current - amount >= 0`). + */ + fun drain(amount: Int) { + val new = Math.max(current - amount, 0) + skills.setCurrentLevel(skill, new) + } + + /** + * Restores the current level of this skill by [amount], if possible (i.e. if `current + amount < maximum`). + */ + fun restore(amount: Int) { + val new = Math.max(current + amount, maximum) + skills.setCurrentLevel(skill, new) + } + +} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/fishing.plugin.kts b/game/plugin/skills/fishing/src/fishing.plugin.kts index cc53c99ce..56755edbb 100644 --- a/game/plugin/skills/fishing/src/fishing.plugin.kts +++ b/game/plugin/skills/fishing/src/fishing.plugin.kts @@ -1,14 +1,13 @@ + import Fishing_plugin.FishingAction import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.message.impl.NpcActionMessage import org.apollo.game.model.Position import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.api.fishing import org.apollo.game.plugin.skills.fishing.FishingSpot import org.apollo.game.plugin.skills.fishing.FishingTool -import org.apollo.game.plugins.api.fishing -import org.apollo.game.plugins.api.skills import java.util.Objects import java.util.Random @@ -62,7 +61,7 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. mob.playAnimation(tool.animation) wait(FISHING_DELAY) - val level = mob.skills.fishing.currentLevel + val level = mob.fishing.current val fish = option.sample(level) if (successfulCatch(level, fish.level)) { @@ -72,7 +71,7 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. mob.inventory.add(fish.id) mob.sendMessage("You catch a ${fish.formattedName}.") - mob.skills.addExperience(Skill.FISHING, fish.experience) + mob.fishing.experience += fish.experience if (mob.inventory.freeSlots() == 0) { mob.inventory.forceCapacityExceeded() @@ -91,7 +90,7 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. * Verifies that the player can gather fish from the [FishingSpot] they clicked. */ private fun verify(): Boolean { - if (mob.skills.fishing.currentLevel < option.level) { + if (mob.fishing.current < option.level) { mob.sendMessage("You need a fishing level of ${option.level} to fish at this spot.") return false } else if (!hasTool(mob, tool)) { @@ -113,7 +112,6 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. if (javaClass != other?.javaClass) return false other as FishingAction - return option == other.option && position == other.position && mob == other.mob } diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index 22c9652ca..418bcbb85 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -5,52 +5,47 @@ import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position import org.apollo.game.model.World import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.api.mining import org.apollo.game.plugin.skills.mining.Ore import org.apollo.game.plugin.skills.mining.PICKAXES import org.apollo.game.plugin.skills.mining.Pickaxe import org.apollo.game.plugin.skills.mining.lookupOreRock -import org.apollo.game.plugins.api.Definitions -import org.apollo.game.plugins.api.mining -import org.apollo.game.plugins.api.skills import org.apollo.net.message.Message -import java.util.* +import java.util.Optional class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { + fun getObject(world: World): Optional { val region = world.regionRepository.fromPosition(position) - val obj = region.findObject(position, objectId) - - return obj + return region.findObject(position, objectId) } fun isSuccessful(mob: Player): Boolean { val offset = if (ore.chanceOffset) 1 else 0 - val percent = (ore.chance * mob.skills.mining.currentLevel + offset) * 100 + val percent = (ore.chance * mob.mining.current + offset) * 100 - return rand(100) < percent; + return rand(100) < percent } + } -class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) : AsyncDistancedAction( - PULSES, - true, - player, - target.position, - ORE_SIZE -) { +class MiningAction( + player: Player, + private val tool: Pickaxe, + private val target: MiningTarget +) : AsyncDistancedAction(PULSES, true, player, target.position, ORE_SIZE) { companion object { private val PULSES = 0 - private val ORE_SIZE = 1; + private val ORE_SIZE = 1 fun pickaxeFor(player: Player): Pickaxe? { return PICKAXES - .filter { it.level <= player.skills.mining.currentLevel } - .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } - .sortedByDescending { it.level } - .firstOrNull() + .filter { it.level <= player.mining.current } + .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } + .sortedByDescending { it.level } + .firstOrNull() } /** @@ -69,10 +64,10 @@ class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) } } - override fun action() : ActionBlock = { + override fun action(): ActionBlock = { mob.turnTo(position) - val level = mob.skills.mining.currentLevel + val level = mob.mining.current if (level < target.ore.level) { mob.sendMessage("You do not have the required level to mine this rock.") stop() @@ -98,7 +93,7 @@ class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) val oreName = Definitions.item(target.ore.id)?.name?.toLowerCase() mob.sendMessage("You manage to mine some $oreName") - mob.skills.addExperience(Skill.MINING, target.ore.exp) + mob.mining.experience += target.ore.exp mob.world.expireObject(obj.get(), target.ore.objects[target.objectId]!!, target.ore.respawn) stop() } @@ -106,25 +101,32 @@ class MiningAction(player: Player, val tool: Pickaxe, val target: MiningTarget) } } -class ExpiredProspectingAction : DistancedAction { - - constructor(mob: Player, position: Position) : super(PROSPECT_PULSES, true, mob, position, ORE_SIZE) +class ExpiredProspectingAction( + mob: Player, + position: Position +) : DistancedAction(PROSPECT_PULSES, true, mob, position, ORE_SIZE) { companion object { private val PROSPECT_PULSES = 0 - private val ORE_SIZE = 1; + private val ORE_SIZE = 1 } override fun executeAction() { mob.sendMessage("There is currently no ore available in this rock.") - stop(); + stop() } + } -class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : AsyncDistancedAction(PROSPECT_PULSES, true, m, p, ORE_SIZE) { +class ProspectingAction( + player: Player, + position: Position, + private val ore: Ore +) : AsyncDistancedAction(PROSPECT_PULSES, true, player, position, ORE_SIZE) { + companion object { private val PROSPECT_PULSES = 3 - private val ORE_SIZE = 1; + private val ORE_SIZE = 1 /** * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. @@ -135,9 +137,10 @@ class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : AsyncDis message.terminate() } + } - override fun action() : ActionBlock = { + override fun action(): ActionBlock = { mob.sendMessage("You examine the rock for ores...") mob.turnTo(position) @@ -148,22 +151,23 @@ class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : AsyncDis stop() } + } on { ObjectActionMessage::class } - .where { option == 1 } - .then { - val ore = lookupOreRock(id) - if (ore != null) { - MiningAction.start(this, it, ore) - } + .where { option == 1 } + .then { + val ore = lookupOreRock(id) + if (ore != null) { + MiningAction.start(this, it, ore) } + } on { ObjectActionMessage::class } - .where { option == 2 } - .then { - var ore = lookupOreRock(id) - if (ore != null) { - ProspectingAction.start(this, it, ore) - } + .where { option == 2 } + .then { + val ore = lookupOreRock(id) + if (ore != null) { // TODO send expired action if rock is expired + ProspectingAction.start(this, it, ore) } + } diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index eb769d492..df04e9fe5 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -1,4 +1,3 @@ -import org.apollo.cache.def.ItemDefinition import org.apollo.game.GameConstants import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction @@ -6,14 +5,14 @@ import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position import org.apollo.game.model.World import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.plugin.skills.woodcutting.* -import org.apollo.game.plugins.api.* -import java.util.* +import org.apollo.game.plugin.api.woodcutting +import org.apollo.game.plugin.skills.woodcutting.Axe +import org.apollo.game.plugin.skills.woodcutting.Tree +import java.util.Optional import java.util.concurrent.TimeUnit -class WoodcuttingTarget(val objectId: Int, val position: Position, val tree: Tree) { +class WoodcuttingTarget(private val objectId: Int, val position: Position, val tree: Tree) { /** * Get the tree object in the world @@ -24,33 +23,37 @@ class WoodcuttingTarget(val objectId: Int, val position: Position, val tree: Tre } /** - * Check if the tree was cut down + * Returns whether or not the tree was cut down. */ - fun isCutDown(mob: Player): Boolean { - return rand(100) <= tree.chance * 100 - } + fun isCutDown(): Boolean = rand(100) <= tree.chance * 100 + } -class WoodcuttingAction(val player: Player, val tool: Axe, val target: WoodcuttingTarget) : AsyncDistancedAction(DELAY, true, player, target.position, TREE_SIZE) { +class WoodcuttingAction( + player: Player, + private val tool: Axe, + private val target: WoodcuttingTarget +) : AsyncDistancedAction(DELAY, true, player, target.position, TREE_SIZE) { companion object { - private val DELAY = 0 - private val TREE_SIZE = 2 - private val MINIMUM_RESPAWN_TIME = 30L //In seconds + private const val DELAY = 0 + private const val TREE_SIZE = 2 + private const val MINIMUM_RESPAWN_TIME = 30L // In seconds /** * Find the highest level axe the player has */ private fun axeFor(player: Player): Axe? { return Axe.getAxes() - .filter { it.level <= player.skills.woodcutting.currentLevel } - .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } - .sortedByDescending { it.level } - .firstOrNull() + .filter { it.level <= player.woodcutting.current } + .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } + .sortedByDescending { it.level } + .firstOrNull() } /** - * Starts a [WoodcuttingAction] for the specified [Player], terminating the [Message] that triggered it. + * Starts a [WoodcuttingAction] for the specified [Player], terminating the [ObjectActionMessage] that triggered + * it. */ fun start(message: ObjectActionMessage, player: Player, wood: Tree) { val axe = axeFor(player) @@ -73,7 +76,7 @@ class WoodcuttingAction(val player: Player, val tool: Axe, val target: Woodcutti override fun action(): ActionBlock = { mob.turnTo(position) - val level = mob.skills.woodcutting.currentLevel + val level = mob.woodcutting.current if (level < target.tree.level) { mob.sendMessage("You do not have the required level to cut down this tree.") stop() @@ -92,12 +95,12 @@ class WoodcuttingAction(val player: Player, val tool: Axe, val target: Woodcutti } if (mob.inventory.add(target.tree.id)) { - val logName = Definitions.item(target.tree.id)?.name?.toLowerCase(); + val logName = Definitions.item(target.tree.id)?.name?.toLowerCase() mob.sendMessage("You managed to cut some $logName.") - mob.skills.addExperience(Skill.WOODCUTTING, target.tree.exp) + mob.woodcutting.experience += target.tree.exp } - if (target.isCutDown(mob)) { + if (target.isCutDown()) { //respawn time: http://runescape.wikia.com/wiki/Trees val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY mob.world.expireObject(obj.get(), target.tree.stump, respawn.toInt()) From 046f373c9e0c38e1caee3ff9dd39a45a7648b4f8 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 24 Sep 2017 22:35:07 +0100 Subject: [PATCH 082/209] Add packages to plugins --- .../game/plugins/api => }/definitions.kt | 2 +- .../{org/apollo/game/plugins/api => }/util.kt | 4 +- .../apollo/game/plugins/api => }/world.kt | 31 ++-- game/plugin/cmd/src/animate-cmd.plugin.kts | 23 +-- game/plugin/cmd/src/bank-cmd.plugin.kts | 2 +- game/plugin/cmd/src/item-cmd.plugin.kts | 55 +++---- game/plugin/cmd/src/lookup.plugin.kts | 95 ++++++------ game/plugin/cmd/src/messaging-cmd.plugin.kts | 12 +- game/plugin/cmd/src/punish-cmd.plugin.kts | 47 +++--- game/plugin/cmd/src/skill-cmd.plugin.kts | 111 +++++++------- game/plugin/cmd/src/spawn-cmd.plugin.kts | 140 +++++++++--------- game/plugin/cmd/src/teleport-cmd.plugin.kts | 59 ++++---- .../entity/following/src/following.plugin.kts | 16 +- .../entity/player-action/src/player_action.kt | 4 +- .../src/player_action.plugin.kts | 26 ++-- game/plugin/entity/spawn/src/spawn.kt | 10 +- game/plugin/entity/spawn/src/spawn.plugin.kts | 15 +- .../al-kharid/src/al-kharid-npcs.plugin.kts | 1 + .../edgeville/src/edgeville-npcs.plugin.kts | 1 + .../falador/src/falador-npcs.plugin.kts | 1 + .../lumbridge/src/lumbridge-npcs.plugin.kts | 2 + .../src/tutorial-island-npcs.plugin.kts | 1 + .../locations/varrock/src/shops.plugin.kts | 2 + .../varrock/src/varrock-npcs.plugin.kts | 1 + game/plugin/navigation/door/src/door.kt | 26 ++-- game/plugin/shops/src/action.kt | 2 + game/plugin/shops/src/dsl.kt | 6 +- game/plugin/shops/src/shop.kt | 12 +- game/plugin/shops/src/shop.plugin.kts | 6 +- game/plugin/skills/fishing/src/spots.kts | 3 +- game/plugin/util/command/src/command.kt | 4 +- game/plugin/util/lookup/src/lookup.kt | 2 + 32 files changed, 377 insertions(+), 345 deletions(-) rename game/plugin/api/src/{org/apollo/game/plugins/api => }/definitions.kt (92%) rename game/plugin/api/src/{org/apollo/game/plugins/api => }/util.kt (58%) rename game/plugin/api/src/{org/apollo/game/plugins/api => }/world.kt (63%) diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/definitions.kt b/game/plugin/api/src/definitions.kt similarity index 92% rename from game/plugin/api/src/org/apollo/game/plugins/api/definitions.kt rename to game/plugin/api/src/definitions.kt index 3de58a113..69966d43c 100644 --- a/game/plugin/api/src/org/apollo/game/plugins/api/definitions.kt +++ b/game/plugin/api/src/definitions.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugins.api +package org.apollo.game.plugin.api import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/util.kt b/game/plugin/api/src/util.kt similarity index 58% rename from game/plugin/api/src/org/apollo/game/plugins/api/util.kt rename to game/plugin/api/src/util.kt index 377af6c8c..01264cbfe 100644 --- a/game/plugin/api/src/org/apollo/game/plugins/api/util.kt +++ b/game/plugin/api/src/util.kt @@ -1,4 +1,6 @@ -import java.util.* +package org.apollo.game.plugin.api + +import java.util.Random val RAND = Random() diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/world.kt b/game/plugin/api/src/world.kt similarity index 63% rename from game/plugin/api/src/org/apollo/game/plugins/api/world.kt rename to game/plugin/api/src/world.kt index 8d77ce1ca..6dd75879b 100644 --- a/game/plugin/api/src/org/apollo/game/plugins/api/world.kt +++ b/game/plugin/api/src/world.kt @@ -1,3 +1,5 @@ +package org.apollo.game.plugin.api + import org.apollo.game.model.Position import org.apollo.game.model.World import org.apollo.game.model.area.Region @@ -7,39 +9,35 @@ import org.apollo.game.model.entity.EntityType.DYNAMIC_OBJECT import org.apollo.game.model.entity.EntityType.STATIC_OBJECT import org.apollo.game.model.entity.obj.DynamicGameObject import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.model.entity.obj.StaticGameObject import org.apollo.game.scheduling.ScheduledTask -import java.lang.IllegalArgumentException -import java.util.* +import java.util.Optional import java.util.stream.Stream -fun Region.find(position: Position, pred: (T) -> Boolean, vararg types: EntityType): Stream { - val result = this.getEntities(position, *types) - - return result.stream() - .filter(pred::invoke) +fun Region.find(position: Position, predicate: (T) -> Boolean, vararg types: EntityType): Stream { + val result = getEntities(position, *types) + return result.stream().filter(predicate::invoke) } fun Region.findObjects(position: Position, id: Int): Stream { - return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) + return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) } fun Region.findObject(position: Position, id: Int): Optional { return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) - .findFirst() + .findFirst() } class ExpireObjectTask( - val world: World, - val obj: GameObject, - val replacement: GameObject, - val respawnDelay: Int + private val world: World, + private val existing: GameObject, + private val replacement: GameObject, + private val respawnDelay: Int ) : ScheduledTask(0, true) { private var respawning: Boolean = false override fun execute() { - val region = world.regionRepository.fromPosition(obj.position) + val region = world.regionRepository.fromPosition(existing.position) if (!respawning) { world.spawn(replacement) @@ -47,7 +45,7 @@ class ExpireObjectTask( setDelay(respawnDelay) } else { region.removeEntity(replacement) - world.spawn(obj) + world.spawn(existing) stop() } } @@ -55,7 +53,6 @@ class ExpireObjectTask( fun World.expireObject(obj: GameObject, replacement: Int, respawnDelay: Int) { val replacementObj = DynamicGameObject.createPublic(this, replacement, obj.position, obj.type, obj.orientation) - val respawnedObj = DynamicGameObject.createPublic(this, obj.id, obj.position, obj.type, obj.orientation) schedule(ExpireObjectTask(this, obj, replacementObj, respawnDelay)) } diff --git a/game/plugin/cmd/src/animate-cmd.plugin.kts b/game/plugin/cmd/src/animate-cmd.plugin.kts index cab210419..427860207 100644 --- a/game/plugin/cmd/src/animate-cmd.plugin.kts +++ b/game/plugin/cmd/src/animate-cmd.plugin.kts @@ -1,17 +1,18 @@ import com.google.common.primitives.Ints import org.apollo.game.model.Animation import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.util.command.valid_arg_length on_command("animate", PrivilegeLevel.MODERATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::animate [animation-id]" - if(valid_arg_length(arguments, 1, player, invalidSyntax)) { - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } - - player.playAnimation(Animation(id)) + .then { player -> + val invalidSyntax = "Invalid syntax - ::animate [animation-id]" + if (valid_arg_length(arguments, 1, player, invalidSyntax)) { + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then } - } \ No newline at end of file + + player.playAnimation(Animation(id)) + } + } \ No newline at end of file diff --git a/game/plugin/cmd/src/bank-cmd.plugin.kts b/game/plugin/cmd/src/bank-cmd.plugin.kts index 181a11943..6ded33ebc 100644 --- a/game/plugin/cmd/src/bank-cmd.plugin.kts +++ b/game/plugin/cmd/src/bank-cmd.plugin.kts @@ -2,4 +2,4 @@ import org.apollo.game.model.entity.setting.PrivilegeLevel // Opens the player's bank if they are an administrator. on_command("bank", PrivilegeLevel.ADMINISTRATOR) - .then { player -> player.openBank() } \ No newline at end of file + .then { player -> player.openBank() } \ No newline at end of file diff --git a/game/plugin/cmd/src/item-cmd.plugin.kts b/game/plugin/cmd/src/item-cmd.plugin.kts index 52eafb181..97f3b8ace 100644 --- a/game/plugin/cmd/src/item-cmd.plugin.kts +++ b/game/plugin/cmd/src/item-cmd.plugin.kts @@ -1,39 +1,40 @@ import com.google.common.primitives.Ints import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.util.command.valid_arg_length on_command("item", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::item [id] [amount]" - if (!valid_arg_length(arguments, 1..2, player, invalidSyntax)) { - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::item [id] [amount]" + if (!valid_arg_length(arguments, 1..2, player, invalidSyntax)) { + return@then + } + + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } - val id = Ints.tryParse(arguments[0]) - if (id == null) { + var amount = 1 + if (arguments.size == 2) { + val amt = Ints.tryParse(arguments[1]) + if (amt == null) { player.sendMessage(invalidSyntax) return@then } + amount = amt + } - var amount = 1 - if (arguments.size == 2) { - val amt = Ints.tryParse(arguments[1]) - if (amt == null) { - player.sendMessage(invalidSyntax) - return@then - } - amount = amt - } + if (id < 0 || id >= ItemDefinition.count()) { + player.sendMessage("The item id you specified is out of bounds!") + return@then + } - if (id < 0 || id >= ItemDefinition.count()) { - player.sendMessage("The item id you specified is out of bounds!") - return@then - } - - if (amount < 0) { - player.sendMessage("The amount you specified is out of bounds!") - return@then - } + if (amount < 0) { + player.sendMessage("The amount you specified is out of bounds!") + return@then + } - player.inventory.add(id, amount) - } \ No newline at end of file + player.inventory.add(id, amount) + } \ No newline at end of file diff --git a/game/plugin/cmd/src/lookup.plugin.kts b/game/plugin/cmd/src/lookup.plugin.kts index a599c0f4c..8f844ecc3 100644 --- a/game/plugin/cmd/src/lookup.plugin.kts +++ b/game/plugin/cmd/src/lookup.plugin.kts @@ -3,64 +3,65 @@ import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.util.command.valid_arg_length on_command("iteminfo", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" - if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" + if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { + return@then + } - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } - val definition = ItemDefinition.lookup(id) - val members = if (definition.isMembersOnly) "members" else "not members" + val definition = ItemDefinition.lookup(id) + val members = if (definition.isMembersOnly) "members" else "not members" - player.sendMessage("Item $id is called ${definition.name}, is $members only, and has a " + - "team of ${definition.team}.") - player.sendMessage("Its description is \"${definition.description}\".") - } + player.sendMessage("Item $id is called ${definition.name}, is $members only, and has a " + + "team of ${definition.team}.") + player.sendMessage("Its description is \"${definition.description}\".") + } on_command("npcinfo", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" - if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" + if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { + return@then + } - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } - val definition = NpcDefinition.lookup(id) - val isCombative = if (definition.hasCombatLevel()) "has a combat level of ${definition.combatLevel}" else - "does not have a combat level" + val definition = NpcDefinition.lookup(id) + val isCombative = if (definition.hasCombatLevel()) "has a combat level of ${definition.combatLevel}" else + "does not have a combat level" - player.sendMessage("Npc $id is called ${definition.name} and $isCombative.") - player.sendMessage("Its description is \"${definition.description}\".") - } + player.sendMessage("Npc $id is called ${definition.name} and $isCombative.") + player.sendMessage("Its description is \"${definition.description}\".") + } on_command("objectinfo", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::objectinfo [object id]" - if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::objectinfo [object id]" + if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { + return@then + } - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } - val definition = ObjectDefinition.lookup(id) - player.sendMessage("Object $id is called ${definition.name} and its description is " + - "\"${definition.description}\".") - player.sendMessage("Its width is ${definition.width} and its length is ${definition.length}.") - } \ No newline at end of file + val definition = ObjectDefinition.lookup(id) + player.sendMessage("Object $id is called ${definition.name} and its description is " + + "\"${definition.description}\".") + player.sendMessage("Its width is ${definition.width} and its length is ${definition.length}.") + } \ No newline at end of file diff --git a/game/plugin/cmd/src/messaging-cmd.plugin.kts b/game/plugin/cmd/src/messaging-cmd.plugin.kts index 883d7a513..304c14685 100644 --- a/game/plugin/cmd/src/messaging-cmd.plugin.kts +++ b/game/plugin/cmd/src/messaging-cmd.plugin.kts @@ -1,11 +1,11 @@ import org.apollo.game.model.entity.setting.PrivilegeLevel on_command("broadcast", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val message = arguments.joinToString(" ") - val broadcast = "[Broadcast] ${player.username.capitalize()}: $message" + .then { player -> + val message = arguments.joinToString(" ") + val broadcast = "[Broadcast] ${player.username.capitalize()}: $message" - player.world.playerRepository.forEach { other -> - other.sendMessage(broadcast) - } + player.world.playerRepository.forEach { other -> + other.sendMessage(broadcast) } + } diff --git a/game/plugin/cmd/src/punish-cmd.plugin.kts b/game/plugin/cmd/src/punish-cmd.plugin.kts index 619d46741..3df799c47 100644 --- a/game/plugin/cmd/src/punish-cmd.plugin.kts +++ b/game/plugin/cmd/src/punish-cmd.plugin.kts @@ -1,4 +1,3 @@ - import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel @@ -6,44 +5,44 @@ import org.apollo.game.model.entity.setting.PrivilegeLevel * Adds a command to mute a player. Admins cannot be muted. */ on_command("mute", PrivilegeLevel.MODERATOR) - .then { player -> - val name = arguments.joinToString(" ") - val targetPlayer = player.world.getPlayer(name) + .then { player -> + val name = arguments.joinToString(" ") + val targetPlayer = player.world.getPlayer(name) - if (validate(player, targetPlayer)) { - targetPlayer.isMuted = true - player.sendMessage("You have just unmuted ${targetPlayer.username}.") - } + if (validate(player, targetPlayer)) { + targetPlayer.isMuted = true + player.sendMessage("You have just unmuted ${targetPlayer.username}.") } + } /** * Adds a command to unmute a player. */ on_command("unmute", PrivilegeLevel.MODERATOR) - .then { player -> - val name = arguments.joinToString(" ") - val targetPlayer = player.world.getPlayer(name) + .then { player -> + val name = arguments.joinToString(" ") + val targetPlayer = player.world.getPlayer(name) - if (validate(player, targetPlayer)) { - targetPlayer.isMuted = false - player.sendMessage("You have just unmuted ${targetPlayer.username}.") - } + if (validate(player, targetPlayer)) { + targetPlayer.isMuted = false + player.sendMessage("You have just unmuted ${targetPlayer.username}.") } + } /** * Adds a command to ban a player. Admins cannot be banned. */ on_command("ban", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val name = arguments.joinToString(" ") - val targetPlayer = player.world.getPlayer(name) - - if (validate(player, targetPlayer)) { - targetPlayer.ban() - targetPlayer.logout() // TODO force logout - player.sendMessage("You have just banned ${targetPlayer.username}.") - } + .then { player -> + val name = arguments.joinToString(" ") + val targetPlayer = player.world.getPlayer(name) + + if (validate(player, targetPlayer)) { + targetPlayer.ban() + targetPlayer.logout() // TODO force logout + player.sendMessage("You have just banned ${targetPlayer.username}.") } + } /** * Ensures the player isn't null, and that they aren't an Administrator. diff --git a/game/plugin/cmd/src/skill-cmd.plugin.kts b/game/plugin/cmd/src/skill-cmd.plugin.kts index ade6e6c02..b95ed0181 100644 --- a/game/plugin/cmd/src/skill-cmd.plugin.kts +++ b/game/plugin/cmd/src/skill-cmd.plugin.kts @@ -1,4 +1,3 @@ - import com.google.common.primitives.Doubles import com.google.common.primitives.Ints import org.apollo.game.model.entity.Skill @@ -9,78 +8,78 @@ import org.apollo.game.model.entity.setting.PrivilegeLevel * Maximises the player's skill set. */ on_command("max", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val skills = player.skillSet + .then { player -> + val skills = player.skillSet - for (skill in 0 until skills.size()) { - skills.addExperience(skill, SkillSet.MAXIMUM_EXP) - } + for (skill in 0 until skills.size()) { + skills.addExperience(skill, SkillSet.MAXIMUM_EXP) } + } /** * Levels the specified skill to the specified level, optionally updating the current level as well. */ on_command("level", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::level [skill-id] [level] " - if (arguments.size !in 2..3) { - player.sendMessage(invalidSyntax) - return@then - } - - val skillId = Ints.tryParse(arguments[0]) - if (skillId == null) { - player.sendMessage(invalidSyntax) - return@then - } - val level = Ints.tryParse(arguments[1]) - if (level == null) { - player.sendMessage(invalidSyntax) - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::level [skill-id] [level] " + if (arguments.size !in 2..3) { + player.sendMessage(invalidSyntax) + return@then + } - if (skillId !in 0..20 || level !in 1..99) { - player.sendMessage(invalidSyntax) - return@then - } + val skillId = Ints.tryParse(arguments[0]) + if (skillId == null) { + player.sendMessage(invalidSyntax) + return@then + } + val level = Ints.tryParse(arguments[1]) + if (level == null) { + player.sendMessage(invalidSyntax) + return@then + } - val experience = SkillSet.getExperienceForLevel(level).toDouble() - var current = level + if (skillId !in 0..20 || level !in 1..99) { + player.sendMessage(invalidSyntax) + return@then + } - if (arguments.size == 3 && arguments[2] == "old") { - val skill = player.skillSet.getSkill(skillId) - current = skill.currentLevel - } + val experience = SkillSet.getExperienceForLevel(level).toDouble() + var current = level - player.skillSet.setSkill(skillId, Skill(experience, current, level)) + if (arguments.size == 3 && arguments[2] == "old") { + val skill = player.skillSet.getSkill(skillId) + current = skill.currentLevel } + player.skillSet.setSkill(skillId, Skill(experience, current, level)) + } + /** * Adds the specified amount of experience to the specified skill. */ on_command("xp", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::xp [skill-id] [experience]" - if (arguments.size != 2) { - player.sendMessage(invalidSyntax) - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::xp [skill-id] [experience]" + if (arguments.size != 2) { + player.sendMessage(invalidSyntax) + return@then + } - val skillId = Ints.tryParse(arguments[0]) - if (skillId == null) { - player.sendMessage(invalidSyntax) - return@then - } - val experience = Doubles.tryParse(arguments[1]) - if (experience == null) { - player.sendMessage(invalidSyntax) - return@then - } + val skillId = Ints.tryParse(arguments[0]) + if (skillId == null) { + player.sendMessage(invalidSyntax) + return@then + } + val experience = Doubles.tryParse(arguments[1]) + if (experience == null) { + player.sendMessage(invalidSyntax) + return@then + } - if (skillId !in 0..20 || experience <= 0) { - player.sendMessage("Invalid syntax - ::xp [skill-id] [experience]") - return@then - } + if (skillId !in 0..20 || experience <= 0) { + player.sendMessage("Invalid syntax - ::xp [skill-id] [experience]") + return@then + } - player.skillSet.addExperience(skillId, experience) - } \ No newline at end of file + player.skillSet.addExperience(skillId, experience) + } \ No newline at end of file diff --git a/game/plugin/cmd/src/spawn-cmd.plugin.kts b/game/plugin/cmd/src/spawn-cmd.plugin.kts index 7f124d895..70b80a2d5 100644 --- a/game/plugin/cmd/src/spawn-cmd.plugin.kts +++ b/game/plugin/cmd/src/spawn-cmd.plugin.kts @@ -13,98 +13,98 @@ val blacklist: IntArray = intArrayOf() * 'y' are not supplied. */ on_command("spawn", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::spawn [npc id] [optional-x] [optional-y] [optional-z]" - if (arguments.size !in intArrayOf(1, 3, 4)) { - player.sendMessage(invalidSyntax) - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::spawn [npc id] [optional-x] [optional-y] [optional-z]" + if (arguments.size !in intArrayOf(1, 3, 4)) { + player.sendMessage(invalidSyntax) + return@then + } - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } - if (id in blacklist) { - player.sendMessage("Sorry, npc $id is blacklisted!") - return@then - } + if (id in blacklist) { + player.sendMessage("Sorry, npc $id is blacklisted!") + return@then + } - val position: Position? - if (arguments.size == 1) { - position = player.position - } else { - var height = player.position.height - if (arguments.size == 4) { - val h = Ints.tryParse(arguments[3]) - if (h == null) { - player.sendMessage(invalidSyntax) - return@then - } - height = h + val position: Position? + if (arguments.size == 1) { + position = player.position + } else { + var height = player.position.height + if (arguments.size == 4) { + val h = Ints.tryParse(arguments[3]) + if (h == null) { + player.sendMessage(invalidSyntax) + return@then } - position = Position(arguments[1].toInt(), arguments[2].toInt(), height) + height = h } - - player.world.register(Npc(player.world, id, position)) + position = Position(arguments[1].toInt(), arguments[2].toInt(), height) } + player.world.register(Npc(player.world, id, position)) + } + /** * Mass spawns npcs around the player. */ on_command("mass", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::mass [npc id] [range (1-5)]" - if (arguments.size != 2) { - player.sendMessage(invalidSyntax) - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::mass [npc id] [range (1-5)]" + if (arguments.size != 2) { + player.sendMessage(invalidSyntax) + return@then + } - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + val id = Ints.tryParse(arguments[0]) + if (id == null) { + player.sendMessage(invalidSyntax) + return@then + } - val range = Ints.tryParse(arguments[1]) - if (range == null) { - player.sendMessage(invalidSyntax) - return@then - } + val range = Ints.tryParse(arguments[1]) + if (range == null) { + player.sendMessage(invalidSyntax) + return@then + } - if (id < 0 || range !in 1..5) { - player.sendMessage(invalidSyntax) - return@then - } + if (id < 0 || range !in 1..5) { + player.sendMessage(invalidSyntax) + return@then + } - if (id in blacklist) { - player.sendMessage("Sorry, npc $id is blacklisted!") - return@then - } + if (id in blacklist) { + player.sendMessage("Sorry, npc $id is blacklisted!") + return@then + } - val centerPosition = player.position + val centerPosition = player.position - val minX = centerPosition.x - range - val minY = centerPosition.y - range - val maxX = centerPosition.x + range - val maxY = centerPosition.y + range - val z = centerPosition.height + val minX = centerPosition.x - range + val minY = centerPosition.y - range + val maxX = centerPosition.x + range + val maxY = centerPosition.y + range + val z = centerPosition.height - for (x in minX..maxX) { - for (y in minY..maxY) { - player.world.register(Npc(player.world, id, Position(x, y, z))) - } + for (x in minX..maxX) { + for (y in minY..maxY) { + player.world.register(Npc(player.world, id, Position(x, y, z))) } - - player.sendMessage("Mass spawning npcs with id $id.") } + player.sendMessage("Mass spawning npcs with id $id.") + } + /** * Unregisters all npcs from the world npc repository. */ on_command("clearnpcs", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - player.world.npcRepository.forEach { npc -> player.world.unregister(npc) } - player.sendMessage("Unregistered all npcs from the world.") - } \ No newline at end of file + .then { player -> + player.world.npcRepository.forEach { npc -> player.world.unregister(npc) } + player.sendMessage("Unregistered all npcs from the world.") + } \ No newline at end of file diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index 75490b9fc..65ae83a71 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -1,48 +1,49 @@ import com.google.common.primitives.Ints import org.apollo.game.model.Position import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.util.command.valid_arg_length /** * Sends the player's position. */ on_command("pos", PrivilegeLevel.MODERATOR) - .then { player -> - player.sendMessage("You are at: ${player.position}.") - } + .then { player -> + player.sendMessage("You are at: ${player.position}.") + } /** * Teleports the player to the specified position. */ on_command("tele", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::tele [x] [y] [optional-z]" - if (!valid_arg_length(arguments, 2..3, player, invalidSyntax)) { - return@then - } + .then { player -> + val invalidSyntax = "Invalid syntax - ::tele [x] [y] [optional-z]" + if (!valid_arg_length(arguments, 2..3, player, invalidSyntax)) { + return@then + } - val x = Ints.tryParse(arguments[0]) - if (x == null) { - player.sendMessage(invalidSyntax) - return@then - } + val x = Ints.tryParse(arguments[0]) + if (x == null) { + player.sendMessage(invalidSyntax) + return@then + } - val y = Ints.tryParse(arguments[1]) - if (y == null) { + val y = Ints.tryParse(arguments[1]) + if (y == null) { + player.sendMessage(invalidSyntax) + return@then + } + + var z = player.position.height + if (arguments.size == 3) { + val plane = Ints.tryParse(arguments[2]) + if (plane == null) { player.sendMessage(invalidSyntax) return@then } + z = plane + } - var z = player.position.height - if (arguments.size == 3) { - val plane = Ints.tryParse(arguments[2]) - if (plane == null) { - player.sendMessage(invalidSyntax) - return@then - } - z = plane - } - - if (z in 0..4) { - player.teleport(Position(x, y, z)) - } - } \ No newline at end of file + if (z in 0..4) { + player.teleport(Position(x, y, z)) + } + } \ No newline at end of file diff --git a/game/plugin/entity/following/src/following.plugin.kts b/game/plugin/entity/following/src/following.plugin.kts index 6037e24d3..3fc65c1fb 100644 --- a/game/plugin/entity/following/src/following.plugin.kts +++ b/game/plugin/entity/following/src/following.plugin.kts @@ -1,11 +1,9 @@ -import com.google.common.primitives.Ints -import org.apollo.game.message.impl.PlayerActionMessage -import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.entity.player_action.PlayerActionType import org.apollo.plugin.entity.following.FollowAction -on_player_event { PlayerActionEvent::class } - .where { action == PlayerActionType.FOLLOW } - .then { - FollowAction.start(it, target) - terminate() - } \ No newline at end of file +on_player_event { org.apollo.game.plugin.entity.player_action.PlayerActionEvent::class } + .where { action == PlayerActionType.FOLLOW } + .then { + FollowAction.start(it, target) + terminate() + } \ No newline at end of file diff --git a/game/plugin/entity/player-action/src/player_action.kt b/game/plugin/entity/player-action/src/player_action.kt index bfec0e6de..2b5c230de 100644 --- a/game/plugin/entity/player-action/src/player_action.kt +++ b/game/plugin/entity/player-action/src/player_action.kt @@ -1,7 +1,9 @@ +package org.apollo.game.plugin.entity.player_action + import org.apollo.game.message.impl.SetPlayerActionMessage import org.apollo.game.model.entity.Player import org.apollo.game.model.event.PlayerEvent -import java.util.* +import java.util.EnumSet enum class PlayerActionType(val displayName: String, val slot: Int, val primary: Boolean = true) { ATTACK("Attack", 2), diff --git a/game/plugin/entity/player-action/src/player_action.plugin.kts b/game/plugin/entity/player-action/src/player_action.plugin.kts index c165f30aa..b3859a79a 100644 --- a/game/plugin/entity/player-action/src/player_action.plugin.kts +++ b/game/plugin/entity/player-action/src/player_action.plugin.kts @@ -1,18 +1,22 @@ import org.apollo.game.message.impl.PlayerActionMessage import org.apollo.game.model.event.impl.LoginEvent +import org.apollo.game.plugin.entity.player_action.PlayerActionEvent +import org.apollo.game.plugin.entity.player_action.PlayerActionType +import org.apollo.game.plugin.entity.player_action.actionAt +import org.apollo.game.plugin.entity.player_action.enableAction on { PlayerActionMessage::class } - .then { - val action = it.actionAt(option) - if (action != null) { - it.world.submit(PlayerActionEvent(it, it.world.playerRepository[index], action)) - } - - terminate() + .then { + val action = it.actionAt(option) + if (action != null) { + it.world.submit(PlayerActionEvent(it, it.world.playerRepository[index], action)) } + terminate() + } + on_player_event { LoginEvent::class } - .then { - it.enableAction(PlayerActionType.FOLLOW) - it.enableAction(PlayerActionType.TRADE) - } \ No newline at end of file + .then { + it.enableAction(PlayerActionType.FOLLOW) + it.enableAction(PlayerActionType.TRADE) + } \ No newline at end of file diff --git a/game/plugin/entity/spawn/src/spawn.kt b/game/plugin/entity/spawn/src/spawn.kt index cb49a6afe..f21f7d20a 100644 --- a/game/plugin/entity/spawn/src/spawn.kt +++ b/game/plugin/entity/spawn/src/spawn.kt @@ -1,8 +1,12 @@ -import org.apollo.game.model.* +package org.apollo.game.plugin.entity.spawn + +import org.apollo.game.model.Animation +import org.apollo.game.model.Direction +import org.apollo.game.model.Graphic +import org.apollo.game.model.Position data class Spawn(val id: Int?, val name: String, val position: Position, val facing: Direction, - val spawnAnimation: Animation? = null, - val spawnGraphic: Graphic? = null) + val spawnAnimation: Animation? = null, val spawnGraphic: Graphic? = null) object Spawns { val list = mutableListOf() diff --git a/game/plugin/entity/spawn/src/spawn.plugin.kts b/game/plugin/entity/spawn/src/spawn.plugin.kts index 37625df2a..0f172491b 100644 --- a/game/plugin/entity/spawn/src/spawn.plugin.kts +++ b/game/plugin/entity/spawn/src/spawn.plugin.kts @@ -1,23 +1,18 @@ import org.apollo.cache.def.NpcDefinition import org.apollo.game.model.entity.Npc +import org.apollo.game.plugin.entity.spawn.Spawns +import org.apollo.game.plugin.util.lookup.lookup_npc start { world -> Spawns.list.forEach { - val definition = if (it.id != null) NpcDefinition.lookup(it.id!!) else lookup_npc(it.name) - if (definition == null) { + val definition = it.id?.let { NpcDefinition.lookup(it) } ?: lookup_npc(it.name) ?: throw IllegalArgumentException("Invalid NPC name or ID ${it.name}, ${it.id}") - } val npc = Npc(world, definition.id, it.position) npc.turnTo(it.position.step(1, it.facing)) - if (it.spawnAnimation != null) { - npc.playAnimation(it.spawnAnimation) - } - - if (it.spawnGraphic != null) { - npc.playGraphic(it.spawnGraphic) - } + it.spawnAnimation?.let(npc::playAnimation) + it.spawnGraphic?.let(npc::playGraphic) world.register(npc) } diff --git a/game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts b/game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts index ba5acf903..278ffea01 100644 --- a/game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts +++ b/game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts @@ -1,4 +1,5 @@ import org.apollo.game.model.Direction +import org.apollo.game.plugin.entity.spawn.npc_spawn // Generic npcs diff --git a/game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts b/game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts index 719195104..be3ba855c 100644 --- a/game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts +++ b/game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts @@ -1,4 +1,5 @@ import org.apollo.game.model.Direction +import org.apollo.game.plugin.entity.spawn.npc_spawn // Generic npcs diff --git a/game/plugin/locations/falador/src/falador-npcs.plugin.kts b/game/plugin/locations/falador/src/falador-npcs.plugin.kts index 1663b60ca..f03926a03 100644 --- a/game/plugin/locations/falador/src/falador-npcs.plugin.kts +++ b/game/plugin/locations/falador/src/falador-npcs.plugin.kts @@ -1,3 +1,4 @@ +import org.apollo.game.plugin.entity.spawn.npc_spawn // Generic npcs diff --git a/game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts b/game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts index fe547d0df..9af0f50d9 100644 --- a/game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts +++ b/game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts @@ -1,3 +1,5 @@ +import org.apollo.game.plugin.entity.spawn.npc_spawn + npc_spawn("woman", id = 4, x = 3232, y = 3207) npc_spawn("man", id = 1, x = 3231, y = 3237) npc_spawn("man", id = 2, x = 3224, y = 3240) diff --git a/game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts b/game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts index d6c6501fc..ed80dacba 100644 --- a/game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts +++ b/game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts @@ -1,4 +1,5 @@ import org.apollo.game.model.Direction +import org.apollo.game.plugin.entity.spawn.npc_spawn // Functional npcs diff --git a/game/plugin/locations/varrock/src/shops.plugin.kts b/game/plugin/locations/varrock/src/shops.plugin.kts index d48e15e6e..9406e91f5 100644 --- a/game/plugin/locations/varrock/src/shops.plugin.kts +++ b/game/plugin/locations/varrock/src/shops.plugin.kts @@ -1,3 +1,5 @@ +import org.apollo.game.plugin.shops.shop + shop("Aubury's Rune Shop.") { operated by "Aubury" diff --git a/game/plugin/locations/varrock/src/varrock-npcs.plugin.kts b/game/plugin/locations/varrock/src/varrock-npcs.plugin.kts index b8d40abb9..11c64a585 100644 --- a/game/plugin/locations/varrock/src/varrock-npcs.plugin.kts +++ b/game/plugin/locations/varrock/src/varrock-npcs.plugin.kts @@ -1,4 +1,5 @@ import org.apollo.game.model.Direction +import org.apollo.game.plugin.entity.spawn.npc_spawn npc_spawn("barbarian_woman", x = 3222, y = 3399) diff --git a/game/plugin/navigation/door/src/door.kt b/game/plugin/navigation/door/src/door.kt index b3369cadb..afc8f14dc 100644 --- a/game/plugin/navigation/door/src/door.kt +++ b/game/plugin/navigation/door/src/door.kt @@ -8,9 +8,9 @@ import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.DynamicGameObject import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.model.event.PlayerEvent +import org.apollo.game.plugin.api.findObject import org.apollo.net.message.Message import java.util.Objects -import findObject enum class DoorType { LEFT, RIGHT, NOT_SUPPORTED @@ -21,17 +21,17 @@ class Door(private val gameObject: GameObject) { companion object { val LEFT_HINGE_ORIENTATION: HashMap = hashMapOf( - Direction.NORTH to Direction.WEST, - Direction.SOUTH to Direction.EAST, - Direction.WEST to Direction.SOUTH, - Direction.EAST to Direction.NORTH + Direction.NORTH to Direction.WEST, + Direction.SOUTH to Direction.EAST, + Direction.WEST to Direction.SOUTH, + Direction.EAST to Direction.NORTH ) val RIGHT_HINGE_ORIENTATION: HashMap = hashMapOf( - Direction.NORTH to Direction.EAST, - Direction.SOUTH to Direction.WEST, - Direction.WEST to Direction.NORTH, - Direction.EAST to Direction.SOUTH + Direction.NORTH to Direction.EAST, + Direction.SOUTH to Direction.WEST, + Direction.WEST to Direction.NORTH, + Direction.EAST to Direction.SOUTH ) val toggledDoors: HashMap = hashMapOf() @@ -94,7 +94,8 @@ class Door(private val gameObject: GameObject) { val position = movePosition() val orientation: Int = translateDirection()?.toOrientationInteger() ?: gameObject.orientation - val toggledDoor = DynamicGameObject.createPublic(world, gameObject.id, position, gameObject.type, orientation) + val toggledDoor = DynamicGameObject.createPublic(world, gameObject.id, position, gameObject.type, + orientation) regionRepository.fromPosition(position).addEntity(toggledDoor) toggledDoors.put(toggledDoor, gameObject) @@ -118,7 +119,7 @@ class Door(private val gameObject: GameObject) { */ private fun translateDirection(): Direction? { val direction = Direction.WNES[gameObject.orientation] - return when(type()) { + return when (type()) { DoorType.LEFT -> LEFT_HINGE_ORIENTATION[direction] DoorType.RIGHT -> RIGHT_HINGE_ORIENTATION[direction] DoorType.NOT_SUPPORTED -> null @@ -127,7 +128,8 @@ class Door(private val gameObject: GameObject) { } -class OpenDoorAction(private val player: Player, private val door: Door, position: Position) : DistancedAction(0, true, player, position, DISTANCE) { +class OpenDoorAction(private val player: Player, private val door: Door, position: Position) : DistancedAction( + 0, true, player, position, DISTANCE) { companion object { diff --git a/game/plugin/shops/src/action.kt b/game/plugin/shops/src/action.kt index db9561e46..0449253cc 100644 --- a/game/plugin/shops/src/action.kt +++ b/game/plugin/shops/src/action.kt @@ -1,3 +1,5 @@ +package org.apollo.game.plugin.shops + import org.apollo.game.action.DistancedAction import org.apollo.game.message.handler.ItemVerificationHandler.InventorySupplier import org.apollo.game.message.impl.SetWidgetTextMessage diff --git a/game/plugin/shops/src/dsl.kt b/game/plugin/shops/src/dsl.kt index 19100bbda..71365f665 100644 --- a/game/plugin/shops/src/dsl.kt +++ b/game/plugin/shops/src/dsl.kt @@ -1,5 +1,9 @@ -import CategoryWrapper.Affix +package org.apollo.game.plugin.shops + import org.apollo.cache.def.NpcDefinition +import org.apollo.game.plugin.shops.CategoryWrapper.Affix +import org.apollo.game.plugin.util.lookup.lookup_item +import org.apollo.game.plugin.util.lookup.lookup_npc import org.jetbrains.kotlin.utils.keysToMap /** diff --git a/game/plugin/shops/src/shop.kt b/game/plugin/shops/src/shop.kt index 90e81086c..208632257 100644 --- a/game/plugin/shops/src/shop.kt +++ b/game/plugin/shops/src/shop.kt @@ -1,13 +1,15 @@ -import Shop.Companion.ExchangeType.BUYING -import Shop.Companion.ExchangeType.SELLING -import Shop.PurchasePolicy.ANY -import Shop.PurchasePolicy.NOTHING -import Shop.PurchasePolicy.OWNED +package org.apollo.game.plugin.shops + import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.Item import org.apollo.game.model.entity.Player import org.apollo.game.model.inv.Inventory import org.apollo.game.model.inv.Inventory.StackMode.STACK_ALWAYS +import org.apollo.game.plugin.shops.Shop.Companion.ExchangeType.BUYING +import org.apollo.game.plugin.shops.Shop.Companion.ExchangeType.SELLING +import org.apollo.game.plugin.shops.Shop.PurchasePolicy.ANY +import org.apollo.game.plugin.shops.Shop.PurchasePolicy.NOTHING +import org.apollo.game.plugin.shops.Shop.PurchasePolicy.OWNED /** * Contains shop-related interface ids. diff --git a/game/plugin/shops/src/shop.plugin.kts b/game/plugin/shops/src/shop.plugin.kts index 8dd974a8b..644e96c34 100644 --- a/game/plugin/shops/src/shop.plugin.kts +++ b/game/plugin/shops/src/shop.plugin.kts @@ -1,8 +1,12 @@ - import org.apollo.game.message.handler.ItemVerificationHandler import org.apollo.game.message.impl.ItemActionMessage import org.apollo.game.message.impl.NpcActionMessage import org.apollo.game.model.entity.Mob +import org.apollo.game.plugin.shops.Interfaces +import org.apollo.game.plugin.shops.OpenShopAction +import org.apollo.game.plugin.shops.PlayerInventorySupplier +import org.apollo.game.plugin.shops.SHOPS +import org.apollo.game.plugin.shops.Shop import org.apollo.game.scheduling.ScheduledTask fun Mob.shop(): Shop? = SHOPS[definition.id] diff --git a/game/plugin/skills/fishing/src/spots.kts b/game/plugin/skills/fishing/src/spots.kts index 83080e29f..46001275b 100644 --- a/game/plugin/skills/fishing/src/spots.kts +++ b/game/plugin/skills/fishing/src/spots.kts @@ -1,6 +1,7 @@ - import org.apollo.game.model.Direction import org.apollo.game.model.Position +import org.apollo.game.plugin.entity.spawn.Spawn +import org.apollo.game.plugin.entity.spawn.Spawns import org.apollo.game.plugin.skills.fishing.FishingSpot import org.apollo.game.plugin.skills.fishing.FishingSpot.CAGE_HARPOON import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_HARPOON diff --git a/game/plugin/util/command/src/command.kt b/game/plugin/util/command/src/command.kt index 7746d948b..dd17c26c4 100644 --- a/game/plugin/util/command/src/command.kt +++ b/game/plugin/util/command/src/command.kt @@ -1,3 +1,5 @@ +package org.apollo.game.plugin.util.command + import org.apollo.game.model.entity.Player /** @@ -17,4 +19,4 @@ fun valid_arg_length(args: Array, length: IntRange, player: Player, mess * message if not. */ fun valid_arg_length(args: Array, length: Int, player: Player, message: String) - = valid_arg_length(args, IntRange(length, length), player, message) \ No newline at end of file + = valid_arg_length(args, IntRange(length, length), player, message) \ No newline at end of file diff --git a/game/plugin/util/lookup/src/lookup.kt b/game/plugin/util/lookup/src/lookup.kt index a789b17d9..895d63c30 100644 --- a/game/plugin/util/lookup/src/lookup.kt +++ b/game/plugin/util/lookup/src/lookup.kt @@ -1,3 +1,5 @@ +package org.apollo.game.plugin.util.lookup + import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition From 6e3ddff51a206f6bd11233949f14d50ba7b2bd88 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 24 Sep 2017 22:56:48 +0100 Subject: [PATCH 083/209] Correctly import api.Definitions --- game/plugin/skills/mining/src/mining.plugin.kts | 4 ++++ game/plugin/skills/woodcutting/src/woodcutting.plugin.kts | 4 ++++ game/plugin/util/lookup/test/LookupTests.kt | 8 +++++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index 418bcbb85..c7d34db26 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -6,7 +6,11 @@ import org.apollo.game.model.Position import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.api.expireObject +import org.apollo.game.plugin.api.findObject import org.apollo.game.plugin.api.mining +import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.skills.mining.Ore import org.apollo.game.plugin.skills.mining.PICKAXES import org.apollo.game.plugin.skills.mining.Pickaxe diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index df04e9fe5..ca20a248f 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -6,6 +6,10 @@ import org.apollo.game.model.Position import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.api.expireObject +import org.apollo.game.plugin.api.findObject +import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.api.woodcutting import org.apollo.game.plugin.skills.woodcutting.Axe import org.apollo.game.plugin.skills.woodcutting.Tree diff --git a/game/plugin/util/lookup/test/LookupTests.kt b/game/plugin/util/lookup/test/LookupTests.kt index fc4c18f9c..680c9c158 100644 --- a/game/plugin/util/lookup/test/LookupTests.kt +++ b/game/plugin/util/lookup/test/LookupTests.kt @@ -1,15 +1,17 @@ import org.apollo.cache.def.ItemDefinition -import org.apollo.game.plugin.testing.* +import org.apollo.game.plugin.testing.KotlinPluginTest +import org.apollo.game.plugin.util.lookup.lookup_item import org.assertj.core.api.Assertions.assertThat import org.junit.Test class LookupTests : KotlinPluginTest() { - @Test fun itemLookup() { + @Test + fun itemLookup() { val testItem = ItemDefinition(0) testItem.name = "sword" ItemDefinition.init(arrayOf(testItem)) - assertThat(lookup_item("sword")).isEqualTo(testItem); + assertThat(lookup_item("sword")).isEqualTo(testItem) } } \ No newline at end of file From 97896a34a47d65a633fee076f7c2453c6853e438 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Thu, 28 Dec 2017 18:41:21 -1000 Subject: [PATCH 084/209] Add implementation of runecrafting skill --- game/plugin/skills/runecrafting/build.gradle | 11 +++ game/plugin/skills/runecrafting/src/action.kt | 75 +++++++++++++++++ game/plugin/skills/runecrafting/src/altar.kt | 23 ++++++ game/plugin/skills/runecrafting/src/rune.kt | 36 +++++++++ .../runecrafting/src/runecrafting.plugin.kts | 81 +++++++++++++++++++ .../skills/runecrafting/src/talisman.kt | 34 ++++++++ game/plugin/skills/runecrafting/src/tiara.kt | 24 ++++++ .../org/apollo/game/model/inv/Inventory.java | 18 +++-- 8 files changed, 297 insertions(+), 5 deletions(-) create mode 100644 game/plugin/skills/runecrafting/build.gradle create mode 100644 game/plugin/skills/runecrafting/src/action.kt create mode 100644 game/plugin/skills/runecrafting/src/altar.kt create mode 100644 game/plugin/skills/runecrafting/src/rune.kt create mode 100644 game/plugin/skills/runecrafting/src/runecrafting.plugin.kts create mode 100644 game/plugin/skills/runecrafting/src/talisman.kt create mode 100644 game/plugin/skills/runecrafting/src/tiara.kt diff --git a/game/plugin/skills/runecrafting/build.gradle b/game/plugin/skills/runecrafting/build.gradle new file mode 100644 index 000000000..595add781 --- /dev/null +++ b/game/plugin/skills/runecrafting/build.gradle @@ -0,0 +1,11 @@ +plugin { + name = "runecrafting-skill" + packageName = "org.apollo.game.plugin.skills.runecrafting" + authors = [ + "Major", + "BugCrusher", + "tlf30" + ] + + dependencies = ["util:lookup", "api"] +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/action.kt b/game/plugin/skills/runecrafting/src/action.kt new file mode 100644 index 000000000..6beb45704 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/action.kt @@ -0,0 +1,75 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.action.DistancedAction +import org.apollo.game.model.Animation +import org.apollo.game.model.Graphic +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.api.runecraft +import org.apollo.util.LanguageUtil + +private val blankTiaraId = 5525 +private val runecraftingAnimation = Animation(791) +private val runecraftingGraphic = Graphic(186, 0, 100) +private val runeEssenceId = 1436 + +class TeleportAction(val player: Player, val start: Position, val distance: Int, val end: Position) : DistancedAction(0, true, player, start, distance) { + override fun executeAction() { + player.teleport(end) + stop() + } +} + +class CreateTiaraAction(val player: Player, val position: Position, val tiara: Tiara, val altar: Altar) : DistancedAction(0, true, player, position, 2) { + override fun executeAction() { + if (tiara.altar != altar) { + player.sendMessage("You can't use that talisman on this altar.") + stop() + return + } + + if (player.inventory.contains(blankTiaraId)) { + player.inventory.remove(blankTiaraId) + player.inventory.add(tiara.id) + player.runecraft.experience += tiara.xp + player.playAnimation(runecraftingAnimation) + player.playGraphic(runecraftingGraphic) + stop() + } + } +} + +class RunecraftingAction(val player: Player, val rune: Rune, altar: Altar) : AsyncDistancedAction(0, true, player, altar.center, 3) { + override fun action(): ActionBlock = { + if (player.runecraft.current < rune.level) { + player.sendMessage("You need a runecrafting level of ${rune.level} to craft this rune.") + stop() + } + + if (!player.inventory.contains(runeEssenceId)) { + player.sendMessage("You need rune essence to craft runes.") + stop() + } + + player.turnTo(position) + player.playAnimation(runecraftingAnimation) + player.playGraphic(runecraftingGraphic) + + wait(1) + + val name = Definitions.item(rune.id)?.name; + val nameArticle = LanguageUtil.getIndefiniteArticle(name) + val essenceAmount = player.inventory.removeAll(runeEssenceId) + val runeAmount = essenceAmount * rune.getBonus() + val runesDescription = if (runeAmount > 1) "some ${name}s" else "$nameArticle $name" + + player.sendMessage("You craft the rune essence into $runesDescription") + player.inventory.add(rune.id, runeAmount.toInt()) + player.runecraft.experience += rune.xp + stop() + } + +} + + diff --git a/game/plugin/skills/runecrafting/src/altar.kt b/game/plugin/skills/runecrafting/src/altar.kt new file mode 100644 index 000000000..3895a26aa --- /dev/null +++ b/game/plugin/skills/runecrafting/src/altar.kt @@ -0,0 +1,23 @@ +import org.apollo.game.model.Position + +enum class Altar(val entranceId: Int, val craftingId: Int, val portalId: Int, val entrance: Position, val exit: Position, val center: Position) { + AIR_ALTAR(2452, 2478, 2465, Position(2841, 4829), Position(2983, 3292), Position(2844, 4834)), + MIND_ALTAR(2453, 2479, 2466, Position(2793, 4828), Position(2980, 3514), Position(2786, 4841)), + WATER_ALTAR(2454, 2480, 2467, Position(2726, 4832), Position(3187, 3166), Position(2716, 4836)), + EARTH_ALTAR(2455, 2481, 2468, Position(2655, 4830), Position(3304, 3474), Position(2658, 4841)), + FIRE_ALTAR(2456, 2482, 2469, Position(2574, 4849), Position(3311, 3256), Position(2585, 4838)), + BODY_ALTAR(2457, 2483, 2470, Position(2524, 4825), Position(3051, 3445), Position(2525, 4832)), + COSMIC_ALTAR(2458, 2484, 2471, Position(2142, 4813), Position(2408, 4379), Position(2142, 4833)), + LAW_ALTAR(2459, 2485, 2472, Position(2464, 4818), Position(2858, 3379), Position(2464, 4832)), + NATURE_ALTAR(2460, 2486, 2473, Position(2400, 4835), Position(2867, 3019), Position(2400, 4841)), + CHAOS_ALTAR(2461, 2487, 2474, Position(2268, 4842), Position(3058, 3591), Position(2271, 4842)), + DEATH_ALTAR(2462, 2488, 2475, Position(2208, 4830), Position(3222, 3222), Position(2205, 4836)); + + companion object { + private val ALTARS = Altar.values() + + fun findByEntranceId(id: Int): Altar? = ALTARS.find { Altar -> Altar.entranceId == id } + fun findByPortalId(id: Int): Altar? = ALTARS.find { Altar -> Altar.portalId == id } + fun findByCraftingId(id: Int): Altar? = ALTARS.find { Altar -> Altar.craftingId == id } + } +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/rune.kt b/game/plugin/skills/runecrafting/src/rune.kt new file mode 100644 index 000000000..bc94e94a3 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/rune.kt @@ -0,0 +1,36 @@ +import Altar.* + +enum class Rune(val id: Int, val altar: Altar, val level: Int, val xp: Double) { + AIR_RUNE(556, AIR_ALTAR, 1, 5.0), + MIND_RUNE(558, MIND_ALTAR, 1, 5.5), + WATER_RUNE(555, WATER_ALTAR, 5, 6.0), + EARTH_RUNE(557, EARTH_ALTAR, 9, 6.5), + FIRE_RUNE(554, FIRE_ALTAR, 14, 7.0), + BODY_RUNE(559, BODY_ALTAR, 20, 7.5), + COSMIC_RUNE(564, COSMIC_ALTAR, 27, 8.0), + CHAOS_RUNE(562, CHAOS_ALTAR, 35, 8.5), + NATURE_RUNE(561, NATURE_ALTAR, 44, 9.0), + LAW_RUNE(563, LAW_ALTAR, 54, 9.5), + DEATH_RUNE(560, DEATH_ALTAR, 65, 10.0); + + companion object { + private val RUNES = Rune.values() + + fun findById(id: Int): Rune? = RUNES.find { rune -> rune.id == id } + fun findByAltarId(id: Int): Rune? = RUNES.find { rune -> rune.altar.craftingId == id } + } + + fun getBonus(): Double = when (this) { + Rune.AIR_RUNE -> (Math.floor((level / 11.0)) + 1) + Rune.MIND_RUNE -> (Math.floor((level / 14.0)) + 1) + Rune.WATER_RUNE -> (Math.floor((level / 19.0)) + 1) + Rune.EARTH_RUNE -> (Math.floor((level / 26.0)) + 1) + Rune.FIRE_RUNE -> (Math.floor((level / 35.0)) + 1) + Rune.BODY_RUNE -> (Math.floor((level / 46.0)) + 1) + Rune.COSMIC_RUNE -> (Math.floor((level / 59.0)) + 1) + Rune.CHAOS_RUNE -> (Math.floor((level / 74.0)) + 1) + Rune.NATURE_RUNE -> (Math.floor((level / 91.0)) + 1) + Rune.LAW_RUNE -> 1.0 + Rune.DEATH_RUNE -> 1.0 + } +} diff --git a/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts b/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts new file mode 100644 index 000000000..ece21c98f --- /dev/null +++ b/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts @@ -0,0 +1,81 @@ +import org.apollo.game.message.impl.* +import org.apollo.game.model.entity.EquipmentConstants +import org.apollo.game.model.event.impl.LoginEvent + +private val changeAltarObjectConfigId = 491 + +on_player_event { LoginEvent::class } + .then { + val equippedHat = player.equipment.get(EquipmentConstants.HAT) + val equippedTiaraConfig = equippedHat?.let { item -> Tiara.findById(item.id)?.configId } ?: 0 + val configValue = 1 shl equippedTiaraConfig + + player.send(ConfigMessage(changeAltarObjectConfigId, configValue)) + } + +on { ObjectActionMessage::class } + .where { option == 2 } + .then { + val tiara = Tiara.findByAltarId(id) ?: return@then + val hat = it.equipment.get(EquipmentConstants.HAT) ?: return@then + + if (hat.id == tiara.id && tiara.altar.entranceId == id) { + it.startAction(TeleportAction(it, position, 2, tiara.altar.entrance)) + terminate() + } + } + +on { ItemActionMessage::class } + .where { option == 1 } + .then { player -> + Tiara.findById(id)?.let { + player.send(ConfigMessage(changeAltarObjectConfigId, 0)) + terminate() + } + } + +on { ItemOnObjectMessage::class } + .then { + val tiara = Tiara.findByTalismanId(id) ?: return@then + val altar = Altar.findByCraftingId(objectId) ?: return@then + + it.startAction(CreateTiaraAction(it, position, tiara, altar)) + terminate() + } + +on { ItemOptionMessage::class } + .where { option == 4 } + .then { + val talisman = Talisman.findById(id) ?: return@then + + talisman.sendProximityMessageTo(it) + terminate() + } + +on { ItemOnObjectMessage::class } + .then { + val talisman = Talisman.findById(id) ?: return@then + val altar = Altar.findByEntranceId(objectId) ?: return@then + + it.startAction(TeleportAction(it, position, 2, altar.entrance)) + terminate() + } + +on { ObjectActionMessage::class } + .where { option == 1 } + .then { + val altar = Altar.findByPortalId(id) ?: return@then + + it.startAction(TeleportAction(it, altar.entrance, 1, altar.exit)) + terminate() + } + +on { ObjectActionMessage::class } + .where { option == 1 } + .then { + val rune = Rune.findByAltarId(id) ?: return@then + val craftingAltar = Altar.findByCraftingId(id) ?: return@then + + it.startAction(RunecraftingAction(it, rune, craftingAltar)) + terminate() + } \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/talisman.kt b/game/plugin/skills/runecrafting/src/talisman.kt new file mode 100644 index 000000000..db81d9dc6 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/talisman.kt @@ -0,0 +1,34 @@ +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player + +enum class Talisman(val id: Int, val altar: Position) { + AIR_TALISMAN(1438, Position(2985, 3292)), + EARTH_TALISMAN(1440, Position(3306, 3474)), + FIRE_TALISMAN(1442, Position(3313, 3255)), + WATER_TALISMAN(1444, Position(3185, 3165)), + BODY_TALISMAN(1446, Position(3053, 3445)), + MIND_TALISMAN(1448, Position(2982, 3514)), + CHAOS_TALISMAN(1452, Position(3059, 3590)), + COSMIC_TALISMAN(1454, Position(2408, 4377)), + DEATH_TALISMAN(1456, Position(0, 0)), + LAW_TALISMAN(1458, Position(2858, 3381)), + NATURE_TALISMAN(1462, Position(2869, 3019)); + + companion object { + private val TALISMANS = Talisman.values() + + fun findById(id: Int): Talisman? = TALISMANS.find { talisman -> talisman.id == id } + } + + fun sendProximityMessageTo(player: Player) { + if (altar.isWithinDistance(player.position, 10)) { + player.sendMessage("Your talisman glows brightly."); + return + } + + var direction = if (player.position.y > altar.y) "North" else "South"; + direction += if (player.position.x > altar.x) "-East" else "-West"; + + player.sendMessage("The talisman pulls toward the $direction"); + } +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/tiara.kt b/game/plugin/skills/runecrafting/src/tiara.kt new file mode 100644 index 000000000..549fe76be --- /dev/null +++ b/game/plugin/skills/runecrafting/src/tiara.kt @@ -0,0 +1,24 @@ +import Altar.* +import Talisman.* + +enum class Tiara(val id: Int, val altar: Altar, val talisman: Talisman, val configId: Int, val xp: Double) { + AIR_TIARA(5527, AIR_ALTAR, AIR_TALISMAN, 0, 25.0), + MIND_TIARA(5529, MIND_ALTAR, MIND_TALISMAN, 1, 27.5), + WATER_TIARA(5531, WATER_ALTAR, WATER_TALISMAN, 2, 30.0), + BODY_TIARA(5533, BODY_ALTAR, BODY_TALISMAN, 5, 37.5), + EARTH_TIARA(5535, EARTH_ALTAR, EARTH_TALISMAN, 3, 32.5), + FIRE_TIARA(5537, FIRE_ALTAR, FIRE_TALISMAN, 4, 35.0), + COSMIC_TIARA(5539, COSMIC_ALTAR, COSMIC_TALISMAN, 6, 40.0), + NATURE_TIARA(5541, NATURE_ALTAR, NATURE_TALISMAN, 8, 45.0), + CHAOS_TIARA(5543, CHAOS_ALTAR, CHAOS_TALISMAN, 9, 42.5), + LAW_TIARA(5545, LAW_ALTAR, LAW_TALISMAN, 7, 47.5), + DEATH_TIARA(5548, DEATH_ALTAR, DEATH_TALISMAN, 10, 50.0); + + companion object { + private val TIARAS = Tiara.values() + + fun findById(id: Int): Tiara? = TIARAS.find { tiara -> tiara.id == id } + fun findByAltarId(id: Int): Tiara? = TIARAS.find { tiara -> tiara.altar.entranceId == id } + fun findByTalismanId(id: Int): Tiara? = TIARAS.find { tiara -> tiara.talisman.id == id } + } +} \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/model/inv/Inventory.java b/game/src/main/java/org/apollo/game/model/inv/Inventory.java index c4ff61769..ae8f081e5 100644 --- a/game/src/main/java/org/apollo/game/model/inv/Inventory.java +++ b/game/src/main/java/org/apollo/game/model/inv/Inventory.java @@ -1,15 +1,14 @@ package org.apollo.game.model.inv; +import com.google.common.base.Preconditions; +import org.apollo.cache.def.ItemDefinition; +import org.apollo.game.model.Item; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; -import org.apollo.cache.def.ItemDefinition; -import org.apollo.game.model.Item; - -import com.google.common.base.Preconditions; - /** * Represents an inventory - a collection of {@link Item}s. * @@ -518,6 +517,15 @@ public int remove(Item item) { return remove(item.getId(), item.getAmount()); } + /** + * Remove all items with the given {@code id} and return the number of + * items removed. + * + * @param id The id of items to remove. + * @return The amount that was removed. + */ + public int removeAll(int id) { return remove(id, getAmount(id)); } + /** * Removes all the listeners. */ From d8116478d4241fee0865df513fc3f25f410f4c96 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 27 Mar 2018 21:12:44 +0100 Subject: [PATCH 085/209] Remove dependency on embedded kotlin compiler This is a large change that significantly simplifies the plugin build system by having the kotlinc handle everything related to script compilation. Since we no longer use package name rewriting, the "packageName" option has been dropped from the gradle script API and has been removed from existing plugins. In addition to simplifying the build system, it should also significantly speed up build times. Previously we ran 2 build processes for every plugin and didn't have fully working incremental compilation for scripts compared to 1 build process with built-in incremental compilation. There were also some random pieces of code that referenced kotlinc directly, so those have either been removed or refactored out. --- buildSrc/build.gradle | 3 +- .../build/plugin/ApolloPluginExtension.groovy | 69 +++------------ .../KotlinCompilerConfigurationFactory.groovy | 59 ------------- .../plugin/compiler/KotlinScriptBinary.groovy | 23 ----- .../KotlinScriptBinaryArtifactRemapper.groovy | 46 ---------- .../compiler/KotlinScriptCompiler.groovy | 73 ---------------- .../KotlinScriptCompilerException.groovy | 11 --- .../tasks/ApolloScriptCompileTask.groovy | 84 ------------------- game/build.gradle | 2 +- game/plugin/bank/build.gradle | 1 - game/plugin/cmd/build.gradle | 1 - game/plugin/consumables/build.gradle | 1 - game/plugin/dummy/build.gradle | 1 - game/plugin/emote-tab/build.gradle | 1 - game/plugin/entity/following/build.gradle | 1 - game/plugin/entity/player-action/build.gradle | 1 - game/plugin/entity/spawn/build.gradle | 1 - game/plugin/entity/walk-to/build.gradle | 1 - game/plugin/locations/al-kharid/build.gradle | 1 - game/plugin/locations/edgeville/build.gradle | 1 - game/plugin/locations/falador/build.gradle | 1 - game/plugin/locations/lumbridge/build.gradle | 1 - .../locations/tutorial-island/build.gradle | 1 - game/plugin/locations/varrock/build.gradle | 1 - game/plugin/navigation/door/build.gradle | 3 +- game/plugin/shops/build.gradle | 1 - game/plugin/shops/src/dsl.kt | 3 +- game/plugin/skills/fishing/build.gradle | 1 - game/plugin/skills/mining/build.gradle | 1 - game/plugin/skills/runecrafting/build.gradle | 1 - game/plugin/skills/woodcutting/build.gradle | 1 - game/plugin/util/command/build.gradle | 3 +- game/plugin/util/lookup/build.gradle | 3 +- .../game/plugin/KotlinPluginEnvironment.java | 23 +---- properties.gradle | 2 +- 35 files changed, 24 insertions(+), 403 deletions(-) delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 404e3214c..76639e171 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -20,7 +20,6 @@ repositories { dependencies { compile gradleApi() - compile group: 'org.ow2.asm', name: 'asm-all', version: '5.0.3' compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" - compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" + compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: "$kotlinVersion" } \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy index ea4c910e4..a87c60823 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -1,10 +1,6 @@ package org.apollo.build.plugin -import org.apollo.build.plugin.tasks.ApolloScriptCompileTask import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.file.FileTree -import org.gradle.api.tasks.testing.Test class ApolloPluginExtension { final Project project @@ -14,11 +10,6 @@ class ApolloPluginExtension { */ String name - /** - * The package that plugin scripts (.kts files) will be packaged under for this plugin. - */ - String packageName = "org.apollo.game.plugins" - /** * An optional description of this plugin. */ @@ -51,21 +42,6 @@ class ApolloPluginExtension { init() } - private def addDependencyOn(Project other, String configuration, boolean includeProject) { - def compileConfiguration = other.configurations.getByName("compile") - def sources = other.sourceSets.main - def deps = compileConfiguration.dependencies - - deps.each { - project.dependencies.add(configuration, it) - } - - project.dependencies.add(configuration, sources.output) - if (includeProject) { - project.dependencies.add(configuration, other) - } - } - /** * Setup the {@link Project} with the correct dependencies and tasks required to build the plugin * and its scripts. @@ -75,44 +51,26 @@ class ApolloPluginExtension { def pluginTestingProject = project.findProject(':game:plugin-testing') project.plugins.apply('kotlin') - project.sourceSets { - main { - kotlin { - srcDir this.srcDir - exclude '*.kts' - } - } + project.dependencies { + def transitiveGameDeps = gameProject.configurations["compile"].dependencies + def gameSources = gameProject.sourceSets.main - test { - kotlin { - srcDir this.testDir - } + transitiveGameDeps.each { dependency -> + compile dependency } - } - - def mainSources = project.sourceSets.main - - addDependencyOn(gameProject, "compile", false) - addDependencyOn(pluginTestingProject, "testCompile", true) - - def buildTask = project.tasks['classes'] - FileTree scripts = project.fileTree(srcDir).matching { - include '*.kts' + compile gameSources.output + testCompile pluginTestingProject } - project.tasks.create('compileScripts', ApolloScriptCompileTask) { - def outputDir = mainSources.output.classesDir - - inputs.files scripts.files - outputsDir = outputDir - - compileClasspath = mainSources.compileClasspath + mainSources.runtimeClasspath + mainSources.output - scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript" - mustRunAfter buildTask + project.sourceSets { + main.kotlin.srcDirs += this.srcDir + test.kotlin.srcDirs += this.testDir } - buildTask.finalizedBy(project.tasks['compileScripts']) + project.tasks["compileKotlin"].kotlinOptions.freeCompilerArgs += [ + "-script-templates", "org.apollo.game.plugin.kotlin.KotlinPluginScript" + ] } def getDependencies() { @@ -126,5 +84,4 @@ class ApolloPluginExtension { this.dependencies = dependencies } - } diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy deleted file mode 100644 index 3da38f157..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinCompilerConfigurationFactory.groovy +++ /dev/null @@ -1,59 +0,0 @@ -package org.apollo.build.plugin.compiler - -import kotlin.jvm.JvmClassMappingKt -import kotlin.reflect.KClass -import kotlin.reflect.full.KClasses -import kotlin.reflect.jvm.internal.KClassImpl -import kotlin.script.templates.ScriptTemplateDefinition -import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate - -import java.lang.management.ManagementFactory - -class KotlinCompilerConfigurationFactory { - - static CompilerConfiguration create(String scriptDefinitionClassName, Collection classpath, MessageCollector messageCollector) { - def parentClassLoader = (URLClassLoader) Thread.currentThread().contextClassLoader - if (parentClassLoader == null) { - throw new RuntimeException("Unable to find current classloader") - } - - URL[] classpathUrls = parentClassLoader.getURLs() - - for (classpathUrl in classpathUrls) { - try { - classpath.add(new File(classpathUrl.toURI())) - } catch (ex) { - throw new RuntimeException("URL returned by ClassLoader is invalid", ex) - } - - } - - def runtimeBean = ManagementFactory.getRuntimeMXBean() - if (!runtimeBean.bootClassPathSupported) { - println("Warning! Boot class path is not supported, must be supplied on the command line") - } else { - def bootClasspath = runtimeBean.bootClassPath - classpath.addAll(bootClasspath.split(File.pathSeparatorChar.toString()).collect { new File(it) }) - } - - def classLoader = new URLClassLoader(classpath.collect { it.toURL() }.toArray(new URL[classpath.size()])) - def configuration = new CompilerConfiguration() - def scriptDefinitionClass = classLoader.loadClass(scriptDefinitionClassName) - - def scriptDefinition = new KotlinScriptDefinitionFromAnnotatedTemplate(JvmClassMappingKt.getKotlinClass(scriptDefinitionClass), - null, null, null, classpath.collect()) - - configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) - configuration.put(JVMConfigurationKeys.CONTENT_ROOTS, classpath.collect { new JvmClasspathRoot(it) }) - configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false) - configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) - configuration.copy() - - return configuration - } -} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy deleted file mode 100644 index 398ed251b..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinary.groovy +++ /dev/null @@ -1,23 +0,0 @@ -package org.apollo.build.plugin.compiler - -import java.nio.file.Path - -class KotlinScriptBinaryArtifact { - final String relativePath - final byte[] data - - KotlinScriptBinaryArtifact(String relativePath, byte[] data) { - this.relativePath = relativePath - this.data = data - } -} - -class KotlinScriptBinary { - final String mainClassName - final List artifacts - - KotlinScriptBinary(String mainClassName, List artifacts) { - this.mainClassName = mainClassName - this.artifacts = artifacts - } -} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy deleted file mode 100644 index ffaae9519..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptBinaryArtifactRemapper.groovy +++ /dev/null @@ -1,46 +0,0 @@ -package org.apollo.build.plugin.compiler - -import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.commons.Remapper -import org.objectweb.asm.commons.RemappingClassAdapter -import org.objectweb.asm.tree.ClassNode - -class KotlinScriptBinaryArtifactRemapper { - final String originalSourceFileName - final String mainClassName - - KotlinScriptBinaryArtifactRemapper(String originalSourceFileName, String mainClassName) { - this.originalSourceFileName = originalSourceFileName - this.mainClassName = mainClassName - } - - KotlinScriptBinaryArtifact remapToPackage(KotlinScriptBinaryArtifact artifact, String packageName) { - def node = new ClassNode() - def writer = new ClassWriter(0) - def reader = new ClassReader(new ByteArrayInputStream(artifact.data)) - reader.accept(node, ClassReader.EXPAND_FRAMES) - - def normalizedPackageName = packageName.replace('.', '/') - def oldClassName = reader.getClassName() - def newClassName = artifact.relativePath.replace(oldClassName, "$normalizedPackageName/$oldClassName") - - def remapper = new Remapper() { - @Override - String map(String typeName) { - if (typeName.equals(mainClassName) || typeName.startsWith("$mainClassName\$")) { - return "$normalizedPackageName/$typeName" - } - - return super.map(typeName); - } - } - - def remappingAdapter = new RemappingClassAdapter(writer, remapper) - node.accept(remappingAdapter) - writer.visitSource(originalSourceFileName, null) - writer.visitEnd() - - return new KotlinScriptBinaryArtifact(newClassName, writer.toByteArray()) - } -} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy deleted file mode 100644 index 98a1716c9..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompiler.groovy +++ /dev/null @@ -1,73 +0,0 @@ -package org.apollo.build.plugin.compiler - -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler -import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer -import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.java.PsiPackageStatementImpl -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.KotlinSourceRoot - -import java.nio.file.Path - -class KotlinScriptCompiler { - private String scriptDefinitionClass - private Collection classpath - private MessageCollector messageCollector - - KotlinScriptCompiler(String scriptDefinitionClass, Collection classpath, MessageCollector messageCollector) { - this.scriptDefinitionClass = scriptDefinitionClass - this.classpath = classpath - this.messageCollector = messageCollector - } - - KotlinScriptBinary compile(Path input) { - def compilerConfiguration = KotlinCompilerConfigurationFactory.create( - scriptDefinitionClass, - classpath, - messageCollector - ) - - def rootDisposable = Disposer.newDisposable() - def configuration = compilerConfiguration.copy() - - - configuration.put(CommonConfigurationKeys.MODULE_NAME, input.toString()) - configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, new KotlinSourceRoot(input.toAbsolutePath().toString())) - - def configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES - def environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, configFiles) - - try { - def generationState = KotlinToJVMBytecodeCompiler.INSTANCE.analyzeAndGenerate(environment) - if (generationState == null) { - throw new KotlinScriptCompilerException("Failed to generate bytecode for kotlin script") - } - - def sourceFiles = environment.getSourceFiles() - def script = sourceFiles[0].script - - if (script == null) { - throw new KotlinScriptCompilerException("Main source file is not a script") - } - - def scriptFilePath = script.fqName.asString().replace('.', '/') + ".class" - def scriptFileClass = generationState.factory.get(scriptFilePath) - - if (scriptFileClass == null) { - throw new KotlinScriptCompilerException("Unable to find compiled plugin class file $scriptFilePath") - } - - def outputs = generationState.factory.asList() - def artifacts = outputs.collect { new KotlinScriptBinaryArtifact(it.relativePath, it.asByteArray()) } - - return new KotlinScriptBinary(script.fqName.asString(), artifacts) - } catch (ex) { - throw new KotlinScriptCompilerException("Compilation failed", ex) - } finally { - Disposer.dispose(rootDisposable) - } - } -} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy deleted file mode 100644 index ae899f487..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/compiler/KotlinScriptCompilerException.groovy +++ /dev/null @@ -1,11 +0,0 @@ -package org.apollo.build.plugin.compiler - -class KotlinScriptCompilerException extends Exception { - KotlinScriptCompilerException(String message) { - super(message) - } - - KotlinScriptCompilerException(String message, Throwable cause) { - super(message, cause) - } -} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy deleted file mode 100644 index df5904101..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/tasks/ApolloScriptCompileTask.groovy +++ /dev/null @@ -1,84 +0,0 @@ -package org.apollo.build.plugin.tasks - -import org.apollo.build.plugin.ApolloPluginExtension -import org.apollo.build.plugin.compiler.KotlinScriptBinaryArtifactRemapper -import org.apollo.build.plugin.compiler.KotlinScriptCompiler -import org.gradle.api.DefaultTask -import org.gradle.api.file.FileCollection -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.incremental.IncrementalTaskInputs -import org.jetbrains.kotlin.cli.common.messages.MessageRenderer -import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector - -import java.nio.file.Files -import java.nio.file.StandardOpenOption - -class ApolloScriptCompileTask extends DefaultTask { - @OutputDirectory - File outputsDir - - @Input - FileCollection compileClasspath - - @Input - String scriptDefinitionClass - - @TaskAction - def execute(IncrementalTaskInputs inputs) { - def extension = getProject().getExtensions().getByType(ApolloPluginExtension.class); - def packageName = extension.packageName - - if (scriptDefinitionClass == null) { - throw new Exception("No script definition class given") - } - - if (compileClasspath == null) { - throw new Exception("No compile classpath given") - } - - def classpath = compileClasspath.files - def messageCollector = new PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, true); - def compiler = new KotlinScriptCompiler(scriptDefinitionClass, classpath, messageCollector) - - outputsDir.mkdirs() - - inputs.outOfDate { - removeBinariesFor(it.file) - - def binary = compiler.compile(it.file.toPath()) - def binaryArtifactRemapper = new KotlinScriptBinaryArtifactRemapper(it.file.name, binary.mainClassName) - def artifacts = binary.artifacts.collect { binaryArtifactRemapper.remapToPackage(it, packageName) } - - artifacts.each { - def artifactOutput = outputsDir.toPath().resolve(it.relativePath) - - Files.createDirectories(artifactOutput.getParent()) - Files.write(artifactOutput, it.data, - StandardOpenOption.CREATE, - StandardOpenOption.WRITE, - StandardOpenOption.TRUNCATE_EXISTING - ) - } - } - - inputs.removed { - removeBinariesFor(it.file) - } - } - - def removeBinariesFor(File file) { - def normalizedFilename = file.name.replace("[^A-Z_]", "_") - def normalizedPrefix = normalizedFilename.subSequence(0, normalizedFilename.lastIndexOf('.')) - - FileFilter filter = { - return it.name.startsWith(normalizedPrefix) - } - - def binaries = outputsDir.listFiles(filter) - binaries.each { - it.delete() - } - } -} diff --git a/game/build.gradle b/game/build.gradle index eae4f98ff..cd8d5f70a 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -33,7 +33,7 @@ dependencies { compile group: 'io.github.lukehutch', name: 'fast-classpath-scanner', version: '2.0.21' compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" - compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion" + compile group: 'org.jetbrains.kotlin', name: 'kotlin-script-runtime', version: "$kotlinVersion" compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-jdk8', version: '0.16' compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '0.16' diff --git a/game/plugin/bank/build.gradle b/game/plugin/bank/build.gradle index ba8a32fae..a8166f04e 100644 --- a/game/plugin/bank/build.gradle +++ b/game/plugin/bank/build.gradle @@ -1,6 +1,5 @@ plugin { name = "banking" - packageName = "org.apollo.game.plugin.banking" authors = [ "Major", ] diff --git a/game/plugin/cmd/build.gradle b/game/plugin/cmd/build.gradle index d7520c630..de1e006f8 100644 --- a/game/plugin/cmd/build.gradle +++ b/game/plugin/cmd/build.gradle @@ -1,6 +1,5 @@ plugin { name = "chat_commands" - packageName = "org.apollo.game.plugin.cmd" authors = [ "Graham", "Major", diff --git a/game/plugin/consumables/build.gradle b/game/plugin/consumables/build.gradle index 97834d7fc..6f5139fa3 100644 --- a/game/plugin/consumables/build.gradle +++ b/game/plugin/consumables/build.gradle @@ -1,6 +1,5 @@ plugin { name = "consumables" - packageName = "org.apollo.game.plugin.consumables" authors = [ "Gary Tierney", ] diff --git a/game/plugin/dummy/build.gradle b/game/plugin/dummy/build.gradle index 23142dcad..46f8224a3 100644 --- a/game/plugin/dummy/build.gradle +++ b/game/plugin/dummy/build.gradle @@ -1,6 +1,5 @@ plugin { name = "training_dummy" - packageName = "org.apollo.game.plugin.entity" authors = [ "Gary Tierney", ] diff --git a/game/plugin/emote-tab/build.gradle b/game/plugin/emote-tab/build.gradle index d54c23e57..04160d86f 100644 --- a/game/plugin/emote-tab/build.gradle +++ b/game/plugin/emote-tab/build.gradle @@ -1,6 +1,5 @@ plugin { name = "emote_tab" - packageName = "org.apollo.game.plugin.widget" authors = [ "Gary Tierney", ] diff --git a/game/plugin/entity/following/build.gradle b/game/plugin/entity/following/build.gradle index da73a832f..7ebc73f9c 100644 --- a/game/plugin/entity/following/build.gradle +++ b/game/plugin/entity/following/build.gradle @@ -1,6 +1,5 @@ plugin { name = "following" - packageName = "org.apollo.game.plugin.entity" authors = [ "Gary Tierney", ] diff --git a/game/plugin/entity/player-action/build.gradle b/game/plugin/entity/player-action/build.gradle index 264d895f3..43f394f3e 100644 --- a/game/plugin/entity/player-action/build.gradle +++ b/game/plugin/entity/player-action/build.gradle @@ -1,6 +1,5 @@ plugin { name = "player_action" - packageName = "org.apollo.game.plugin.entity" authors = [ "Gary Tierney", ] diff --git a/game/plugin/entity/spawn/build.gradle b/game/plugin/entity/spawn/build.gradle index e417db46d..adc0d4668 100644 --- a/game/plugin/entity/spawn/build.gradle +++ b/game/plugin/entity/spawn/build.gradle @@ -1,6 +1,5 @@ plugin { name = "spawning" - packageName = "org.apollo.game.plugin.entity" authors = [ "Gary Tierney", ] diff --git a/game/plugin/entity/walk-to/build.gradle b/game/plugin/entity/walk-to/build.gradle index 4f14b86f0..13ca8949f 100644 --- a/game/plugin/entity/walk-to/build.gradle +++ b/game/plugin/entity/walk-to/build.gradle @@ -1,6 +1,5 @@ plugin { name = "walkto" - packageName = "org.apollo.plugin.entity.walkto" authors = [ "Gary Tierney", ] diff --git a/game/plugin/locations/al-kharid/build.gradle b/game/plugin/locations/al-kharid/build.gradle index 8eb8ee02b..a587f4fee 100644 --- a/game/plugin/locations/al-kharid/build.gradle +++ b/game/plugin/locations/al-kharid/build.gradle @@ -1,6 +1,5 @@ plugin { name = "al_kharid_npc_spawns" - packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] diff --git a/game/plugin/locations/edgeville/build.gradle b/game/plugin/locations/edgeville/build.gradle index 663066a87..6c9023e3d 100644 --- a/game/plugin/locations/edgeville/build.gradle +++ b/game/plugin/locations/edgeville/build.gradle @@ -1,6 +1,5 @@ plugin { name = "edgeville_npc_spawns" - packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] diff --git a/game/plugin/locations/falador/build.gradle b/game/plugin/locations/falador/build.gradle index ffff3f044..c599f40ca 100644 --- a/game/plugin/locations/falador/build.gradle +++ b/game/plugin/locations/falador/build.gradle @@ -1,6 +1,5 @@ plugin { name = "falador_npc_spawns" - packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] diff --git a/game/plugin/locations/lumbridge/build.gradle b/game/plugin/locations/lumbridge/build.gradle index a85c254ad..60f39625d 100644 --- a/game/plugin/locations/lumbridge/build.gradle +++ b/game/plugin/locations/lumbridge/build.gradle @@ -1,6 +1,5 @@ plugin { name = "lumbridge_npc_spawns" - packageName = "org.apollo.game.plugin.locations" authors = [ "Gary Tierney", ] diff --git a/game/plugin/locations/tutorial-island/build.gradle b/game/plugin/locations/tutorial-island/build.gradle index 44c5e1a51..60631802e 100644 --- a/game/plugin/locations/tutorial-island/build.gradle +++ b/game/plugin/locations/tutorial-island/build.gradle @@ -1,6 +1,5 @@ plugin { name = "tutorial_island_npc_spawns" - packageName = "org.apollo.game.plugin.locations" authors = [ "Jesse W", ] diff --git a/game/plugin/locations/varrock/build.gradle b/game/plugin/locations/varrock/build.gradle index 1443d085b..f094b1bc2 100644 --- a/game/plugin/locations/varrock/build.gradle +++ b/game/plugin/locations/varrock/build.gradle @@ -1,6 +1,5 @@ plugin { name = "varrock" - packageName = "org.apollo.game.plugin.locations.varrock" authors = [ "Jesse W", "Major", diff --git a/game/plugin/navigation/door/build.gradle b/game/plugin/navigation/door/build.gradle index 2d62d81fa..8ac642154 100644 --- a/game/plugin/navigation/door/build.gradle +++ b/game/plugin/navigation/door/build.gradle @@ -1,7 +1,6 @@ plugin { name = "door" - packageName = "org.apollo.game.plugin.navigation.door" - dependencies = ["api"] + dependencies = ["api"] authors = [ "Shiver", "Arin" diff --git a/game/plugin/shops/build.gradle b/game/plugin/shops/build.gradle index 1147de622..2532af029 100644 --- a/game/plugin/shops/build.gradle +++ b/game/plugin/shops/build.gradle @@ -1,6 +1,5 @@ plugin { name = "shops" - packageName = "org.apollo.game.plugin.shops" authors = [ "Stuart", "Major", diff --git a/game/plugin/shops/src/dsl.kt b/game/plugin/shops/src/dsl.kt index 71365f665..7aba837bf 100644 --- a/game/plugin/shops/src/dsl.kt +++ b/game/plugin/shops/src/dsl.kt @@ -4,7 +4,6 @@ import org.apollo.cache.def.NpcDefinition import org.apollo.game.plugin.shops.CategoryWrapper.Affix import org.apollo.game.plugin.util.lookup.lookup_item import org.apollo.game.plugin.util.lookup.lookup_npc -import org.jetbrains.kotlin.utils.keysToMap /** * Creates a [Shop]. @@ -16,7 +15,7 @@ fun shop(name: String, builder: ShopBuilder.() -> Unit) { builder(shop) val built = shop.build() - val operators = shop.operators().keysToMap { built } + val operators = shop.operators().map { it to built }.toMap() SHOPS.putAll(operators) } diff --git a/game/plugin/skills/fishing/build.gradle b/game/plugin/skills/fishing/build.gradle index 4e13f4397..6f870b9df 100644 --- a/game/plugin/skills/fishing/build.gradle +++ b/game/plugin/skills/fishing/build.gradle @@ -1,6 +1,5 @@ plugin { name = "fishing_skill" - packageName = "org.apollo.game.plugin.skills.fishing" authors = [ "Linux", "Major", diff --git a/game/plugin/skills/mining/build.gradle b/game/plugin/skills/mining/build.gradle index 00a165376..c301b2161 100644 --- a/game/plugin/skills/mining/build.gradle +++ b/game/plugin/skills/mining/build.gradle @@ -1,6 +1,5 @@ plugin { name = "mining-skill" - packageName = "org.apollo.game.plugin.skills.mining" authors = [ "Graham", "Mikey`", diff --git a/game/plugin/skills/runecrafting/build.gradle b/game/plugin/skills/runecrafting/build.gradle index 595add781..123631a8d 100644 --- a/game/plugin/skills/runecrafting/build.gradle +++ b/game/plugin/skills/runecrafting/build.gradle @@ -1,6 +1,5 @@ plugin { name = "runecrafting-skill" - packageName = "org.apollo.game.plugin.skills.runecrafting" authors = [ "Major", "BugCrusher", diff --git a/game/plugin/skills/woodcutting/build.gradle b/game/plugin/skills/woodcutting/build.gradle index 0c154fb3f..0da7a40d9 100644 --- a/game/plugin/skills/woodcutting/build.gradle +++ b/game/plugin/skills/woodcutting/build.gradle @@ -1,6 +1,5 @@ plugin { name = "woodcutting_skill" - packageName = "org.apollo.game.plugin.skills.woodcutting" authors = [ "tlf30" ] diff --git a/game/plugin/util/command/build.gradle b/game/plugin/util/command/build.gradle index 58e59401e..3648da32f 100644 --- a/game/plugin/util/command/build.gradle +++ b/game/plugin/util/command/build.gradle @@ -1,4 +1,3 @@ plugin { name = "command_utilities" - packageName = "org.apollo.game.plugins.util" -} \ No newline at end of file + } \ No newline at end of file diff --git a/game/plugin/util/lookup/build.gradle b/game/plugin/util/lookup/build.gradle index e910e2fad..6c225ddfa 100644 --- a/game/plugin/util/lookup/build.gradle +++ b/game/plugin/util/lookup/build.gradle @@ -1,4 +1,3 @@ plugin { name = "entity_lookup" - packageName = "org.apollo.game.plugins.util" -} \ No newline at end of file + } \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java index 853326aa6..cc187cb18 100644 --- a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -1,29 +1,14 @@ package org.apollo.game.plugin; -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; +import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; +import org.apollo.game.model.World; +import org.apollo.game.plugin.kotlin.KotlinPluginScript; + import java.lang.reflect.Constructor; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; - -import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; -import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult; -import org.apollo.game.model.World; -import org.apollo.game.plugin.kotlin.KotlinPluginScript; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.kotlin.cli.common.messages.MessageCollector; public class KotlinPluginEnvironment implements PluginEnvironment { diff --git a/properties.gradle b/properties.gradle index e19e24a28..d44cfccfa 100644 --- a/properties.gradle +++ b/properties.gradle @@ -1,3 +1,3 @@ ext { - kotlinVersion = '1.1.4-3' + kotlinVersion = '1.2.31' } \ No newline at end of file From 179c35fc2dfef71ebff0150a7088cedb3fe4968a Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 27 Mar 2018 21:31:22 +0100 Subject: [PATCH 086/209] Add IntelliJ kotlinc configuration This removes the need for the plugin stub. --- .idea/kotlinc.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .idea/kotlinc.xml diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 000000000..7825b132c --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file From 5d77ed5e4b31b1f5ff0f7c6be9dba879d93eaa7e Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 27 Mar 2018 21:49:22 +0100 Subject: [PATCH 087/209] Remove plugin script stub --- game/build.gradle | 8 -------- game/src/main/kotlin/stub.kt | 28 ---------------------------- 2 files changed, 36 deletions(-) delete mode 100644 game/src/main/kotlin/stub.kt diff --git a/game/build.gradle b/game/build.gradle index cd8d5f70a..52b8ba6f0 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -12,14 +12,6 @@ buildscript { apply plugin: 'kotlin' -sourceSets { - main { - kotlin { - exclude 'stub.kt' - } - } -} - allprojects { it.plugins.withId('kotlin') { kotlin { experimental { coroutines 'enable' } } diff --git a/game/src/main/kotlin/stub.kt b/game/src/main/kotlin/stub.kt deleted file mode 100644 index 0f49676b1..000000000 --- a/game/src/main/kotlin/stub.kt +++ /dev/null @@ -1,28 +0,0 @@ -/** - * NOTE: This file is a stub, intended only for use within an IDE. It should be updated - * each time [org.apollo.game.plugin.kotlin.KotlinPluginScript] has a new method added to it. - * - * Until IntelliJ IDEA starts to support ScriptTemplateDefinitions this is - * required to resolve references within plugin code. - */ - -import org.apollo.game.command.Command -import org.apollo.game.message.impl.ButtonMessage -import org.apollo.game.model.World -import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.model.event.Event -import org.apollo.game.model.event.PlayerEvent -import org.apollo.game.plugin.kotlin.KotlinEventHandler -import org.apollo.game.plugin.kotlin.KotlinPlayerHandlerProxyTrait -import org.apollo.net.message.Message -import kotlin.reflect.KClass - -fun on(type: () -> KClass): KotlinPlayerHandlerProxyTrait = null!! -fun on_player_event(type: () -> KClass): KotlinPlayerHandlerProxyTrait = null!! -fun on_event(type: () -> KClass): KotlinEventHandler = null!! -fun on_command(command: String, privileges: PrivilegeLevel): KotlinPlayerHandlerProxyTrait = null!! -fun on_button(button: Int): KotlinPlayerHandlerProxyTrait = null!! - -fun start(callback: (World) -> Unit) {} -fun stop(callback: (World) -> Unit) = {} - From b2f48815bfe028fd86161b44ab3aab11d16dd4a2 Mon Sep 17 00:00:00 2001 From: Major Date: Tue, 27 Mar 2018 20:06:35 +0100 Subject: [PATCH 088/209] Fix nitpicks in Fishing plugin --- game/plugin/skills/fishing/build.gradle | 4 +- game/plugin/skills/fishing/src/fishing.kt | 104 ++++++++---------- .../skills/fishing/src/fishing.plugin.kts | 99 ++++++++--------- game/plugin/skills/fishing/src/spots.kts | 1 - 4 files changed, 97 insertions(+), 111 deletions(-) diff --git a/game/plugin/skills/fishing/build.gradle b/game/plugin/skills/fishing/build.gradle index 6f870b9df..a7c3c5df2 100644 --- a/game/plugin/skills/fishing/build.gradle +++ b/game/plugin/skills/fishing/build.gradle @@ -6,6 +6,8 @@ plugin { "tlf30" ] dependencies = [ - "util:lookup", "entity:spawn", "api" + "api", + "entity:spawn", + "util:lookup" ] } diff --git a/game/plugin/skills/fishing/src/fishing.kt b/game/plugin/skills/fishing/src/fishing.kt index e045a445b..b59949357 100644 --- a/game/plugin/skills/fishing/src/fishing.kt +++ b/game/plugin/skills/fishing/src/fishing.kt @@ -1,50 +1,54 @@ package org.apollo.game.plugin.skills.fishing -import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.Animation +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.skills.fishing.Fish.* import org.apollo.game.plugin.skills.fishing.FishingTool.* -import java.util.Random /** * A fish that can be gathered using the fishing skill. */ enum class Fish(val id: Int, val level: Int, val experience: Double) { - SHRIMP(317, 1, 10.0), - SARDINE(327, 5, 20.0), - MACKEREL(353, 16, 20.0), - HERRING(345, 10, 30.0), - ANCHOVY(321, 15, 40.0), - TROUT(335, 20, 50.0), - COD(341, 23, 45.0), - PIKE(349, 25, 60.0), - SALMON(331, 30, 70.0), - TUNA(359, 35, 80.0), - LOBSTER(377, 40, 90.0), - BASS(363, 46, 100.0), - SWORDFISH(371, 50, 100.0), - SHARK(383, 76, 110.0); + SHRIMP(id = 317, level = 1, experience = 10.0), + SARDINE(id = 327, level = 5, experience = 20.0), + MACKEREL(id = 353, level = 16, experience = 20.0), + HERRING(id = 345, level = 10, experience = 30.0), + ANCHOVY(id = 321, level = 15, experience = 40.0), + TROUT(id = 335, level = 20, experience = 50.0), + COD(id = 341, level = 23, experience = 45.0), + PIKE(id = 349, level = 25, experience = 60.0), + SALMON(id = 331, level = 30, experience = 70.0), + TUNA(id = 359, level = 35, experience = 80.0), + LOBSTER(id = 377, level = 40, experience = 90.0), + BASS(id = 363, level = 46, experience = 100.0), + SWORDFISH(id = 371, level = 50, experience = 100.0), + SHARK(id = 383, level = 76, experience = 110.0); /** * The name of this fish, formatted so it can be inserted into a message. */ - val formattedName = ItemDefinition.lookup(id).name.toLowerCase() + val formattedName = Definitions.item(id)!!.name.toLowerCase() + // TODO this leads to incorrect messages, e.g. 'You catch a raw shrimps'. } /** * A tool used to gather [Fish] from a [FishingSpot]. */ -enum class FishingTool(val id: Int, animation: Int, val message: String, val bait: Int, val baitName: String?) { - LOBSTER_CAGE(301, 619, "You attempt to catch a lobster..."), - SMALL_NET(303, 620, "You cast out your net..."), - BIG_NET(305, 620, "You cast out your net..."), - HARPOON(311, 618, "You start harpooning fish..."), - FISHING_ROD(307, 622, "You attempt to catch a fish...", 313, "feathers"), - FLY_FISHING_ROD(309, 622, "You attempt to catch a fish...", 314, "fishing bait"); - - @Suppress("unused") // IntelliJ bug, doesn't detect that this constructor is used - constructor(id: Int, animation: Int, message: String) : this(id, animation, message, -1, null) +enum class FishingTool( + val message: String, + val id: Int, + animation: Int, + val bait: Int = -1, + val baitName: String? = null +) { + LOBSTER_CAGE("You attempt to catch a lobster...", id = 301, animation = 619), + SMALL_NET("You cast out your net...", id = 303, animation = 620), + BIG_NET("You cast out your net...", id = 305, animation = 620), + HARPOON("You start harpooning fish...", id = 311, animation = 618), + FISHING_ROD("You attempt to catch a fish...", id = 307, animation = 622, bait = 313, baitName = "feathers"), + FLY_FISHING_ROD("You attempt to catch a fish...", id = 309, animation = 622, bait = 314, baitName = "fishing bait"); /** * The [Animation] played when fishing with this tool. @@ -54,7 +58,7 @@ enum class FishingTool(val id: Int, animation: Int, val message: String, val bai /** * The name of this tool, formatted so it can be inserted into a message. */ - val formattedName = ItemDefinition.lookup(id).name.toLowerCase() + val formattedName = Definitions.item(id)!!.name.toLowerCase() } @@ -68,14 +72,12 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco NET_ROD(316, Option.of(SMALL_NET, SHRIMP, ANCHOVY), Option.of(FISHING_ROD, SARDINE, HERRING)); companion object { - private val FISHING_SPOTS = FishingSpot.values().associateBy({ it.npc }, { it }) /** * Returns the [FishingSpot] with the specified [id], or `null` if the spot does not exist. */ fun lookup(id: Int): FishingSpot? = FISHING_SPOTS[id] - } /** @@ -94,19 +96,6 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco */ sealed class Option { - companion object { - - fun of(tool: FishingTool, primary: Fish): Option = Single(tool, primary) - - fun of(tool: FishingTool, primary: Fish, secondary: Fish): Option { - return when { - primary.level < secondary.level -> Pair(tool, primary, secondary) - else -> Pair(tool, secondary, primary) - } - } - - } - /** * The tool used to obtain fish */ @@ -131,35 +120,38 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco override val level = primary.level override fun sample(level: Int): Fish = primary - } /** * A [FishingSpot] [Option] that can provide a two different types of fish. */ private data class Pair(override val tool: FishingTool, val primary: Fish, val secondary: Fish) : Option() { + override val level = Math.min(primary.level, secondary.level) - companion object { - - val random = Random() + override fun sample(level: Int): Fish { + return if (level < secondary.level || rand(100) < WEIGHTING) { + primary + } else { + secondary + } + } + private companion object { /** * The weighting factor that causes the lower-level fish to be returned more frequently. */ - const val WEIGHTING = 70 - + private const val WEIGHTING = 70 } + } - override val level = Math.min(primary.level, secondary.level) + companion object { - override fun sample(level: Int): Fish { - if (secondary.level > level) { - return primary - } + fun of(tool: FishingTool, primary: Fish): Option = Single(tool, primary) + fun of(tool: FishingTool, primary: Fish, secondary: Fish): Option { return when { - random.nextInt(100) < WEIGHTING -> primary - else -> secondary + primary.level < secondary.level -> Pair(tool, primary, secondary) + else -> Pair(tool, secondary, primary) } } diff --git a/game/plugin/skills/fishing/src/fishing.plugin.kts b/game/plugin/skills/fishing/src/fishing.plugin.kts index 56755edbb..a2138bd9e 100644 --- a/game/plugin/skills/fishing/src/fishing.plugin.kts +++ b/game/plugin/skills/fishing/src/fishing.plugin.kts @@ -6,44 +6,31 @@ import org.apollo.game.message.impl.NpcActionMessage import org.apollo.game.model.Position import org.apollo.game.model.entity.Player import org.apollo.game.plugin.api.fishing +import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.skills.fishing.FishingSpot import org.apollo.game.plugin.skills.fishing.FishingTool import java.util.Objects -import java.util.Random // TODO: moving fishing spots, seaweed and caskets, evil bob -class FishingAction(player: Player, position: Position, val option: FishingSpot.Option) : - AsyncDistancedAction(0, true, player, position, SPOT_DISTANCE) { - - companion object { - private const val SPOT_DISTANCE = 1 - private const val FISHING_DELAY = 4 - - /** - * The random number generator used by the fishing plugin. - */ - private val random = Random() - - /** - * Returns whether or not the catch was successful. - * TODO: We need to identify the correct algorithm for this - */ - private fun successfulCatch(level: Int, req: Int): Boolean = minOf(level - req + 5, 40) > random.nextInt(100) - - /** - * Returns whether or not the [Player] has (or does not need) bait. - */ - private fun hasBait(player: Player, bait: Int): Boolean = bait == -1 || player.inventory.contains(bait) +/** + * Intercepts the [NpcActionMessage] and starts a [FishingAction] if the npc + */ +on { NpcActionMessage::class } + .where { option == 1 || option == 3 } + .then { player -> + val entity = player.world.npcRepository[index] + val spot = FishingSpot.lookup(entity.id) ?: return@then - /** - * @return if the player has the needed tool to fish at the spot. - */ - private fun hasTool(player: Player, tool: FishingTool): Boolean = player.equipment.contains(tool.id) || - player.inventory.contains(tool.id) + val option = spot.option(option) + player.startAction(FishingAction(player, entity.position, option)) + terminate() } +class FishingAction(player: Player, position: Position, val option: FishingSpot.Option) : + AsyncDistancedAction(0, true, player, position, SPOT_DISTANCE) { + /** * The [FishingTool] used for the fishing spot. */ @@ -75,10 +62,12 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. if (mob.inventory.freeSlots() == 0) { mob.inventory.forceCapacityExceeded() + mob.stopAnimation() stop() } else if (!hasBait(mob, tool.bait)) { mob.sendMessage("You need more ${tool.baitName} to fish at this spot.") + mob.stopAnimation() stop() } @@ -90,21 +79,17 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. * Verifies that the player can gather fish from the [FishingSpot] they clicked. */ private fun verify(): Boolean { - if (mob.fishing.current < option.level) { - mob.sendMessage("You need a fishing level of ${option.level} to fish at this spot.") - return false - } else if (!hasTool(mob, tool)) { - mob.sendMessage("You need a ${tool.formattedName} to fish at this spot.") - return false - } else if (!hasBait(mob, tool.bait)) { - mob.sendMessage("You need some ${tool.baitName} to fish at this spot.") - return false - } else if (mob.inventory.freeSlots() == 0) { - mob.inventory.forceCapacityExceeded() - return false + val current = mob.fishing.current + + when { + current < option.level -> mob.sendMessage("You need a fishing level of ${option.level} to fish at this spot.") + !hasTool(mob, tool) -> mob.sendMessage("You need a ${tool.formattedName} to fish at this spot.") + !hasBait(mob, tool.bait) -> mob.sendMessage("You need some ${tool.baitName} to fish at this spot.") + mob.inventory.freeSlots() == 0 -> mob.inventory.forceCapacityExceeded() + else -> return true } - return true + return false } override fun equals(other: Any?): Boolean { @@ -117,19 +102,27 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. override fun hashCode(): Int = Objects.hash(option, position, mob) -} + private companion object { + private const val SPOT_DISTANCE = 1 + private const val FISHING_DELAY = 4 -/** - * Intercepts the [NpcActionMessage] and starts a [FishingAction] if the npc - */ -on { NpcActionMessage::class } - .where { option == 1 || option == 3 } - .then { - val entity = it.world.npcRepository[index] - val spot = FishingSpot.lookup(entity.id) ?: return@then + /** + * Returns whether or not the catch was successful. + * TODO: We need to identify the correct algorithm for this + */ + private fun successfulCatch(level: Int, req: Int): Boolean = minOf(level - req + 5, 40) > rand(100) - val option = spot.option(option) - it.startAction(FishingAction(it, entity.position, option)) + /** + * Returns whether or not the [Player] has (or does not need) bait. + */ + private fun hasBait(player: Player, bait: Int): Boolean = bait == -1 || player.inventory.contains(bait) + + /** + * Returns whether or not the player has the required tool to fish at the spot. + */ + private fun hasTool(player: Player, tool: FishingTool): Boolean = player.equipment.contains(tool.id) || + player.inventory.contains(tool.id) - terminate() } + +} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/spots.kts b/game/plugin/skills/fishing/src/spots.kts index 46001275b..014c5d131 100644 --- a/game/plugin/skills/fishing/src/spots.kts +++ b/game/plugin/skills/fishing/src/spots.kts @@ -163,7 +163,6 @@ register(NET_ROD, x = 2990, y = 3169) register(NET_ROD, x = 2986, y = 3176) // Shilo Village - register(ROD, x = 2855, y = 2974) register(ROD, x = 2865, y = 2972) register(ROD, x = 2860, y = 2972) From 45a0b43eee995d6050271f857e3a9524db468cef Mon Sep 17 00:00:00 2001 From: Major Date: Tue, 27 Mar 2018 20:07:31 +0100 Subject: [PATCH 089/209] Remove incorrect Gunnarsgrunn fishing spots The spots are actually on Tutorial Island and result in two fishing spots stacked on top of each other. --- game/plugin/skills/fishing/src/spots.kts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/game/plugin/skills/fishing/src/spots.kts b/game/plugin/skills/fishing/src/spots.kts index 014c5d131..b86b6e8f0 100644 --- a/game/plugin/skills/fishing/src/spots.kts +++ b/game/plugin/skills/fishing/src/spots.kts @@ -125,10 +125,6 @@ register(ROD, x = 2385, y = 3422) register(ROD, x = 2384, y = 3419) register(ROD, x = 2383, y = 3417) -// Gunnarsgrunn -register(ROD, x = 3101, y = 3092) -register(ROD, x = 3103, y = 3092) - // Karamja register(NET_ROD, x = 2921, y = 3178) register(CAGE_HARPOON, x = 2923, y = 3179) From 173623b76b15f6e3f5b24a71bb3ef7fd14f3f90b Mon Sep 17 00:00:00 2001 From: Major Date: Wed, 28 Mar 2018 01:21:12 +0100 Subject: [PATCH 090/209] Fix nitpicks in Woodcutting plugin --- game/plugin/skills/woodcutting/src/axe.kt | 35 ++++--- game/plugin/skills/woodcutting/src/wood.kt | 97 +++++++------------ .../woodcutting/src/woodcutting.plugin.kts | 48 ++++----- 3 files changed, 74 insertions(+), 106 deletions(-) diff --git a/game/plugin/skills/woodcutting/src/axe.kt b/game/plugin/skills/woodcutting/src/axe.kt index d7d23e818..ab51ec0da 100644 --- a/game/plugin/skills/woodcutting/src/axe.kt +++ b/game/plugin/skills/woodcutting/src/axe.kt @@ -1,23 +1,28 @@ package org.apollo.game.plugin.skills.woodcutting -import org.apollo.game.model.Animation; +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.woodcutting -//Animation IDs thanks to Deadly A G S at rune-server.ee -enum class Axe(val id: Int, val level: Int, val animation: Animation, val pulses: Int) { - RUNE(1359, 41, Animation(867), 3), - ADAMANT(1357, 31, Animation(869), 4), - MITHRIL(1355, 21, Animation(871), 5), - BLACK(1361, 11, Animation(873), 6), - STEEL(1353, 6, Animation(875), 6), - IRON(1349, 1, Animation(877), 7), - BRONZE(1351, 1, Animation(879), 8); +enum class Axe(val id: Int, val level: Int, animation: Int, val pulses: Int) { + BRONZE(id = 1351, level = 1, animation = 879, pulses = 8), + IRON(id = 1349, level = 1, animation = 877, pulses = 7), + STEEL(id = 1353, level = 6, animation = 875, pulses = 6), + BLACK(id = 1361, level = 11, animation = 873, pulses = 6), + MITHRIL(id = 1355, level = 21, animation = 871, pulses = 5), + ADAMANT(id = 1357, level = 31, animation = 869, pulses = 4), + RUNE(id = 1359, level = 41, animation = 867, pulses = 3); + + val animation = Animation(animation) companion object { - private val AXES = Axe.values() - fun getAxes(): Array { - return AXES + private val AXES = Axe.values().sortedByDescending { it.level } + + fun bestFor(player: Player): Axe? { + return AXES.asSequence() + .filter { it.level <= player.woodcutting.current } + .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } + .firstOrNull() } } } - - diff --git a/game/plugin/skills/woodcutting/src/wood.kt b/game/plugin/skills/woodcutting/src/wood.kt index 71c910ad6..51a274a0e 100644 --- a/game/plugin/skills/woodcutting/src/wood.kt +++ b/game/plugin/skills/woodcutting/src/wood.kt @@ -1,67 +1,27 @@ package org.apollo.game.plugin.skills.woodcutting -private val NORMAL_STUMP = 1342 -private val ACHEY_STUMP = 3371 -private val OAK_STUMP = 1342 -private val WILLOW_STUMP = 1342 -private val TEAK_STUMP = 1342 -private val MAPLE_STUMP = 1342 -private val MAHOGANY_STUMP = 1342 -private val YEW_STUMP = 1342 -private val MAGIC_STUMP = 1324 - -private val NORMAL_OBJECTS = hashSetOf( - 1276, 1277, 1278, 1279, 1280, 1282, 1283, 1284, 1285, 1285, 1286, 1289, 1290, 1291, 1315, - 1316, 1318, 1330, 1331, 1332, 1365, 1383, 1384, 2409, 3033, 3034, 3035, 3036, 3881, 3882, - 3883, 5902, 5903, 5904, 10041 -) - -private val ACHEY_OBJECTS = hashSetOf( - 2023 -) - -private val OAK_OBJECTS = hashSetOf( - 1281, 3037 -) - -private val WILLOW_OBJECTS = hashSetOf( - 5551, 5552, 5553 -) - -private val TEAK_OBJECTS = hashSetOf( - 9036 -) - - -private val MAPLE_OBJECTS = hashSetOf( - 1307, 4674 -) - -private val MAHOGANY_OBJECTS = hashSetOf( - 9034 -) - -private val YEW_OBJECTS = hashSetOf( - 1309 -) - -private val MAGIC_OBJECTS = hashSetOf( - 1292, 1306 -) - -/** - * values thanks to: http://oldschoolrunescape.wikia.com/wiki/Woodcutting +/* + * Values thanks to: http://oldschoolrunescape.wikia.com/wiki/Woodcutting + * https://twitter.com/JagexKieren/status/713409506273787904 */ -enum class Tree(val id: Int, val objects: HashSet, val stump: Int, val level: Int, val exp: Double, val chance: Double) { - NORMAL(1511, NORMAL_OBJECTS, NORMAL_STUMP, 1, 25.0, 100.0), - ACHEY(2862, ACHEY_OBJECTS, ACHEY_STUMP, 1, 25.0, 100.0), - OAK(1521, OAK_OBJECTS, OAK_STUMP, 15, 37.5, 0.125), - WILLOW(1519, WILLOW_OBJECTS, WILLOW_STUMP, 30, 67.5, 0.125), - TEAK(6333, TEAK_OBJECTS, TEAK_STUMP, 35, 85.0, 0.125), - MAPLE(1517, MAPLE_OBJECTS, MAPLE_STUMP, 45, 100.0, 0.125), - MAHOGANY(6332, MAHOGANY_OBJECTS, MAHOGANY_STUMP, 50, 125.0, 0.125), - YEW(1515, YEW_OBJECTS, YEW_STUMP, 60, 175.0, 0.125), - MAGIC(1513, MAGIC_OBJECTS, MAGIC_STUMP, 75, 250.0, 0.125); + +enum class Tree( + val objects: Set, + val id: Int, + val stump: Int, + val level: Int, + val exp: Double, + val chance: Double +) { + NORMAL(NORMAL_OBJECTS, id = 1511, stump = 1342, level = 1, exp = 25.0, chance = 100.0), + ACHEY(ACHEY_OBJECTS, id = 2862, stump = 3371, level = 1, exp = 25.0, chance = 100.0), + OAK(OAK_OBJECTS, id = 1521, stump = 1342, level = 15, exp = 37.5, chance = 12.5), + WILLOW(WILLOW_OBJECTS, id = 1519, stump = 1342, level = 30, exp = 67.5, chance = 12.5), + TEAK(TEAK_OBJECTS, id = 6333, stump = 1342, level = 35, exp = 85.0, chance = 12.5), + MAPLE(MAPLE_OBJECTS, id = 1517, stump = 1342, level = 45, exp = 100.0, chance = 12.5), + MAHOGANY(MAHOGANY_OBJECTS, id = 6332, stump = 1342, level = 50, exp = 125.0, chance = 12.5), + YEW(YEW_OBJECTS, id = 1515, stump = 1342, level = 60, exp = 175.0, chance = 12.5), + MAGIC(MAGIC_OBJECTS, id = 1513, stump = 1324, level = 75, exp = 250.0, chance = 12.5); companion object { private val TREES = Tree.values().flatMap { tree -> tree.objects.map { Pair(it, tree) } }.toMap() @@ -69,4 +29,17 @@ enum class Tree(val id: Int, val objects: HashSet, val stump: Int, val leve } } - +private val NORMAL_OBJECTS = hashSetOf( + 1276, 1277, 1278, 1279, 1280, 1282, 1283, 1284, 1285, 1285, 1286, 1289, 1290, 1291, 1315, + 1316, 1318, 1330, 1331, 1332, 1365, 1383, 1384, 2409, 3033, 3034, 3035, 3036, 3881, 3882, + 3883, 5902, 5903, 5904, 10041 +) + +private val ACHEY_OBJECTS = hashSetOf(2023) +private val OAK_OBJECTS = hashSetOf(1281, 3037) +private val WILLOW_OBJECTS = hashSetOf(5551, 5552, 5553) +private val TEAK_OBJECTS = hashSetOf(9036) +private val MAPLE_OBJECTS = hashSetOf(1307, 4674) +private val MAHOGANY_OBJECTS = hashSetOf(9034) +private val YEW_OBJECTS = hashSetOf(1309) +private val MAGIC_OBJECTS = hashSetOf(1292, 1306) \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index ca20a248f..9d3de2aec 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -1,3 +1,4 @@ + import org.apollo.game.GameConstants import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction @@ -13,17 +14,24 @@ import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.api.woodcutting import org.apollo.game.plugin.skills.woodcutting.Axe import org.apollo.game.plugin.skills.woodcutting.Tree -import java.util.Optional import java.util.concurrent.TimeUnit +// TODO Accurate chopping rates, e.g. https://twitter.com/JagexKieren/status/713403124464107520 + +on { ObjectActionMessage::class } + .where { option == 1 } + .then { player -> + Tree.lookup(id)?.let { WoodcuttingAction.start(this, player, it) } + } + class WoodcuttingTarget(private val objectId: Int, val position: Position, val tree: Tree) { /** * Get the tree object in the world */ - fun getObject(world: World): Optional { + fun getObject(world: World): GameObject? { val region = world.regionRepository.fromPosition(position) - return region.findObject(position, objectId) + return region.findObject(position, objectId).orElse(null) } /** @@ -44,23 +52,12 @@ class WoodcuttingAction( private const val TREE_SIZE = 2 private const val MINIMUM_RESPAWN_TIME = 30L // In seconds - /** - * Find the highest level axe the player has - */ - private fun axeFor(player: Player): Axe? { - return Axe.getAxes() - .filter { it.level <= player.woodcutting.current } - .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } - .sortedByDescending { it.level } - .firstOrNull() - } - /** * Starts a [WoodcuttingAction] for the specified [Player], terminating the [ObjectActionMessage] that triggered * it. */ fun start(message: ObjectActionMessage, player: Player, wood: Tree) { - val axe = axeFor(player) + val axe = Axe.bestFor(player) if (axe != null) { if (player.inventory.freeSlots() == 0) { player.inventory.forceCapacityExceeded() @@ -92,33 +89,26 @@ class WoodcuttingAction( wait(tool.pulses) - //Check that the object exists in the world + // Check that the object exists in the world val obj = target.getObject(mob.world) - if (!obj.isPresent) { + if (obj == null) { stop() } if (mob.inventory.add(target.tree.id)) { - val logName = Definitions.item(target.tree.id)?.name?.toLowerCase() + val logName = Definitions.item(target.tree.id)!!.name.toLowerCase() mob.sendMessage("You managed to cut some $logName.") mob.woodcutting.experience += target.tree.exp } if (target.isCutDown()) { - //respawn time: http://runescape.wikia.com/wiki/Trees + // respawn time: http://runescape.wikia.com/wiki/Trees val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY - mob.world.expireObject(obj.get(), target.tree.stump, respawn.toInt()) + + mob.world.expireObject(obj!!, target.tree.stump, respawn.toInt()) stop() } } } -} -on { ObjectActionMessage::class } - .where { option == 1 } - .then { - val tree = Tree.lookup(id) - if (tree != null) { - WoodcuttingAction.start(this, it, tree) - } - } +} \ No newline at end of file From 6941fc9de0056ebde22f765f6bc3613d2fade09d Mon Sep 17 00:00:00 2001 From: Major Date: Wed, 28 Mar 2018 16:50:43 +0100 Subject: [PATCH 091/209] Fix nitpicks in Mining plugin Also adds equals() and hashcode() implementations to the various Mining actions. --- game/plugin/skills/mining/build.gradle | 1 + game/plugin/skills/mining/src/gem.kt | 19 +- .../skills/mining/src/mining.plugin.kts | 134 ++++++---- game/plugin/skills/mining/src/ore.kt | 237 +++++++++--------- game/plugin/skills/mining/src/pickaxe.kt | 44 ++-- 5 files changed, 239 insertions(+), 196 deletions(-) diff --git a/game/plugin/skills/mining/build.gradle b/game/plugin/skills/mining/build.gradle index c301b2161..71bc90208 100644 --- a/game/plugin/skills/mining/build.gradle +++ b/game/plugin/skills/mining/build.gradle @@ -3,6 +3,7 @@ plugin { authors = [ "Graham", "Mikey`", + "Major", "WH:II:DOW", "Requa", "Clifton", diff --git a/game/plugin/skills/mining/src/gem.kt b/game/plugin/skills/mining/src/gem.kt index 6414bfe61..6f8fa2e72 100644 --- a/game/plugin/skills/mining/src/gem.kt +++ b/game/plugin/skills/mining/src/gem.kt @@ -1,12 +1,13 @@ package org.apollo.game.plugin.skills.mining -enum class Gem(val id: Int, val chance: Int) { - UNCUT_SAPPHIRE(1623, 0), - UNCUT_EMERALD(1605, 0), - UNCUT_RUBY(1619, 0), - UNCUT_DIAMOND(1617, 0) -} +enum class Gem(val id: Int) { // TODO add gem drop chances + UNCUT_SAPPHIRE(1623), + UNCUT_EMERALD(1605), + UNCUT_RUBY(1619), + UNCUT_DIAMOND(1617); -val GEMS = Gem.values() - -fun lookupGem(id: Int): Gem? = GEMS.find { it.id == id } + companion object { + private val GEMS = Gem.values().associateBy({ it.id }, { it }) + fun lookup(id: Int): Gem? = GEMS[id] + } +} \ No newline at end of file diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index c7d34db26..2c380f1ce 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -12,17 +12,33 @@ import org.apollo.game.plugin.api.findObject import org.apollo.game.plugin.api.mining import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.skills.mining.Ore -import org.apollo.game.plugin.skills.mining.PICKAXES import org.apollo.game.plugin.skills.mining.Pickaxe -import org.apollo.game.plugin.skills.mining.lookupOreRock import org.apollo.net.message.Message -import java.util.Optional +import java.util.Objects -class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { +on { ObjectActionMessage::class } + .where { option == Actions.MINING } + .then { player -> + Ore.fromRock(id)?.let { ore -> + MiningAction.start(this, player, ore) + } + } - fun getObject(world: World): Optional { +on { ObjectActionMessage::class } + .where { option == Actions.PROSPECTING } + .then { player -> + val ore = Ore.fromRock(id) + + if (ore != null) { + ProspectingAction.start(this, player, ore) + } + } + +data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { + + fun getObject(world: World): GameObject? { val region = world.regionRepository.fromPosition(position) - return region.findObject(position, objectId) + return region.findObject(position, objectId).orElse(null) } fun isSuccessful(mob: Player): Boolean { @@ -41,27 +57,22 @@ class MiningAction( ) : AsyncDistancedAction(PULSES, true, player, target.position, ORE_SIZE) { companion object { - private val PULSES = 0 - private val ORE_SIZE = 1 - - fun pickaxeFor(player: Player): Pickaxe? { - return PICKAXES - .filter { it.level <= player.mining.current } - .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } - .sortedByDescending { it.level } - .firstOrNull() - } + private const val PULSES = 0 + private const val ORE_SIZE = 1 /** * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. */ fun start(message: ObjectActionMessage, player: Player, ore: Ore) { - val pickaxe = pickaxeFor(player) - if (pickaxe != null) { - val action = MiningAction(player, pickaxe, MiningTarget(message.id, message.position, ore)) - player.startAction(action) - } else { + val pickaxe = Pickaxe.bestFor(player) + + if (pickaxe == null) { player.sendMessage("You do not have a pickaxe for which you have the level to use.") + } else { + val target = MiningTarget(message.id, message.position, ore) + val action = MiningAction(player, pickaxe, target) + + player.startAction(action) } message.terminate() @@ -83,7 +94,7 @@ class MiningAction( wait(tool.pulses) val obj = target.getObject(mob.world) - if (!obj.isPresent) { + if (obj == null) { stop() } @@ -94,25 +105,46 @@ class MiningAction( } if (mob.inventory.add(target.ore.id)) { - val oreName = Definitions.item(target.ore.id)?.name?.toLowerCase() + val oreName = Definitions.item(target.ore.id)!!.name.toLowerCase() mob.sendMessage("You manage to mine some $oreName") mob.mining.experience += target.ore.exp - mob.world.expireObject(obj.get(), target.ore.objects[target.objectId]!!, target.ore.respawn) + mob.world.expireObject(obj!!, target.ore.objects[target.objectId]!!, target.ore.respawn) stop() } } } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MiningAction + return mob == other.mob && target == other.target + } + + override fun hashCode(): Int = Objects.hash(mob, target) + } class ExpiredProspectingAction( mob: Player, position: Position -) : DistancedAction(PROSPECT_PULSES, true, mob, position, ORE_SIZE) { +) : DistancedAction(DELAY, true, mob, position, ORE_SIZE) { companion object { - private val PROSPECT_PULSES = 0 - private val ORE_SIZE = 1 + private const val DELAY = 0 + private const val ORE_SIZE = 1 + + /** + * Starts a [ExpiredProspectingAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player) { + val action = ExpiredProspectingAction(player, message.position) + player.startAction(action) + + message.terminate() + } } override fun executeAction() { @@ -120,17 +152,27 @@ class ExpiredProspectingAction( stop() } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ExpiredProspectingAction + return mob == other.mob && position == other.position + } + + override fun hashCode(): Int = Objects.hash(mob, position) + } class ProspectingAction( player: Player, position: Position, private val ore: Ore -) : AsyncDistancedAction(PROSPECT_PULSES, true, player, position, ORE_SIZE) { +) : AsyncDistancedAction(DELAY, true, player, position, ORE_SIZE) { companion object { - private val PROSPECT_PULSES = 3 - private val ORE_SIZE = 1 + private const val DELAY = 3 + private const val ORE_SIZE = 1 /** * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. @@ -141,7 +183,6 @@ class ProspectingAction( message.terminate() } - } override fun action(): ActionBlock = { @@ -151,27 +192,24 @@ class ProspectingAction( wait() val oreName = Definitions.item(ore.id)?.name?.toLowerCase() - mob.sendMessage("This rock contains $oreName") + mob.sendMessage("This rock contains $oreName.") stop() } -} + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false -on { ObjectActionMessage::class } - .where { option == 1 } - .then { - val ore = lookupOreRock(id) - if (ore != null) { - MiningAction.start(this, it, ore) - } + other as ProspectingAction + return mob == other.mob && position == other.position && ore == other.ore } -on { ObjectActionMessage::class } - .where { option == 2 } - .then { - val ore = lookupOreRock(id) - if (ore != null) { // TODO send expired action if rock is expired - ProspectingAction.start(this, it, ore) - } - } + override fun hashCode(): Int = Objects.hash(mob, position, ore) + +} + +private object Actions { + const val MINING = 1 + const val PROSPECTING = 2 +} \ No newline at end of file diff --git a/game/plugin/skills/mining/src/ore.kt b/game/plugin/skills/mining/src/ore.kt index 90001fdcc..e272b182c 100644 --- a/game/plugin/skills/mining/src/ore.kt +++ b/game/plugin/skills/mining/src/ore.kt @@ -1,155 +1,154 @@ package org.apollo.game.plugin.skills.mining -import com.google.common.collect.Maps.asMap - /* Thanks to Mikey` for helping to find some of the item/object IDs, minimum levels and experiences. Thanks to Clifton for helping to find some of the expired object IDs. */ +/** + * Chance values thanks to: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula + * Respawn times and xp thanks to: http://oldschoolrunescape.wikia.com/wiki/ + */ +enum class Ore( + val objects: Map, + val id: Int, + val level: Int, + val exp: Double, + val respawn: Int, + val chance: Double, + val chanceOffset: Boolean = false +) { + CLAY(CLAY_OBJECTS, id = 434, level = 1, exp = 5.0, respawn = 1, chance = 0.0085, chanceOffset = true), + COPPER(COPPER_OBJECTS, id = 436, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = true), + TIN(TIN_OBJECTS, id = 438, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = true), + IRON(IRON_OBJECTS, id = 440, level = 15, exp = 35.0, respawn = 9, chance = 0.0085, chanceOffset = true), + COAL(COAL_OBJECTS, id = 453, level = 30, exp = 50.0, respawn = 50, chance = 0.004), + GOLD(GOLD_OBJECTS, id = 444, level = 40, exp = 65.0, respawn = 100, chance = 0.003), + SILVER(SILVER_OBJECTS, id = 442, level = 20, exp = 40.0, respawn = 100, chance = 0.0085), + MITHRIL(MITHRIL_OBJECTS, id = 447, level = 55, exp = 80.0, respawn = 200, chance = 0.002), + ADAMANT(ADAMANT_OBJECTS, id = 449, level = 70, exp = 95.0, respawn = 800, chance = 0.001), + RUNITE(RUNITE_OBJECTS, id = 451, level = 85, exp = 125.0, respawn = 1_200, chance = 0.0008); + + companion object { + private val ORE_ROCKS = Ore.values().flatMap { ore -> ore.objects.map { Pair(it.key, ore) } }.toMap() + private val EXPIRED_ORE = Ore.values().flatMap { ore -> ore.objects.map { Pair(it.value, ore) } }.toMap() + + fun fromRock(id: Int): Ore? = ORE_ROCKS[id] + fun fromExpiredRock(id: Int): Ore? = EXPIRED_ORE[id] + + } +} + +// Maps from regular rock id to expired rock id. val CLAY_OBJECTS = mapOf( - 2108 to 450, - 2109 to 451, - 14904 to 14896, - 14905 to 14897 + 2108 to 450, + 2109 to 451, + 14904 to 14896, + 14905 to 14897 ) val COPPER_OBJECTS = mapOf( - 11960 to 11555, - 11961 to 11556, - 11962 to 11557, - 11936 to 11552, - 11937 to 11553, - 11938 to 11554, - 2090 to 450, - 2091 to 451, - 14906 to 14898, - 14907 to 14899, - 14856 to 14832, - 14857 to 14833, - 14858 to 14834 + 11960 to 11555, + 11961 to 11556, + 11962 to 11557, + 11936 to 11552, + 11937 to 11553, + 11938 to 11554, + 2090 to 450, + 2091 to 451, + 14906 to 14898, + 14907 to 14899, + 14856 to 14832, + 14857 to 14833, + 14858 to 14834 ) val TIN_OBJECTS = mapOf( - 11597 to 11555, - 11958 to 11556, - 11959 to 11557, - 11933 to 11552, - 11934 to 11553, - 11935 to 11554, - 2094 to 450, - 2095 to 451, - 14092 to 14894, - 14903 to 14895 + 11597 to 11555, + 11958 to 11556, + 11959 to 11557, + 11933 to 11552, + 11934 to 11553, + 11935 to 11554, + 2094 to 450, + 2095 to 451, + 14092 to 14894, + 14903 to 14895 ) val IRON_OBJECTS = mapOf( - 11954 to 11555, - 11955 to 11556, - 11956 to 11557, - 2092 to 450, - 2093 to 451, - 14900 to 14892, - 14901 to 14893, - 14913 to 14915, - 14914 to 14916 + 11954 to 11555, + 11955 to 11556, + 11956 to 11557, + 2092 to 450, + 2093 to 451, + 14900 to 14892, + 14901 to 14893, + 14913 to 14915, + 14914 to 14916 ) val COAL_OBJECTS = mapOf( - 11963 to 11555, - 11964 to 11556, - 11965 to 11557, - 11930 to 11552, - 11931 to 11553, - 11932 to 11554, - 2096 to 450, - 2097 to 451, - 14850 to 14832, - 14851 to 14833, - 14852 to 14834 + 11963 to 11555, + 11964 to 11556, + 11965 to 11557, + 11930 to 11552, + 11931 to 11553, + 11932 to 11554, + 2096 to 450, + 2097 to 451, + 14850 to 14832, + 14851 to 14833, + 14852 to 14834 ) -val SILVER_OBJECTS = mapOf ( - 11948 to 11555, - 11949 to 11556, - 11950 to 11557, - 2100 to 450, - 2101 to 451 +val SILVER_OBJECTS = mapOf( + 11948 to 11555, + 11949 to 11556, + 11950 to 11557, + 2100 to 450, + 2101 to 451 ) val GOLD_OBJECTS = mapOf( - 11951 to 11555, - 11952 to 11556, - 11953 to 11557, - 2098 to 450, - 2099 to 451 + 11951 to 11555, + 11952 to 11556, + 11953 to 11557, + 2098 to 450, + 2099 to 451 ) val MITHRIL_OBJECTS = mapOf( - 11945 to 11555, - 11946 to 11556, - 11947 to 11557, - 11942 to 11552, - 11943 to 11553, - 11944 to 11554, - 2102 to 450, - 2103 to 451, - 14853 to 14832, - 14854 to 14833, - 14855 to 14834 + 11945 to 11555, + 11946 to 11556, + 11947 to 11557, + 11942 to 11552, + 11943 to 11553, + 11944 to 11554, + 2102 to 450, + 2103 to 451, + 14853 to 14832, + 14854 to 14833, + 14855 to 14834 ) val ADAMANT_OBJECTS = mapOf( - 11939 to 11552, - 11940 to 11553, - 11941 to 11554, - 2104 to 450, - 2105 to 451, - 14862 to 14832, - 14863 to 14833, - 14864 to 14834 + 11939 to 11552, + 11940 to 11553, + 11941 to 11554, + 2104 to 450, + 2105 to 451, + 14862 to 14832, + 14863 to 14833, + 14864 to 14834 ) val RUNITE_OBJECTS = mapOf( - 2106 to 450, - 2107 to 451, - 14859 to 14832, - 14860 to 14833, - 14861 to 14834 -) - - -/** - * Chance values thanks to: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula - * Respawn times and xp thanks to: http://oldschoolrunescape.wikia.com/wiki/ - */ -enum class Ore(val id: Int, val objects: Map, val level: Int, val exp: Double, val respawn: Int, val chance: Double, val chanceOffset: Boolean) { - CLAY(434, CLAY_OBJECTS, 1, 5.0, 1, 0.0085, true), - COPPER(436, COPPER_OBJECTS, 1, 17.5, 4, 0.0085, true), - TIN(438, TIN_OBJECTS, 1, 17.5, 4, 0.0085, true), - IRON(440, IRON_OBJECTS, 15, 35.0, 9, 0.0085, true), - COAL(453, COAL_OBJECTS, 30, 50.0, 50, 0.004, false), - GOLD(444, GOLD_OBJECTS, 40, 65.0, 100, 0.003, false), - SILVER(442, SILVER_OBJECTS, 20, 40.0, 100, 0.0085, false), - MITHRIL(447, MITHRIL_OBJECTS, 55, 80.0, 200, 0.002, false), - ADAMANT(449, ADAMANT_OBJECTS, 70, 95.0, 800, 0.001, false), - RUNITE(451, RUNITE_OBJECTS, 85, 125.0, 1200, 0.0008, false) -} - -val ORES = enumValues() - -fun lookupOre(id: Int): Ore? = ORES.find { it.id == id } - -fun lookupOreRock(id: Int): Ore? { - for (ore in enumValues()) { - for (rock in ore.objects) { - if (rock.key == id) { - return ore - } - } - } - return null -} - + 2106 to 450, + 2107 to 451, + 14859 to 14832, + 14860 to 14833, + 14861 to 14834 +) \ No newline at end of file diff --git a/game/plugin/skills/mining/src/pickaxe.kt b/game/plugin/skills/mining/src/pickaxe.kt index 4b5f0faa1..a669f492e 100644 --- a/game/plugin/skills/mining/src/pickaxe.kt +++ b/game/plugin/skills/mining/src/pickaxe.kt @@ -1,23 +1,27 @@ package org.apollo.game.plugin.skills.mining -import org.apollo.game.model.Animation; - -enum class Pickaxe(val id: Int, val level: Int, val animation: Animation, val pulses: Int) { - RUNE(1275, 41, Animation(624), 3), - ADAMANT(1271, 31, Animation(628), 4), - MITHRIL(1273, 21, Animation(629), 5), - STEEL(1269, 1, Animation(627), 6), - ITRON(1267, 1, Animation(626), 7), - BRONZE(1265, 1, Animation(625), 8) -} - -val PICKAXES = Pickaxe.values() - - - -fun getPickaxes(): Array { - return PICKAXES +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.mining + +enum class Pickaxe(val id: Int, val level: Int, animation: Int, val pulses: Int) { + BRONZE(id = 1265, level = 1, animation = 625, pulses = 8), + ITRON(id = 1267, level = 1, animation = 626, pulses = 7), + STEEL(id = 1269, level = 1, animation = 627, pulses = 6), + MITHRIL(id = 1273, level = 21, animation = 629, pulses = 5), + ADAMANT(id = 1271, level = 31, animation = 628, pulses = 4), + RUNE(id = 1275, level = 41, animation = 624, pulses = 3); + + val animation = Animation(animation) + + companion object { + private val PICKAXES = Pickaxe.values().sortedByDescending { it.level } + + fun bestFor(player: Player): Pickaxe? { + return PICKAXES.asSequence() + .filter { it.level <= player.mining.current } + .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } + .firstOrNull() + } + } } - -fun lookupPickaxe(id: Int): Pickaxe? = PICKAXES.find { it.id == id } - From 0d7b2ea6e890454c897813f842117096af536cd2 Mon Sep 17 00:00:00 2001 From: Major Date: Wed, 28 Mar 2018 16:52:23 +0100 Subject: [PATCH 092/209] Add prospecting on expired rocks --- game/plugin/skills/mining/src/mining.plugin.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index 2c380f1ce..09ecc88c6 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -31,6 +31,8 @@ on { ObjectActionMessage::class } if (ore != null) { ProspectingAction.start(this, player, ore) + } else if (Ore.fromExpiredRock(id) != null) { + ExpiredProspectingAction.start(this, player) } } From 4b68b8e47e3303a2af88bc384ac745e179f7204c Mon Sep 17 00:00:00 2001 From: Major Date: Wed, 28 Mar 2018 17:34:38 +0100 Subject: [PATCH 093/209] Separate prospecting actions --- .../skills/mining/src/mining.plugin.kts | 99 ++----------------- game/plugin/skills/mining/src/prospecting.kt | 92 +++++++++++++++++ 2 files changed, 100 insertions(+), 91 deletions(-) create mode 100644 game/plugin/skills/mining/src/prospecting.kt diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index 09ecc88c6..83ad0621d 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -1,6 +1,5 @@ import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction -import org.apollo.game.action.DistancedAction import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position import org.apollo.game.model.World @@ -36,22 +35,6 @@ on { ObjectActionMessage::class } } } -data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { - - fun getObject(world: World): GameObject? { - val region = world.regionRepository.fromPosition(position) - return region.findObject(position, objectId).orElse(null) - } - - fun isSuccessful(mob: Player): Boolean { - val offset = if (ore.chanceOffset) 1 else 0 - val percent = (ore.chance * mob.mining.current + offset) * 100 - - return rand(100) < percent - } - -} - class MiningAction( player: Player, private val tool: Pickaxe, @@ -129,86 +112,20 @@ class MiningAction( } -class ExpiredProspectingAction( - mob: Player, - position: Position -) : DistancedAction(DELAY, true, mob, position, ORE_SIZE) { - - companion object { - private const val DELAY = 0 - private const val ORE_SIZE = 1 - - /** - * Starts a [ExpiredProspectingAction] for the specified [Player], terminating the [Message] that triggered it. - */ - fun start(message: ObjectActionMessage, player: Player) { - val action = ExpiredProspectingAction(player, message.position) - player.startAction(action) - - message.terminate() - } - } - - override fun executeAction() { - mob.sendMessage("There is currently no ore available in this rock.") - stop() - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as ExpiredProspectingAction - return mob == other.mob && position == other.position - } - - override fun hashCode(): Int = Objects.hash(mob, position) - -} - -class ProspectingAction( - player: Player, - position: Position, - private val ore: Ore -) : AsyncDistancedAction(DELAY, true, player, position, ORE_SIZE) { - - companion object { - private const val DELAY = 3 - private const val ORE_SIZE = 1 - - /** - * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. - */ - fun start(message: ObjectActionMessage, player: Player, ore: Ore) { - val action = ProspectingAction(player, message.position, ore) - player.startAction(action) - - message.terminate() - } - } - - override fun action(): ActionBlock = { - mob.sendMessage("You examine the rock for ores...") - mob.turnTo(position) - - wait() - - val oreName = Definitions.item(ore.id)?.name?.toLowerCase() - mob.sendMessage("This rock contains $oreName.") +data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { - stop() + fun getObject(world: World): GameObject? { + val region = world.regionRepository.fromPosition(position) + return region.findObject(position, objectId).orElse(null) } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false + fun isSuccessful(mob: Player): Boolean { + val offset = if (ore.chanceOffset) 1 else 0 + val percent = (ore.chance * mob.mining.current + offset) * 100 - other as ProspectingAction - return mob == other.mob && position == other.position && ore == other.ore + return rand(100) < percent } - override fun hashCode(): Int = Objects.hash(mob, position, ore) - } private object Actions { diff --git a/game/plugin/skills/mining/src/prospecting.kt b/game/plugin/skills/mining/src/prospecting.kt new file mode 100644 index 000000000..9b0f3d1cc --- /dev/null +++ b/game/plugin/skills/mining/src/prospecting.kt @@ -0,0 +1,92 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.skills.mining.Ore +import org.apollo.net.message.Message +import java.util.Objects + +class ProspectingAction( + player: Player, + position: Position, + private val ore: Ore +) : AsyncDistancedAction(DELAY, true, player, position, ORE_SIZE) { + + companion object { + private const val DELAY = 3 + private const val ORE_SIZE = 1 + + /** + * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player, ore: Ore) { + val action = ProspectingAction(player, message.position, ore) + player.startAction(action) + + message.terminate() + } + } + + override fun action(): ActionBlock = { + mob.sendMessage("You examine the rock for ores...") + mob.turnTo(position) + + wait() + + val oreName = Definitions.item(ore.id)?.name?.toLowerCase() + mob.sendMessage("This rock contains $oreName.") + + stop() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ProspectingAction + return mob == other.mob && position == other.position && ore == other.ore + } + + override fun hashCode(): Int = Objects.hash(mob, position, ore) + +} + +class ExpiredProspectingAction( + mob: Player, + position: Position +) : DistancedAction(DELAY, true, mob, position, ORE_SIZE) { + + companion object { + private const val DELAY = 0 + private const val ORE_SIZE = 1 + + /** + * Starts a [ExpiredProspectingAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player) { + val action = ExpiredProspectingAction(player, message.position) + player.startAction(action) + + message.terminate() + } + } + + override fun executeAction() { + mob.sendMessage("There is currently no ore available in this rock.") + stop() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ExpiredProspectingAction + return mob == other.mob && position == other.position + } + + override fun hashCode(): Int = Objects.hash(mob, position) + +} \ No newline at end of file From 0316753f46b6ac61375cf443b249b54c165799e2 Mon Sep 17 00:00:00 2001 From: Major Date: Wed, 28 Mar 2018 17:48:07 +0100 Subject: [PATCH 094/209] Improve ::position command message --- game/plugin/cmd/build.gradle | 11 ++++++----- game/plugin/cmd/src/teleport-cmd.plugin.kts | 8 +++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/game/plugin/cmd/build.gradle b/game/plugin/cmd/build.gradle index de1e006f8..6ff14b6b7 100644 --- a/game/plugin/cmd/build.gradle +++ b/game/plugin/cmd/build.gradle @@ -1,12 +1,13 @@ plugin { name = "chat_commands" authors = [ - "Graham", - "Major", - "lare96", - "cubeee", + "Graham", + "Major", + "lare96", + "cubeee", ] dependencies = [ - "util:command", + "api", + "util:command", ] } \ No newline at end of file diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index 65ae83a71..ba5a0709c 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -2,13 +2,19 @@ import com.google.common.primitives.Ints import org.apollo.game.model.Position import org.apollo.game.model.entity.setting.PrivilegeLevel import org.apollo.game.plugin.util.command.valid_arg_length +import org.apollo.game.plugins.api.component1 +import org.apollo.game.plugins.api.component2 +import org.apollo.game.plugins.api.component3 /** * Sends the player's position. */ on_command("pos", PrivilegeLevel.MODERATOR) .then { player -> - player.sendMessage("You are at: ${player.position}.") + val (x, y, z) = player.position + val region = player.position.regionCoordinates + + player.sendMessage("You are at: ($x, $y, $z) in region (${region.x}, ${region.y}).") } /** From 9c4eff712e1f93edfd040069304bc2c75421c363 Mon Sep 17 00:00:00 2001 From: Major Date: Wed, 28 Mar 2018 21:36:09 +0100 Subject: [PATCH 095/209] Move Position destructuring functions to their own object --- .../api/src/org/apollo/game/plugins/api/position.kt | 13 ++++++++----- game/plugin/areas/src/area.kt | 6 +++--- game/plugin/cmd/src/teleport-cmd.plugin.kts | 7 ++++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/position.kt b/game/plugin/api/src/org/apollo/game/plugins/api/position.kt index ffd3534d1..59e6d3deb 100644 --- a/game/plugin/api/src/org/apollo/game/plugins/api/position.kt +++ b/game/plugin/api/src/org/apollo/game/plugins/api/position.kt @@ -2,8 +2,11 @@ package org.apollo.game.plugins.api import org.apollo.game.model.Position -// Support destructuring a Position into its components. - -operator fun Position.component1(): Int = x -operator fun Position.component2(): Int = y -operator fun Position.component3(): Int = height +/** + * Support destructuring a Position into its components. + */ +object Position { + operator fun Position.component1(): Int = x + operator fun Position.component2(): Int = y + operator fun Position.component3(): Int = height +} \ No newline at end of file diff --git a/game/plugin/areas/src/area.kt b/game/plugin/areas/src/area.kt index 3c53fb1cc..a924ca44e 100644 --- a/game/plugin/areas/src/area.kt +++ b/game/plugin/areas/src/area.kt @@ -2,9 +2,9 @@ package org.apollo.game.plugins.area import org.apollo.game.model.Position import org.apollo.game.model.entity.Player -import org.apollo.game.plugins.api.component1 -import org.apollo.game.plugins.api.component2 -import org.apollo.game.plugins.api.component3 +import org.apollo.game.plugins.api.Position.component1 +import org.apollo.game.plugins.api.Position.component2 +import org.apollo.game.plugins.api.Position.component3 /** * An area in the game world. diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index ba5a0709c..712fb720c 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -1,10 +1,11 @@ + import com.google.common.primitives.Ints import org.apollo.game.model.Position import org.apollo.game.model.entity.setting.PrivilegeLevel import org.apollo.game.plugin.util.command.valid_arg_length -import org.apollo.game.plugins.api.component1 -import org.apollo.game.plugins.api.component2 -import org.apollo.game.plugins.api.component3 +import org.apollo.game.plugins.api.Position.component1 +import org.apollo.game.plugins.api.Position.component2 +import org.apollo.game.plugins.api.Position.component3 /** * Sends the player's position. From 94783da9e56096ddbd58f36a50ff2bcb190c4cc4 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Fri, 29 Dec 2017 20:15:42 -1000 Subject: [PATCH 096/209] Ported prayer plugin to kotlin --- game/plugin/skills/prayer/build.gradle | 12 +++ game/plugin/skills/prayer/src/data.kt | 78 +++++++++++++++++++ .../skills/prayer/src/prayer.plugin.kts | 48 ++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 game/plugin/skills/prayer/build.gradle create mode 100644 game/plugin/skills/prayer/src/data.kt create mode 100644 game/plugin/skills/prayer/src/prayer.plugin.kts diff --git a/game/plugin/skills/prayer/build.gradle b/game/plugin/skills/prayer/build.gradle new file mode 100644 index 000000000..36b415bbe --- /dev/null +++ b/game/plugin/skills/prayer/build.gradle @@ -0,0 +1,12 @@ +plugin { + name = "prayer_skill" + packageName = "org.apollo.game.plugin.skills.prayer" + authors = [ + "Major", + "010253", + "tlf30" + ] + dependencies = [ + "util:lookup", "api" + ] +} diff --git a/game/plugin/skills/prayer/src/data.kt b/game/plugin/skills/prayer/src/data.kt new file mode 100644 index 000000000..aeb999911 --- /dev/null +++ b/game/plugin/skills/prayer/src/data.kt @@ -0,0 +1,78 @@ +import org.apollo.game.message.impl.ConfigMessage +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Mob +import org.apollo.game.model.entity.Player + +val BURY_BONE_ANIMATION = Animation(827) + +val PLAYER_PRAYERS = hashMapOf() + +fun Player.getCurrentPrayer(): Prayer? = PLAYER_PRAYERS[this] +fun Player.setCurrentPrayer(prayer: Prayer?) = {PLAYER_PRAYERS[this] = prayer} + +enum class Bone(val id: Int, val xp: Double) { + REGULAR_BONES(526, 5.0), + BURNT_BONES(528, 5.0), + BAT_BONES(530, 4.0), + BIG_BONES(532, 45.0), + BABYDRAGON_BONES(534, 30.0), + DRAGON_BONES(536, 72.0), + WOLF_BONES(2859, 14.0), + SHAIKAHAN_BONES(3123, 25.0), + JOGRE_BONES(3125, 15.0), + BURNT_ZOGRE_BONES(3127, 25.0), + MONKEY_BONES_SMALL_0(3179, 14.0), + MONKEY_BONES_MEDIUM(3180, 14.0), + MONKEY_BONES_LARGE_0(3181, 14.0), + MONKEY_BONES_LARGE_1(3182, 14.0), + MONKEY_BONES_SMALL_1(3183, 14.0), + SHAKING_BONES(3187, 14.0), + FAYRG_BONES(4830, 84.0), + RAURG_BONES(4832, 96.0), + OURG_BONES(4834, 140.0); + + companion object { + fun findById(id: Int): Bone? = Bone.values().find { bone -> bone.id == id } + } +} + +enum class Prayer(val button: Int, val level: Int, val setting: Int, val drain: Double) { + THICK_SKIN(5609, 1, 83, 0.01), + BURST_OF_STRENGHT(5610, 4, 84, 0.01), + CLARITY_OF_THOUGHT(5611, 7, 85, 0.01), + ROCK_SKIN(5612, 10, 86, 0.04), + SUPERHUMAN_STRENGTH(5613, 13, 87, 0.04), + IMPROVED_REFLEXES(5614, 16, 88, 0.04), + RAPID_RESORE(5615, 19, 89, 0.01), + RAPID_HEAL(5615, 22, 90, 0.01), + PROTECT_ITEM(5617, 25, 91, 0.01), + STEEL_SKIN(5618, 28, 92, 0.1), + ULTIMATE_STRENGTH(5619, 31, 93, 0.1), + INCREDIBLE_REFLEXES(5620, 34, 94, 0.1), + PROTECT_FROM_MAGIC(5621, 37, 95, 0.15), + PROTECT_FROM_MISSILES(5622, 40, 96, 0.15), + PROTECT_FROM_MELEE(5623, 43, 97, 0.15), + RETRIBUTION(683, 46, 98, 0.15), + REDEMPTION(684, 49, 99, 0.15), + SMITE(685, 52, 100, 0.2); + + companion object { + fun findByButton(button: Int): Prayer? = Prayer.values().find { prayer -> prayer.button == button } + } +} + +fun updatePrayer(player: Player, prayer: Prayer?) { + //Clear active prayer + if (prayer != null) { + if (player.getCurrentPrayer() == prayer) { + player.send(ConfigMessage(prayer.setting, 0)) + } else if (player.getCurrentPrayer() == null) { + player.send(ConfigMessage(prayer.setting, 1)) + } else { + val cprayer: Prayer = player.getCurrentPrayer()!! + player.send(ConfigMessage(cprayer.setting, 0)) + player.send(ConfigMessage(prayer.setting, 1)) + } + } + player.setCurrentPrayer(prayer) +} \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/prayer.plugin.kts b/game/plugin/skills/prayer/src/prayer.plugin.kts new file mode 100644 index 000000000..008b1b61c --- /dev/null +++ b/game/plugin/skills/prayer/src/prayer.plugin.kts @@ -0,0 +1,48 @@ +import org.apollo.game.action.Action +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncAction +import org.apollo.game.message.impl.ButtonMessage +import org.apollo.game.message.impl.ItemOptionMessage +import org.apollo.game.model.entity.Player +import org.apollo.game.model.event.impl.LogoutEvent +import org.apollo.game.plugin.api.prayer + +//Clear the player prayer on logout +on_player_event { LogoutEvent::class } + .then { + PLAYER_PRAYERS[it] = null; + } + +on { ButtonMessage::class } + .then { + val prayer = Prayer.findByButton(widgetId) ?: return@then + if (prayer.level > it.prayer.current) { + updatePrayer(it,null) + terminate(); + return@then + } + updatePrayer(it, prayer) + terminate() + } + +on { ItemOptionMessage::class } + .where { option == 1 } + .then { + val bone = Bone.findById(id) ?: return@then + it.startAction(BuryBoneAction(it, slot, bone)) + terminate() + } + +class BuryBoneAction(val player: Player, val slot: Int, val bone: Bone): AsyncAction(0, true, player) { + override fun action(): ActionBlock = { + if (player.inventory.get(slot).id == bone.id) { + player.sendMessage("You dig a hole in the ground...") + player.playAnimation(BURY_BONE_ANIMATION) + wait(1) //Wait for animation + player.inventory.reset(slot) + player.sendMessage("You bury the bones.") + player.prayer.experience += bone.xp + } + stop() + } +} \ No newline at end of file From 1c0b1d827fc2fcbe779c7eebd961b2c788a8d3a2 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Fri, 30 Mar 2018 18:54:11 -0700 Subject: [PATCH 097/209] Fix to allow multiple prayers. Fixed not caching enum values. --- game/plugin/skills/prayer/src/data.kt | 31 +++++++++---------- .../skills/prayer/src/prayer.plugin.kts | 1 - 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/game/plugin/skills/prayer/src/data.kt b/game/plugin/skills/prayer/src/data.kt index aeb999911..34f61bc4f 100644 --- a/game/plugin/skills/prayer/src/data.kt +++ b/game/plugin/skills/prayer/src/data.kt @@ -5,10 +5,12 @@ import org.apollo.game.model.entity.Player val BURY_BONE_ANIMATION = Animation(827) -val PLAYER_PRAYERS = hashMapOf() +val PLAYER_PRAYERS = hashMapOf?>() -fun Player.getCurrentPrayer(): Prayer? = PLAYER_PRAYERS[this] -fun Player.setCurrentPrayer(prayer: Prayer?) = {PLAYER_PRAYERS[this] = prayer} +fun Player.getCurrentPrayers(): ArrayList { + PLAYER_PRAYERS[this] = PLAYER_PRAYERS[this] ?: ArrayList(); //Make sure that the array list exists + return PLAYER_PRAYERS[this]!! +} enum class Bone(val id: Int, val xp: Double) { REGULAR_BONES(526, 5.0), @@ -32,7 +34,8 @@ enum class Bone(val id: Int, val xp: Double) { OURG_BONES(4834, 140.0); companion object { - fun findById(id: Int): Bone? = Bone.values().find { bone -> bone.id == id } + val BONES = Bone.values() + fun findById(id: Int): Bone? = BONES.find { bone -> bone.id == id } } } @@ -57,22 +60,16 @@ enum class Prayer(val button: Int, val level: Int, val setting: Int, val drain: SMITE(685, 52, 100, 0.2); companion object { - fun findByButton(button: Int): Prayer? = Prayer.values().find { prayer -> prayer.button == button } + val PRAYERS = Prayer.values() + fun findByButton(button: Int): Prayer? = PRAYERS.find { prayer -> prayer.button == button } } } -fun updatePrayer(player: Player, prayer: Prayer?) { +fun updatePrayer(player: Player, prayer: Prayer) { //Clear active prayer - if (prayer != null) { - if (player.getCurrentPrayer() == prayer) { - player.send(ConfigMessage(prayer.setting, 0)) - } else if (player.getCurrentPrayer() == null) { - player.send(ConfigMessage(prayer.setting, 1)) - } else { - val cprayer: Prayer = player.getCurrentPrayer()!! - player.send(ConfigMessage(cprayer.setting, 0)) - player.send(ConfigMessage(prayer.setting, 1)) - } + if (player.getCurrentPrayers().contains(prayer)) { + player.send(ConfigMessage(prayer.setting, 0)) + } else { + player.send(ConfigMessage(prayer.setting, 1)) } - player.setCurrentPrayer(prayer) } \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/prayer.plugin.kts b/game/plugin/skills/prayer/src/prayer.plugin.kts index 008b1b61c..8a57dd740 100644 --- a/game/plugin/skills/prayer/src/prayer.plugin.kts +++ b/game/plugin/skills/prayer/src/prayer.plugin.kts @@ -17,7 +17,6 @@ on { ButtonMessage::class } .then { val prayer = Prayer.findByButton(widgetId) ?: return@then if (prayer.level > it.prayer.current) { - updatePrayer(it,null) terminate(); return@then } From 28c85d1ecc712bfe81d0f4b6280d15c1c749d5bf Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 31 Mar 2018 21:57:28 +0100 Subject: [PATCH 098/209] Remove now invalid packageName from prayer plugin --- game/plugin/skills/prayer/build.gradle | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/game/plugin/skills/prayer/build.gradle b/game/plugin/skills/prayer/build.gradle index 36b415bbe..fa5c27cec 100644 --- a/game/plugin/skills/prayer/build.gradle +++ b/game/plugin/skills/prayer/build.gradle @@ -1,12 +1,11 @@ plugin { name = "prayer_skill" - packageName = "org.apollo.game.plugin.skills.prayer" authors = [ - "Major", - "010253", - "tlf30" + "Major", + "010253", + "tlf30" ] dependencies = [ - "util:lookup", "api" + "util:lookup", "api" ] } From 59a651a1ebd1d883fba971c92212a5c8482d722b Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 31 Mar 2018 21:58:53 +0100 Subject: [PATCH 099/209] Fix code-style in prayer plugin Adds named arguments to enum declarations along with lookup functions, fixes continuation indent, and replaces Map> with a SetMultimap. --- game/plugin/skills/prayer/src/data.kt | 94 ++++++++++--------- .../skills/prayer/src/prayer.plugin.kts | 36 +++---- 2 files changed, 67 insertions(+), 63 deletions(-) diff --git a/game/plugin/skills/prayer/src/data.kt b/game/plugin/skills/prayer/src/data.kt index 34f61bc4f..603536643 100644 --- a/game/plugin/skills/prayer/src/data.kt +++ b/game/plugin/skills/prayer/src/data.kt @@ -1,67 +1,71 @@ +import com.google.common.collect.MultimapBuilder +import com.google.common.collect.SetMultimap import org.apollo.game.message.impl.ConfigMessage import org.apollo.game.model.Animation -import org.apollo.game.model.entity.Mob import org.apollo.game.model.entity.Player val BURY_BONE_ANIMATION = Animation(827) -val PLAYER_PRAYERS = hashMapOf?>() +val PLAYER_PRAYERS: SetMultimap = MultimapBuilder.hashKeys() + .enumSetValues(Prayer::class.java) + .build() -fun Player.getCurrentPrayers(): ArrayList { - PLAYER_PRAYERS[this] = PLAYER_PRAYERS[this] ?: ArrayList(); //Make sure that the array list exists - return PLAYER_PRAYERS[this]!! +fun Player.getCurrentPrayers(): Set { + return PLAYER_PRAYERS[this] } enum class Bone(val id: Int, val xp: Double) { - REGULAR_BONES(526, 5.0), - BURNT_BONES(528, 5.0), - BAT_BONES(530, 4.0), - BIG_BONES(532, 45.0), - BABYDRAGON_BONES(534, 30.0), - DRAGON_BONES(536, 72.0), - WOLF_BONES(2859, 14.0), - SHAIKAHAN_BONES(3123, 25.0), - JOGRE_BONES(3125, 15.0), - BURNT_ZOGRE_BONES(3127, 25.0), - MONKEY_BONES_SMALL_0(3179, 14.0), - MONKEY_BONES_MEDIUM(3180, 14.0), - MONKEY_BONES_LARGE_0(3181, 14.0), - MONKEY_BONES_LARGE_1(3182, 14.0), - MONKEY_BONES_SMALL_1(3183, 14.0), - SHAKING_BONES(3187, 14.0), - FAYRG_BONES(4830, 84.0), - RAURG_BONES(4832, 96.0), - OURG_BONES(4834, 140.0); + REGULAR_BONES(id = 526, xp = 5.0), + BURNT_BONES(id = 528, xp = 5.0), + BAT_BONES(id = 530, xp = 4.0), + BIG_BONES(id = 532, xp = 45.0), + BABY_DRAGON_BONES(id = 534, xp = 30.0), + DRAGON_BONES(id = 536, xp = 72.0), + WOLF_BONES(id = 2859, xp = 14.0), + SHAIKAHAN_BONES(id = 3123, xp = 25.0), + JOGRE_BONES(id = 3125, xp = 15.0), + BURNT_ZOGRE_BONES(id = 3127, xp = 25.0), + MONKEY_BONES_SMALL_0(id = 3179, xp = 14.0), + MONKEY_BONES_MEDIUM(id = 3180, xp = 14.0), + MONKEY_BONES_LARGE_0(id = 3181, xp = 14.0), + MONKEY_BONES_LARGE_1(id = 3182, xp = 14.0), + MONKEY_BONES_SMALL_1(id = 3183, xp = 14.0), + SHAKING_BONES(id = 3187, xp = 14.0), + FAYRG_BONES(id = 4830, xp = 84.0), + RAURG_BONES(id = 4832, xp = 96.0), + OURG_BONES(id = 4834, xp = 140.0); companion object { - val BONES = Bone.values() - fun findById(id: Int): Bone? = BONES.find { bone -> bone.id == id } + private val BONES = Bone.values() + + operator fun get(id: Int) = BONES.find { bone -> bone.id == id } } } enum class Prayer(val button: Int, val level: Int, val setting: Int, val drain: Double) { - THICK_SKIN(5609, 1, 83, 0.01), - BURST_OF_STRENGHT(5610, 4, 84, 0.01), - CLARITY_OF_THOUGHT(5611, 7, 85, 0.01), - ROCK_SKIN(5612, 10, 86, 0.04), - SUPERHUMAN_STRENGTH(5613, 13, 87, 0.04), - IMPROVED_REFLEXES(5614, 16, 88, 0.04), - RAPID_RESORE(5615, 19, 89, 0.01), - RAPID_HEAL(5615, 22, 90, 0.01), - PROTECT_ITEM(5617, 25, 91, 0.01), - STEEL_SKIN(5618, 28, 92, 0.1), - ULTIMATE_STRENGTH(5619, 31, 93, 0.1), - INCREDIBLE_REFLEXES(5620, 34, 94, 0.1), - PROTECT_FROM_MAGIC(5621, 37, 95, 0.15), - PROTECT_FROM_MISSILES(5622, 40, 96, 0.15), - PROTECT_FROM_MELEE(5623, 43, 97, 0.15), - RETRIBUTION(683, 46, 98, 0.15), - REDEMPTION(684, 49, 99, 0.15), - SMITE(685, 52, 100, 0.2); + THICK_SKIN(button = 5609, level = 1, setting = 83, drain = 0.01), + BURST_OF_STRENGTH(button = 5610, level = 4, setting = 84, drain = 0.01), + CLARITY_OF_THOUGHT(button = 5611, level = 7, setting = 85, drain = 0.01), + ROCK_SKIN(button = 5612, level = 10, setting = 86, drain = 0.04), + SUPERHUMAN_STRENGTH(button = 5613, level = 13, setting = 87, drain = 0.04), + IMPROVED_REFLEXES(button = 5614, level = 16, setting = 88, drain = 0.04), + RAPID_RESTORE(button = 5615, level = 19, setting = 89, drain = 0.01), + RAPID_HEAL(button = 5615, level = 22, setting = 90, drain = 0.01), + PROTECT_ITEM(button = 5617, level = 25, setting = 91, drain = 0.01), + STEEL_SKIN(button = 5618, level = 28, setting = 92, drain = 0.1), + ULTIMATE_STRENGTH(button = 5619, level = 31, setting = 93, drain = 0.1), + INCREDIBLE_REFLEXES(button = 5620, level = 34, setting = 94, drain = 0.1), + PROTECT_FROM_MAGIC(button = 5621, level = 37, setting = 95, drain = 0.15), + PROTECT_FROM_MISSILES(button = 5622, level = 40, setting = 96, drain = 0.15), + PROTECT_FROM_MELEE(button = 5623, level = 43, setting = 97, drain = 0.15), + RETRIBUTION(button = 683, level = 46, setting = 98, drain = 0.15), + REDEMPTION(button = 684, level = 49, setting = 99, drain = 0.15), + SMITE(button = 685, level = 52, setting = 100, drain = 0.2); companion object { val PRAYERS = Prayer.values() - fun findByButton(button: Int): Prayer? = PRAYERS.find { prayer -> prayer.button == button } + + fun forButton(button: Int) = PRAYERS.find { it.button == button } } } diff --git a/game/plugin/skills/prayer/src/prayer.plugin.kts b/game/plugin/skills/prayer/src/prayer.plugin.kts index 8a57dd740..5317ade28 100644 --- a/game/plugin/skills/prayer/src/prayer.plugin.kts +++ b/game/plugin/skills/prayer/src/prayer.plugin.kts @@ -1,4 +1,3 @@ -import org.apollo.game.action.Action import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncAction import org.apollo.game.message.impl.ButtonMessage @@ -9,30 +8,31 @@ import org.apollo.game.plugin.api.prayer //Clear the player prayer on logout on_player_event { LogoutEvent::class } - .then { - PLAYER_PRAYERS[it] = null; - } + .then { + PLAYER_PRAYERS.removeAll(it) + } on { ButtonMessage::class } - .then { - val prayer = Prayer.findByButton(widgetId) ?: return@then - if (prayer.level > it.prayer.current) { - terminate(); - return@then - } - updatePrayer(it, prayer) + .then { + val prayer = Prayer.forButton(widgetId) ?: return@then + if (prayer.level > it.prayer.current) { terminate() + return@then } + updatePrayer(it, prayer) + terminate() + } on { ItemOptionMessage::class } - .where { option == 1 } - .then { - val bone = Bone.findById(id) ?: return@then - it.startAction(BuryBoneAction(it, slot, bone)) - terminate() - } + .where { option == 1 } + .then { + val bone = Bone[id] ?: return@then + + it.startAction(BuryBoneAction(it, slot, bone)) + terminate() + } -class BuryBoneAction(val player: Player, val slot: Int, val bone: Bone): AsyncAction(0, true, player) { +class BuryBoneAction(val player: Player, val slot: Int, val bone: Bone) : AsyncAction(0, true, player) { override fun action(): ActionBlock = { if (player.inventory.get(slot).id == bone.id) { player.sendMessage("You dig a hole in the ground...") From 7c59c2c3a5b703a9b81cd8664355e3eea2ea7e3e Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 31 Mar 2018 22:12:34 +0100 Subject: [PATCH 100/209] Clean up remaining issues on prayer plugin --- game/plugin/skills/prayer/src/data.kt | 16 ++++++++-------- game/plugin/skills/prayer/src/prayer.plugin.kts | 6 ++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/game/plugin/skills/prayer/src/data.kt b/game/plugin/skills/prayer/src/data.kt index 603536643..73510c661 100644 --- a/game/plugin/skills/prayer/src/data.kt +++ b/game/plugin/skills/prayer/src/data.kt @@ -10,9 +10,8 @@ val PLAYER_PRAYERS: SetMultimap = MultimapBuilder.hashKeys() .enumSetValues(Prayer::class.java) .build() -fun Player.getCurrentPrayers(): Set { - return PLAYER_PRAYERS[this] -} +val Player.currentPrayers : Set + get() = PLAYER_PRAYERS[this] enum class Bone(val id: Int, val xp: Double) { REGULAR_BONES(id = 526, xp = 5.0), @@ -63,17 +62,18 @@ enum class Prayer(val button: Int, val level: Int, val setting: Int, val drain: SMITE(button = 685, level = 52, setting = 100, drain = 0.2); companion object { - val PRAYERS = Prayer.values() + private val PRAYERS = Prayer.values() fun forButton(button: Int) = PRAYERS.find { it.button == button } } } fun updatePrayer(player: Player, prayer: Prayer) { - //Clear active prayer - if (player.getCurrentPrayers().contains(prayer)) { - player.send(ConfigMessage(prayer.setting, 0)) + val prayerSettingValue = if (player.currentPrayers.contains(prayer)) { + 1 } else { - player.send(ConfigMessage(prayer.setting, 1)) + 0 } + + player.send(ConfigMessage(prayer.setting, prayerSettingValue)) } \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/prayer.plugin.kts b/game/plugin/skills/prayer/src/prayer.plugin.kts index 5317ade28..a86262b20 100644 --- a/game/plugin/skills/prayer/src/prayer.plugin.kts +++ b/game/plugin/skills/prayer/src/prayer.plugin.kts @@ -34,14 +34,16 @@ on { ItemOptionMessage::class } class BuryBoneAction(val player: Player, val slot: Int, val bone: Bone) : AsyncAction(0, true, player) { override fun action(): ActionBlock = { - if (player.inventory.get(slot).id == bone.id) { + if (player.inventory.removeSlot(slot, 1) > 0) { player.sendMessage("You dig a hole in the ground...") player.playAnimation(BURY_BONE_ANIMATION) + wait(1) //Wait for animation - player.inventory.reset(slot) + player.sendMessage("You bury the bones.") player.prayer.experience += bone.xp } + stop() } } \ No newline at end of file From 2b7a62d9972c72dbb7c22a7e8ff0ef063d44987f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sat, 31 Mar 2018 22:24:10 +0100 Subject: [PATCH 101/209] Use a map for bone and prayer lookups --- game/plugin/skills/prayer/src/data.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/game/plugin/skills/prayer/src/data.kt b/game/plugin/skills/prayer/src/data.kt index 73510c661..0c2ed9958 100644 --- a/game/plugin/skills/prayer/src/data.kt +++ b/game/plugin/skills/prayer/src/data.kt @@ -10,7 +10,7 @@ val PLAYER_PRAYERS: SetMultimap = MultimapBuilder.hashKeys() .enumSetValues(Prayer::class.java) .build() -val Player.currentPrayers : Set +val Player.currentPrayers: Set get() = PLAYER_PRAYERS[this] enum class Bone(val id: Int, val xp: Double) { @@ -35,9 +35,9 @@ enum class Bone(val id: Int, val xp: Double) { OURG_BONES(id = 4834, xp = 140.0); companion object { - private val BONES = Bone.values() + private val BONES = Bone.values().associateBy { it.id } - operator fun get(id: Int) = BONES.find { bone -> bone.id == id } + operator fun get(id: Int) = BONES[id] } } @@ -62,9 +62,9 @@ enum class Prayer(val button: Int, val level: Int, val setting: Int, val drain: SMITE(button = 685, level = 52, setting = 100, drain = 0.2); companion object { - private val PRAYERS = Prayer.values() + private val PRAYERS = Prayer.values().associateBy { it.button } - fun forButton(button: Int) = PRAYERS.find { it.button == button } + fun forButton(button: Int) = PRAYERS[button] } } From 7ca09f462bb7a1d8d50fad8ceb5b484c36b74d8f Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 1 Apr 2018 20:38:41 +0100 Subject: [PATCH 102/209] Rename npc spawning scripts --- .../src/{al-kharid-npcs.plugin.kts => npcs.plugin.kts} | 2 +- .../src/{edgeville-npcs.plugin.kts => npcs.plugin.kts} | 0 .../falador/src/{falador-npcs.plugin.kts => npcs.plugin.kts} | 0 .../src/{lumbridge-npcs.plugin.kts => npcs.plugin.kts} | 0 .../src/{tutorial-island-npcs.plugin.kts => npcs.plugin.kts} | 0 .../varrock/src/{varrock-npcs.plugin.kts => npcs.plugin.kts} | 0 6 files changed, 1 insertion(+), 1 deletion(-) rename game/plugin/locations/al-kharid/src/{al-kharid-npcs.plugin.kts => npcs.plugin.kts} (99%) rename game/plugin/locations/edgeville/src/{edgeville-npcs.plugin.kts => npcs.plugin.kts} (100%) rename game/plugin/locations/falador/src/{falador-npcs.plugin.kts => npcs.plugin.kts} (100%) rename game/plugin/locations/lumbridge/src/{lumbridge-npcs.plugin.kts => npcs.plugin.kts} (100%) rename game/plugin/locations/tutorial-island/src/{tutorial-island-npcs.plugin.kts => npcs.plugin.kts} (100%) rename game/plugin/locations/varrock/src/{varrock-npcs.plugin.kts => npcs.plugin.kts} (100%) diff --git a/game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts b/game/plugin/locations/al-kharid/src/npcs.plugin.kts similarity index 99% rename from game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts rename to game/plugin/locations/al-kharid/src/npcs.plugin.kts index 278ffea01..7fd53bd7e 100644 --- a/game/plugin/locations/al-kharid/src/al-kharid-npcs.plugin.kts +++ b/game/plugin/locations/al-kharid/src/npcs.plugin.kts @@ -19,7 +19,7 @@ npc_spawn("spider", x = 3323, y = 3138) npc_spawn("scorpion", x = 3282, y = 3149) -//Camels +// Camels npc_spawn("cam_the_camel", x = 3295, y = 3232) npc_spawn("elly_the_camel", x = 3312, y = 3210) diff --git a/game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts b/game/plugin/locations/edgeville/src/npcs.plugin.kts similarity index 100% rename from game/plugin/locations/edgeville/src/edgeville-npcs.plugin.kts rename to game/plugin/locations/edgeville/src/npcs.plugin.kts diff --git a/game/plugin/locations/falador/src/falador-npcs.plugin.kts b/game/plugin/locations/falador/src/npcs.plugin.kts similarity index 100% rename from game/plugin/locations/falador/src/falador-npcs.plugin.kts rename to game/plugin/locations/falador/src/npcs.plugin.kts diff --git a/game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts b/game/plugin/locations/lumbridge/src/npcs.plugin.kts similarity index 100% rename from game/plugin/locations/lumbridge/src/lumbridge-npcs.plugin.kts rename to game/plugin/locations/lumbridge/src/npcs.plugin.kts diff --git a/game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts b/game/plugin/locations/tutorial-island/src/npcs.plugin.kts similarity index 100% rename from game/plugin/locations/tutorial-island/src/tutorial-island-npcs.plugin.kts rename to game/plugin/locations/tutorial-island/src/npcs.plugin.kts diff --git a/game/plugin/locations/varrock/src/varrock-npcs.plugin.kts b/game/plugin/locations/varrock/src/npcs.plugin.kts similarity index 100% rename from game/plugin/locations/varrock/src/varrock-npcs.plugin.kts rename to game/plugin/locations/varrock/src/npcs.plugin.kts From 8394a035c714c10d1f39c5f981e71ae1dd7f2064 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 1 Apr 2018 20:42:13 +0100 Subject: [PATCH 103/209] Optimise Mob.walkTo for paths that require no verification --- game/plugin/entity/walk-to/src/walk_to.kt | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/game/plugin/entity/walk-to/src/walk_to.kt b/game/plugin/entity/walk-to/src/walk_to.kt index 3fda1dba8..87a1135d4 100644 --- a/game/plugin/entity/walk-to/src/walk_to.kt +++ b/game/plugin/entity/walk-to/src/walk_to.kt @@ -2,7 +2,10 @@ package org.apollo.plugin.entity.walkto import org.apollo.game.model.Direction import org.apollo.game.model.Position -import org.apollo.game.model.entity.* +import org.apollo.game.model.entity.Entity +import org.apollo.game.model.entity.Mob +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.model.entity.path.SimplePathfindingAlgorithm @@ -41,7 +44,7 @@ fun Mob.walkBehind(target: Mob) { walkTo(target, target.lastDirection.opposite()) } -fun Mob.walkTo(target: Position, positionPredicate: (Position) -> Boolean = { true }) { +fun Mob.walkTo(target: Position, positionPredicate: ((Position) -> Boolean)? = null) { if (position == target) { return } @@ -49,11 +52,15 @@ fun Mob.walkTo(target: Position, positionPredicate: (Position) -> Boolean = { tr val pathfinder = SimplePathfindingAlgorithm(world.collisionManager) val path = pathfinder.find(position, target) - for (step in path) { - if (!positionPredicate.invoke(step)) { - return - } + if (positionPredicate == null) { + path.forEach(walkingQueue::addStep) + } else { + for (step in path) { + if (!positionPredicate.invoke(step)) { + return + } - walkingQueue.addStep(step) + walkingQueue.addStep(step) + } } } \ No newline at end of file From 81e019ca93913093169604b9625d329fc6be9b3e Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 1 Apr 2018 22:49:26 +0100 Subject: [PATCH 104/209] Fix nitpicks in emote plugin --- .../plugin/emote-tab/src/emote-tab.plugin.kts | 51 ++----------------- game/plugin/emote-tab/src/emote.kt | 40 +++++++++++++++ 2 files changed, 44 insertions(+), 47 deletions(-) create mode 100644 game/plugin/emote-tab/src/emote.kt diff --git a/game/plugin/emote-tab/src/emote-tab.plugin.kts b/game/plugin/emote-tab/src/emote-tab.plugin.kts index b5b886293..0f546e818 100644 --- a/game/plugin/emote-tab/src/emote-tab.plugin.kts +++ b/game/plugin/emote-tab/src/emote-tab.plugin.kts @@ -1,50 +1,7 @@ import org.apollo.game.message.impl.ButtonMessage -import org.apollo.game.model.Animation - -val ANGRY_EMOTE = Animation(859) -val BECKON_EMOTE = Animation(864) -val BLOW_KISS_EMOTE = Animation(1368) -val BOW_EMOTE = Animation(858) -val CHEER_EMOTE = Animation(862) -val CLAP_EMOTE = Animation(865) -val CLIMB_ROPE_EMOTE = Animation(1130) -val CRY_EMOTE = Animation(860) -val DANCE_EMOTE = Animation(866) -val GLASS_BOX_EMOTE = Animation(1131) -val GLASS_WALL_EMOTE = Animation(1128) -val GOBLIN_BOW_EMOTE = Animation(2127) -val GOBLIN_DANCE_EMOTE = Animation(2128) -val HEAD_BANG_EMOTE = Animation(2108) -val JIG_EMOTE = Animation(2106) -val JOY_JUMP_EMOTE = Animation(2109) -val LAUGH_EMOTE = Animation(861) -val LEAN_EMOTE = Animation(1129) -val NO_EMOTE = Animation(856) -val PANIC_EMOTE = Animation(2105) -val RASPBERRY_EMOTE = Animation(2110) -val SALUTE_EMOTE = Animation(2112) -val SHRUG_EMOTE = Animation(2113) -val SPIN_EMOTE = Animation(2107) -val THINKING_EMOTE = Animation(857) -val WAVE_EMOTE = Animation(863) -val YAWN_EMOTE = Animation(2111) -val YES_EMOTE = Animation(855) - -val EMOTE_MAP = mapOf( - 162 to THINKING_EMOTE, 6_503 to CLIMB_ROPE_EMOTE, 169 to NO_EMOTE, - 164 to BOW_EMOTE, 13_384 to GOBLIN_DANCE_EMOTE, 161 to CRY_EMOTE, - 170 to LAUGH_EMOTE, 171 to CHEER_EMOTE, 163 to WAVE_EMOTE, - 167 to BECKON_EMOTE, 3_362 to PANIC_EMOTE, 172 to CLAP_EMOTE, - 166 to DANCE_EMOTE, 13_363 to JIG_EMOTE, 13_364 to SPIN_EMOTE, - 13_365 to HEAD_BANG_EMOTE, 6_506 to LEAN_EMOTE, 165 to ANGRY_EMOTE, - 13_368 to YAWN_EMOTE, 13_366 to JOY_JUMP_EMOTE, 667 to GLASS_BOX_EMOTE, - 13_367 to RASPBERRY_EMOTE, 13_369 to SALUTE_EMOTE, 13_370 to SHRUG_EMOTE, - 11_100 to BLOW_KISS_EMOTE, 666 to GLASS_WALL_EMOTE, 168 to YES_EMOTE, - 13_383 to GOBLIN_BOW_EMOTE -) on { ButtonMessage::class } - .where { widgetId in EMOTE_MAP } - .then { - it.playAnimation(EMOTE_MAP[widgetId]) - } \ No newline at end of file + .where { widgetId in Emote.MAP } + .then { player -> + player.playAnimation(Emote.fromButton(widgetId)!!.animation) + } \ No newline at end of file diff --git a/game/plugin/emote-tab/src/emote.kt b/game/plugin/emote-tab/src/emote.kt new file mode 100644 index 000000000..2b61f88ba --- /dev/null +++ b/game/plugin/emote-tab/src/emote.kt @@ -0,0 +1,40 @@ +import org.apollo.game.model.Animation + +enum class Emote(val button: Int, animation: Int) { + ANGRY_EMOTE(button = 165, animation = 859), + BECKON_EMOTE(button = 167, animation = 864), + BLOW_KISS_EMOTE(button = 11_100, animation = 1368), + BOW_EMOTE(button = 164, animation = 858), + CHEER_EMOTE(button = 171, animation = 862), + CLAP_EMOTE(button = 172, animation = 865), + CLIMB_ROPE_EMOTE(button = 6503, animation = 1130), + CRY_EMOTE(button = 161, animation = 860), + DANCE_EMOTE(button = 166, animation = 866), + GLASS_BOX_EMOTE(button = 667, animation = 1131), + GLASS_WALL_EMOTE(button = 666, animation = 1128), + GOBLIN_BOW_EMOTE(button = 13_383, animation = 2127), + GOBLIN_DANCE_EMOTE(button = 13_384, animation = 2128), + HEAD_BANG_EMOTE(button = 13_365, animation = 2108), + JIG_EMOTE(button = 13_363, animation = 2106), + JOY_JUMP_EMOTE(button = 13_366, animation = 2109), + LAUGH_EMOTE(button = 170, animation = 861), + LEAN_EMOTE(button = 6_506, animation = 1129), + NO_EMOTE(button = 169, animation = 856), + PANIC_EMOTE(button = 3_362, animation = 2105), + RASPBERRY_EMOTE(button = 13_367, animation = 2110), + SALUTE_EMOTE(button = 13_369, animation = 2112), + SHRUG_EMOTE(button = 13_370, animation = 2113), + SPIN_EMOTE(button = 13_364, animation = 2107), + THINKING_EMOTE(button = 162, animation = 857), + WAVE_EMOTE(button = 163, animation = 863), + YAWN_EMOTE(button = 13_368, animation = 2111), + YES_EMOTE(button = 168, animation = 855); + + val animation = Animation(animation) + + companion object { + internal val MAP = Emote.values().associateBy { it.button } + + fun fromButton(button: Int): Emote? = MAP[button] + } +} \ No newline at end of file From 78520fe5307cacde1bbea5d5d1eaa9df6db7056c Mon Sep 17 00:00:00 2001 From: Major Date: Mon, 2 Apr 2018 20:46:35 +0100 Subject: [PATCH 105/209] Fix scriptTemplatesClasspath for most users Users will have to build using IntelliJ at least once, but this should reflect the workflow of the majority of users. --- .idea/kotlinc.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 7825b132c..ee4beb076 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -10,6 +10,6 @@ \ No newline at end of file From 34f06b20c49b957e48baaf49ba7ed35735d37e95 Mon Sep 17 00:00:00 2001 From: Caleb Foust Date: Sun, 1 Apr 2018 18:17:11 -0700 Subject: [PATCH 106/209] Add teleportation to places using ::tele [name] --- game/plugin/cmd/src/teleport-cmd.plugin.kts | 60 ++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index 712fb720c..bd1162ccc 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -18,12 +18,68 @@ on_command("pos", PrivilegeLevel.MODERATOR) player.sendMessage("You are at: ($x, $y, $z) in region (${region.x}, ${region.y}).") } +val TELEPORT_DESTINATIONS = listOf( + "alkharid" to Position(3292, 3171, 0), + "ardougne" to Position(2662, 3304, 0), + "barrows" to Position(3565, 3314, 0), + "brimhaven" to Position(2802, 3179, 0), + "burthorpe" to Position(2898, 3545, 0), + "camelot" to Position(2757, 3478, 0), + "canifis" to Position(3493, 3489, 0), + "cw" to Position(2442, 3090, 0), + "draynor" to Position(3082, 3249, 0), + "duelarena" to Position(3370, 3267, 0), + "edgeville" to Position(3087, 3504, 0), + "entrana" to Position(2827, 3343, 0), + "falador" to Position(2965, 3379, 0), + "ge" to Position(3164, 3476, 0), + "kbd" to Position(2273, 4680, 0), + "keldagrim" to Position(2845, 10210, 0), + "kq" to Position(3507, 9494, 0), + "lumbridge" to Position(3222, 3219, 0), + "lunar" to Position(2113, 3915, 0), + "misc" to Position(2515, 3866, 0), + "neit" to Position(2332, 3804, 0), + "pc" to Position(2658, 2660, 0), + "rellekka" to Position(2660, 3657, 0), + "shilo" to Position(2852, 2955, 0), + "taverley" to Position(2895, 3443, 0), + "tutorial" to Position(3094, 3107, 0), + "tzhaar" to Position(2480, 5175, 0), + "varrock" to Position(3212, 3423, 0), + "yanille" to Position(2605, 3096, 0), + "zanaris" to Position(2452, 4473, 0) +) + /** * Teleports the player to the specified position. */ on_command("tele", PrivilegeLevel.ADMINISTRATOR) .then { player -> - val invalidSyntax = "Invalid syntax - ::tele [x] [y] [optional-z]" + val invalidSyntax = "Invalid syntax - ::tele [x] [y] [optional-z] or ::tele [place name]" + + if (arguments.size == 1) { + val query = arguments[0] + val results = TELEPORT_DESTINATIONS.filter { + (name, _) -> name.startsWith(query) + } + + if (results.size == 0) { + player.sendMessage("No destinations matching '$query'.") + return@then + } else if (results.size > 1) { + player.sendMessage("Ambiguous query '$query' (could " + + "be $results). Please disambiguate.") + return@then + } + + val (name, dest) = results[0] + player.sendMessage("Teleporting to $name.") + player.teleport(dest) + + return@then + } + if (!valid_arg_length(arguments, 2..3, player, invalidSyntax)) { return@then } @@ -53,4 +109,4 @@ on_command("tele", PrivilegeLevel.ADMINISTRATOR) if (z in 0..4) { player.teleport(Position(x, y, z)) } - } \ No newline at end of file + } From a52837975e95ba70e1b8fd8aeef05894a725eb71 Mon Sep 17 00:00:00 2001 From: Chivvon Date: Fri, 6 Apr 2018 16:50:27 +0200 Subject: [PATCH 107/209] Port Herblore plugin to Kotlin --- game/plugin/skills/herblore/build.gradle | 10 +++ .../herblore/src/CrushIngredientAction.kt | 39 ++++++++++ game/plugin/skills/herblore/src/Herb.kt | 34 +++++++++ .../skills/herblore/src/IdentifyHerbAction.kt | 49 +++++++++++++ game/plugin/skills/herblore/src/Ingredient.kt | 60 +++++++++++++++ .../herblore/src/MakeFinishedPotionAction.kt | 50 +++++++++++++ .../src/MakeUnfinishedPotionAction.kt | 47 ++++++++++++ game/plugin/skills/herblore/src/Potion.kt | 73 +++++++++++++++++++ .../skills/herblore/src/herblore.plugin.kts | 48 ++++++++++++ 9 files changed, 410 insertions(+) create mode 100644 game/plugin/skills/herblore/build.gradle create mode 100644 game/plugin/skills/herblore/src/CrushIngredientAction.kt create mode 100644 game/plugin/skills/herblore/src/Herb.kt create mode 100644 game/plugin/skills/herblore/src/IdentifyHerbAction.kt create mode 100644 game/plugin/skills/herblore/src/Ingredient.kt create mode 100644 game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt create mode 100644 game/plugin/skills/herblore/src/MakeUnfinishedPotionAction.kt create mode 100644 game/plugin/skills/herblore/src/Potion.kt create mode 100644 game/plugin/skills/herblore/src/herblore.plugin.kts diff --git a/game/plugin/skills/herblore/build.gradle b/game/plugin/skills/herblore/build.gradle new file mode 100644 index 000000000..6dc08aac4 --- /dev/null +++ b/game/plugin/skills/herblore/build.gradle @@ -0,0 +1,10 @@ +plugin { + name = "herblore_skill" + authors = [ + "Chivvon", + "Chris Fletcher", + "Major" + ] + + dependencies = ["api"] +} diff --git a/game/plugin/skills/herblore/src/CrushIngredientAction.kt b/game/plugin/skills/herblore/src/CrushIngredientAction.kt new file mode 100644 index 000000000..bf9cb2834 --- /dev/null +++ b/game/plugin/skills/herblore/src/CrushIngredientAction.kt @@ -0,0 +1,39 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncAction +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import java.util.Objects + +class CrushIngredientAction( + player: Player, + private val ingredient: CrushableIngredient +) : AsyncAction(0, true, player) { + + override fun action(): ActionBlock = { + mob.playAnimation(GRINDING_ANIM) + wait(pulses = 1) + + val inventory = mob.inventory + if (inventory.remove(ingredient.uncrushed)) { + inventory.add(ingredient.id) + + mob.sendMessage("You carefully grind the ${ingredient.uncrushedName} to dust.") + } + + stop() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as CrushIngredientAction + return mob == other.mob && ingredient == other.ingredient + } + + override fun hashCode(): Int = Objects.hash(mob, ingredient) + + private companion object { + private val GRINDING_ANIM = Animation(364) + } +} \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/Herb.kt b/game/plugin/skills/herblore/src/Herb.kt new file mode 100644 index 000000000..c80e1edff --- /dev/null +++ b/game/plugin/skills/herblore/src/Herb.kt @@ -0,0 +1,34 @@ +import org.apollo.game.plugin.api.Definitions + +enum class Herb( + val identified: Int, + val unidentified: Int, + val level: Int, + val experience: Double +) { + GUAM_LEAF(identified = 249, unidentified = 199, level = 1, experience = 2.5), + MARRENTILL(identified = 251, unidentified = 201, level = 5, experience = 3.8), + TARROMIN(identified = 253, unidentified = 203, level = 11, experience = 5.0), + HARRALANDER(identified = 255, unidentified = 205, level = 20, experience = 6.3), + RANARR(identified = 257, unidentified = 207, level = 25, experience = 7.5), + TOADFLAX(identified = 2998, unidentified = 2998, level = 30, experience = 8.0), + IRIT_LEAF(identified = 259, unidentified = 209, level = 40, experience = 8.8), + AVANTOE(identified = 261, unidentified = 211, level = 48, experience = 10.0), + KWUARM(identified = 263, unidentified = 213, level = 54, experience = 11.3), + SNAPDRAGON(identified = 3000, unidentified = 3051, level = 59, experience = 11.8), + CADANTINE(identified = 265, unidentified = 215, level = 65, experience = 12.5), + LANTADYME(identified = 2481, unidentified = 2485, level = 67, experience = 13.1), + DWARF_WEED(identified = 267, unidentified = 217, level = 70, experience = 13.8), + TORSTOL(identified = 269, unidentified = 219, level = 75, experience = 15.0); + + val identifiedName: String = Definitions.item(identified)!!.name + + companion object { + private val identified = Herb.values().map(Herb::identified).toHashSet() + private val herbs = Herb.values().associateBy(Herb::unidentified) + + operator fun get(id: Int): Herb? = herbs[id] + internal fun Int.isUnidentified(): Boolean = this in herbs + internal fun Int.isIdentified(): Boolean = this in identified + } +} \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/IdentifyHerbAction.kt b/game/plugin/skills/herblore/src/IdentifyHerbAction.kt new file mode 100644 index 000000000..a3b11ac90 --- /dev/null +++ b/game/plugin/skills/herblore/src/IdentifyHerbAction.kt @@ -0,0 +1,49 @@ + +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncAction +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.herblore +import org.apollo.util.LanguageUtil +import java.util.Objects + +class IdentifyHerbAction( + player: Player, + private val slot: Int, + private val herb: Herb +) : AsyncAction(0, true, player) { + + override fun action(): ActionBlock = { + if (mob.herblore.current < herb.level) { + mob.sendMessage("You need a Herblore level of ${herb.level} to clean this herb.") + stop() + } + + val inventory = mob.inventory + + if (inventory.removeSlot(slot, 1) > 0) { + inventory.add(herb.identified) + mob.herblore.experience += herb.experience + + val name = herb.identifiedName + val article = LanguageUtil.getIndefiniteArticle(name) + + mob.sendMessage("You identify the herb as $article $name.") + } + + stop() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as IdentifyHerbAction + return mob == other.mob && herb == other.herb && slot == other.slot + } + + override fun hashCode(): Int = Objects.hash(mob, herb, slot) + + companion object { + const val IDENTIFY_OPTION = 1 + } +} \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/Ingredient.kt b/game/plugin/skills/herblore/src/Ingredient.kt new file mode 100644 index 000000000..3784f0905 --- /dev/null +++ b/game/plugin/skills/herblore/src/Ingredient.kt @@ -0,0 +1,60 @@ +import CrushableIngredient.Companion.isCrushable +import NormalIngredient.Companion.isNormalIngredient +import org.apollo.game.plugin.api.Definitions + +/** + * A secondary ingredient in a potion. + */ +interface Ingredient { + val id: Int + + companion object { + internal fun Int.isIngredient(): Boolean = isNormalIngredient() || isCrushable() + } +} + +enum class CrushableIngredient(val uncrushed: Int, override val id: Int) : Ingredient { + UNICORN_HORN(uncrushed = 237, id = 235), + DRAGON_SCALE(uncrushed = 243, id = 241), + CHOCOLATE_BAR(uncrushed = 1973, id = 1975), + BIRDS_NEST(uncrushed = 5075, id = 6693); + + val uncrushedName: String = Definitions.item(uncrushed)!!.name + + companion object { + private const val PESTLE_AND_MORTAR = 233 + private const val KNIFE = 5605 + + private val ingredients = CrushableIngredient.values().associateBy(CrushableIngredient::uncrushed) + operator fun get(id: Int): CrushableIngredient? = ingredients[id] + + internal fun Int.isCrushable(): Boolean = this in ingredients + internal fun Int.isGrindingTool(): Boolean = this == KNIFE || this == PESTLE_AND_MORTAR + } +} + +enum class NormalIngredient(override val id: Int) : Ingredient { + EYE_NEWT(id = 221), + RED_SPIDERS_EGGS(id = 223), + LIMPWURT_ROOT(id = 225), + SNAPE_GRASS(id = 231), + WHITE_BERRIES(id = 239), + WINE_ZAMORAK(id = 245), + JANGERBERRIES(id = 247), + TOADS_LEGS(id = 2152), + MORT_MYRE_FUNGI(id = 2970), + POTATO_CACTUS(id = 3138), + PHOENIX_FEATHER(id = 4621), + FROG_SPAWN(id = 5004), + PAPAYA_FRUIT(id = 5972), + POISON_IVY_BERRIES(id = 6018), + YEW_ROOTS(id = 6049), + MAGIC_ROOTS(id = 6051); + + companion object { + private val ingredients = NormalIngredient.values().associateBy(NormalIngredient::id) + operator fun get(id: Int): NormalIngredient? = ingredients[id] + + internal fun Int.isNormalIngredient(): Boolean = this in ingredients + } +} \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt b/game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt new file mode 100644 index 000000000..37cc56d5f --- /dev/null +++ b/game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt @@ -0,0 +1,50 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncAction +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.herblore +import java.util.Objects + +class MakeFinishedPotionAction( + player: Player, + private val potion: FinishedPotion +) : AsyncAction(1, true, player) { + + override fun action(): ActionBlock = { + val level = mob.herblore.current + + if (level < potion.level) { + mob.sendMessage("You need a Herblore level of ${potion.level} to make this.") + stop() + } + + val unfinished = potion.unfinished.id + val inventory = mob.inventory + + if (inventory.contains(unfinished) && inventory.contains(potion.ingredient)) { + inventory.remove(unfinished) + inventory.remove(potion.ingredient) + + mob.playAnimation(MIXING_ANIMATION) + + inventory.add(potion.id) + mob.herblore.experience += potion.experience + + mob.sendMessage("You mix the ${potion.ingredientName} into your potion.") + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MakeFinishedPotionAction + return mob == other.mob && potion == other.potion + } + + override fun hashCode(): Int = Objects.hash(mob, potion) + + private companion object { + private val MIXING_ANIMATION = Animation(363) + } +} \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/MakeUnfinishedPotionAction.kt b/game/plugin/skills/herblore/src/MakeUnfinishedPotionAction.kt new file mode 100644 index 000000000..03bbd5a7d --- /dev/null +++ b/game/plugin/skills/herblore/src/MakeUnfinishedPotionAction.kt @@ -0,0 +1,47 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncAction +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.herblore +import java.util.Objects + +class MakeUnfinishedPotionAction( + player: Player, + private val potion: UnfinishedPotion +) : AsyncAction(1, true, player) { + + override fun action(): ActionBlock = { + val level = mob.herblore.current + + if (level < potion.level) { + mob.sendMessage("You need a Herblore level of ${potion.level} to make this.") + stop() + } + + val inventory = mob.inventory + + if (inventory.contains(VIAL_OF_WATER) && inventory.contains(potion.herb)) { + inventory.remove(VIAL_OF_WATER) + inventory.remove(potion.herb) + + mob.playAnimation(MIXING_ANIMATION) + + inventory.add(potion.id) + mob.sendMessage("You put the ${potion.herbName} into the vial of water.") + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MakeUnfinishedPotionAction + return mob == other.mob && potion == other.potion + } + + override fun hashCode(): Int = Objects.hash(mob, potion) + + private companion object { + private val MIXING_ANIMATION = Animation(363) + } +} \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/Potion.kt b/game/plugin/skills/herblore/src/Potion.kt new file mode 100644 index 000000000..299a82987 --- /dev/null +++ b/game/plugin/skills/herblore/src/Potion.kt @@ -0,0 +1,73 @@ +import CrushableIngredient.CHOCOLATE_BAR +import CrushableIngredient.DRAGON_SCALE +import CrushableIngredient.UNICORN_HORN +import NormalIngredient.* +import UnfinishedPotion.* +import org.apollo.game.plugin.api.Definitions + +const val VIAL_OF_WATER = 227 + +enum class UnfinishedPotion(val id: Int, herb: Herb, val level: Int) { + GUAM(id = 91, herb = Herb.GUAM_LEAF, level = 1), + MARRENTILL(id = 93, herb = Herb.MARRENTILL, level = 5), + TARROMIN(id = 95, herb = Herb.TARROMIN, level = 12), + HARRALANDER(id = 97, herb = Herb.HARRALANDER, level = 22), + RANARR(id = 99, herb = Herb.RANARR, level = 30), + TOADFLAX(id = 3002, herb = Herb.TOADFLAX, level = 34), + IRIT(id = 101, herb = Herb.IRIT_LEAF, level = 45), + AVANTOE(id = 103, herb = Herb.AVANTOE, level = 50), + KWUARM(id = 105, herb = Herb.KWUARM, level = 55), + SNAPDRAGON(id = 3004, herb = Herb.SNAPDRAGON, level = 63), + CADANTINE(id = 107, herb = Herb.CADANTINE, level = 66), + LANTADYME(id = 2483, herb = Herb.LANTADYME, level = 69), + DWARF_WEED(id = 109, herb = Herb.DWARF_WEED, level = 72), + TORSTOL(id = 111, herb = Herb.TORSTOL, level = 78); + + val herb = herb.identified + val herbName: String = Definitions.item(herb.identified)!!.name + + companion object { + private val ids = values().map(UnfinishedPotion::id).toHashSet() + private val potions = values().associateBy(UnfinishedPotion::herb) + + operator fun get(id: Int) = potions[id] + internal fun Int.isUnfinished(): Boolean = this in ids + } +} + +enum class FinishedPotion( + val id: Int, + val unfinished: UnfinishedPotion, + ingredient: Ingredient, + val level: Int, + val experience: Double +) { + ATTACK(id = 121, unfinished = GUAM, ingredient = EYE_NEWT, level = 1, experience = 25.0), + ANTIPOISON(id = 175, unfinished = MARRENTILL, ingredient = UNICORN_HORN, level = 5, experience = 37.5), + STRENGTH(id = 115, unfinished = TARROMIN, ingredient = LIMPWURT_ROOT, level = 12, experience = 50.0), + RESTORE(id = 127, unfinished = HARRALANDER, ingredient = RED_SPIDERS_EGGS, level = 18, experience = 62.5), + ENERGY(id = 3010, unfinished = HARRALANDER, ingredient = CHOCOLATE_BAR, level = 26, experience = 67.5), + DEFENCE(id = 133, unfinished = RANARR, ingredient = WHITE_BERRIES, level = 30, experience = 75.0), + AGILITY(id = 3034, unfinished = TOADFLAX, ingredient = TOADS_LEGS, level = 34, experience = 80.0), + PRAYER(id = 139, unfinished = RANARR, ingredient = SNAPE_GRASS, level = 38, experience = 87.5), + SUPER_ATTACK(id = 145, unfinished = IRIT, ingredient = EYE_NEWT, level = 45, experience = 100.0), + SUPER_ANTIPOISON(id = 181, unfinished = IRIT, ingredient = UNICORN_HORN, level = 48, experience = 106.3), + FISHING(id = 151, unfinished = AVANTOE, ingredient = SNAPE_GRASS, level = 50, experience = 112.5), + SUPER_ENERGY(id = 3018, unfinished = AVANTOE, ingredient = MORT_MYRE_FUNGI, level = 52, experience = 117.5), + SUPER_STRENGTH(id = 157, unfinished = KWUARM, ingredient = LIMPWURT_ROOT, level = 55, experience = 125.0), + WEAPON_POISON(id = 187, unfinished = KWUARM, ingredient = DRAGON_SCALE, level = 60, experience = 137.5), + SUPER_RESTORE(id = 3026, unfinished = SNAPDRAGON, ingredient = RED_SPIDERS_EGGS, level = 63, experience = 142.5), + SUPER_DEFENCE(id = 163, unfinished = CADANTINE, ingredient = WHITE_BERRIES, level = 66, experience = 150.0), + ANTIFIRE(id = 2428, unfinished = LANTADYME, ingredient = DRAGON_SCALE, level = 69, experience = 157.5), + RANGING(id = 169, unfinished = DWARF_WEED, ingredient = WINE_ZAMORAK, level = 72, experience = 162.5), + MAGIC(id = 3042, unfinished = LANTADYME, ingredient = POTATO_CACTUS, level = 76, experience = 172.5), + ZAMORAK_BREW(id = 189, unfinished = TORSTOL, ingredient = JANGERBERRIES, level = 78, experience = 175.0); + + val ingredientName = Definitions.item(ingredient.id)!!.name.toLowerCase() + val ingredient = ingredient.id + + companion object { + private val potions = FinishedPotion.values().associateBy { Pair(it.unfinished.id, it.ingredient) } + operator fun get(key: Pair) = potions[key] + } +} diff --git a/game/plugin/skills/herblore/src/herblore.plugin.kts b/game/plugin/skills/herblore/src/herblore.plugin.kts new file mode 100644 index 000000000..f575a6532 --- /dev/null +++ b/game/plugin/skills/herblore/src/herblore.plugin.kts @@ -0,0 +1,48 @@ + +import CrushableIngredient.Companion.isCrushable +import CrushableIngredient.Companion.isGrindingTool +import Herb.Companion.isIdentified +import Herb.Companion.isUnidentified +import Ingredient.Companion.isIngredient +import UnfinishedPotion.Companion.isUnfinished +import org.apollo.game.message.impl.ItemOnItemMessage +import org.apollo.game.message.impl.ItemOptionMessage + +on { ItemOptionMessage::class } + .where { option == IdentifyHerbAction.IDENTIFY_OPTION && id.isUnidentified() } + .then { player -> + val unidentified = Herb[id]!! + + player.startAction(IdentifyHerbAction(player, slot, unidentified)) + terminate() + } + +on { ItemOnItemMessage::class } + .where { (id.isGrindingTool() && targetId.isCrushable() || id.isCrushable() && targetId.isGrindingTool()) } + .then { player -> + val crushableId = if (id.isCrushable()) id else targetId + val raw = CrushableIngredient[crushableId]!! + + player.startAction(CrushIngredientAction(player, raw)) + terminate() + } + +on { ItemOnItemMessage::class } + .where { id == VIAL_OF_WATER && targetId.isIdentified() || id.isIdentified() && targetId == VIAL_OF_WATER } + .then { player -> + val herbId = if (id.isIdentified()) id else targetId + val unfinished = UnfinishedPotion[herbId]!! + + player.startAction(MakeUnfinishedPotionAction(player, unfinished)) + terminate() + } + +on { ItemOnItemMessage::class } + .where { id.isUnfinished() && targetId.isIngredient() || id.isIngredient() && targetId.isUnfinished() } + .then { player -> + val key = if (id.isUnfinished()) Pair(id, targetId) else Pair(targetId, id) + val finished = FinishedPotion[key]!! + + player.startAction(MakeFinishedPotionAction(player, finished)) + terminate() + } \ No newline at end of file From f7bf5fde34ea46d524967e3e19f3908f3241d0da Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 8 Apr 2018 04:12:04 +0100 Subject: [PATCH 108/209] Fix nitpicks in prayer plugin --- game/plugin/skills/prayer/src/Bone.kt | 28 +++++++++ .../skills/prayer/src/BoneBuryAction.kt | 32 ++++++++++ .../skills/prayer/src/{data.kt => Prayer.kt} | 61 ++++--------------- .../skills/prayer/src/prayer.plugin.kts | 48 ++++++--------- 4 files changed, 91 insertions(+), 78 deletions(-) create mode 100644 game/plugin/skills/prayer/src/Bone.kt create mode 100644 game/plugin/skills/prayer/src/BoneBuryAction.kt rename game/plugin/skills/prayer/src/{data.kt => Prayer.kt} (52%) diff --git a/game/plugin/skills/prayer/src/Bone.kt b/game/plugin/skills/prayer/src/Bone.kt new file mode 100644 index 000000000..9f3c73c13 --- /dev/null +++ b/game/plugin/skills/prayer/src/Bone.kt @@ -0,0 +1,28 @@ +enum class Bone(val id: Int, val xp: Double) { + REGULAR_BONES(id = 526, xp = 5.0), + BURNT_BONES(id = 528, xp = 5.0), + BAT_BONES(id = 530, xp = 4.0), + BIG_BONES(id = 532, xp = 45.0), + BABY_DRAGON_BONES(id = 534, xp = 30.0), + DRAGON_BONES(id = 536, xp = 72.0), + WOLF_BONES(id = 2859, xp = 14.0), + SHAIKAHAN_BONES(id = 3123, xp = 25.0), + JOGRE_BONES(id = 3125, xp = 15.0), + BURNT_ZOGRE_BONES(id = 3127, xp = 25.0), + MONKEY_BONES_SMALL_0(id = 3179, xp = 14.0), + MONKEY_BONES_MEDIUM(id = 3180, xp = 14.0), + MONKEY_BONES_LARGE_0(id = 3181, xp = 14.0), + MONKEY_BONES_LARGE_1(id = 3182, xp = 14.0), + MONKEY_BONES_SMALL_1(id = 3183, xp = 14.0), + SHAKING_BONES(id = 3187, xp = 14.0), + FAYRG_BONES(id = 4830, xp = 84.0), + RAURG_BONES(id = 4832, xp = 96.0), + OURG_BONES(id = 4834, xp = 140.0); + + companion object { + private val BONES = Bone.values().associateBy(Bone::id) + + operator fun get(id: Int) = BONES[id] + internal fun Int.isBone(): Boolean = this in BONES + } +} \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/BoneBuryAction.kt b/game/plugin/skills/prayer/src/BoneBuryAction.kt new file mode 100644 index 000000000..f3c463575 --- /dev/null +++ b/game/plugin/skills/prayer/src/BoneBuryAction.kt @@ -0,0 +1,32 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncAction +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.prayer + +class BuryBoneAction( + player: Player, + private val slot: Int, + private val bone: Bone +) : AsyncAction(0, true, player) { + + override fun action(): ActionBlock = { + if (mob.inventory.removeSlot(slot, 1) > 0) { + mob.sendMessage("You dig a hole in the ground...") + mob.playAnimation(BURY_BONE_ANIMATION) + + wait(pulses = 1) + + mob.sendMessage("You bury the bones.") + mob.prayer.experience += bone.xp + } + + stop() + } + + companion object { + private val BURY_BONE_ANIMATION = Animation(827) + internal const val BURY_OPTION = 1 + } + +} \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/data.kt b/game/plugin/skills/prayer/src/Prayer.kt similarity index 52% rename from game/plugin/skills/prayer/src/data.kt rename to game/plugin/skills/prayer/src/Prayer.kt index 0c2ed9958..3f281cc05 100644 --- a/game/plugin/skills/prayer/src/data.kt +++ b/game/plugin/skills/prayer/src/Prayer.kt @@ -1,46 +1,8 @@ import com.google.common.collect.MultimapBuilder import com.google.common.collect.SetMultimap import org.apollo.game.message.impl.ConfigMessage -import org.apollo.game.model.Animation import org.apollo.game.model.entity.Player -val BURY_BONE_ANIMATION = Animation(827) - -val PLAYER_PRAYERS: SetMultimap = MultimapBuilder.hashKeys() - .enumSetValues(Prayer::class.java) - .build() - -val Player.currentPrayers: Set - get() = PLAYER_PRAYERS[this] - -enum class Bone(val id: Int, val xp: Double) { - REGULAR_BONES(id = 526, xp = 5.0), - BURNT_BONES(id = 528, xp = 5.0), - BAT_BONES(id = 530, xp = 4.0), - BIG_BONES(id = 532, xp = 45.0), - BABY_DRAGON_BONES(id = 534, xp = 30.0), - DRAGON_BONES(id = 536, xp = 72.0), - WOLF_BONES(id = 2859, xp = 14.0), - SHAIKAHAN_BONES(id = 3123, xp = 25.0), - JOGRE_BONES(id = 3125, xp = 15.0), - BURNT_ZOGRE_BONES(id = 3127, xp = 25.0), - MONKEY_BONES_SMALL_0(id = 3179, xp = 14.0), - MONKEY_BONES_MEDIUM(id = 3180, xp = 14.0), - MONKEY_BONES_LARGE_0(id = 3181, xp = 14.0), - MONKEY_BONES_LARGE_1(id = 3182, xp = 14.0), - MONKEY_BONES_SMALL_1(id = 3183, xp = 14.0), - SHAKING_BONES(id = 3187, xp = 14.0), - FAYRG_BONES(id = 4830, xp = 84.0), - RAURG_BONES(id = 4832, xp = 96.0), - OURG_BONES(id = 4834, xp = 140.0); - - companion object { - private val BONES = Bone.values().associateBy { it.id } - - operator fun get(id: Int) = BONES[id] - } -} - enum class Prayer(val button: Int, val level: Int, val setting: Int, val drain: Double) { THICK_SKIN(button = 5609, level = 1, setting = 83, drain = 0.01), BURST_OF_STRENGTH(button = 5610, level = 4, setting = 84, drain = 0.01), @@ -62,18 +24,21 @@ enum class Prayer(val button: Int, val level: Int, val setting: Int, val drain: SMITE(button = 685, level = 52, setting = 100, drain = 0.2); companion object { - private val PRAYERS = Prayer.values().associateBy { it.button } + private val prayers = Prayer.values().associateBy(Prayer::button) - fun forButton(button: Int) = PRAYERS[button] + fun forButton(button: Int) = prayers[button] + internal fun Int.isPrayerButton(): Boolean = this in prayers } } -fun updatePrayer(player: Player, prayer: Prayer) { - val prayerSettingValue = if (player.currentPrayers.contains(prayer)) { - 1 - } else { - 0 - } +val Player.currentPrayers: Set + get() = playerPrayers[this] + +fun Player.updatePrayer(prayer: Prayer) { + val value = if (currentPrayers.contains(prayer)) 1 else 0 + send(ConfigMessage(prayer.setting, value)) +} - player.send(ConfigMessage(prayer.setting, prayerSettingValue)) -} \ No newline at end of file +internal val playerPrayers: SetMultimap = MultimapBuilder.hashKeys() + .enumSetValues(Prayer::class.java) + .build() \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/prayer.plugin.kts b/game/plugin/skills/prayer/src/prayer.plugin.kts index a86262b20..c2857a8f9 100644 --- a/game/plugin/skills/prayer/src/prayer.plugin.kts +++ b/game/plugin/skills/prayer/src/prayer.plugin.kts @@ -1,49 +1,37 @@ -import org.apollo.game.action.ActionBlock -import org.apollo.game.action.AsyncAction +import Bone.Companion.isBone +import Prayer.Companion.isPrayerButton import org.apollo.game.message.impl.ButtonMessage import org.apollo.game.message.impl.ItemOptionMessage -import org.apollo.game.model.entity.Player import org.apollo.game.model.event.impl.LogoutEvent import org.apollo.game.plugin.api.prayer -//Clear the player prayer on logout +// Clear the player's prayer(s) on logout on_player_event { LogoutEvent::class } .then { - PLAYER_PRAYERS.removeAll(it) + playerPrayers.removeAll(it) } on { ButtonMessage::class } - .then { - val prayer = Prayer.forButton(widgetId) ?: return@then - if (prayer.level > it.prayer.current) { + .where { widgetId.isPrayerButton() } + .then { player -> + val prayer = Prayer.forButton(widgetId)!! + val level = prayer.level + + if (level > player.prayer.current) { + player.sendMessage("You need a prayer level of $level to use this prayer.") terminate() return@then } - updatePrayer(it, prayer) + + player.updatePrayer(prayer) terminate() } on { ItemOptionMessage::class } - .where { option == 1 } - .then { - val bone = Bone[id] ?: return@then + .where { option == BuryBoneAction.BURY_OPTION && id.isBone() } + .then { player -> + val bone = Bone[id]!! - it.startAction(BuryBoneAction(it, slot, bone)) + player.startAction(BuryBoneAction(player, slot, bone)) terminate() - } - -class BuryBoneAction(val player: Player, val slot: Int, val bone: Bone) : AsyncAction(0, true, player) { - override fun action(): ActionBlock = { - if (player.inventory.removeSlot(slot, 1) > 0) { - player.sendMessage("You dig a hole in the ground...") - player.playAnimation(BURY_BONE_ANIMATION) - - wait(1) //Wait for animation - - player.sendMessage("You bury the bones.") - player.prayer.experience += bone.xp - } - - stop() - } -} \ No newline at end of file + } \ No newline at end of file From 6e94f4c7d0507ae980ca8d30b047fbb154a76c6d Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 8 Apr 2018 04:14:41 +0100 Subject: [PATCH 109/209] Add kotlin continuation indent to editorconfig --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index 4430bd40f..723b479c2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,7 @@ tab_width=4 [*.{kt, kts}] indent_style=space tab_width=4 +continuation_indent_size=4 [*.rb] indent_style=space From 275da1331b5ce5e4f1af56fe8025ecc39886f4a5 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 8 Apr 2018 05:15:48 +0100 Subject: [PATCH 110/209] Remove command utilities plugin --- game/plugin/cmd/build.gradle | 3 +- game/plugin/cmd/src/animate-cmd.plugin.kts | 15 ++-- game/plugin/cmd/src/item-cmd.plugin.kts | 18 ++--- game/plugin/cmd/src/lookup.plugin.kts | 77 ++++++++------------ game/plugin/cmd/src/teleport-cmd.plugin.kts | 79 ++++++++++----------- game/plugin/entity/following/build.gradle | 1 - game/plugin/util/command/build.gradle | 3 - game/plugin/util/command/src/command.kt | 22 ------ 8 files changed, 86 insertions(+), 132 deletions(-) delete mode 100644 game/plugin/util/command/build.gradle delete mode 100644 game/plugin/util/command/src/command.kt diff --git a/game/plugin/cmd/build.gradle b/game/plugin/cmd/build.gradle index 6ff14b6b7..051b171ca 100644 --- a/game/plugin/cmd/build.gradle +++ b/game/plugin/cmd/build.gradle @@ -7,7 +7,6 @@ plugin { "cubeee", ] dependencies = [ - "api", - "util:command", + "api" ] } \ No newline at end of file diff --git a/game/plugin/cmd/src/animate-cmd.plugin.kts b/game/plugin/cmd/src/animate-cmd.plugin.kts index 427860207..20993a93c 100644 --- a/game/plugin/cmd/src/animate-cmd.plugin.kts +++ b/game/plugin/cmd/src/animate-cmd.plugin.kts @@ -1,18 +1,15 @@ -import com.google.common.primitives.Ints import org.apollo.game.model.Animation import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.util.command.valid_arg_length on_command("animate", PrivilegeLevel.MODERATOR) .then { player -> - val invalidSyntax = "Invalid syntax - ::animate [animation-id]" - if (valid_arg_length(arguments, 1, player, invalidSyntax)) { - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) + arguments.firstOrNull() + ?.let(String::toIntOrNull) + ?.let(::Animation) + ?.let { + player.playAnimation(it) return@then } - player.playAnimation(Animation(id)) - } + player.sendMessage("Invalid syntax - ::animate [animation-id]") } \ No newline at end of file diff --git a/game/plugin/cmd/src/item-cmd.plugin.kts b/game/plugin/cmd/src/item-cmd.plugin.kts index 97f3b8ace..f6c27ab85 100644 --- a/game/plugin/cmd/src/item-cmd.plugin.kts +++ b/game/plugin/cmd/src/item-cmd.plugin.kts @@ -1,29 +1,31 @@ import com.google.common.primitives.Ints import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.util.command.valid_arg_length on_command("item", PrivilegeLevel.ADMINISTRATOR) .then { player -> - val invalidSyntax = "Invalid syntax - ::item [id] [amount]" - if (!valid_arg_length(arguments, 1..2, player, invalidSyntax)) { + if (arguments.size !in 1..2) { + player.sendMessage("Invalid syntax - ::item [id] [amount]") return@then } val id = Ints.tryParse(arguments[0]) if (id == null) { - player.sendMessage(invalidSyntax) + player.sendMessage("Invalid syntax - ::item [id] [amount]") return@then } - var amount = 1 - if (arguments.size == 2) { + val amount = if (arguments.size == 2) { val amt = Ints.tryParse(arguments[1]) + if (amt == null) { - player.sendMessage(invalidSyntax) + player.sendMessage("Invalid syntax - ::item [id] [amount]") return@then } - amount = amt + + amt + } else { + 1 } if (id < 0 || id >= ItemDefinition.count()) { diff --git a/game/plugin/cmd/src/lookup.plugin.kts b/game/plugin/cmd/src/lookup.plugin.kts index 8f844ecc3..80d5178c0 100644 --- a/game/plugin/cmd/src/lookup.plugin.kts +++ b/game/plugin/cmd/src/lookup.plugin.kts @@ -1,67 +1,52 @@ -import com.google.common.primitives.Ints -import org.apollo.cache.def.ItemDefinition -import org.apollo.cache.def.NpcDefinition -import org.apollo.cache.def.ObjectDefinition import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.util.command.valid_arg_length +import org.apollo.game.plugin.api.Definitions on_command("iteminfo", PrivilegeLevel.ADMINISTRATOR) .then { player -> - val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" - if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { - return@then - } + arguments.firstOrNull() + ?.let(String::toIntOrNull) + ?.let(Definitions::item) + ?.apply { + val members = if (isMembersOnly) "members" else "not members" - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + player.sendMessage("Item $id is called $name and is $members only.") + player.sendMessage("Its description is `$description`.") - val definition = ItemDefinition.lookup(id) - val members = if (definition.isMembersOnly) "members" else "not members" + return@then + } - player.sendMessage("Item $id is called ${definition.name}, is $members only, and has a " + - "team of ${definition.team}.") - player.sendMessage("Its description is \"${definition.description}\".") + player.sendMessage("Invalid syntax - ::iteminfo [item id]") } on_command("npcinfo", PrivilegeLevel.ADMINISTRATOR) .then { player -> - val invalidSyntax = "Invalid syntax - ::npcinfo [npc id]" - if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { - return@then - } + arguments.firstOrNull() + ?.let(String::toIntOrNull) + ?.let(Definitions::npc) + ?.apply { + val combat = if (hasCombatLevel()) "has a combat level of $combatLevel" else + "does not have a combat level" - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + player.sendMessage("Npc $id is called $name and $combat.") + player.sendMessage("Its description is `$description`.") - val definition = NpcDefinition.lookup(id) - val isCombative = if (definition.hasCombatLevel()) "has a combat level of ${definition.combatLevel}" else - "does not have a combat level" + return@then + } - player.sendMessage("Npc $id is called ${definition.name} and $isCombative.") - player.sendMessage("Its description is \"${definition.description}\".") + player.sendMessage("Invalid syntax - ::npcinfo [npc id]") } on_command("objectinfo", PrivilegeLevel.ADMINISTRATOR) .then { player -> - val invalidSyntax = "Invalid syntax - ::objectinfo [object id]" - if (!valid_arg_length(arguments, 1, player, invalidSyntax)) { - return@then - } + arguments.firstOrNull() + ?.let(String::toIntOrNull) + ?.let(Definitions::obj) + ?.apply { + player.sendMessage("Object ${arguments[0]} is called $name (width=$width, length=$length).") + player.sendMessage("Its description is `$description`.") - val id = Ints.tryParse(arguments[0]) - if (id == null) { - player.sendMessage(invalidSyntax) - return@then - } + return@then + } - val definition = ObjectDefinition.lookup(id) - player.sendMessage("Object $id is called ${definition.name} and its description is " + - "\"${definition.description}\".") - player.sendMessage("Its width is ${definition.width} and its length is ${definition.length}.") + player.sendMessage("Invalid syntax - ::objectinfo [object id]") } \ No newline at end of file diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index bd1162ccc..381118a45 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -2,7 +2,6 @@ import com.google.common.primitives.Ints import org.apollo.game.model.Position import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.util.command.valid_arg_length import org.apollo.game.plugins.api.Position.component1 import org.apollo.game.plugins.api.Position.component2 import org.apollo.game.plugins.api.Position.component3 @@ -18,39 +17,6 @@ on_command("pos", PrivilegeLevel.MODERATOR) player.sendMessage("You are at: ($x, $y, $z) in region (${region.x}, ${region.y}).") } -val TELEPORT_DESTINATIONS = listOf( - "alkharid" to Position(3292, 3171, 0), - "ardougne" to Position(2662, 3304, 0), - "barrows" to Position(3565, 3314, 0), - "brimhaven" to Position(2802, 3179, 0), - "burthorpe" to Position(2898, 3545, 0), - "camelot" to Position(2757, 3478, 0), - "canifis" to Position(3493, 3489, 0), - "cw" to Position(2442, 3090, 0), - "draynor" to Position(3082, 3249, 0), - "duelarena" to Position(3370, 3267, 0), - "edgeville" to Position(3087, 3504, 0), - "entrana" to Position(2827, 3343, 0), - "falador" to Position(2965, 3379, 0), - "ge" to Position(3164, 3476, 0), - "kbd" to Position(2273, 4680, 0), - "keldagrim" to Position(2845, 10210, 0), - "kq" to Position(3507, 9494, 0), - "lumbridge" to Position(3222, 3219, 0), - "lunar" to Position(2113, 3915, 0), - "misc" to Position(2515, 3866, 0), - "neit" to Position(2332, 3804, 0), - "pc" to Position(2658, 2660, 0), - "rellekka" to Position(2660, 3657, 0), - "shilo" to Position(2852, 2955, 0), - "taverley" to Position(2895, 3443, 0), - "tutorial" to Position(3094, 3107, 0), - "tzhaar" to Position(2480, 5175, 0), - "varrock" to Position(3212, 3423, 0), - "yanille" to Position(2605, 3096, 0), - "zanaris" to Position(2452, 4473, 0) -) - /** * Teleports the player to the specified position. */ @@ -60,16 +26,13 @@ on_command("tele", PrivilegeLevel.ADMINISTRATOR) if (arguments.size == 1) { val query = arguments[0] - val results = TELEPORT_DESTINATIONS.filter { - (name, _) -> name.startsWith(query) - } + val results = TELEPORT_DESTINATIONS.filter { (name) -> name.startsWith(query) } - if (results.size == 0) { + if (results.isEmpty()) { player.sendMessage("No destinations matching '$query'.") return@then } else if (results.size > 1) { - player.sendMessage("Ambiguous query '$query' (could " + - "be $results). Please disambiguate.") + player.sendMessage("Ambiguous query '$query' (could be $results). Please disambiguate.") return@then } @@ -80,7 +43,8 @@ on_command("tele", PrivilegeLevel.ADMINISTRATOR) return@then } - if (!valid_arg_length(arguments, 2..3, player, invalidSyntax)) { + if (arguments.size !in 2..3) { + player.sendMessage(invalidSyntax) return@then } @@ -110,3 +74,36 @@ on_command("tele", PrivilegeLevel.ADMINISTRATOR) player.teleport(Position(x, y, z)) } } + +private val TELEPORT_DESTINATIONS = listOf( + "alkharid" to Position(3292, 3171, 0), + "ardougne" to Position(2662, 3304, 0), + "barrows" to Position(3565, 3314, 0), + "brimhaven" to Position(2802, 3179, 0), + "burthorpe" to Position(2898, 3545, 0), + "camelot" to Position(2757, 3478, 0), + "canifis" to Position(3493, 3489, 0), + "cw" to Position(2442, 3090, 0), + "draynor" to Position(3082, 3249, 0), + "duelarena" to Position(3370, 3267, 0), + "edgeville" to Position(3087, 3504, 0), + "entrana" to Position(2827, 3343, 0), + "falador" to Position(2965, 3379, 0), + "ge" to Position(3164, 3476, 0), + "kbd" to Position(2273, 4680, 0), + "keldagrim" to Position(2845, 10210, 0), + "kq" to Position(3507, 9494, 0), + "lumbridge" to Position(3222, 3219, 0), + "lunar" to Position(2113, 3915, 0), + "misc" to Position(2515, 3866, 0), + "neit" to Position(2332, 3804, 0), + "pc" to Position(2658, 2660, 0), + "rellekka" to Position(2660, 3657, 0), + "shilo" to Position(2852, 2955, 0), + "taverley" to Position(2895, 3443, 0), + "tutorial" to Position(3094, 3107, 0), + "tzhaar" to Position(2480, 5175, 0), + "varrock" to Position(3212, 3423, 0), + "yanille" to Position(2605, 3096, 0), + "zanaris" to Position(2452, 4473, 0) +) \ No newline at end of file diff --git a/game/plugin/entity/following/build.gradle b/game/plugin/entity/following/build.gradle index 7ebc73f9c..a252080ec 100644 --- a/game/plugin/entity/following/build.gradle +++ b/game/plugin/entity/following/build.gradle @@ -5,7 +5,6 @@ plugin { ] dependencies = [ "entity:walk-to", - "util:command", "entity:player-action", ] } \ No newline at end of file diff --git a/game/plugin/util/command/build.gradle b/game/plugin/util/command/build.gradle deleted file mode 100644 index 3648da32f..000000000 --- a/game/plugin/util/command/build.gradle +++ /dev/null @@ -1,3 +0,0 @@ -plugin { - name = "command_utilities" - } \ No newline at end of file diff --git a/game/plugin/util/command/src/command.kt b/game/plugin/util/command/src/command.kt deleted file mode 100644 index dd17c26c4..000000000 --- a/game/plugin/util/command/src/command.kt +++ /dev/null @@ -1,22 +0,0 @@ -package org.apollo.game.plugin.util.command - -import org.apollo.game.model.entity.Player - -/** - * Checks whether the amount of arguments provided is correct, sending the player the specified - * message if not. - */ -fun valid_arg_length(args: Array, length: IntRange, player: Player, message: String): Boolean { - val valid = length.contains(args.size) - if (!valid) { - player.sendMessage(message) - } - return valid -} - -/** - * Checks whether the amount of arguments provided is correct, sending the player the specified - * message if not. - */ -fun valid_arg_length(args: Array, length: Int, player: Player, message: String) - = valid_arg_length(args, IntRange(length, length), player, message) \ No newline at end of file From d2a197f680beb58f745159c630aa2b418d560105 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 8 Apr 2018 15:46:06 +0100 Subject: [PATCH 111/209] Fix typo in shops dsl --- game/plugin/shops/src/dsl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/plugin/shops/src/dsl.kt b/game/plugin/shops/src/dsl.kt index 7aba837bf..639ccb166 100644 --- a/game/plugin/shops/src/dsl.kt +++ b/game/plugin/shops/src/dsl.kt @@ -343,7 +343,7 @@ class SellBuilder(val amount: Int, val items: MutableList>) { * Overloads the unary minus on Pairs so that name+id pairs can be listed. Only intended to be used with the * overloaded String invokation operator. */ // ShopBuilder uses the lookup plugin, which can operate on _ids tacked on the end - operator fun Pair.unaryMinus() = items.add(Pair("{$this.first}_${this.second}", amount)) + operator fun Pair.unaryMinus() = items.add(Pair("${this.first}_${this.second}", amount)) /** * Overloads function invokation on Strings to map `"ambiguous_npc_name"(id)` to a [Pair]. From fdabea8162dea10db8fff95d3b1fbd65b978584c Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 8 Apr 2018 16:19:29 +0100 Subject: [PATCH 112/209] Add gradle to .editorconfig --- .editorconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.editorconfig b/.editorconfig index 723b479c2..3a188f337 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,6 +13,11 @@ indent_style=space tab_width=4 continuation_indent_size=4 +[*.gradle] +indent_style=space +tab_width=4 +continuation_indent_size=4 + [*.rb] indent_style=space indent_size=2 From 8fe09880b7d6cdd45ee4874bdf47d300d4712f69 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 8 Apr 2018 16:19:02 +0100 Subject: [PATCH 113/209] Remove util:lookup plugin Behaviour moved into the api plugin. --- game/plugin/api/src/definitions.kt | 34 +++++++++++++++++ .../test/NamedLookupTests.kt} | 6 +-- game/plugin/entity/spawn/build.gradle | 2 +- game/plugin/entity/spawn/src/spawn.plugin.kts | 18 ++++----- game/plugin/shops/build.gradle | 8 ++-- game/plugin/shops/src/dsl.kt | 7 ++-- game/plugin/skills/fishing/build.gradle | 11 +++--- game/plugin/skills/prayer/build.gradle | 2 +- game/plugin/skills/runecrafting/build.gradle | 10 +++-- game/plugin/util/lookup/build.gradle | 3 -- game/plugin/util/lookup/src/lookup.kt | 37 ------------------- 11 files changed, 66 insertions(+), 72 deletions(-) rename game/plugin/{util/lookup/test/LookupTests.kt => api/test/NamedLookupTests.kt} (67%) delete mode 100644 game/plugin/util/lookup/build.gradle delete mode 100644 game/plugin/util/lookup/src/lookup.kt diff --git a/game/plugin/api/src/definitions.kt b/game/plugin/api/src/definitions.kt index 69966d43c..b2f826e5f 100644 --- a/game/plugin/api/src/definitions.kt +++ b/game/plugin/api/src/definitions.kt @@ -9,11 +9,45 @@ object Definitions { return ItemDefinition.lookup(id) } + fun item(name: String): ItemDefinition? { + return findEntity(ItemDefinition::getDefinitions, ItemDefinition::getName, name) + } + fun obj(id: Int): ObjectDefinition? { return ObjectDefinition.lookup(id) } + fun obj(name: String): ObjectDefinition? { + return findEntity(ObjectDefinition::getDefinitions, ObjectDefinition::getName, name) + } + fun npc(id: Int): NpcDefinition? { return NpcDefinition.lookup(id) } + + fun npc(name: String): NpcDefinition? { + return findEntity(NpcDefinition::getDefinitions, NpcDefinition::getName, name) + } + + /** + * The [Regex] used to match 'names' that have an id attached to the end. + */ + private val ID_REGEX = Regex(".+_[0-9]+$") + + private fun findEntity( + definitionsProvider: () -> Array, + nameSupplier: T.() -> String, + name: String + ): T? { + val definitions = definitionsProvider.invoke() + + if (ID_REGEX matches name) { + val id = name.substring(name.lastIndexOf('_') + 1, name.length).toInt() + return definitions.getOrNull(id) + } + + val normalizedName = name.replace('_', ' ') + return definitions.firstOrNull { it.nameSupplier().equals(normalizedName, ignoreCase = true) } + } + } \ No newline at end of file diff --git a/game/plugin/util/lookup/test/LookupTests.kt b/game/plugin/api/test/NamedLookupTests.kt similarity index 67% rename from game/plugin/util/lookup/test/LookupTests.kt rename to game/plugin/api/test/NamedLookupTests.kt index 680c9c158..4f361db68 100644 --- a/game/plugin/util/lookup/test/LookupTests.kt +++ b/game/plugin/api/test/NamedLookupTests.kt @@ -1,10 +1,10 @@ import org.apollo.cache.def.ItemDefinition +import org.apollo.game.plugin.api.Definitions import org.apollo.game.plugin.testing.KotlinPluginTest -import org.apollo.game.plugin.util.lookup.lookup_item import org.assertj.core.api.Assertions.assertThat import org.junit.Test -class LookupTests : KotlinPluginTest() { +class NamedLookupTests : KotlinPluginTest() { @Test fun itemLookup() { val testItem = ItemDefinition(0) @@ -12,6 +12,6 @@ class LookupTests : KotlinPluginTest() { ItemDefinition.init(arrayOf(testItem)) - assertThat(lookup_item("sword")).isEqualTo(testItem) + assertThat(Definitions.item("sword")).isEqualTo(testItem) } } \ No newline at end of file diff --git a/game/plugin/entity/spawn/build.gradle b/game/plugin/entity/spawn/build.gradle index adc0d4668..e0bb28287 100644 --- a/game/plugin/entity/spawn/build.gradle +++ b/game/plugin/entity/spawn/build.gradle @@ -4,6 +4,6 @@ plugin { "Gary Tierney", ] dependencies = [ - "util:lookup", + "api", ] } \ No newline at end of file diff --git a/game/plugin/entity/spawn/src/spawn.plugin.kts b/game/plugin/entity/spawn/src/spawn.plugin.kts index 0f172491b..87e3bb51c 100644 --- a/game/plugin/entity/spawn/src/spawn.plugin.kts +++ b/game/plugin/entity/spawn/src/spawn.plugin.kts @@ -1,18 +1,18 @@ -import org.apollo.cache.def.NpcDefinition + import org.apollo.game.model.entity.Npc +import org.apollo.game.plugin.api.Definitions import org.apollo.game.plugin.entity.spawn.Spawns -import org.apollo.game.plugin.util.lookup.lookup_npc start { world -> - Spawns.list.forEach { - val definition = it.id?.let { NpcDefinition.lookup(it) } ?: lookup_npc(it.name) ?: - throw IllegalArgumentException("Invalid NPC name or ID ${it.name}, ${it.id}") + Spawns.list.forEach { spawn -> + val definition = spawn.id?.let(Definitions::npc) ?: Definitions.npc(spawn.name) + ?: throw IllegalArgumentException("Invalid NPC name or ID ${spawn.name}, ${spawn.id}") - val npc = Npc(world, definition.id, it.position) - npc.turnTo(it.position.step(1, it.facing)) + val npc = Npc(world, definition.id, spawn.position) + npc.turnTo(spawn.position.step(1, spawn.facing)) - it.spawnAnimation?.let(npc::playAnimation) - it.spawnGraphic?.let(npc::playGraphic) + spawn.spawnAnimation?.let(npc::playAnimation) + spawn.spawnGraphic?.let(npc::playGraphic) world.register(npc) } diff --git a/game/plugin/shops/build.gradle b/game/plugin/shops/build.gradle index 2532af029..369bf235d 100644 --- a/game/plugin/shops/build.gradle +++ b/game/plugin/shops/build.gradle @@ -1,11 +1,11 @@ plugin { name = "shops" authors = [ - "Stuart", - "Major", - "tlf30" + "Stuart", + "Major", + "tlf30" ] dependencies = [ - "util:lookup", + "api", ] } diff --git a/game/plugin/shops/src/dsl.kt b/game/plugin/shops/src/dsl.kt index 639ccb166..b5f5da39d 100644 --- a/game/plugin/shops/src/dsl.kt +++ b/game/plugin/shops/src/dsl.kt @@ -1,9 +1,8 @@ package org.apollo.game.plugin.shops import org.apollo.cache.def.NpcDefinition +import org.apollo.game.plugin.api.Definitions import org.apollo.game.plugin.shops.CategoryWrapper.Affix -import org.apollo.game.plugin.util.lookup.lookup_item -import org.apollo.game.plugin.util.lookup.lookup_npc /** * Creates a [Shop]. @@ -109,7 +108,7 @@ class ShopBuilder(val name: String) { * Converts this builder into a [Shop]. */ internal fun build(): Shop { - val items = sold.associateBy({ (first) -> lookup_item(first)!!.id }, Pair::second) + val items = sold.associateBy({ (first) -> Definitions.item(first)!!.id }, Pair::second) val npc = NpcDefinition.lookup(operators().first()) return Shop(name, action.action(npc), items, trades.currency, buys.policy) @@ -174,7 +173,7 @@ class OperatorBuilder internal constructor() { * Adds a shop operator, using the specified [name] to resolve the npc id. */ infix fun by(name: String): OperatorBuilder { - operators.add(lookup_npc(name)!!.id) + operators.add(Definitions.npc(name)!!.id) return this } diff --git a/game/plugin/skills/fishing/build.gradle b/game/plugin/skills/fishing/build.gradle index a7c3c5df2..435281cb3 100644 --- a/game/plugin/skills/fishing/build.gradle +++ b/game/plugin/skills/fishing/build.gradle @@ -1,13 +1,12 @@ plugin { name = "fishing_skill" authors = [ - "Linux", - "Major", - "tlf30" + "Linux", + "Major", + "tlf30" ] dependencies = [ - "api", - "entity:spawn", - "util:lookup" + "api", + "entity:spawn", ] } diff --git a/game/plugin/skills/prayer/build.gradle b/game/plugin/skills/prayer/build.gradle index fa5c27cec..5ea5c0b26 100644 --- a/game/plugin/skills/prayer/build.gradle +++ b/game/plugin/skills/prayer/build.gradle @@ -6,6 +6,6 @@ plugin { "tlf30" ] dependencies = [ - "util:lookup", "api" + "api" ] } diff --git a/game/plugin/skills/runecrafting/build.gradle b/game/plugin/skills/runecrafting/build.gradle index 123631a8d..74ddffb6f 100644 --- a/game/plugin/skills/runecrafting/build.gradle +++ b/game/plugin/skills/runecrafting/build.gradle @@ -1,10 +1,12 @@ plugin { name = "runecrafting-skill" authors = [ - "Major", - "BugCrusher", - "tlf30" + "Major", + "BugCrusher", + "tlf30" ] - dependencies = ["util:lookup", "api"] + dependencies = [ + "api" + ] } \ No newline at end of file diff --git a/game/plugin/util/lookup/build.gradle b/game/plugin/util/lookup/build.gradle deleted file mode 100644 index 6c225ddfa..000000000 --- a/game/plugin/util/lookup/build.gradle +++ /dev/null @@ -1,3 +0,0 @@ -plugin { - name = "entity_lookup" - } \ No newline at end of file diff --git a/game/plugin/util/lookup/src/lookup.kt b/game/plugin/util/lookup/src/lookup.kt deleted file mode 100644 index 895d63c30..000000000 --- a/game/plugin/util/lookup/src/lookup.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.apollo.game.plugin.util.lookup - -import org.apollo.cache.def.ItemDefinition -import org.apollo.cache.def.NpcDefinition -import org.apollo.cache.def.ObjectDefinition - -fun lookup_object(name: String): ObjectDefinition? { - return find_entity(ObjectDefinition::getDefinitions, ObjectDefinition::getName, name) -} - -fun lookup_npc(name: String): NpcDefinition? { - return find_entity(NpcDefinition::getDefinitions, NpcDefinition::getName, name) -} - -fun lookup_item(name: String): ItemDefinition? { - return find_entity(ItemDefinition::getDefinitions, ItemDefinition::getName, name) -} - -/** - * The [Regex] used to match 'names' that have an id attached to the end. - */ -private val ID_REGEX = Regex(".+_[0-9]+$") - -private fun find_entity(definitionsProvider: () -> Array, - nameSupplier: T.() -> String, - name: String): T? { - val definitions = definitionsProvider.invoke() - - if (ID_REGEX matches name) { - val id = name.substring(name.lastIndexOf('_') + 1, name.length).toInt() - return definitions.getOrNull(id) - } - - val normalizedName = name.replace('_', ' ') - - return definitions.firstOrNull { it.nameSupplier().equals(normalizedName, true) } -} \ No newline at end of file From 90659291ea6c5d96128eab410f1261a89c4d2fb8 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 28 Sep 2017 19:57:59 +0100 Subject: [PATCH 114/209] Add Slack invite link to the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26786ba1e..46147d6b6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Apollo is a high-performance, modular RuneScape emulator with a collection of ut ### Developer information -Most discussion related to the development of Apollo happens on the IRC channel _#apollorsps_ on _irc.freenode.net_. If you have a problem and can't get in touch with anyone, create a GitHub issue. If making a pull request, please make sure all tests are still passing after making your changes, and that your code style is consistent with the rest of Apollo. +Most discussion related to the development of Apollo happens on our [Slack team](https://join.slack.com/t/apollo-rsps/shared_invite/enQtMjQ0NTYwNzkwMjExLTI5NGVmOWZjZGRkYzY4NjM1MjgxNjYyYmEyZWQxMzcxZTA5NDM1MGJkNmRkMjc2ZDQ2NjUwMjAzOGI1NjY1Zjk). If you have a problem and can't get in touch with anyone, create a GitHub issue. If making a pull request, please make sure all tests are still passing after making your changes, and that your code style is consistent with the rest of Apollo. ### Getting started From b74be81f057517d07893ae996641ebb36da2f5ea Mon Sep 17 00:00:00 2001 From: Steve Soltys Date: Sat, 14 Jul 2018 12:12:19 -0400 Subject: [PATCH 115/209] Fix numerical attribute encoding --- .../org/apollo/game/model/entity/attr/NumericalAttribute.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/game/src/main/java/org/apollo/game/model/entity/attr/NumericalAttribute.java b/game/src/main/java/org/apollo/game/model/entity/attr/NumericalAttribute.java index 0aa287006..48b53f469 100644 --- a/game/src/main/java/org/apollo/game/model/entity/attr/NumericalAttribute.java +++ b/game/src/main/java/org/apollo/game/model/entity/attr/NumericalAttribute.java @@ -30,13 +30,13 @@ public NumericalAttribute(Number value) { @Override public byte[] encode() { - long encoded = type == AttributeType.DOUBLE ? Double.doubleToLongBits((double) value) : (long) value; + long encoded = type == AttributeType.DOUBLE ? Double.doubleToLongBits(value.doubleValue()) : value.longValue(); return Longs.toByteArray(encoded); } @Override public String toString() { - return type == AttributeType.DOUBLE ? Double.toString((double) value) : Long.toString((long) value); + return type == AttributeType.DOUBLE ? Double.toString(value.doubleValue()) : Long.toString(value.longValue()); } } \ No newline at end of file From c44a94297680b1892ff6d3252c45c38663143568 Mon Sep 17 00:00:00 2001 From: Steve Soltys Date: Wed, 18 Jul 2018 18:56:20 -0400 Subject: [PATCH 116/209] Optimize collision matrix building --- .../area/collision/CollisionManager.java | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/game/src/main/java/org/apollo/game/model/area/collision/CollisionManager.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionManager.java index 4b54b36ac..d8a428ff7 100644 --- a/game/src/main/java/org/apollo/game/model/area/collision/CollisionManager.java +++ b/game/src/main/java/org/apollo/game/model/area/collision/CollisionManager.java @@ -1,19 +1,21 @@ package org.apollo.game.model.area.collision; import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.apollo.game.model.Direction; import org.apollo.game.model.Position; import org.apollo.game.model.area.Region; +import org.apollo.game.model.area.RegionCoordinates; import org.apollo.game.model.area.RegionRepository; import org.apollo.game.model.area.collision.CollisionUpdate.DirectionFlag; import org.apollo.game.model.entity.EntityType; import org.apollo.game.model.entity.obj.GameObject; import java.util.Collection; -import java.util.Comparator; +import java.util.HashSet; import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.Set; import static org.apollo.game.model.entity.EntityType.DYNAMIC_OBJECT; import static org.apollo.game.model.entity.EntityType.STATIC_OBJECT; @@ -25,20 +27,14 @@ public final class CollisionManager { /** - * A comparator that sorts {@link Position}s by their X coordinate, then Y, then height. + * A {@code HashMultimap} of region coordinates mapped to positions where the tile is completely blocked. */ - private static final Comparator POSITION_COMPARATOR = - Comparator.comparingInt(Position::getX).thenComparingInt(Position::getY).thenComparingInt(Position::getHeight); + private final Multimap blocked = HashMultimap.create(); /** - * A {@code SortedSet} of positions where the tile is part of a bridged structure. + * A {@code HashSet} of positions where the tile is part of a bridged structure. */ - private final SortedSet bridges = new TreeSet<>(POSITION_COMPARATOR); - - /** - * A {@code SortedSet} of positions where the tile is completely blocked. - */ - private final SortedSet blocked = new TreeSet<>(POSITION_COMPARATOR); + private final Set bridges = new HashSet<>(); /** * The {@link RegionRepository} used to lookup {@link CollisionMatrix} objects. @@ -69,31 +65,33 @@ public void build(boolean rebuilding) { } } - CollisionUpdate.Builder builder = new CollisionUpdate.Builder(); - builder.type(CollisionUpdateType.ADDING); + regions.getRegions().forEach(region -> { + CollisionUpdate.Builder builder = new CollisionUpdate.Builder(); + builder.type(CollisionUpdateType.ADDING); - for (Position tile : blocked) { - int x = tile.getX(), y = tile.getY(); - int height = tile.getHeight(); + blocked.get(region.getCoordinates()).forEach(tile -> { + int x = tile.getX(), y = tile.getY(); + int height = tile.getHeight(); - if (bridges.contains(new Position(x, y, 1))) { - height--; - } + if (bridges.contains(new Position(x, y, 1))) { + height--; + } - if (height >= 0) { - builder.tile(new Position(x, y, height), false, Direction.NESW); - } - } + if (height >= 0) { + builder.tile(new Position(x, y, height), false, Direction.NESW); + } + }); - apply(builder.build()); + apply(builder.build()); - for (Region region : regions.getRegions()) { CollisionUpdate.Builder objects = new CollisionUpdate.Builder(); objects.type(CollisionUpdateType.ADDING); - region.getEntities(STATIC_OBJECT, DYNAMIC_OBJECT).forEach(entity -> objects.object((GameObject) entity)); + region.getEntities(STATIC_OBJECT, DYNAMIC_OBJECT) + .forEach(entity -> objects.object((GameObject) entity)); + apply(objects.build()); - } + }); } /** @@ -255,7 +253,7 @@ private void flag(CollisionUpdateType type, CollisionMatrix matrix, int localX, * @param position The {@link Position} of the tile. */ public void block(Position position) { - blocked.add(position); + blocked.put(position.getRegionCoordinates(), position); } /** From 84f05ef51a0f32f4a4ec8bab27dcb27947805546 Mon Sep 17 00:00:00 2001 From: Steve Soltys Date: Sun, 22 Jul 2018 15:14:03 -0400 Subject: [PATCH 117/209] Add support for checking the bounds of entities --- .../org/apollo/game/model/entity/Entity.java | 33 +++++++++++++ .../game/model/entity/EntityBounds.java | 48 +++++++++++++++++++ .../apollo/game/model/entity/GroundItem.java | 10 ++++ .../org/apollo/game/model/entity/Mob.java | 10 ++++ .../apollo/game/model/entity/Projectile.java | 10 ++++ .../game/model/entity/obj/GameObject.java | 19 +++++++- 6 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 game/src/main/java/org/apollo/game/model/entity/EntityBounds.java diff --git a/game/src/main/java/org/apollo/game/model/entity/Entity.java b/game/src/main/java/org/apollo/game/model/entity/Entity.java index 97e35349f..3f5a955a9 100644 --- a/game/src/main/java/org/apollo/game/model/entity/Entity.java +++ b/game/src/main/java/org/apollo/game/model/entity/Entity.java @@ -20,6 +20,11 @@ public abstract class Entity { */ protected final World world; + /** + * The EntityBounds for this Entity. + */ + private EntityBounds bounds; + /** * Creates the Entity. * @@ -34,6 +39,20 @@ public Entity(World world, Position position) { @Override public abstract boolean equals(Object obj); + /** + * Gets the {@link EntityBounds} for this Entity. + * + * @return The EntityBounds. + */ + public EntityBounds getBounds() { + + if(bounds == null) { + bounds = new EntityBounds(this); + } + + return bounds; + } + /** * Gets the {@link Position} of this Entity. * @@ -59,6 +78,20 @@ public World getWorld() { */ public abstract EntityType getEntityType(); + /** + * Gets the length of this Entity. + * + * @return The length. + */ + public abstract int getLength(); + + /** + * Gets the width of this Entity. + * + * @return The width. + */ + public abstract int getWidth(); + @Override public abstract int hashCode(); diff --git a/game/src/main/java/org/apollo/game/model/entity/EntityBounds.java b/game/src/main/java/org/apollo/game/model/entity/EntityBounds.java new file mode 100644 index 000000000..3d4c3a9ae --- /dev/null +++ b/game/src/main/java/org/apollo/game/model/entity/EntityBounds.java @@ -0,0 +1,48 @@ +package org.apollo.game.model.entity; + +import org.apollo.game.model.Position; + +/** + * The bounds of an {@link Entity}. + * + * @author Steve Soltys + */ +public class EntityBounds { + + /** + * The {@link Entity}. + */ + private final Entity entity; + + /** + * Creates an EntityBounds. + * + * @param entity The entity. + */ + EntityBounds(Entity entity) { + this.entity = entity; + } + + /** + * Checks whether the given position is within the Entity's bounds. + * + * @param position The position. + * @return A flag indicating whether or not the position exists within the Entity's bounds. + */ + public boolean contains(Position position) { + int positionX = position.getX(); + int positionY = position.getY(); + int positionHeight = position.getHeight(); + + int entityX = entity.getPosition().getX(); + int entityY = entity.getPosition().getY(); + int entityHeight = entity.getPosition().getHeight(); + + int width = entity.getWidth(); + int length = entity.getLength(); + + return positionX >= entityX && positionX < entityX + width && + positionY >= entityY && positionY < entityY + length && + positionHeight == entityHeight; + } +} diff --git a/game/src/main/java/org/apollo/game/model/entity/GroundItem.java b/game/src/main/java/org/apollo/game/model/entity/GroundItem.java index a81c612c1..a338d4149 100644 --- a/game/src/main/java/org/apollo/game/model/entity/GroundItem.java +++ b/game/src/main/java/org/apollo/game/model/entity/GroundItem.java @@ -80,6 +80,16 @@ public EntityType getEntityType() { return EntityType.GROUND_ITEM; } + @Override + public int getLength() { + return 1; + } + + @Override + public int getWidth() { + return 1; + } + /** * Gets the {@link Item} displayed on the ground. * diff --git a/game/src/main/java/org/apollo/game/model/entity/Mob.java b/game/src/main/java/org/apollo/game/model/entity/Mob.java index 82cdba964..4e90d48f1 100644 --- a/game/src/main/java/org/apollo/game/model/entity/Mob.java +++ b/game/src/main/java/org/apollo/game/model/entity/Mob.java @@ -327,6 +327,16 @@ public final WalkingQueue getWalkingQueue() { return walkingQueue; } + @Override + public int getLength() { + return definition.map(NpcDefinition::getSize).orElse(1); + } + + @Override + public int getWidth() { + return definition.map(NpcDefinition::getSize).orElse(1); + } + /** * Returns whether or not this mob has an {@link NpcDefinition}. * diff --git a/game/src/main/java/org/apollo/game/model/entity/Projectile.java b/game/src/main/java/org/apollo/game/model/entity/Projectile.java index db5459d89..a05f218b1 100644 --- a/game/src/main/java/org/apollo/game/model/entity/Projectile.java +++ b/game/src/main/java/org/apollo/game/model/entity/Projectile.java @@ -414,6 +414,16 @@ public EntityType getEntityType() { return EntityType.PROJECTILE; } + @Override + public int getLength() { + return 1; + } + + @Override + public int getWidth() { + return 1; + } + @Override public int hashCode() { return Objects.hashCode(position, destination, delay, lifetime, target, startHeight, diff --git a/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java b/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java index cdb0f749d..0d8391bfc 100644 --- a/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java +++ b/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java @@ -2,6 +2,7 @@ import org.apollo.cache.def.ObjectDefinition; import org.apollo.game.model.Position; +import org.apollo.game.model.Direction; import org.apollo.game.model.World; import org.apollo.game.model.area.EntityUpdateType; import org.apollo.game.model.area.Region; @@ -85,6 +86,23 @@ public int getType() { return packed >> 2 & 0x3F; } + + @Override + public int getLength() { + Direction direction = Direction.WNES[getOrientation()]; + + return direction == Direction.WEST || direction == Direction.EAST ? + getDefinition().getWidth() : getDefinition().getLength(); + } + + @Override + public int getWidth() { + Direction direction = Direction.WNES[getOrientation()]; + + return direction == Direction.WEST || direction == Direction.EAST ? + getDefinition().getLength() : getDefinition().getWidth(); + } + @Override public int hashCode() { return packed; @@ -109,5 +127,4 @@ public ObjectUpdateOperation toUpdateOperation(Region region, EntityUpdateType o * @return {@code true} if the Player can see this GameObject, {@code false} if not. */ public abstract boolean viewableBy(Player player, World world); - } \ No newline at end of file From 7fee8277ab974a993a03b820a6c4592337ad74a5 Mon Sep 17 00:00:00 2001 From: Steve Soltys Date: Mon, 30 Jul 2018 21:09:03 -0400 Subject: [PATCH 118/209] Fix A* pathfinding when height is greater than zero --- .../game/model/entity/path/AStarPathfindingAlgorithm.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/game/src/main/java/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java b/game/src/main/java/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java index 0f2f1bc7a..2b8482f52 100644 --- a/game/src/main/java/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java +++ b/game/src/main/java/org/apollo/game/model/entity/path/AStarPathfindingAlgorithm.java @@ -11,8 +11,6 @@ import org.apollo.game.model.Direction; import org.apollo.game.model.Position; -import org.apollo.game.model.World; -import org.apollo.game.model.area.RegionRepository; import org.apollo.game.model.area.collision.CollisionManager; /** @@ -76,7 +74,7 @@ public Deque find(Position origin, Position target) { continue; } - Position adjacent = new Position(nextX, nextY); + Position adjacent = new Position(nextX, nextY, position.getHeight()); Direction direction = Direction.between(adjacent, position); if (traversable(adjacent, direction)) { Node node = nodes.computeIfAbsent(adjacent, Node::new); From 0651d535fa360ca969ebe046e477c00353ed6fc0 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 19:26:51 +0100 Subject: [PATCH 119/209] Update to Kotlin 1.60 and Gradle 4.9 Removes the dependency on legacy script compilation and now relies on script discovery. In addition, the Gradle build scripts were refactored and updated to be compatible with Gradle 5.0 and make use of the new java-library configurations. --- .idea/kotlinc.xml | 15 ----- build.gradle | 55 ++++------------- buildSrc/build.gradle | 15 ----- buildSrc/settings.gradle | 0 .../build/plugin/ApolloPluginExtension.groovy | 21 ++----- cache/build.gradle | 7 ++- game/build.gradle | 50 ++++++---------- game/plugin-testing/build.gradle | 18 +++--- game/plugin/build.gradle | 39 ++---------- .../src/{spots.kts => spots.plugin.kts} | 6 +- .../game/model/entity/attr/AttributeMap.java | 3 - .../game/plugin/kotlin/KotlinPluginScript.kt | 8 +-- ...ollo.game.plugin.kotlin.KotlinPluginScript | 0 gradle/jacoco.gradle | 59 +++++++++++++++++++ gradle/kotlin.gradle | 5 ++ gradle/properties.gradle | 14 +++++ net/build.gradle | 14 ++++- properties.gradle | 3 - settings.gradle | 4 +- util/build.gradle | 14 +++++ 20 files changed, 170 insertions(+), 180 deletions(-) delete mode 100644 .idea/kotlinc.xml create mode 100644 buildSrc/settings.gradle rename game/plugin/skills/fishing/src/{spots.kts => spots.plugin.kts} (95%) create mode 100644 game/src/main/resources/META-INF/kotlin/script/templates/org.apollo.game.plugin.kotlin.KotlinPluginScript create mode 100644 gradle/jacoco.gradle create mode 100644 gradle/kotlin.gradle create mode 100644 gradle/properties.gradle delete mode 100644 properties.gradle diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml deleted file mode 100644 index ee4beb076..000000000 --- a/.idea/kotlinc.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5ce4fad5e..f8a414e4f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,52 +1,23 @@ -allprojects { - group = 'apollo' - version = '0.0.1' +plugins { + id 'org.jetbrains.kotlin.jvm' version "1.2.60" apply(false) } -apply from: 'properties.gradle' - -subprojects { - apply plugin: 'java' +wrapper { + gradleVersion = "4.9" + distributionType = Wrapper.DistributionType.ALL +} - sourceCompatibility = 1.8 - targetCompatibility = 1.8 +allprojects { + group = 'apollo' + version = '0.0.1' repositories { mavenLocal() maven { url "https://repo.maven.apache.org/maven2" } maven { url "https://dl.bintray.com/kotlin/kotlinx/" } } - - dependencies { - compile group: 'org.apache.commons', name: 'commons-compress', version: '1.10' - compile group: 'org.jruby', name: 'jruby-complete', version: '9.0.5.0' - compile group: 'com.google.guava', name: 'guava', version: '19.0' - compile group: 'io.netty', name: 'netty-all', version: '4.0.34.Final' - compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0' - compile group: 'com.mchange', name: 'c3p0', version: '0.9.5.2' - compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.54' - testCompile group: 'junit', name: 'junit', version: '4.12' - testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.6.4' - testCompile group: 'org.powermock', name: 'powermock-api-mockito', version: '1.6.4' - } - - sourceSets { - main { - java { - srcDirs = ['src/main/java'] - } - } - - test { - java { - srcDirs = ['src/test/java'] - } - } - } - - test { - testLogging { - events "passed", "skipped", "failed" - } - } } + +apply from: 'gradle/properties.gradle' +apply from: 'gradle/kotlin.gradle' +apply from: 'gradle/jacoco.gradle' \ No newline at end of file diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 76639e171..8768ea0f2 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,18 +1,5 @@ -apply plugin: 'kotlin' apply plugin: 'groovy' -buildscript { - apply from: '../properties.gradle' - - repositories { - mavenCentral() - } - - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - } -} - repositories { mavenLocal() maven { url "https://repo.maven.apache.org/maven2" } @@ -20,6 +7,4 @@ repositories { dependencies { compile gradleApi() - compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" - compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: "$kotlinVersion" } \ No newline at end of file diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 000000000..e69de29bb diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy index a87c60823..aa554e478 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -47,30 +47,19 @@ class ApolloPluginExtension { * and its scripts. */ def init() { - def gameProject = project.findProject(":game") - def pluginTestingProject = project.findProject(':game:plugin-testing') - project.plugins.apply('kotlin') project.dependencies { - def transitiveGameDeps = gameProject.configurations["compile"].dependencies - def gameSources = gameProject.sourceSets.main - - transitiveGameDeps.each { dependency -> - compile dependency - } - - compile gameSources.output - testCompile pluginTestingProject + implementation project.findProject(':game') + implementation project.findProject(':cache') + implementation project.findProject(':net') + implementation project.findProject(':util') + testImplementation project.findProject(':game:plugin-testing') } project.sourceSets { main.kotlin.srcDirs += this.srcDir test.kotlin.srcDirs += this.testDir } - - project.tasks["compileKotlin"].kotlinOptions.freeCompilerArgs += [ - "-script-templates", "org.apollo.game.plugin.kotlin.KotlinPluginScript" - ] } def getDependencies() { diff --git a/cache/build.gradle b/cache/build.gradle index 47511913d..b8542ce72 100644 --- a/cache/build.gradle +++ b/cache/build.gradle @@ -1,5 +1,10 @@ +plugins { + id "java-library" +} + description = 'Apollo Cache' dependencies { - compile project(':util') + implementation project(':util') + implementation group: 'com.google.guava', name: 'guava', version: guavaVersion } diff --git a/game/build.gradle b/game/build.gradle index 52b8ba6f0..4dfde3b38 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -1,44 +1,28 @@ -description = 'Apollo Game' - -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath group: 'org.jetbrains.kotlin', name: 'kotlin-gradle-plugin', version: "$kotlinVersion" - } +plugins { + id 'application' + id 'org.jetbrains.kotlin.jvm' + id 'org.jetbrains.kotlin.plugin.scripting' } -apply plugin: 'kotlin' - -allprojects { - it.plugins.withId('kotlin') { - kotlin { experimental { coroutines 'enable' } } - } -} +description = 'Apollo Game' +mainClassName = 'org.apollo.Server' dependencies { compile project(':cache') compile project(':net') compile project(':util') - compile group: 'io.github.lukehutch', name: 'fast-classpath-scanner', version: '2.0.21' - compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion" - compile group: 'org.jetbrains.kotlin', name: 'kotlin-script-runtime', version: "$kotlinVersion" - compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-jdk8', version: '0.16' - compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '0.16' + compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8' + compile group: 'org.jetbrains.kotlin', name: 'kotlin-scripting-common' + compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-jdk8', version: kotlinxCoroutinesVersion + compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: kotlinxCoroutinesVersion - project(":game:plugin").subprojects.each { plugin -> - runtime plugin - } + implementation group: 'com.google.guava', name: 'guava', version: guavaVersion + implementation group: 'io.github.lukehutch', name: 'fast-classpath-scanner', version: classpathScannerVersion + implementation group: 'com.lambdaworks', name: 'scrypt', version: scryptVersion - testCompile group: 'org.assertj', name: 'assertj-core', version: '3.8.0' + testImplementation group: 'junit', name: 'junit', version: junitVersion + testImplementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion + testImplementation group: 'org.powermock', name: 'powermock-api-mockito', version: powermockVersion + testImplementation group: 'org.assertj', name: 'assertj-core', version: assertjVersion } - -task run(type: JavaExec, dependsOn: classes) { - main = 'org.apollo.Server' - classpath = sourceSets.main.runtimeClasspath - jvmArgs = ['-Xmx1750M'] - workingDir = "$rootDir" -} \ No newline at end of file diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index b9735b373..ce0c1592d 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -1,13 +1,15 @@ -apply plugin: 'kotlin' +plugins { + id 'java-library' + id 'org.jetbrains.kotlin.jvm' +} dependencies { - compileOnly project(':game') - compile group: 'org.assertj', name: 'assertj-core', version: '3.8.0' + api project(':game') + api project(':net') - def gameTestConfiguration = project(':game').configurations.testCompile - def gameTestDependencies = gameTestConfiguration.dependencies + api group: 'junit', name: 'junit', version: junitVersion + api group: 'org.powermock', name: 'powermock-api-mockito', version: powermockVersion + api group: 'org.assertj', name: 'assertj-core', version: assertjVersion - gameTestDependencies.each { - compile it - } + implementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion } \ No newline at end of file diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index 74cfb889a..b1897a929 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,14 +1,5 @@ -buildscript { - repositories { - jcenter() - mavenCentral() - - maven { url "https://plugins.gradle.org/m2/" } - } - - dependencies { - classpath "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0.RC4-3" - } +plugins { + id "io.gitlab.arturbosch.detekt" version "1.0.0.RC8" apply(false) } def detektConfig = "${project.projectDir}/detekt.yml" @@ -18,33 +9,15 @@ subprojects { subproj -> apply plugin: 'apollo-plugin' apply plugin: 'io.gitlab.arturbosch.detekt' - buildscript { - repositories { - jcenter() - mavenCentral() - - maven { url "https://plugins.gradle.org/m2/" } - } - - dependencies { - classpath "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0.RC4-3" - } - } - - repositories { - mavenCentral() - maven { - url { 'https://dl.bintray.com/kotlin/kotlinx/' } - } - } - detekt { - version = "1.0.0.RC4-3" - profile("main") { input = "${subproj.projectDir}/src" config = detektConfig } } + + dependencies { + implementation group: 'com.google.guava', name: 'guava', version: guavaVersion + } } } diff --git a/game/plugin/skills/fishing/src/spots.kts b/game/plugin/skills/fishing/src/spots.plugin.kts similarity index 95% rename from game/plugin/skills/fishing/src/spots.kts rename to game/plugin/skills/fishing/src/spots.plugin.kts index b86b6e8f0..8aa824b6f 100644 --- a/game/plugin/skills/fishing/src/spots.kts +++ b/game/plugin/skills/fishing/src/spots.plugin.kts @@ -1,12 +1,10 @@ + import org.apollo.game.model.Direction import org.apollo.game.model.Position import org.apollo.game.plugin.entity.spawn.Spawn import org.apollo.game.plugin.entity.spawn.Spawns import org.apollo.game.plugin.skills.fishing.FishingSpot -import org.apollo.game.plugin.skills.fishing.FishingSpot.CAGE_HARPOON -import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_HARPOON -import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_ROD -import org.apollo.game.plugin.skills.fishing.FishingSpot.ROD +import org.apollo.game.plugin.skills.fishing.FishingSpot.* // Al-Kharid register(NET_ROD, x = 3267, y = 3148) diff --git a/game/src/main/java/org/apollo/game/model/entity/attr/AttributeMap.java b/game/src/main/java/org/apollo/game/model/entity/attr/AttributeMap.java index 0ee12779d..c521e7b79 100644 --- a/game/src/main/java/org/apollo/game/model/entity/attr/AttributeMap.java +++ b/game/src/main/java/org/apollo/game/model/entity/attr/AttributeMap.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.Map; -import org.jruby.RubySymbol; import com.google.common.base.Preconditions; @@ -118,8 +117,6 @@ private Attribute createAttribute(T value, AttributeType type) { return new NumericalAttribute((Double) value); case STRING: return new StringAttribute((String) value); - case SYMBOL: - return new StringAttribute(((RubySymbol) value).asJavaString(), true); case BOOLEAN: return new BooleanAttribute((Boolean) value); } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index a1b551513..fca5698d9 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -13,11 +13,11 @@ import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message import kotlin.reflect.KClass -import kotlin.script.templates.ScriptTemplateDefinition +import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.annotations.KotlinScriptFileExtension -@ScriptTemplateDefinition( - scriptFilePattern = ".*\\.plugin\\.kts" -) +@KotlinScript("Apollo Plugin Script") +@KotlinScriptFileExtension("plugin.kts") abstract class KotlinPluginScript(private var world: World, val context: PluginContext) { var startListener: (World) -> Unit = { _ -> } var stopListener: (World) -> Unit = { _ -> } diff --git a/game/src/main/resources/META-INF/kotlin/script/templates/org.apollo.game.plugin.kotlin.KotlinPluginScript b/game/src/main/resources/META-INF/kotlin/script/templates/org.apollo.game.plugin.kotlin.KotlinPluginScript new file mode 100644 index 000000000..e69de29bb diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle new file mode 100644 index 000000000..9d9267623 --- /dev/null +++ b/gradle/jacoco.gradle @@ -0,0 +1,59 @@ +apply plugin: "jacoco" + +allprojects { + tasks.withType(Test) { + jacoco { + toolVersion = '0.8.1' + } + + afterEvaluate { + jacocoTestReport { + dependsOn tasks.test + + sourceSets sourceSets.main + reports { + html.enabled = true + xml.enabled = true + csv.enabled = false + } + } + } + } +} + +task jacocoTestReport(type: JacocoReport) { + sourceDirectories = files() + classDirectories = files() + executionData = files() + + reports { + html.enabled = true + xml.enabled = true + csv.enabled = false + } + + // Work-around to allow us to build list of executionData files in doFirst + onlyIf = { + true + } + + /* + * Builds list of source dirs, class dirs, and executionData files + * when task is run, not at script evaluation time + */ + doFirst { + subprojects.findAll { subproject -> + subproject.pluginManager.hasPlugin('java') + }.each { subproject -> + additionalSourceDirs files((Set) subproject.sourceSets.main.allJava.srcDirs) + additionalClassDirs((FileCollection) subproject.sourceSets.main.output) + if (subproject.pluginManager.hasPlugin('jacoco')) { + executionData subproject.tasks.jacocoTestReport.executionData + } + } + + executionData = files(executionData.findAll { + it.exists() + }) + } +} \ No newline at end of file diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle new file mode 100644 index 000000000..0851617ec --- /dev/null +++ b/gradle/kotlin.gradle @@ -0,0 +1,5 @@ +allprojects { + plugins.withId('kotlin') { + kotlin { experimental { coroutines 'enable' } } + } +} \ No newline at end of file diff --git a/gradle/properties.gradle b/gradle/properties.gradle new file mode 100644 index 000000000..1eb5cd9af --- /dev/null +++ b/gradle/properties.gradle @@ -0,0 +1,14 @@ +ext { + kotlinVersion = '1.2.60' + kotlinxCoroutinesVersion = '0.24.0' + junitVersion = '4.12' + powermockVersion = '1.6.4' + bouncycastleVersion = '1.54' + c3p0Version = '0.9.5.2' + scryptVersion = '1.4.0' + nettyVersion = '4.0.34.Final' + guavaVersion = '19.0' + commonsCompressVersion = '1.10' + assertjVersion = '3.8.0' + classpathScannerVersion = '2.0.21' +} \ No newline at end of file diff --git a/net/build.gradle b/net/build.gradle index b004467da..7aa134bc5 100644 --- a/net/build.gradle +++ b/net/build.gradle @@ -1,6 +1,16 @@ +plugins { + id 'java-library' +} + description = 'Apollo Net' dependencies { - compile project(':cache') - compile project(':util') + api project(':cache') + + implementation project(':util') + implementation group: 'io.netty', name: 'netty-all', version: nettyVersion + implementation group: 'com.google.guava', name: 'guava', version: guavaVersion + implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: bouncycastleVersion + + testImplementation group: 'junit', name: 'junit', version: junitVersion } diff --git a/properties.gradle b/properties.gradle deleted file mode 100644 index d44cfccfa..000000000 --- a/properties.gradle +++ /dev/null @@ -1,3 +0,0 @@ -ext { - kotlinVersion = '1.2.31' -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 25f8e47f0..6f0626f13 100644 --- a/settings.gradle +++ b/settings.gradle @@ -34,4 +34,6 @@ def processPluginDir(Path pluginDir) { } } -pluginDirs.each { processPluginDir(it) } \ No newline at end of file +pluginDirs.each { processPluginDir(it) } +include 'test-plugin' + diff --git a/util/build.gradle b/util/build.gradle index 80b6ad3dc..f10e362c0 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -1 +1,15 @@ +plugins { + id "java-library" +} + description = 'Apollo Utilities' + +dependencies { + api group: 'io.netty', name: 'netty-all', version: nettyVersion + + implementation group: 'org.apache.commons', name: 'commons-compress', version: commonsCompressVersion + implementation group: 'com.google.guava', name: 'guava', version: guavaVersion + implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: bouncycastleVersion + + testImplementation group: 'junit', name: 'junit', version: junitVersion +} \ No newline at end of file From c687f549dae2109148c5a4ac3b4917ddd6f64f2b Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 19:37:36 +0100 Subject: [PATCH 120/209] Add core plugins to the servers runtime classpath --- game/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/game/build.gradle b/game/build.gradle index 4dfde3b38..7f3d8aa4a 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -25,4 +25,10 @@ dependencies { testImplementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion testImplementation group: 'org.powermock', name: 'powermock-api-mockito', version: powermockVersion testImplementation group: 'org.assertj', name: 'assertj-core', version: assertjVersion + + project(":game:plugin").subprojects { pluginProject -> + plugins.withId('apollo-plugin') { + runtimeClasspath pluginProject + } + } } From 09346134fabb48556bdd3db79df90217581c6b6f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 19:50:27 +0100 Subject: [PATCH 121/209] Make buildscripts backwards compatible with Gradle 4.0 --- .travis.yml | 2 ++ cache/build.gradle | 4 +--- game/build.gradle | 8 +++----- game/plugin-testing/build.gradle | 6 ++---- net/build.gradle | 4 +--- util/build.gradle | 4 +--- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 031ceca60..1e232e7b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: java jdk: - oraclejdk8 +before_install: + - gradle wrapper before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ diff --git a/cache/build.gradle b/cache/build.gradle index b8542ce72..95ef6d6a6 100644 --- a/cache/build.gradle +++ b/cache/build.gradle @@ -1,6 +1,4 @@ -plugins { - id "java-library" -} +apply plugin: 'java-library' description = 'Apollo Cache' diff --git a/game/build.gradle b/game/build.gradle index 7f3d8aa4a..01b83e368 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -1,8 +1,6 @@ -plugins { - id 'application' - id 'org.jetbrains.kotlin.jvm' - id 'org.jetbrains.kotlin.plugin.scripting' -} +apply plugin: 'application' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'org.jetbrains.kotlin.plugin.scripting' description = 'Apollo Game' mainClassName = 'org.apollo.Server' diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index ce0c1592d..4bac95131 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -1,7 +1,5 @@ -plugins { - id 'java-library' - id 'org.jetbrains.kotlin.jvm' -} +apply plugin: 'java-library' +apply plugin: 'org.jetbrains.kotlin.jvm' dependencies { api project(':game') diff --git a/net/build.gradle b/net/build.gradle index 7aa134bc5..adfcb303d 100644 --- a/net/build.gradle +++ b/net/build.gradle @@ -1,6 +1,4 @@ -plugins { - id 'java-library' -} +apply plugin: 'java-library' description = 'Apollo Net' diff --git a/util/build.gradle b/util/build.gradle index f10e362c0..c28c6c4ab 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -1,6 +1,4 @@ -plugins { - id "java-library" -} +apply plugin: 'java-library' description = 'Apollo Utilities' From bd6db246dce67a0d9d2c0b8c2e9e5b27dd55a153 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 19:52:51 +0100 Subject: [PATCH 122/209] Remove Detekt configuration --- game/plugin/build.gradle | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index b1897a929..e423c472c 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,20 +1,6 @@ -plugins { - id "io.gitlab.arturbosch.detekt" version "1.0.0.RC8" apply(false) -} - -def detektConfig = "${project.projectDir}/detekt.yml" - subprojects { subproj -> if (subproj.buildFile.exists()) { apply plugin: 'apollo-plugin' - apply plugin: 'io.gitlab.arturbosch.detekt' - - detekt { - profile("main") { - input = "${subproj.projectDir}/src" - config = detektConfig - } - } dependencies { implementation group: 'com.google.guava', name: 'guava', version: guavaVersion From 82b79ba60c6db105b9a6b71321ef0e2b4ab5bcc5 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 19:59:05 +0100 Subject: [PATCH 123/209] Remove Kotlin scripting Gradle plugin --- game/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/game/build.gradle b/game/build.gradle index 01b83e368..f82e75023 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'application' apply plugin: 'org.jetbrains.kotlin.jvm' -apply plugin: 'org.jetbrains.kotlin.plugin.scripting' description = 'Apollo Game' mainClassName = 'org.apollo.Server' From e255bd195e929884d261e7fa7cb5ba2cb3bae3de Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 20:32:42 +0100 Subject: [PATCH 124/209] Replace fast-classpath-scanner with classgraph --- game/build.gradle | 2 +- .../game/plugin/KotlinPluginEnvironment.java | 38 ++++++++++++------- gradle/properties.gradle | 2 +- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/game/build.gradle b/game/build.gradle index f82e75023..378fa03f5 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -15,7 +15,7 @@ dependencies { compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: kotlinxCoroutinesVersion implementation group: 'com.google.guava', name: 'guava', version: guavaVersion - implementation group: 'io.github.lukehutch', name: 'fast-classpath-scanner', version: classpathScannerVersion + implementation group: 'io.github.classgraph', name: 'classgraph', version: classGraphVersion implementation group: 'com.lambdaworks', name: 'scrypt', version: scryptVersion testImplementation group: 'junit', name: 'junit', version: junitVersion diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java index cc187cb18..d86cd0edd 100644 --- a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -1,6 +1,9 @@ package org.apollo.game.plugin; -import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ClassInfoList; +import io.github.classgraph.ScanResult; import org.apollo.game.model.World; import org.apollo.game.plugin.kotlin.KotlinPluginScript; @@ -13,6 +16,7 @@ public class KotlinPluginEnvironment implements PluginEnvironment { private static final Logger logger = Logger.getLogger(KotlinPluginEnvironment.class.getName()); + private static final String PLUGIN_SUFFIX = "_plugin"; private final World world; private PluginContext context; @@ -26,25 +30,26 @@ public void load(Collection plugins) { List pluginScripts = new ArrayList<>(); List> pluginClasses = new ArrayList<>(); - new FastClasspathScanner() - .matchSubclassesOf(KotlinPluginScript.class, pluginClasses::add) - .scan(); + ClassGraph classGraph = new ClassGraph().enableAllInfo(); - try { - for (Class pluginClass : pluginClasses) { - Constructor pluginConstructor = - pluginClass.getConstructor(World.class, PluginContext.class); + try (ScanResult scanResult = classGraph.scan()) { + ClassInfoList pluginClassList = scanResult + .getSubclasses(KotlinPluginScript.class.getName()) + .directOnly(); - pluginScripts.add(pluginConstructor.newInstance(world, context)); + for (ClassInfo pluginClassInfo : pluginClassList) { + Class scriptClass = pluginClassInfo.loadClass(KotlinPluginScript.class); + Constructor scriptConstructor = scriptClass.getConstructor(World.class, + PluginContext.class); + + pluginScripts.add(scriptConstructor.newInstance(world, context)); + logger.info(String.format("Loaded plugin: %s", pluginDescriptor(scriptClass))); } } catch (Exception e) { throw new RuntimeException(e); } - pluginScripts.forEach(script -> { - logger.info("Starting script: " + script.getClass().getName()); - script.doStart(world); - }); + pluginScripts.forEach(script -> script.doStart(world)); } @Override @@ -52,4 +57,11 @@ public void setContext(PluginContext context) { this.context = context; } + private static String pluginDescriptor(Class clazz) { + String className = clazz.getSimpleName(); + String name = className.substring(0, className.length() - PLUGIN_SUFFIX.length()); + Package pkg = clazz.getPackage(); + + return pkg == null ? name : name + " from " + pkg.getName(); + } } diff --git a/gradle/properties.gradle b/gradle/properties.gradle index 1eb5cd9af..a5b882c57 100644 --- a/gradle/properties.gradle +++ b/gradle/properties.gradle @@ -10,5 +10,5 @@ ext { guavaVersion = '19.0' commonsCompressVersion = '1.10' assertjVersion = '3.8.0' - classpathScannerVersion = '2.0.21' + classGraphVersion = '4.0.6' } \ No newline at end of file From 248a7d97d956adbdb505a59aeb03b3ff5aa1d8a4 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 22:28:41 +0100 Subject: [PATCH 125/209] Update plugin test framework to junit5 Updates the testing infrastructure to use the latest relesae of junit and leverages the new extension mechanism to create an easy to use testing framework. Also adds additional test coverage for several plugins. --- game/plugin-testing/build.gradle | 10 +- .../game/plugin/testing/KotlinPluginTest.kt | 34 ---- .../plugin/testing/KotlinPluginTestHelpers.kt | 121 --------------- .../testing/assertions/actionAsserts.kt | 21 +++ .../testing/assertions/stringAsserts.kt | 7 + .../testing/fakes/FakePluginContextFactory.kt | 20 ++- .../testing/junit/ApolloTestExtension.kt | 127 +++++++++++++++ .../plugin/testing/junit/ApolloTestState.kt | 72 +++++++++ .../plugin/testing/junit/api/ActionCapture.kt | 94 +++++++++++ .../junit/api/ActionCaptureCallback.kt | 7 + .../api/ActionCaptureCallbackRegistration.kt | 5 + .../testing/junit/api/ActionCaptureDelay.kt | 6 + .../api/annotations/definitionAnnotations.kt | 5 + .../junit/api/annotations/stubAnnotations.kt | 8 + .../junit/api/annotations/testAnnotations.kt | 6 + .../testing/junit/api/interactions/player.kt | 42 +++++ .../testing/junit/api/interactions/world.kt | 35 +++++ .../testing/junit/mocking/StubPrototype.kt | 5 + .../testing/junit/stubs/GameObjectStubInfo.kt | 2 + .../plugin/testing/junit/stubs/NpcStubInfo.kt | 2 + .../testing/junit/stubs/PlayerStubInfo.kt | 25 +++ .../testing/mockito/KotlinArgMatcher.kt | 25 --- .../mockito/KotlinMockitoExtensions.kt | 14 -- game/plugin/api/src/player.kt | 24 ++- game/plugin/api/src/util.kt | 4 +- game/plugin/api/test/NamedLookupTests.kt | 17 -- game/plugin/bank/test/OpenBankTest.kt | 35 +++-- game/plugin/build.gradle | 15 ++ .../consumables/test/FoodOrDrinkTests.kt | 91 ++++++----- game/plugin/dummy/test/TrainingDummyTest.kt | 53 +++++-- game/plugin/logout/test/LogoutTests.kt | 24 ++- game/plugin/skills/fishing/src/fishing.kt | 33 ++-- .../skills/fishing/src/fishing.plugin.kts | 2 +- game/plugin/skills/mining/build.gradle | 2 +- game/plugin/skills/mining/src/gem.kt | 2 +- game/plugin/skills/mining/src/mining.kt | 146 ++++++++++++++++++ .../skills/mining/src/mining.plugin.kts | 107 ------------- game/plugin/skills/mining/src/ore.kt | 10 +- game/plugin/skills/mining/src/pickaxe.kt | 2 +- .../skills/mining/test/MiningActionTests.kt | 80 ++++++++++ .../plugin/skills/mining/test/PickaxeTests.kt | 75 +++++++++ .../skills/mining/test/ProspectingTests.kt | 46 ++++++ game/plugin/skills/mining/test/TestData.kt | 17 ++ .../skills/prayer/src/BoneBuryAction.kt | 2 +- .../skills/prayer/src/prayer.plugin.kts | 2 +- .../skills/prayer/test/BuryBoneTests.kt | 72 +++++++++ .../woodcutting/src/woodcutting.plugin.kts | 7 +- .../skills/woodcutting/test/AxeTests.kt | 72 +++++++++ .../skills/woodcutting/test/TestData.kt | 17 ++ .../woodcutting/test/WoodcuttingTests.kt | 88 +++++++++++ game/plugin/util/lookup/build.gradle | 3 + .../java/org/apollo/game/model/World.java | 4 +- .../org/apollo/game/model/entity/Mob.java | 18 +++ .../org/apollo/game/action/ActionCoroutine.kt | 13 +- .../apollo/game/action/ActionCoroutineTest.kt | 5 +- gradle/properties.gradle | 5 + 56 files changed, 1325 insertions(+), 461 deletions(-) delete mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt delete mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallback.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallbackRegistration.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureDelay.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/player.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/mocking/StubPrototype.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt delete mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt delete mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt delete mode 100644 game/plugin/api/test/NamedLookupTests.kt create mode 100644 game/plugin/skills/mining/src/mining.kt create mode 100644 game/plugin/skills/mining/test/MiningActionTests.kt create mode 100644 game/plugin/skills/mining/test/PickaxeTests.kt create mode 100644 game/plugin/skills/mining/test/ProspectingTests.kt create mode 100644 game/plugin/skills/mining/test/TestData.kt create mode 100644 game/plugin/skills/prayer/test/BuryBoneTests.kt create mode 100644 game/plugin/skills/woodcutting/test/AxeTests.kt create mode 100644 game/plugin/skills/woodcutting/test/TestData.kt create mode 100644 game/plugin/skills/woodcutting/test/WoodcuttingTests.kt create mode 100644 game/plugin/util/lookup/build.gradle diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index 4bac95131..2568f3a67 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -5,9 +5,15 @@ dependencies { api project(':game') api project(':net') - api group: 'junit', name: 'junit', version: junitVersion - api group: 'org.powermock', name: 'powermock-api-mockito', version: powermockVersion + // JUnit Jupiter API and TestEngine implementation + api("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}") + api("org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}") + implementation("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}") + implementation("org.junit.platform:junit-platform-launcher:${junitPlatformVersion}") + + api group: 'io.mockk', name: 'mockk', version: mockkVersion api group: 'org.assertj', name: 'assertj-core', version: assertjVersion + api group: 'com.willowtreeapps.assertk', name: 'assertk', version: assertkVersion implementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt deleted file mode 100644 index 08fecc641..000000000 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -package org.apollo.game.plugin.testing - -import org.apollo.game.message.handler.MessageHandlerChainSet -import org.apollo.game.model.World -import org.apollo.game.model.entity.Player -import org.apollo.game.plugin.* -import org.apollo.game.plugin.testing.fakes.FakePluginContextFactory -import org.junit.Before -import org.junit.runner.RunWith -import org.powermock.api.mockito.PowerMockito -import org.powermock.core.classloader.annotations.PrepareForTest -import org.powermock.modules.junit4.PowerMockRunner -import java.util.* - -@RunWith(PowerMockRunner::class) -@PrepareForTest(World::class, PluginContext::class, Player::class) -abstract class KotlinPluginTest: KotlinPluginTestHelpers() { - override lateinit var world: World - override lateinit var player: Player - override lateinit var messageHandlers: MessageHandlerChainSet - - @Before - open fun setup() { - messageHandlers = MessageHandlerChainSet() - world = PowerMockito.spy(World()) - - val pluginEnvironment = KotlinPluginEnvironment(world) - pluginEnvironment.setContext(FakePluginContextFactory.create(messageHandlers)) - pluginEnvironment.load(ArrayList()) - - player = world.spawnPlayer("testPlayer") - } - -} diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt deleted file mode 100644 index 9dd4898a9..000000000 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/KotlinPluginTestHelpers.kt +++ /dev/null @@ -1,121 +0,0 @@ -package org.apollo.game.plugin.testing - -import org.apollo.cache.def.ItemDefinition -import org.apollo.cache.def.NpcDefinition -import org.apollo.game.action.Action -import org.apollo.game.message.handler.MessageHandlerChainSet -import org.apollo.game.message.impl.* -import org.apollo.game.model.* -import org.apollo.game.model.entity.* -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.model.entity.obj.StaticGameObject -import org.apollo.net.message.Message -import org.apollo.util.security.PlayerCredentials -import org.junit.Assert -import org.mockito.* -import org.powermock.api.mockito.PowerMockito - -/** - * A base class containing a set of helper methods to be used within plugin tests. - */ -abstract class KotlinPluginTestHelpers { - abstract var world: World - abstract var player: Player - abstract var messageHandlers: MessageHandlerChainSet - - /** - * Waits for an [Action] to complete within a specified number of pulses, and with an optional predicate - * to test the [Action] against. - */ - fun Player.waitForActionCompletion(predicate: (Action) -> Boolean = { _ -> true }, timeout: Int = 15) { - val actionCaptor: ArgumentCaptor> = ArgumentCaptor.forClass(Action::class.java) - Mockito.verify(this).startAction(actionCaptor.capture()) - - val action: Action = actionCaptor.value as Action - Assert.assertTrue("Found wrong action type", predicate.invoke(action)) - - var pulses = 0 - - do { - action.pulse() - - /** - * Introducing an artificial delay is necessary to prevent the timeout being exceeded before - * an asynchronous [Action] really starts. When a job is submitted to a new coroutine context - * there may be a delay before it is actually executed. - * - * This delay is typically sub-millisecond and is only incurred with startup. Since game actions - * have larger delays of their own this isn't a problem in practice. - */ - Thread.sleep(50L) - } while (action.isRunning && pulses++ < timeout) - - Assert.assertFalse("Exceeded timeout waiting for action completion", pulses > timeout) - } - - /** - * Spawns a new NPC with the minimum set of dependencies required to function correctly in the world. - */ - fun World.spawnNpc(id: Int, position: Position): Npc { - val definition = NpcDefinition(id) - val npc = Npc(this, position, definition, arrayOfNulls(4)) - val region = regionRepository.fromPosition(position) - val npcs = npcRepository - - npcs.add(npc) - region.addEntity(npc) - - return npc - } - - /** - * Spawn a new player stub in the world, with a dummy game session. - */ - fun World.spawnPlayer(username: String, position: Position = Position(3200, 3200, 0)): Player { - val credentials = PlayerCredentials(username, "test", 1, 1, "0.0.0.0") - val region = regionRepository.fromPosition(position) - - val player = PowerMockito.spy(Player(this, credentials, position)) - register(player) - region.addEntity(player) - - PowerMockito.doNothing().`when`(player).send(Matchers.any()) - - return player - } - - /** - * Spawn a new static game object into the world with the given id and position. - */ - fun World.spawnObject(id: Int, position: Position): GameObject { - val obj = StaticGameObject(this, id, position, 0, 0) - - spawn(obj) - - return obj - } - - /** - * Fake a client [Message] originating from a player and send it to the relevant - * message handlers. - */ - fun Player.notify(message: Message) { - messageHandlers.notify(this, message) - } - - /** - * Move the player within interaction distance to the given [Entity] and fake an action - * message. - */ - fun Player.interactWith(entity: Entity, option: Int = 1) { - position = entity.position.step(1, Direction.NORTH) - - when (entity) { - is GameObject -> notify(ObjectActionMessage(option, entity.id, entity.position)) - is Npc -> notify(NpcActionMessage(option, entity.index)) - is Player -> notify(PlayerActionMessage(option, entity.index)) - } - } - -} - diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt new file mode 100644 index 000000000..7433a0337 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt @@ -0,0 +1,21 @@ +package org.apollo.game.plugin.testing.assertions + +import io.mockk.MockKVerificationScope +import io.mockk.verify +import org.apollo.game.plugin.testing.junit.api.ActionCaptureCallbackRegistration + + +/** + * Verify some expectations on a [mock] after a delayed event (specified by [DelayMode]). + */ +fun verifyAfter(registration: ActionCaptureCallbackRegistration, description: String? = null, verifier: MockKVerificationScope.() -> Unit) { + after(registration, description) { verify(verifyBlock = verifier) } +} + +/** + * Run a [callback] after a given delay, specified by [DelayMode]. + */ +fun after(registration: ActionCaptureCallbackRegistration, description: String? = null, callback: () -> Unit) { + registration.function = callback + registration.description = description +} \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt new file mode 100644 index 000000000..a21d4a498 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt @@ -0,0 +1,7 @@ +package org.apollo.game.plugin.testing.assertions + +import io.mockk.MockKMatcherScope + +inline fun MockKMatcherScope.contains(search: String) = match { it.contains(search) } +inline fun MockKMatcherScope.startsWith(search: String) = match { it.startsWith(search) } +inline fun MockKMatcherScope.endsWith(search: String) = match { it.endsWith(search) } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt index aac823298..701900478 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/fakes/FakePluginContextFactory.kt @@ -1,21 +1,25 @@ package org.apollo.game.plugin.testing.fakes +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot import org.apollo.game.message.handler.MessageHandler import org.apollo.game.message.handler.MessageHandlerChainSet import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message -import org.mockito.invocation.InvocationOnMock -import org.mockito.stubbing.Answer -import org.powermock.api.mockito.PowerMockito object FakePluginContextFactory { fun create(messageHandlers: MessageHandlerChainSet): PluginContext { - val answer = Answer { invocation: InvocationOnMock -> - messageHandlers.putHandler( - invocation.arguments[0] as Class, - invocation.arguments[1] as MessageHandler<*>) + val ctx = mockk() + val typeCapture = slot>() + val handlerCapture = slot>() + + every { + ctx.addMessageHandler(capture(typeCapture), capture(handlerCapture)) + } answers { + messageHandlers.putHandler(typeCapture.captured, handlerCapture.captured) } - return PowerMockito.mock(PluginContext::class.java, answer) + return ctx } } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt new file mode 100644 index 000000000..b36404654 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt @@ -0,0 +1,127 @@ +package org.apollo.game.plugin.testing.junit + +import io.mockk.every +import io.mockk.slot +import io.mockk.spyk +import io.mockk.staticMockk +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.message.handler.MessageHandlerChainSet +import org.apollo.game.model.World +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.KotlinPluginEnvironment +import org.apollo.game.plugin.PluginMetaData +import org.apollo.game.plugin.testing.fakes.FakePluginContextFactory +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.mocking.StubPrototype +import org.junit.jupiter.api.extension.* +import java.util.* +import kotlin.reflect.KMutableProperty +import kotlin.reflect.full.createType +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.jvm.jvmErasure + +internal val supportedTestDoubleTypes = setOf( + Player::class.createType(), + Npc::class.createType(), + GameObject::class.createType(), + World::class.createType(), + ActionCapture::class.createType() +) + +class ApolloTestingExtension : + AfterTestExecutionCallback, + BeforeAllCallback, + AfterAllCallback, + BeforeEachCallback, + AfterEachCallback, + ParameterResolver { + + private val namespace = ExtensionContext.Namespace.create("apollo") + + private fun cleanup(context: ExtensionContext) { + val store = context.getStore(namespace) + val state = store.get(ApolloTestState::class) as ApolloTestState + + try { + state.actionCapture?.runAction() + } finally { + state.reset() + } + } + + override fun afterAll(context: ExtensionContext) { + val store = context.getStore(namespace) + store.remove(ApolloTestState::class) + } + + override fun afterEach(context: ExtensionContext) = cleanup(context) + + override fun afterTestExecution(context: ExtensionContext) = cleanup(context) + + override fun beforeAll(context: ExtensionContext) { + val stubHandlers = MessageHandlerChainSet() + val stubWorld = spyk(World()) + + val pluginEnvironment = KotlinPluginEnvironment(stubWorld) + pluginEnvironment.setContext(FakePluginContextFactory.create(stubHandlers)) + pluginEnvironment.load(ArrayList()) + + val state = ApolloTestState(stubHandlers, stubWorld) + val store = context.getStore(namespace) + store.put(ApolloTestState::class, state) + } + + override fun beforeEach(context: ExtensionContext) { + val testClass = context.requiredTestClass.kotlin + val testClassInstance = context.requiredTestInstance + val testClassProps = testClass.declaredMemberProperties + val testClassMethods = context.testClass.map { it.kotlin.declaredMemberFunctions }.orElse(emptyList()) + val testClassItemDefs = testClassMethods.asSequence() + .mapNotNull { it.findAnnotation()?.let { anno -> it to anno } } + .flatMap { (it.first.call(context.requiredTestInstance as Any) as Collection).asSequence() } + .map { it.id to it } + .toMap() + + if (testClassItemDefs.isNotEmpty()) { + val itemIdSlot = slot() + + staticMockk().mock() + every { ItemDefinition.lookup(capture(itemIdSlot)) } answers { testClassItemDefs[itemIdSlot.captured] } + } + + val store = context.getStore(namespace) + val state = store.get(ApolloTestState::class) as ApolloTestState + + val propertyStubSites = testClassProps.asSequence() + .mapNotNull { it as? KMutableProperty<*> } + .filter { supportedTestDoubleTypes.contains(it.returnType) } + + propertyStubSites.forEach { + it.setter.call( + testClassInstance, + state.createStub(StubPrototype(it.returnType.jvmErasure, it.annotations)) + ) + } + } + + override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean { + val param = parameterContext.parameter + val paramType = param.type.kotlin + + return supportedTestDoubleTypes.contains(paramType.createType()) + } + + override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any { + val param = parameterContext.parameter + val paramType = param.type.kotlin + val testStore = extensionContext.getStore(namespace) + val testState = testStore.get(ApolloTestState::class) as ApolloTestState + + return testState.createStub(StubPrototype(paramType, param.annotations.toList())) + } +} \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt new file mode 100644 index 000000000..a9e8c4f13 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt @@ -0,0 +1,72 @@ +package org.apollo.game.plugin.testing.junit + +import io.mockk.every +import io.mockk.slot +import io.mockk.spyk +import org.apollo.game.action.Action +import org.apollo.game.message.handler.MessageHandlerChainSet +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.mocking.StubPrototype +import org.apollo.game.plugin.testing.junit.stubs.PlayerStubInfo +import org.apollo.net.message.Message +import org.apollo.util.security.PlayerCredentials +import kotlin.reflect.KClass + +data class ApolloTestState(val handlers: MessageHandlerChainSet, val world: World) { + val players = mutableListOf() + var actionCapture: ActionCapture? = null + + fun createActionCapture(type: KClass>): ActionCapture { + if (actionCapture != null) { + throw IllegalStateException("Cannot specify more than one ActionCapture") + } + + actionCapture = ActionCapture(type) + return actionCapture!! + } + + fun createStub(proto: StubPrototype): T { + val annotations = proto.annotations + + return when (proto.type) { + Player::class -> createPlayer(PlayerStubInfo.create(annotations)) as T + World::class -> world as T + ActionCapture::class -> createActionCapture(Action::class) as T + else -> throw IllegalArgumentException("Can't stub ${proto.type.qualifiedName}") + } + } + + fun createPlayer(info: PlayerStubInfo): Player { + val credentials = PlayerCredentials(info.name, "test", 1, 1, "0.0.0.0") + val region = world.regionRepository.fromPosition(info.position) + + val player = spyk(Player(world, credentials, info.position)) + + world.register(player) + region.addEntity(player) + players.add(player) + + val actionSlot = slot>() + val messageSlot = slot() + + every { player.send(capture(messageSlot)) } answers { handlers.notify(player, messageSlot.captured) } + every { player.startAction(capture(actionSlot)) } answers { + actionCapture?.capture(actionSlot.captured) + true + } + + return player + } + + fun reset() { + actionCapture = null + players.forEach { + it.stopAction() + world.unregister(it) + } + + players.clear() + } +} \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt new file mode 100644 index 000000000..9d0a1478d --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt @@ -0,0 +1,94 @@ +package org.apollo.game.plugin.testing.junit.api + +import org.apollo.game.action.Action +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import kotlin.reflect.KClass +import kotlin.reflect.full.isSuperclassOf + +class ActionCapture(val type: KClass>) { + private var action: Action<*>? = null + private val callbacks = mutableListOf() + private var lastTicks: Int = 0 + + fun capture(captured: Action<*>) { + assertTrue(type.isSuperclassOf(captured::class)) { + "${captured::class.simpleName} is not an instance of ${type.simpleName}" + } + + this.action = captured + } + + private fun callback(delay: ActionCaptureDelay): ActionCaptureCallbackRegistration { + val registration = ActionCaptureCallbackRegistration() + val callback = ActionCaptureCallback(delay, registration) + + callbacks.add(callback) + return registration + } + + fun runAction(timeout: Int = 50) { + action?.let { + var pulses = 0 + + do { + it.pulse() + pulses++ + + val tickCallbacks = callbacks.filter { it.delay == ActionCaptureDelay.Ticks(pulses) } + tickCallbacks.forEach { it.invoke() } + + callbacks.removeAll(tickCallbacks) + } while (it.isRunning && pulses < timeout) + + val completionCallbacks = callbacks.filter { it.delay == ActionCaptureDelay.Completed } + completionCallbacks.forEach { it.invoke() } + + callbacks.removeAll(completionCallbacks) + } + + assertEquals(0, callbacks.size, { + "untriggered callbacks:\n" + callbacks + .map { + val delayDescription = when (it.delay) { + is ActionCaptureDelay.Ticks -> "${it.delay.count} ticks" + is ActionCaptureDelay.Completed -> "action completion" + } + + "$delayDescription (${it.callbackRegistration.description ?: ""})" + } + .joinToString("\n") + .prependIndent(" ") + }) + } + + + /** + * Create a callback registration that triggers after exactly [count] ticks. + */ + fun exactTicks(count: Int) = callback(ActionCaptureDelay.Ticks(count)) + + /** + * Create a callback registration that triggers after [count] ticks. This method is cumulative, + * and will take into account previous calls to [ticks] when creating new callbacks. + * + * To run a callback after an exact number of ticks use [exactTicks]. + */ + fun ticks(count: Int): ActionCaptureCallbackRegistration { + lastTicks += count + + return exactTicks(lastTicks) + } + + /** + * Create a callback registration that triggers when an [Action] completes. + */ + fun complete() = callback(ActionCaptureDelay.Completed) + + /** + * Check if this capture has a pending [Action] to run. + */ + fun isPending(): Boolean { + return action?.isRunning ?: false + } +} \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallback.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallback.kt new file mode 100644 index 000000000..7f9f9b78c --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallback.kt @@ -0,0 +1,7 @@ +package org.apollo.game.plugin.testing.junit.api + +data class ActionCaptureCallback(val delay: ActionCaptureDelay, val callbackRegistration: ActionCaptureCallbackRegistration) { + fun invoke() { + callbackRegistration.function?.invoke() + } +} \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallbackRegistration.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallbackRegistration.kt new file mode 100644 index 000000000..15d940f5f --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureCallbackRegistration.kt @@ -0,0 +1,5 @@ +package org.apollo.game.plugin.testing.junit.api + +typealias Function = () -> Unit + +class ActionCaptureCallbackRegistration(var function: Function? = null, var description: String? = null) \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureDelay.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureDelay.kt new file mode 100644 index 000000000..f24ff8b68 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCaptureDelay.kt @@ -0,0 +1,6 @@ +package org.apollo.game.plugin.testing.junit.api + +sealed class ActionCaptureDelay { + data class Ticks(val count: Int) : ActionCaptureDelay() + object Completed : ActionCaptureDelay() +} diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt new file mode 100644 index 000000000..484d0b2c9 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt @@ -0,0 +1,5 @@ +package org.apollo.game.plugin.testing.junit.api.annotations + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class ItemDefinitions \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt new file mode 100644 index 000000000..9166616fc --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt @@ -0,0 +1,8 @@ +package org.apollo.game.plugin.testing.junit.api.annotations + +annotation class Id(val value: Int) +annotation class Pos(val x: Int, val y: Int, val height: Int = 0) + +@Target(AnnotationTarget.FIELD) +@Retention(AnnotationRetention.RUNTIME) +annotation class TestMock \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt new file mode 100644 index 000000000..03aa36a17 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt @@ -0,0 +1,6 @@ +package org.apollo.game.plugin.testing.junit.api.annotations + +import org.apollo.game.action.Action +import kotlin.reflect.KClass + +annotation class ActionTest(val value: KClass> = Action::class) \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/player.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/player.kt new file mode 100644 index 000000000..6fffee19a --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/player.kt @@ -0,0 +1,42 @@ +package org.apollo.game.plugin.testing.junit.api.interactions + +import org.apollo.game.message.impl.ItemOptionMessage +import org.apollo.game.message.impl.NpcActionMessage +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.message.impl.PlayerActionMessage +import org.apollo.game.model.Direction +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Entity +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.GameObject + +/** + * Send an [ItemOptionMessage] for the given [id], [option], [slot], and [interfaceId], simulating a + * player interacting with an item. + */ +fun Player.interactWithItem(id: Int, option: Int, slot: Int? = null, interfaceId: Int? = null) { + send(ItemOptionMessage(option, interfaceId ?: -1, id, slot ?: inventory.slotOf(id))) +} + +/** + * Spawn a new object (defaulting to in-front of the player) and immediately interact with it. + */ +fun Player.interactWithObject(id: Int, option: Int, at: Position? = null) { + val obj = world.spawnObject(id, at ?: position.step(1, Direction.NORTH)) + interactWith(obj, option) +} + +/** + * Move the player within interaction distance to the given [Entity] and fake an action + * message. + */ +fun Player.interactWith(entity: Entity, option: Int = 1) { + position = entity.position.step(1, Direction.NORTH) + + when (entity) { + is GameObject -> send(ObjectActionMessage(option, entity.id, entity.position)) + is Npc -> send(NpcActionMessage(option, entity.index)) + is Player -> send(PlayerActionMessage(option, entity.index)) + } +} \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt new file mode 100644 index 000000000..c94c6e10a --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt @@ -0,0 +1,35 @@ +package org.apollo.game.plugin.testing.junit.api.interactions + +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.entity.obj.StaticGameObject + +/** + * Spawn a new static game object into the world with the given id and position. + */ +fun World.spawnObject(id: Int, position: Position): GameObject { + val obj = StaticGameObject(this, id, position, 0, 0) + + spawn(obj) + + return obj +} + + +/** + * Spawns a new NPC with the minimum set of dependencies required to function correctly in the world. + */ +fun World.spawnNpc(id: Int, position: Position): Npc { + val definition = NpcDefinition(id) + val npc = Npc(this, position, definition, arrayOfNulls(4)) + val region = regionRepository.fromPosition(position) + val npcs = npcRepository + + npcs.add(npc) + region.addEntity(npc) + + return npc +} \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/mocking/StubPrototype.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/mocking/StubPrototype.kt new file mode 100644 index 000000000..924b2d5b5 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/mocking/StubPrototype.kt @@ -0,0 +1,5 @@ +package org.apollo.game.plugin.testing.junit.mocking + +import kotlin.reflect.KClass + +data class StubPrototype(val type: KClass, val annotations: Collection) diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt new file mode 100644 index 000000000..c5306f1f7 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt @@ -0,0 +1,2 @@ +package org.apollo.game.plugin.testing.junit.stubs + diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt new file mode 100644 index 000000000..c5306f1f7 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt @@ -0,0 +1,2 @@ +package org.apollo.game.plugin.testing.junit.stubs + diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt new file mode 100644 index 000000000..95f4404a8 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt @@ -0,0 +1,25 @@ +package org.apollo.game.plugin.testing.junit.stubs + +import org.apollo.game.model.Position +import org.apollo.game.plugin.testing.junit.api.annotations.Pos + +class PlayerStubInfo { + companion object { + fun create(annotations: Collection): PlayerStubInfo { + val info = PlayerStubInfo() + + annotations.forEach { + when (it) { + is Pos -> info.position = Position(it.x, it.y, it.height) + } + } + + return info + } + + } + + var position = Position(3222, 3222) + var name = "test" +} + diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt deleted file mode 100644 index 748146266..000000000 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinArgMatcher.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.apollo.game.plugin.testing.mockito - -import org.mockito.ArgumentMatcher -import java.lang.AssertionError -import java.util.function.Consumer - -class KotlinArgMatcher(val consumer: Consumer) : ArgumentMatcher() { - private var error: String? = null - - override fun matches(argument: Any?): Boolean { - try { - consumer.accept(argument as T) - return true - } catch (err: AssertionError) { - error = err.message - println(error) - return false - } - } - - override fun toString(): String { - return error ?: "" - } -} - diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt deleted file mode 100644 index 0bfad4915..000000000 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/mockito/KotlinMockitoExtensions.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.apollo.game.plugin.testing.mockito - -import org.mockito.Mockito -import java.util.function.Consumer - - -object KotlinMockitoExtensions { - inline fun matches(crossinline callback: T.() -> Unit): T { - val consumer = Consumer { it.callback() } - val matcher = KotlinArgMatcher(consumer) - - return Mockito.argThat(matcher) - } -} diff --git a/game/plugin/api/src/player.kt b/game/plugin/api/src/player.kt index 473b13f61..069ffe972 100644 --- a/game/plugin/api/src/player.kt +++ b/game/plugin/api/src/player.kt @@ -29,30 +29,28 @@ val Player.runecraft: SkillProxy get() = SkillProxy(skillSet, Skill.RUNECRAFT) /** * A proxy class to allow */ -class SkillProxy(val skills: SkillSet, val skill: Int) { +class SkillProxy(private val skills: SkillSet, private val skill: Int) { /** * The maximum level of this skill. */ - val maximum = skills.getMaximumLevel(skill) + val maximum: Int + get() = skills.getMaximumLevel(skill) /** * The current level of this skill. */ - val current = skills.getCurrentLevel(skill) - - val experience = ExperienceProxy() + val current: Int + get() = skills.getCurrentLevel(skill) /** - * A proxy class to make [experience] (effectively) write-only. + * The amount of experience in this skill a player has. */ - inner class ExperienceProxy { - - operator fun plusAssign(amount: Int) = skills.addExperience(skill, amount.toDouble()) - - operator fun plusAssign(amount: Double) = skills.addExperience(skill, amount) - - } + var experience: Double + get() = skills.getExperience(skill) + set(value) { + skills.setExperience(skill, value) + } /** * Boosts the current level of this skill by [amount], if possible (i.e. if `current + amount <= maximum + amount`). diff --git a/game/plugin/api/src/util.kt b/game/plugin/api/src/util.kt index 01264cbfe..663aa3de5 100644 --- a/game/plugin/api/src/util.kt +++ b/game/plugin/api/src/util.kt @@ -1,8 +1,8 @@ package org.apollo.game.plugin.api -import java.util.Random +import java.util.* -val RAND = Random() +public val RAND = Random() fun rand(bounds: Int): Int { return RAND.nextInt(bounds) diff --git a/game/plugin/api/test/NamedLookupTests.kt b/game/plugin/api/test/NamedLookupTests.kt deleted file mode 100644 index 4f361db68..000000000 --- a/game/plugin/api/test/NamedLookupTests.kt +++ /dev/null @@ -1,17 +0,0 @@ -import org.apollo.cache.def.ItemDefinition -import org.apollo.game.plugin.api.Definitions -import org.apollo.game.plugin.testing.KotlinPluginTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test - -class NamedLookupTests : KotlinPluginTest() { - @Test - fun itemLookup() { - val testItem = ItemDefinition(0) - testItem.name = "sword" - - ItemDefinition.init(arrayOf(testItem)) - - assertThat(Definitions.item("sword")).isEqualTo(testItem) - } -} \ No newline at end of file diff --git a/game/plugin/bank/test/OpenBankTest.kt b/game/plugin/bank/test/OpenBankTest.kt index d7b4ed1cf..58b7b5e49 100644 --- a/game/plugin/bank/test/OpenBankTest.kt +++ b/game/plugin/bank/test/OpenBankTest.kt @@ -1,9 +1,19 @@ -import org.apollo.game.model.Position -import org.apollo.game.plugin.testing.KotlinPluginTest -import org.junit.Test -import org.mockito.Mockito.verify -class OpenBankTest() : KotlinPluginTest() { +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.interactWith +import org.apollo.game.plugin.testing.junit.api.interactions.spawnNpc +import org.apollo.game.plugin.testing.junit.api.interactions.spawnObject +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class OpenBankTest { companion object { const val BANK_BOOTH_ID = 2213 @@ -12,15 +22,23 @@ class OpenBankTest() : KotlinPluginTest() { val BANK_POSITION = Position(3200, 3200, 0) } + @TestMock + lateinit var action: ActionCapture + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var world: World + @Test fun `Interacting with a bank teller should open the players bank`() { val bankTeller = world.spawnNpc(BANK_TELLER_ID, BANK_POSITION) // @todo - these option numbers only match by coincidence, we should be looking up the correct ones player.interactWith(bankTeller, option = 2) - player.waitForActionCompletion() - verify(player).openBank() + verifyAfter(action.complete()) { player.openBank() } } @Test @@ -28,9 +46,8 @@ class OpenBankTest() : KotlinPluginTest() { val bankBooth = world.spawnObject(BANK_BOOTH_ID, BANK_POSITION) player.interactWith(bankBooth, option = 2) - player.waitForActionCompletion() - verify(player).openBank() + verifyAfter(action.complete()) { player.openBank() } } } \ No newline at end of file diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index e423c472c..7bc92461e 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,6 +1,21 @@ +buildscript { + repositories { + jcenter() + mavenCentral() + + maven { url "https://plugins.gradle.org/m2/" } + } + + dependencies { + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.1.0' + } +} + subprojects { subproj -> if (subproj.buildFile.exists()) { apply plugin: 'apollo-plugin' + apply plugin: 'org.junit.platform.gradle.plugin' + dependencies { implementation group: 'com.google.guava', name: 'guava', version: guavaVersion diff --git a/game/plugin/consumables/test/FoodOrDrinkTests.kt b/game/plugin/consumables/test/FoodOrDrinkTests.kt index 1394e64b2..851f32900 100644 --- a/game/plugin/consumables/test/FoodOrDrinkTests.kt +++ b/game/plugin/consumables/test/FoodOrDrinkTests.kt @@ -1,16 +1,24 @@ package org.apollo.plugin.consumables -import org.apollo.game.message.impl.ItemOptionMessage +import io.mockk.verify +import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill -import org.apollo.game.plugin.testing.KotlinPluginTest -import org.apollo.game.plugin.testing.mockito.KotlinMockitoExtensions.matches -import org.assertj.core.api.Assertions.assertThat -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify - -class FoodOrDrinkTests : KotlinPluginTest() { +import org.apollo.game.plugin.testing.assertions.contains +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.interactWithItem +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class FoodOrDrinkTests { companion object { const val TEST_FOOD_NAME = "test_food" @@ -25,9 +33,14 @@ class FoodOrDrinkTests : KotlinPluginTest() { const val MAX_HP_LEVEL = 10 } - @Before override fun setup() { - super.setup() + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + @BeforeEach + fun setup() { val skills = player.skillSet skills.setCurrentLevel(Skill.HITPOINTS, HP_LEVEL) skills.setMaximumLevel(Skill.HITPOINTS, MAX_HP_LEVEL) @@ -36,51 +49,47 @@ class FoodOrDrinkTests : KotlinPluginTest() { drink("test_drink", TEST_DRINK_ID, TEST_DRINK_RESTORATION) } - @Test fun `Consuming food or drink should restore the players hitpoints`() { + @Test + fun `Consuming food or drink should restore the players hitpoints`() { val expectedHpLevel = TEST_FOOD_RESTORATION + HP_LEVEL - player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) - player.waitForActionCompletion() + player.interactWithItem(TEST_FOOD_ID, option = 1, slot = 1) - val currentHpLevel = player.skillSet.getCurrentLevel(Skill.HITPOINTS) - assertThat(currentHpLevel).isEqualTo(expectedHpLevel) + after(action.complete()) { + assertEquals(expectedHpLevel, player.skillSet.getCurrentLevel(Skill.HITPOINTS)) + } } - @Test fun `A message should be sent notifying the player if the item restored hitpoints`() { - player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) - player.waitForActionCompletion() + @Test + fun `A message should be sent notifying the player if the item restored hitpoints`() { + player.interactWithItem(TEST_FOOD_ID, option = 1, slot = 1) - verify(player).sendMessage(matches { - assertThat(this).contains("heals some health") - }) + verifyAfter(action.complete()) { player.sendMessage("It heals some health.") } } - @Test fun `A message should not be sent to the player if the item did not restore hitpoints`() { + @Test + fun `A message should not be sent to the player if the item did not restore hitpoints`() { player.skillSet.setCurrentLevel(Skill.HITPOINTS, MAX_HP_LEVEL) - player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) - player.waitForActionCompletion() + player.interactWithItem(TEST_FOOD_ID, option = 1, slot = 1) - verify(player, never()).sendMessage(matches { - assertThat(this).contains("heals some health") - }) + after(action.complete()) { + verify(exactly = 0) { player.sendMessage(contains("it heals some")) } + } } - @Test fun `A message should be sent saying the player has drank an item when consuming a drink`() { - player.notify(ItemOptionMessage(1, -1, TEST_DRINK_ID, 1)) - player.waitForActionCompletion() + @Test + fun `A message should be sent saying the player has drank an item when consuming a drink`() { + player.interactWithItem(TEST_DRINK_ID, option = 1, slot = 1) + + verifyAfter(action.complete()) { player.sendMessage("You drink the ${TEST_DRINK_NAME}.") } - verify(player).sendMessage(matches { - assertThat(this).contains("You drink the ${TEST_DRINK_NAME}") - }) } - @Test fun `A message should be sent saying the player has eaten an item when consuming food`() { - player.notify(ItemOptionMessage(1, -1, TEST_FOOD_ID, 1)) - player.waitForActionCompletion() + @Test + fun `A message should be sent saying the player has eaten an item when consuming food`() { + player.interactWithItem(TEST_FOOD_ID, option = 1, slot = 1) - verify(player).sendMessage(matches { - assertThat(this).contains("You eat the ${TEST_FOOD_NAME}") - }) + verifyAfter(action.complete()) { player.sendMessage("You eat the ${TEST_FOOD_NAME}.") } } } \ No newline at end of file diff --git a/game/plugin/dummy/test/TrainingDummyTest.kt b/game/plugin/dummy/test/TrainingDummyTest.kt index 2e99e313c..4a4284b52 100644 --- a/game/plugin/dummy/test/TrainingDummyTest.kt +++ b/game/plugin/dummy/test/TrainingDummyTest.kt @@ -1,43 +1,64 @@ + +import io.mockk.verify import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill -import org.apollo.game.plugin.testing.* -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test -import org.mockito.Mockito.contains -import org.mockito.Mockito.verify +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.interactWith +import org.apollo.game.plugin.testing.junit.api.interactions.spawnObject +import org.apollo.game.plugin.testing.assertions.contains +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith -class TrainingDummyTest : KotlinPluginTest() { +@ExtendWith(ApolloTestingExtension::class) +class TrainingDummyTest { companion object { const val DUMMY_ID = 823 val DUMMY_POSITION = Position(3200, 3230, 0) } - @Test fun `Hitting the training dummy should give the player attack experience`() { + @TestMock + lateinit var action: ActionCapture + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var world: World + + @Test + fun `Hitting the training dummy should give the player attack experience`() { val dummy = world.spawnObject(DUMMY_ID, DUMMY_POSITION) val skills = player.skillSet val beforeExp = skills.getExperience(Skill.ATTACK) player.interactWith(dummy, option = 2) - player.waitForActionCompletion() - val afterExp = skills.getExperience(Skill.ATTACK) - assertThat(afterExp).isGreaterThan(beforeExp) + after(action.complete()) { + assertTrue(skills.getExperience(Skill.ATTACK) > beforeExp) + } } - @Test fun `The player should stop getting attack experience from the training dummy at level 8`() { + @Test + fun `The player should stop getting attack experience from the training dummy at level 8`() { val dummy = world.spawnObject(DUMMY_ID, DUMMY_POSITION) val skills = player.skillSet skills.setMaximumLevel(Skill.ATTACK, 8) val beforeExp = skills.getExperience(Skill.ATTACK) player.interactWith(dummy, option = 2) - player.waitForActionCompletion() - - val afterExp = skills.getExperience(Skill.ATTACK) - verify(player).sendMessage(contains("nothing more you can learn")) - assertThat(afterExp).isEqualTo(beforeExp) + after(action.complete()) { + verify { player.sendMessage(contains("nothing more you can learn")) } + assertEquals(beforeExp, skills.getExperience(Skill.ATTACK)) + } } } diff --git a/game/plugin/logout/test/LogoutTests.kt b/game/plugin/logout/test/LogoutTests.kt index e974c135a..c536976f2 100644 --- a/game/plugin/logout/test/LogoutTests.kt +++ b/game/plugin/logout/test/LogoutTests.kt @@ -1,19 +1,27 @@ + +import io.mockk.verify import org.apollo.game.message.impl.ButtonMessage -import org.apollo.game.plugin.testing.KotlinPluginTest -import org.junit.Test -import org.mockito.Mockito.times -import org.mockito.Mockito.verify +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith -class LogoutTests : KotlinPluginTest() { +@ExtendWith(ApolloTestingExtension::class) +class LogoutTests { companion object { const val LOGOUT_BUTTON_ID = 2458 } - @Test fun `The player should be logged out when they click the logout button`() { - player.notify(ButtonMessage(LOGOUT_BUTTON_ID)) + @TestMock + lateinit var player: Player + + @Test + fun `The player should be logged out when they click the logout button`() { + player.send(ButtonMessage(LOGOUT_BUTTON_ID)) - verify(player, times(1)).logout() + verify { player.logout() } } } \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/fishing.kt b/game/plugin/skills/fishing/src/fishing.kt index b59949357..807ac994d 100644 --- a/game/plugin/skills/fishing/src/fishing.kt +++ b/game/plugin/skills/fishing/src/fishing.kt @@ -9,12 +9,12 @@ import org.apollo.game.plugin.skills.fishing.FishingTool.* /** * A fish that can be gathered using the fishing skill. */ -enum class Fish(val id: Int, val level: Int, val experience: Double) { - SHRIMP(id = 317, level = 1, experience = 10.0), +enum class Fish(val id: Int, val level: Int, val experience: Double, catchSuffix: String? = null) { + SHRIMPS(id = 317, level = 1, experience = 10.0, catchSuffix = "some shrimp."), SARDINE(id = 327, level = 5, experience = 20.0), MACKEREL(id = 353, level = 16, experience = 20.0), HERRING(id = 345, level = 10, experience = 30.0), - ANCHOVY(id = 321, level = 15, experience = 40.0), + ANCHOVIES(id = 321, level = 15, experience = 40.0, catchSuffix = "some anchovies."), TROUT(id = 335, level = 20, experience = 50.0), COD(id = 341, level = 23, experience = 45.0), PIKE(id = 349, level = 25, experience = 60.0), @@ -23,13 +23,14 @@ enum class Fish(val id: Int, val level: Int, val experience: Double) { LOBSTER(id = 377, level = 40, experience = 90.0), BASS(id = 363, level = 46, experience = 100.0), SWORDFISH(id = 371, level = 50, experience = 100.0), - SHARK(id = 383, level = 76, experience = 110.0); + SHARK(id = 383, level = 76, experience = 110.0, catchSuffix = "a shark!"); /** * The name of this fish, formatted so it can be inserted into a message. */ - val formattedName = Definitions.item(id)!!.name.toLowerCase() - // TODO this leads to incorrect messages, e.g. 'You catch a raw shrimps'. + val catchMessage = "You catch ${catchSuffix ?: "a ${catchName()}."}" + + private fun catchName() = Definitions.item(id)!!.name.toLowerCase().removePrefix("raw ") } @@ -69,16 +70,7 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco ROD(309, Option.of(FLY_FISHING_ROD, TROUT, SALMON), Option.of(FISHING_ROD, PIKE)), CAGE_HARPOON(312, Option.of(LOBSTER_CAGE, LOBSTER), Option.of(HARPOON, TUNA, SWORDFISH)), NET_HARPOON(313, Option.of(BIG_NET, MACKEREL, COD), Option.of(HARPOON, BASS, SHARK)), - NET_ROD(316, Option.of(SMALL_NET, SHRIMP, ANCHOVY), Option.of(FISHING_ROD, SARDINE, HERRING)); - - companion object { - private val FISHING_SPOTS = FishingSpot.values().associateBy({ it.npc }, { it }) - - /** - * Returns the [FishingSpot] with the specified [id], or `null` if the spot does not exist. - */ - fun lookup(id: Int): FishingSpot? = FISHING_SPOTS[id] - } + NET_ROD(316, Option.of(SMALL_NET, SHRIMPS, ANCHOVIES), Option.of(FISHING_ROD, SARDINE, HERRING)); /** * Returns the [FishingSpot.Option] associated with the specified action id. @@ -159,4 +151,13 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco } + companion object { + private val FISHING_SPOTS = FishingSpot.values().associateBy(FishingSpot::npc) + + /** + * Returns the [FishingSpot] with the specified [id], or `null` if the spot does not exist. + */ + fun lookup(id: Int): FishingSpot? = FISHING_SPOTS[id] + } + } diff --git a/game/plugin/skills/fishing/src/fishing.plugin.kts b/game/plugin/skills/fishing/src/fishing.plugin.kts index a2138bd9e..250545647 100644 --- a/game/plugin/skills/fishing/src/fishing.plugin.kts +++ b/game/plugin/skills/fishing/src/fishing.plugin.kts @@ -57,7 +57,7 @@ class FishingAction(player: Player, position: Position, val option: FishingSpot. } mob.inventory.add(fish.id) - mob.sendMessage("You catch a ${fish.formattedName}.") + mob.sendMessage(fish.catchMessage) mob.fishing.experience += fish.experience if (mob.inventory.freeSlots() == 0) { diff --git a/game/plugin/skills/mining/build.gradle b/game/plugin/skills/mining/build.gradle index 71bc90208..3ea6934ed 100644 --- a/game/plugin/skills/mining/build.gradle +++ b/game/plugin/skills/mining/build.gradle @@ -10,5 +10,5 @@ plugin { "tlf30" ] - dependencies = ["api"] + dependencies = ["api", "util:lookup"] } \ No newline at end of file diff --git a/game/plugin/skills/mining/src/gem.kt b/game/plugin/skills/mining/src/gem.kt index 6f8fa2e72..2252ea4e4 100644 --- a/game/plugin/skills/mining/src/gem.kt +++ b/game/plugin/skills/mining/src/gem.kt @@ -8,6 +8,6 @@ enum class Gem(val id: Int) { // TODO add gem drop chances companion object { private val GEMS = Gem.values().associateBy({ it.id }, { it }) - fun lookup(id: Int): Gem? = GEMS[id] + operator fun get(id: Int): Gem? = GEMS[id] } } \ No newline at end of file diff --git a/game/plugin/skills/mining/src/mining.kt b/game/plugin/skills/mining/src/mining.kt new file mode 100644 index 000000000..0dc0f778c --- /dev/null +++ b/game/plugin/skills/mining/src/mining.kt @@ -0,0 +1,146 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.api.* +import org.apollo.game.plugin.skills.mining.Ore +import org.apollo.game.plugin.skills.mining.Pickaxe +import org.apollo.net.message.Message +import java.util.* + +class MiningAction( + player: Player, + private val tool: Pickaxe, + private val target: MiningTarget +) : AsyncDistancedAction(PULSES, true, player, target.position, ORE_SIZE) { + + companion object { + private const val PULSES = 0 + private const val ORE_SIZE = 1 + + /** + * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player, ore: Ore) { + val pickaxe = Pickaxe.bestFor(player) + + if (pickaxe == null) { + player.sendMessage("You do not have a pickaxe for which you have the level to use.") + } else { + val target = MiningTarget(message.id, message.position, ore) + val action = MiningAction(player, pickaxe, target) + + player.startAction(action) + } + + message.terminate() + } + } + + override fun action(): ActionBlock = { + mob.turnTo(position) + + if (!target.skillRequirementsMet(mob)) { + mob.sendMessage("You do not have the required level to mine this rock.") + stop() + } + + mob.sendMessage("You swing your pick at the rock.") + mob.playAnimation(tool.animation) + + wait(tool.pulses) + + if (!target.isValid(mob.world)) { + stop() + } + + val successChance = rand(100) + + if (target.isSuccessful(mob, successChance)) { + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + stop() + } + + if (target.reward(mob)) { + mob.sendMessage("You manage to mine some ${target.oreName()}") + target.deplete(mob.world) + + stop() + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MiningAction + return mob == other.mob && target == other.target + } + + override fun hashCode(): Int = Objects.hash(mob, target) + +} + +data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { + + /** + * Get the [GameObject] represented by this target. + * + * @todo: api: shouldn't be as verbose + */ + private fun getObject(world: World): GameObject? { + val region = world.regionRepository.fromPosition(position) + return region.findObject(position, objectId).orElse(null) + } + + /** + * Deplete this mining resource from the [World], and schedule it to be respawned + * in a number of ticks specified by the [Ore]. + */ + fun deplete(world: World) { + world.expireObject(getObject(world)!!, ore.objects[objectId]!!, ore.respawn) + } + + /** + * Check if the [Player] was successful in mining this ore with a random success [chance] value between 0 and 100. + */ + fun isSuccessful(mob: Player, chance: Int): Boolean { + val percent = (ore.chance * mob.mining.current + ore.chanceOffset) * 100 + return chance < percent + } + + /** + * Check if this target is still valid in the [World] (i.e. has not been [deplete]d). + */ + fun isValid(world: World) = getObject(world) != null + + /** + * Get the normalized name of the [Ore] represented by this target. + */ + fun oreName() = Definitions.item(ore.id)!!.name.toLowerCase() + + /** + * Reward a [player] with experience and ore if they have the inventory capacity to take a new ore. + */ + fun reward(player: Player): Boolean { + val hasInventorySpace = player.inventory.add(ore.id) + + if (hasInventorySpace) { + player.mining.experience += ore.exp + } + + return hasInventorySpace + } + + /** + * Check if the [mob] has met the skill requirements to mine te [Ore] represented by + * this [MiningTarget]. + */ + fun skillRequirementsMet(mob: Player) = mob.mining.current < ore.level +} + diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index 83ad0621d..8b3f61d1e 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -1,19 +1,5 @@ -import org.apollo.game.action.ActionBlock -import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.message.impl.ObjectActionMessage -import org.apollo.game.model.Position -import org.apollo.game.model.World -import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.plugin.api.Definitions -import org.apollo.game.plugin.api.expireObject -import org.apollo.game.plugin.api.findObject -import org.apollo.game.plugin.api.mining -import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.skills.mining.Ore -import org.apollo.game.plugin.skills.mining.Pickaxe -import org.apollo.net.message.Message -import java.util.Objects on { ObjectActionMessage::class } .where { option == Actions.MINING } @@ -35,99 +21,6 @@ on { ObjectActionMessage::class } } } -class MiningAction( - player: Player, - private val tool: Pickaxe, - private val target: MiningTarget -) : AsyncDistancedAction(PULSES, true, player, target.position, ORE_SIZE) { - - companion object { - private const val PULSES = 0 - private const val ORE_SIZE = 1 - - /** - * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. - */ - fun start(message: ObjectActionMessage, player: Player, ore: Ore) { - val pickaxe = Pickaxe.bestFor(player) - - if (pickaxe == null) { - player.sendMessage("You do not have a pickaxe for which you have the level to use.") - } else { - val target = MiningTarget(message.id, message.position, ore) - val action = MiningAction(player, pickaxe, target) - - player.startAction(action) - } - - message.terminate() - } - } - - override fun action(): ActionBlock = { - mob.turnTo(position) - - val level = mob.mining.current - if (level < target.ore.level) { - mob.sendMessage("You do not have the required level to mine this rock.") - stop() - } - - mob.sendMessage("You swing your pick at the rock.") - mob.playAnimation(tool.animation) - - wait(tool.pulses) - - val obj = target.getObject(mob.world) - if (obj == null) { - stop() - } - - if (target.isSuccessful(mob)) { - if (mob.inventory.freeSlots() == 0) { - mob.inventory.forceCapacityExceeded() - stop() - } - - if (mob.inventory.add(target.ore.id)) { - val oreName = Definitions.item(target.ore.id)!!.name.toLowerCase() - mob.sendMessage("You manage to mine some $oreName") - - mob.mining.experience += target.ore.exp - mob.world.expireObject(obj!!, target.ore.objects[target.objectId]!!, target.ore.respawn) - stop() - } - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as MiningAction - return mob == other.mob && target == other.target - } - - override fun hashCode(): Int = Objects.hash(mob, target) - -} - -data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { - - fun getObject(world: World): GameObject? { - val region = world.regionRepository.fromPosition(position) - return region.findObject(position, objectId).orElse(null) - } - - fun isSuccessful(mob: Player): Boolean { - val offset = if (ore.chanceOffset) 1 else 0 - val percent = (ore.chance * mob.mining.current + offset) * 100 - - return rand(100) < percent - } - -} - private object Actions { const val MINING = 1 const val PROSPECTING = 2 diff --git a/game/plugin/skills/mining/src/ore.kt b/game/plugin/skills/mining/src/ore.kt index e272b182c..7e76cf81c 100644 --- a/game/plugin/skills/mining/src/ore.kt +++ b/game/plugin/skills/mining/src/ore.kt @@ -17,12 +17,12 @@ enum class Ore( val exp: Double, val respawn: Int, val chance: Double, - val chanceOffset: Boolean = false + val chanceOffset: Double = 0.0 ) { - CLAY(CLAY_OBJECTS, id = 434, level = 1, exp = 5.0, respawn = 1, chance = 0.0085, chanceOffset = true), - COPPER(COPPER_OBJECTS, id = 436, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = true), - TIN(TIN_OBJECTS, id = 438, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = true), - IRON(IRON_OBJECTS, id = 440, level = 15, exp = 35.0, respawn = 9, chance = 0.0085, chanceOffset = true), + CLAY(CLAY_OBJECTS, id = 434, level = 1, exp = 5.0, respawn = 1, chance = 0.0085, chanceOffset = 0.45), + COPPER(COPPER_OBJECTS, id = 436, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = 0.45), + TIN(TIN_OBJECTS, id = 438, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = 0.45), + IRON(IRON_OBJECTS, id = 440, level = 15, exp = 35.0, respawn = 9, chance = 0.0085, chanceOffset = 0.45), COAL(COAL_OBJECTS, id = 453, level = 30, exp = 50.0, respawn = 50, chance = 0.004), GOLD(GOLD_OBJECTS, id = 444, level = 40, exp = 65.0, respawn = 100, chance = 0.003), SILVER(SILVER_OBJECTS, id = 442, level = 20, exp = 40.0, respawn = 100, chance = 0.0085), diff --git a/game/plugin/skills/mining/src/pickaxe.kt b/game/plugin/skills/mining/src/pickaxe.kt index a669f492e..45071f0c9 100644 --- a/game/plugin/skills/mining/src/pickaxe.kt +++ b/game/plugin/skills/mining/src/pickaxe.kt @@ -7,7 +7,7 @@ import org.apollo.game.plugin.api.mining enum class Pickaxe(val id: Int, val level: Int, animation: Int, val pulses: Int) { BRONZE(id = 1265, level = 1, animation = 625, pulses = 8), ITRON(id = 1267, level = 1, animation = 626, pulses = 7), - STEEL(id = 1269, level = 1, animation = 627, pulses = 6), + STEEL(id = 1269, level = 6, animation = 627, pulses = 6), MITHRIL(id = 1273, level = 21, animation = 629, pulses = 5), ADAMANT(id = 1271, level = 31, animation = 628, pulses = 4), RUNE(id = 1275, level = 41, animation = 624, pulses = 3); diff --git a/game/plugin/skills/mining/test/MiningActionTests.kt b/game/plugin/skills/mining/test/MiningActionTests.kt new file mode 100644 index 000000000..a378f0ca3 --- /dev/null +++ b/game/plugin/skills/mining/test/MiningActionTests.kt @@ -0,0 +1,80 @@ + +import io.mockk.every +import io.mockk.spyk +import io.mockk.staticMockk +import io.mockk.verify +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.api.expireObject +import org.apollo.game.plugin.skills.mining.Ore +import org.apollo.game.plugin.skills.mining.Pickaxe +import org.apollo.game.plugin.skills.mining.TIN_OBJECTS +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.spawnObject +import org.apollo.game.plugin.testing.assertions.contains +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class MiningActionTests { + private val TIN_OBJ_IDS = TIN_OBJECTS.entries.first() + + @ItemDefinitions + fun ores() = Ore.values() + .map { ItemDefinition(it.id).also { it.name = "" } } + + @ItemDefinitions + fun pickaxes() = listOf(ItemDefinition(Pickaxe.BRONZE.id)) + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + @Test + fun `Attempting to mine a rock we don't have the skill to should send the player a message`() { + val obj = world.spawnObject(1, player.position) + val target = spyk(MiningTarget(obj.id, obj.position, Ore.TIN)) + + every { target.skillRequirementsMet(player) } returns false + player.startAction(MiningAction(player, Pickaxe.BRONZE, target)) + verifyAfter(action.complete()) { player.sendMessage(contains("do not have the required level")) } + } + + @Test + fun `Mining a rock we have the skill to mine should eventually reward ore and experience`() { + val (tinId, expiredTinId) = TIN_OBJ_IDS + val obj = world.spawnObject(tinId, player.position) + val target = spyk(MiningTarget(obj.id, obj.position, Ore.TIN)) + staticMockk("org.apollo.game.plugin.api.WorldKt").mock() + + every { target.skillRequirementsMet(player) } returns true + every { target.isSuccessful(player, any()) } returns true + every { world.expireObject(obj, any(), any()) } answers {} + + player.skillSet.setCurrentLevel(Skill.MINING, Ore.TIN.level) + player.startAction(MiningAction(player, Pickaxe.BRONZE, target)) + + verifyAfter(action.ticks(1)) { player.sendMessage(contains("You swing your pick")) } + after(action.complete()) { + verify { player.sendMessage("You manage to mine some ") } + verify { world.expireObject(obj, expiredTinId, Ore.TIN.respawn) } + + assertTrue(player.inventory.contains(Ore.TIN.id)) + assertEquals(player.skillSet.getExperience(Skill.MINING), Ore.TIN.exp) + } + } +} \ No newline at end of file diff --git a/game/plugin/skills/mining/test/PickaxeTests.kt b/game/plugin/skills/mining/test/PickaxeTests.kt new file mode 100644 index 000000000..15198c0d1 --- /dev/null +++ b/game/plugin/skills/mining/test/PickaxeTests.kt @@ -0,0 +1,75 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.skills.mining.Pickaxe +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +@ExtendWith(ApolloTestingExtension::class) +class PickaxeTests { + + @ItemDefinitions + fun pickaxes() = Pickaxe.values().map { + ItemDefinition(it.id).apply { isStackable = false } + } + + @TestMock + lateinit var player: Player + + @ParameterizedTest + @EnumSource(Pickaxe::class) + fun `No pickaxe is chosen if none are available`(pickaxe: Pickaxe) { + player.skillSet.setCurrentLevel(Skill.MINING, pickaxe.level) + + assertEquals(null, Pickaxe.bestFor(player)) + } + + + @ParameterizedTest + @EnumSource(Pickaxe::class) + fun `The highest level pickaxe is chosen when available`(pickaxe: Pickaxe) { + player.skillSet.setCurrentLevel(Skill.MINING, pickaxe.level) + player.inventory.add(pickaxe.id) + + assertEquals(pickaxe, Pickaxe.bestFor(player)) + } + + @ParameterizedTest + @EnumSource(Pickaxe::class) + fun `Only pickaxes the player has are chosen`(pickaxe: Pickaxe) { + player.skillSet.setCurrentLevel(Skill.MINING, pickaxe.level) + player.inventory.add(Pickaxe.BRONZE.id) + + assertEquals(Pickaxe.BRONZE, Pickaxe.bestFor(player)) + } + + + @ParameterizedTest + @EnumSource(value = Pickaxe::class) + fun `Pickaxes can be chosen from equipment as well as inventory`(pickaxe: Pickaxe) { + player.skillSet.setCurrentLevel(Skill.MINING, pickaxe.level) + player.inventory.add(pickaxe.id) + + assertEquals(pickaxe, Pickaxe.bestFor(player)) + } + + + @ParameterizedTest + @EnumSource(value = Pickaxe::class) + fun `Pickaxes with a level requirement higher than the player's are ignored`(pickaxe: Pickaxe) { + player.skillSet.setCurrentLevel(Skill.MINING, pickaxe.level) + player.inventory.add(pickaxe.id) + + Pickaxe.values() + .filter { it.level > pickaxe.level } + .forEach { player.inventory.add(it.id) } + + assertEquals(pickaxe, Pickaxe.bestFor(player)) + } + +} \ No newline at end of file diff --git a/game/plugin/skills/mining/test/ProspectingTests.kt b/game/plugin/skills/mining/test/ProspectingTests.kt new file mode 100644 index 000000000..0274951d8 --- /dev/null +++ b/game/plugin/skills/mining/test/ProspectingTests.kt @@ -0,0 +1,46 @@ + +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.skills.mining.Ore +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.interactWithObject +import org.apollo.game.plugin.testing.assertions.contains +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource + +@ExtendWith(ApolloTestingExtension::class) +class ProspectingTests { + + @ItemDefinitions + fun ores() = Ore.values().map { + ItemDefinition(it.id).also { it.name = "" } + } + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + @ParameterizedTest + @ArgumentsSource(MiningTestDataProvider::class) + fun `Prospecting a rock should reveal the type of ore it contains`(data: MiningTestData) { + player.interactWithObject(data.rockId, 2) + + verifyAfter(action.ticks(1)) { player.sendMessage(contains("examine the rock")) } + verifyAfter(action.complete()) { player.sendMessage(contains("This rock contains ")) } + } + + @ParameterizedTest + @ArgumentsSource(MiningTestDataProvider::class) + fun `Prospecting an expired rock should reveal it contains no ore`(data: MiningTestData) { + player.interactWithObject(data.expiredRockId, 2) + + verifyAfter(action.complete()) { player.sendMessage(contains("no ore available in this rock")) } + } +} \ No newline at end of file diff --git a/game/plugin/skills/mining/test/TestData.kt b/game/plugin/skills/mining/test/TestData.kt new file mode 100644 index 000000000..e6583035b --- /dev/null +++ b/game/plugin/skills/mining/test/TestData.kt @@ -0,0 +1,17 @@ +import org.apollo.game.plugin.skills.mining.Ore +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import java.util.stream.Stream + +data class MiningTestData(val rockId: Int, val expiredRockId: Int, val ore: Ore) + +fun miningTestData(): Collection = Ore.values() + .flatMap { ore -> ore.objects.map { MiningTestData(it.key, it.value, ore) } } + .toList() + +class MiningTestDataProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream { + return miningTestData().map { Arguments { arrayOf(it) } }.stream() + } +} \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/BoneBuryAction.kt b/game/plugin/skills/prayer/src/BoneBuryAction.kt index f3c463575..c5fe00897 100644 --- a/game/plugin/skills/prayer/src/BoneBuryAction.kt +++ b/game/plugin/skills/prayer/src/BoneBuryAction.kt @@ -25,7 +25,7 @@ class BuryBoneAction( } companion object { - private val BURY_BONE_ANIMATION = Animation(827) + public val BURY_BONE_ANIMATION = Animation(827) internal const val BURY_OPTION = 1 } diff --git a/game/plugin/skills/prayer/src/prayer.plugin.kts b/game/plugin/skills/prayer/src/prayer.plugin.kts index c2857a8f9..2338d8332 100644 --- a/game/plugin/skills/prayer/src/prayer.plugin.kts +++ b/game/plugin/skills/prayer/src/prayer.plugin.kts @@ -34,4 +34,4 @@ on { ItemOptionMessage::class } player.startAction(BuryBoneAction(player, slot, bone)) terminate() - } \ No newline at end of file + } diff --git a/game/plugin/skills/prayer/test/BuryBoneTests.kt b/game/plugin/skills/prayer/test/BuryBoneTests.kt new file mode 100644 index 000000000..d5aaae14b --- /dev/null +++ b/game/plugin/skills/prayer/test/BuryBoneTests.kt @@ -0,0 +1,72 @@ + +import BuryBoneAction.Companion.BURY_BONE_ANIMATION +import io.mockk.verify +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.prayer +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.startsWith +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.interactWithItem +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +@ExtendWith(ApolloTestingExtension::class) +class BuryBoneTests { + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + @ItemDefinitions + fun bones(): Collection { + return Bone.values().map { ItemDefinition(it.id) } + } + + @ParameterizedTest + @EnumSource(value = Bone::class) + fun `Burying a bone should send a message`(bone: Bone) { + player.inventory.add(bone.id) + player.interactWithItem(bone.id, option = 1) + + verifyAfter(action.ticks(1), "message is sent") { + player.sendMessage(startsWith("You dig a hole")) + } + } + + @ParameterizedTest + @EnumSource(value = Bone::class) + fun `Burying a bone should play an animation`(bone: Bone) { + player.inventory.add(bone.id) + player.interactWithItem(bone.id, option = 1) + + verifyAfter(action.ticks(1), "animation is played") { + player.playAnimation(eq(BURY_BONE_ANIMATION)) + } + } + + @ParameterizedTest + @EnumSource(value = Bone::class) + fun `Burying a bone should give the player experience`(bone: Bone) { + player.inventory.add(bone.id) + player.interactWithItem(bone.id, option = 1) + + action.ticks(1) + + after(action.complete(), "experience is granted after bone burial") { + verify { player.sendMessage(startsWith("You bury the bones")) } + + assertEquals(bone.xp, player.prayer.experience) + assertEquals(player.inventory.getAmount(bone.id), 0) + } + } + +} \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index 9d3de2aec..f14e5b73f 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -90,10 +90,7 @@ class WoodcuttingAction( wait(tool.pulses) // Check that the object exists in the world - val obj = target.getObject(mob.world) - if (obj == null) { - stop() - } + val obj = target.getObject(mob.world) ?: stop() if (mob.inventory.add(target.tree.id)) { val logName = Definitions.item(target.tree.id)!!.name.toLowerCase() @@ -105,7 +102,7 @@ class WoodcuttingAction( // respawn time: http://runescape.wikia.com/wiki/Trees val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY - mob.world.expireObject(obj!!, target.tree.stump, respawn.toInt()) + mob.world.expireObject(obj, target.tree.stump, respawn.toInt()) stop() } } diff --git a/game/plugin/skills/woodcutting/test/AxeTests.kt b/game/plugin/skills/woodcutting/test/AxeTests.kt new file mode 100644 index 000000000..2b2d3a2b6 --- /dev/null +++ b/game/plugin/skills/woodcutting/test/AxeTests.kt @@ -0,0 +1,72 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.skills.woodcutting.Axe +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +@ExtendWith(ApolloTestingExtension::class) +class AxeTests { + + @ItemDefinitions + fun axes() = Axe.values().map { + ItemDefinition(it.id).apply { isStackable = false } + } + + @TestMock + lateinit var player: Player + + @ParameterizedTest + @EnumSource(Axe::class) + fun `No axe is chosen if none are available`(axe: Axe) { + player.skillSet.setCurrentLevel(Skill.WOODCUTTING, axe.level) + + assertEquals(null, Axe.bestFor(player)) + } + + @ParameterizedTest + @EnumSource(Axe::class) + fun `The highest level axe is chosen when available`(axe: Axe) { + player.skillSet.setCurrentLevel(Skill.WOODCUTTING, axe.level) + player.inventory.add(axe.id) + + assertEquals(axe, Axe.bestFor(player)) + } + + @ParameterizedTest + @EnumSource(Axe::class) + fun `Only axes the player has are chosen`(axe: Axe) { + player.skillSet.setCurrentLevel(Skill.WOODCUTTING, axe.level) + player.inventory.add(Axe.BRONZE.id) + + assertEquals(Axe.BRONZE, Axe.bestFor(player)) + } + + @ParameterizedTest + @EnumSource(Axe::class) + fun `Axes can be chosen from equipment as well as inventory`(axe: Axe) { + player.skillSet.setCurrentLevel(Skill.WOODCUTTING, axe.level) + player.inventory.add(axe.id) + + assertEquals(axe, Axe.bestFor(player)) + } + + @ParameterizedTest + @EnumSource(Axe::class) + fun `Axes with a level requirement higher than the player's are ignored`(axe: Axe) { + player.skillSet.setCurrentLevel(Skill.WOODCUTTING, axe.level) + player.inventory.add(axe.id) + + Axe.values() + .filter { it.level > axe.level } + .forEach { player.inventory.add(it.id) } + + assertEquals(axe, Axe.bestFor(player)) + } + +} \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/test/TestData.kt b/game/plugin/skills/woodcutting/test/TestData.kt new file mode 100644 index 000000000..073b81ef1 --- /dev/null +++ b/game/plugin/skills/woodcutting/test/TestData.kt @@ -0,0 +1,17 @@ +import org.apollo.game.plugin.skills.woodcutting.Tree +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import java.util.stream.Stream + +data class WoodcuttingTestData(val treeId: Int, val stumpId: Int, val tree: Tree) + +fun woodcuttingTestData(): Collection = Tree.values() + .flatMap { tree -> tree.objects.map { WoodcuttingTestData(it, tree.stump, tree) } } + .toList() + +class WoodcuttingTestDataProvider : ArgumentsProvider { + override fun provideArguments(context: ExtensionContext?): Stream { + return woodcuttingTestData().map { Arguments { arrayOf(it) } }.stream() + } +} \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt b/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt new file mode 100644 index 000000000..8c8f1cd47 --- /dev/null +++ b/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt @@ -0,0 +1,88 @@ + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.skills.woodcutting.Axe +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.contains +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.interactWithObject +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assumptions.assumeTrue +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource +import java.util.* + +@ExtendWith(ApolloTestingExtension::class) +class WoodcuttingTests { + + @ItemDefinitions + fun logs() = woodcuttingTestData().map { + ItemDefinition(it.tree.id).also { it.name = "" } + } + + @ItemDefinitions + fun tools() = listOf(ItemDefinition(Axe.BRONZE.id)) + + @TestMock + lateinit var action: ActionCapture + + @TestMock + lateinit var player: Player + + @ParameterizedTest + @ArgumentsSource(WoodcuttingTestDataProvider::class) + fun `Attempting to cut a tree when the player has no axe should send a message`(data: WoodcuttingTestData) { + player.interactWithObject(data.treeId, 1) + + verify { player.sendMessage(contains("do not have an axe")) } + } + + @ParameterizedTest + @ArgumentsSource(WoodcuttingTestDataProvider::class) + fun `Attempting to cut a tree when the player is too low levelled should send a message`(data: WoodcuttingTestData) { + assumeTrue(data.tree.level > 1, "Normal trees are covered by axe requirements") + + player.inventory.add(Axe.BRONZE.id) + player.skillSet.setCurrentLevel(Skill.WOODCUTTING, data.tree.level - 1) + + player.interactWithObject(data.treeId, 1) + + verifyAfter(action.complete()) { player.sendMessage(contains("do not have the required level")) } + } + + @Disabled("Mocking constructors is not supported in mockk. Update WoodcuttingAction to pass a chance value") + @ParameterizedTest + @ArgumentsSource(WoodcuttingTestDataProvider::class) + fun `Cutting a tree we have the skill to cut should eventually reward logs and experience`( + data: WoodcuttingTestData + ) { + // Mock RNG instances used by mining internally to determine success + // @todo - improve this so we don't have to mock Random + val rng = mockk() + every { rng.nextInt(100) } answers { 0 } + + player.inventory.add(Axe.BRONZE.id) + player.skillSet.setCurrentLevel(Skill.WOODCUTTING, data.tree.level) + + player.interactWithObject(data.treeId, 1) + + verifyAfter(action.ticks(1)) { player.sendMessage(contains("You swing your axe")) } + + after(action.ticks(Axe.BRONZE.pulses)) { + // @todo - cummulative ticks() calls? + verify { player.sendMessage("You manage to cut some ") } + assertEquals(data.tree.exp, player.skillSet.getExperience(Skill.WOODCUTTING)) + assertEquals(1, player.inventory.getAmount(data.tree.id)) + } + } +} \ No newline at end of file diff --git a/game/plugin/util/lookup/build.gradle b/game/plugin/util/lookup/build.gradle new file mode 100644 index 000000000..e2d4a3625 --- /dev/null +++ b/game/plugin/util/lookup/build.gradle @@ -0,0 +1,3 @@ +plugin { + name = "entity_lookup" +} \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/model/World.java b/game/src/main/java/org/apollo/game/model/World.java index 991a41fc6..5d5adb0f8 100644 --- a/game/src/main/java/org/apollo/game/model/World.java +++ b/game/src/main/java/org/apollo/game/model/World.java @@ -299,7 +299,7 @@ public void register(Player player) { playerRepository.add(player); players.put(NameUtil.encodeBase37(username), player); - logger.info("Registered player: " + player + " [count=" + playerRepository.size() + "]"); + logger.finest("Registered player: " + player + " [count=" + playerRepository.size() + "]"); } /** @@ -359,7 +359,7 @@ public void unregister(final Player player) { region.removeEntity(player); playerRepository.remove(player); - logger.info("Unregistered player: " + player + " [count=" + playerRepository.size() + "]"); + logger.finest("Unregistered player: " + player + " [count=" + playerRepository.size() + "]"); } /** diff --git a/game/src/main/java/org/apollo/game/model/entity/Mob.java b/game/src/main/java/org/apollo/game/model/entity/Mob.java index 4e90d48f1..ec09bb9cb 100644 --- a/game/src/main/java/org/apollo/game/model/entity/Mob.java +++ b/game/src/main/java/org/apollo/game/model/entity/Mob.java @@ -235,6 +235,15 @@ public final Direction getFirstDirection() { return firstDirection; } + /** + * Gets the current action, if any, of this mob. + * + * @return The action. + */ + public final Action getAction() { + return action; + } + /** * Gets the index of this mob. * @@ -337,6 +346,15 @@ public int getWidth() { return definition.map(NpcDefinition::getSize).orElse(1); } + /** + * Check whether this mob has a current active {@link Action}. + * + * @return {@code true} if this mob has a non-null {@link Action}. + */ + public final boolean hasAction() { + return action != null; + } + /** * Returns whether or not this mob has an {@link NpcDefinition}. * diff --git a/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt index 1087142b7..5c49c794e 100644 --- a/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt +++ b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt @@ -55,7 +55,7 @@ class ActionCoroutine : Continuation { * Create a new `ActionCoroutine` and immediately execute the given `block`, returning a continuation that * can be resumed. */ - fun start(block: ActionBlock) : ActionCoroutine { + fun start(block: ActionBlock): ActionCoroutine { val coroutine = ActionCoroutine() val continuation = block.createCoroutineUnchecked(coroutine, coroutine) @@ -95,10 +95,7 @@ class ActionCoroutine : Continuation { * Update this continuation and check if the condition for the next step to be resumed is satisfied. */ fun pulse() { - val nextStep = next.getAndSet(null) - if (nextStep == null) { - return - } + val nextStep = next.getAndSet(null) ?: return val condition = nextStep.condition val continuation = nextStep.continuation @@ -120,11 +117,13 @@ class ActionCoroutine : Continuation { /** * Stop execution of this continuation. */ - suspend fun stop() { - return suspendCancellableCoroutine(true) { cont -> + suspend fun stop(): Nothing { + suspendCancellableCoroutine(true) { cont -> next.set(null) cont.cancel() } + + error("Tried to resume execution a coroutine that should have been cancelled.") } /** diff --git a/game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt b/game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt index 4b6df03d7..a8f165cef 100644 --- a/game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt +++ b/game/src/test/kotlin/org/apollo/game/action/ActionCoroutineTest.kt @@ -1,7 +1,7 @@ package org.apollo.game.action -import org.apollo.game.action.ActionCoroutine -import org.junit.Assert.* +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test class ActionCoroutineTest { @@ -29,7 +29,6 @@ class ActionCoroutineTest { fun `Coroutine cancels on stop() calls`() { val coroutine = ActionCoroutine.start { stop() - wait(1) } assertTrue(coroutine.stopped()) diff --git a/gradle/properties.gradle b/gradle/properties.gradle index a5b882c57..bf7c25579 100644 --- a/gradle/properties.gradle +++ b/gradle/properties.gradle @@ -11,4 +11,9 @@ ext { commonsCompressVersion = '1.10' assertjVersion = '3.8.0' classGraphVersion = '4.0.6' + junitVintageVersion = '5.1.0' + junitPlatformVersion = '1.1.0' + junitJupiterVersion = '5.1.0' + mockkVersion = '1.7.15' + assertkVersion = '0.9' } \ No newline at end of file From ebeaa7cd9243352b14a3bf33194e8532b456f7a4 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 19 Aug 2018 23:43:42 +0100 Subject: [PATCH 126/209] Use Gradles built-in JUnit 5 support --- game/plugin-testing/build.gradle | 2 ++ game/plugin/build.gradle | 16 +--------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index 2568f3a67..9e26f3b54 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -2,6 +2,8 @@ apply plugin: 'java-library' apply plugin: 'org.jetbrains.kotlin.jvm' dependencies { + test.useJUnitPlatform() + api project(':game') api project(':net') diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index 7bc92461e..fe8e0f37d 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,23 +1,9 @@ -buildscript { - repositories { - jcenter() - mavenCentral() - - maven { url "https://plugins.gradle.org/m2/" } - } - - dependencies { - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.1.0' - } -} - subprojects { subproj -> if (subproj.buildFile.exists()) { apply plugin: 'apollo-plugin' - apply plugin: 'org.junit.platform.gradle.plugin' - dependencies { + test.useJUnitPlatform() implementation group: 'com.google.guava', name: 'guava', version: guavaVersion } } From 88b0305cc8c22f28fc8cbc7d813dc9ef002b29fc Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 20 Aug 2018 00:00:55 +0100 Subject: [PATCH 127/209] Update test runner and coverage for CI --- .travis.yml | 6 +++++- build.gradle | 8 ++------ gradle/jacoco.gradle | 2 +- gradle/wrapper.gradle | 3 +++ 4 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 gradle/wrapper.gradle diff --git a/.travis.yml b/.travis.yml index 1e232e7b9..91a7bb96b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,12 @@ language: java jdk: - oraclejdk8 +after_success: +- bash <(curl -s https://codecov.io/bash) before_install: - - gradle wrapper + - gradle -b gradle/wrapper.gradle + - mv gradle/gradlew gradle/gradlew.bat . + - mv gradle/gradle/wrapper gradle/ before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ diff --git a/build.gradle b/build.gradle index f8a414e4f..899294782 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,6 @@ plugins { id 'org.jetbrains.kotlin.jvm' version "1.2.60" apply(false) } -wrapper { - gradleVersion = "4.9" - distributionType = Wrapper.DistributionType.ALL -} - allprojects { group = 'apollo' version = '0.0.1' @@ -20,4 +15,5 @@ allprojects { apply from: 'gradle/properties.gradle' apply from: 'gradle/kotlin.gradle' -apply from: 'gradle/jacoco.gradle' \ No newline at end of file +apply from: 'gradle/jacoco.gradle' +apply from: 'gradle/wrapper.gradle' \ No newline at end of file diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle index 9d9267623..31ff7aecf 100644 --- a/gradle/jacoco.gradle +++ b/gradle/jacoco.gradle @@ -43,7 +43,7 @@ task jacocoTestReport(type: JacocoReport) { */ doFirst { subprojects.findAll { subproject -> - subproject.pluginManager.hasPlugin('java') + subproject.pluginManager.hasPlugin('java') || subproject.pluginManager.hasPlugin('kotlin') }.each { subproject -> additionalSourceDirs files((Set) subproject.sourceSets.main.allJava.srcDirs) additionalClassDirs((FileCollection) subproject.sourceSets.main.output) diff --git a/gradle/wrapper.gradle b/gradle/wrapper.gradle new file mode 100644 index 000000000..35e4d7ddd --- /dev/null +++ b/gradle/wrapper.gradle @@ -0,0 +1,3 @@ +wrapper { + gradleVersion = "4.9" +} From ab64a099ba1ee325ce427b82cf9f466ff045bede Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 20 Aug 2018 00:03:12 +0100 Subject: [PATCH 128/209] Add missing wrapper task in Travis config --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 91a7bb96b..74311d007 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ jdk: after_success: - bash <(curl -s https://codecov.io/bash) before_install: - - gradle -b gradle/wrapper.gradle + - gradle -b gradle/wrapper.gradle wrapper - mv gradle/gradlew gradle/gradlew.bat . - mv gradle/gradle/wrapper gradle/ before_cache: From 5307a62f8dd3f9c5e7353b921d5d0157cf04befa Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 20 Aug 2018 00:13:25 +0100 Subject: [PATCH 129/209] Put plugins with the same name in unique packages --- game/plugin/locations/al-kharid/src/npcs.plugin.kts | 2 ++ game/plugin/locations/edgeville/src/npcs.plugin.kts | 2 ++ game/plugin/locations/falador/src/npcs.plugin.kts | 2 ++ game/plugin/locations/lumbridge/src/npcs.plugin.kts | 2 ++ game/plugin/locations/tutorial-island/src/npcs.plugin.kts | 2 ++ game/plugin/locations/varrock/src/npcs.plugin.kts | 2 ++ 6 files changed, 12 insertions(+) diff --git a/game/plugin/locations/al-kharid/src/npcs.plugin.kts b/game/plugin/locations/al-kharid/src/npcs.plugin.kts index 7fd53bd7e..71fa6ce03 100644 --- a/game/plugin/locations/al-kharid/src/npcs.plugin.kts +++ b/game/plugin/locations/al-kharid/src/npcs.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.alKharid + import org.apollo.game.model.Direction import org.apollo.game.plugin.entity.spawn.npc_spawn diff --git a/game/plugin/locations/edgeville/src/npcs.plugin.kts b/game/plugin/locations/edgeville/src/npcs.plugin.kts index be3ba855c..2fa94f88a 100644 --- a/game/plugin/locations/edgeville/src/npcs.plugin.kts +++ b/game/plugin/locations/edgeville/src/npcs.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.edgeville + import org.apollo.game.model.Direction import org.apollo.game.plugin.entity.spawn.npc_spawn diff --git a/game/plugin/locations/falador/src/npcs.plugin.kts b/game/plugin/locations/falador/src/npcs.plugin.kts index f03926a03..68b676f2e 100644 --- a/game/plugin/locations/falador/src/npcs.plugin.kts +++ b/game/plugin/locations/falador/src/npcs.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.falador + import org.apollo.game.plugin.entity.spawn.npc_spawn // Generic npcs diff --git a/game/plugin/locations/lumbridge/src/npcs.plugin.kts b/game/plugin/locations/lumbridge/src/npcs.plugin.kts index 9af0f50d9..28b055058 100644 --- a/game/plugin/locations/lumbridge/src/npcs.plugin.kts +++ b/game/plugin/locations/lumbridge/src/npcs.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.lumbridge + import org.apollo.game.plugin.entity.spawn.npc_spawn npc_spawn("woman", id = 4, x = 3232, y = 3207) diff --git a/game/plugin/locations/tutorial-island/src/npcs.plugin.kts b/game/plugin/locations/tutorial-island/src/npcs.plugin.kts index ed80dacba..f3165e697 100644 --- a/game/plugin/locations/tutorial-island/src/npcs.plugin.kts +++ b/game/plugin/locations/tutorial-island/src/npcs.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.tutorialIsland + import org.apollo.game.model.Direction import org.apollo.game.plugin.entity.spawn.npc_spawn diff --git a/game/plugin/locations/varrock/src/npcs.plugin.kts b/game/plugin/locations/varrock/src/npcs.plugin.kts index 11c64a585..4ffecf07b 100644 --- a/game/plugin/locations/varrock/src/npcs.plugin.kts +++ b/game/plugin/locations/varrock/src/npcs.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.varrock + import org.apollo.game.model.Direction import org.apollo.game.plugin.entity.spawn.npc_spawn From 37547ee3aaf1e3b831b7ba7a4f5a8497dd98ebbc Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 20 Aug 2018 00:14:08 +0100 Subject: [PATCH 130/209] Produce coverage report with JaCoCo during CI --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 74311d007..3e1191abd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,8 @@ language: java jdk: - oraclejdk8 after_success: -- bash <(curl -s https://codecov.io/bash) + - ./gradlew jacocoTestReport + - bash <(curl -s https://codecov.io/bash) before_install: - gradle -b gradle/wrapper.gradle wrapper - mv gradle/gradlew gradle/gradlew.bat . From 5d84cdf40f59c94074c084b23c4befa6ed0797ec Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 20 Aug 2018 01:29:52 +0100 Subject: [PATCH 131/209] Fix recording of code coverage --- game/build.gradle | 6 +++ game/plugin/build.gradle | 4 ++ gradle/jacoco.gradle | 80 +++++++++++++++++++--------------------- settings.gradle | 1 - 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/game/build.gradle b/game/build.gradle index 378fa03f5..a357a982a 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -18,6 +18,12 @@ dependencies { implementation group: 'io.github.classgraph', name: 'classgraph', version: classGraphVersion implementation group: 'com.lambdaworks', name: 'scrypt', version: scryptVersion + test.useJUnitPlatform() + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitJupiterVersion + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitJupiterVersion + testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVintageVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-launcher', version: junitPlatformVersion + testImplementation group: 'junit', name: 'junit', version: junitVersion testImplementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion testImplementation group: 'org.powermock', name: 'powermock-api-mockito', version: powermockVersion diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index fe8e0f37d..90c96c9a6 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -2,6 +2,10 @@ subprojects { subproj -> if (subproj.buildFile.exists()) { apply plugin: 'apollo-plugin' + test { + useJUnitPlatform() + } + dependencies { test.useJUnitPlatform() implementation group: 'com.google.guava', name: 'guava', version: guavaVersion diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle index 31ff7aecf..1e87c9a57 100644 --- a/gradle/jacoco.gradle +++ b/gradle/jacoco.gradle @@ -1,59 +1,53 @@ -apply plugin: "jacoco" +apply plugin: 'jacoco' + +def testedProjects() { + subprojects.findAll { subproject -> subproject.plugins.hasPlugin('java') || subproject.plugins.hasPlugin('kotlin') } +} + +gradle.projectsEvaluated { + + configure(testedProjects()) { + apply plugin: 'jacoco' -allprojects { - tasks.withType(Test) { jacoco { toolVersion = '0.8.1' } - afterEvaluate { - jacocoTestReport { - dependsOn tasks.test + jacocoTestReport { + sourceDirectories = files(sourceSets.main.allSource.srcDirs) + classDirectories = files(sourceSets.main.output) + } - sourceSets sourceSets.main - reports { - html.enabled = true - xml.enabled = true - csv.enabled = false - } + test { + jacoco { + append = false + destinationFile = file("$buildDir/jacoco/jacocoTest.exec") + classDumpDir = file("$buildDir/jacoco/classpathdumps") } } } -} -task jacocoTestReport(type: JacocoReport) { - sourceDirectories = files() - classDirectories = files() - executionData = files() + task jacocoTestReport(type: JacocoReport) { + def tests = [] + def sourceDirs = files() + def classDirs = files() + def execData = files() - reports { - html.enabled = true - xml.enabled = true - csv.enabled = false - } - - // Work-around to allow us to build list of executionData files in doFirst - onlyIf = { - true - } + testedProjects().each { subproject -> + sourceDirs += files(subproject.sourceSets.main.allSource.srcDirs) + classDirs += files(subproject.sourceSets.main.output) + execData += files(subproject.tasks.jacocoTestReport.executionData.findAll { + it.exists() + }) - /* - * Builds list of source dirs, class dirs, and executionData files - * when task is run, not at script evaluation time - */ - doFirst { - subprojects.findAll { subproject -> - subproject.pluginManager.hasPlugin('java') || subproject.pluginManager.hasPlugin('kotlin') - }.each { subproject -> - additionalSourceDirs files((Set) subproject.sourceSets.main.allJava.srcDirs) - additionalClassDirs((FileCollection) subproject.sourceSets.main.output) - if (subproject.pluginManager.hasPlugin('jacoco')) { - executionData subproject.tasks.jacocoTestReport.executionData - } + tests += subproject.tasks.test } - executionData = files(executionData.findAll { - it.exists() - }) + dependsOn tests + sourceDirectories = sourceDirs + classDirectories = classDirs + executionData = execData } + + } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 6f0626f13..6cd4ff993 100644 --- a/settings.gradle +++ b/settings.gradle @@ -35,5 +35,4 @@ def processPluginDir(Path pluginDir) { } pluginDirs.each { processPluginDir(it) } -include 'test-plugin' From 50d7e8630259bfabfbcf1218191ba1647468a29f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 20 Aug 2018 01:38:43 +0100 Subject: [PATCH 132/209] Produce XML coverage report for codecov.io --- gradle/jacoco.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle index 1e87c9a57..4fee3f85c 100644 --- a/gradle/jacoco.gradle +++ b/gradle/jacoco.gradle @@ -33,6 +33,11 @@ gradle.projectsEvaluated { def classDirs = files() def execData = files() + reports { + xml.enabled = true + html.enabled = true + } + testedProjects().each { subproject -> sourceDirs += files(subproject.sourceSets.main.allSource.srcDirs) classDirs += files(subproject.sourceSets.main.output) From 71158b3b5e089cd13f240074c274b1389a164ee1 Mon Sep 17 00:00:00 2001 From: Major Date: Mon, 20 Aug 2018 21:46:15 +0100 Subject: [PATCH 133/209] Add unit tests for areas plugin --- game/plugin/areas/src/Area.kt | 27 ++++++ game/plugin/areas/src/AreaAction.kt | 51 ++++++++++ game/plugin/areas/src/AreaActionBuilder.kt | 42 +++++++++ .../{areas.plugin.kts => Areas.plugin.kts} | 0 game/plugin/areas/src/action.kt | 18 ---- game/plugin/areas/src/area.kt | 94 ------------------- game/plugin/areas/test/AreaActionTests.kt | 59 ++++++++++++ 7 files changed, 179 insertions(+), 112 deletions(-) create mode 100644 game/plugin/areas/src/Area.kt create mode 100644 game/plugin/areas/src/AreaAction.kt create mode 100644 game/plugin/areas/src/AreaActionBuilder.kt rename game/plugin/areas/src/{areas.plugin.kts => Areas.plugin.kts} (100%) delete mode 100644 game/plugin/areas/src/action.kt delete mode 100644 game/plugin/areas/src/area.kt create mode 100644 game/plugin/areas/test/AreaActionTests.kt diff --git a/game/plugin/areas/src/Area.kt b/game/plugin/areas/src/Area.kt new file mode 100644 index 000000000..6efdae069 --- /dev/null +++ b/game/plugin/areas/src/Area.kt @@ -0,0 +1,27 @@ +package org.apollo.game.plugins.area + +import org.apollo.game.model.Position +import org.apollo.game.plugins.api.Position.component1 +import org.apollo.game.plugins.api.Position.component2 +import org.apollo.game.plugins.api.Position.component3 + +/** + * An area in the game world. + */ +interface Area { + + /** + * Returns whether or not the specified [Position] is inside this [Area]. + */ + operator fun contains(position: Position): Boolean + +} + +internal class RectangularArea(private val x: IntRange, private val y: IntRange, private val height: Int) : Area { + + override operator fun contains(position: Position): Boolean { + val (x, y, z) = position + return x in this.x && y in this.y && z == height + } + +} diff --git a/game/plugin/areas/src/AreaAction.kt b/game/plugin/areas/src/AreaAction.kt new file mode 100644 index 000000000..85d8141a5 --- /dev/null +++ b/game/plugin/areas/src/AreaAction.kt @@ -0,0 +1,51 @@ +package org.apollo.game.plugins.area + +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player + +/** + * A set of actions to execute when a player enters, moves inside, or exits a specific area of the world. + */ +internal class AreaAction(val entrance: AreaListener, val inside: AreaListener, val exit: AreaListener) + +/** + * A function that is invoked when a player enters, moves inside of, or exits an [Area]. + */ +typealias AreaListener = Player.(Position) -> Unit + +/** + * Registers an [AreaAction] for the specified [Area] using the builder. + */ +fun action(name: String, area: Area, builder: AreaActionBuilder.() -> Unit) { + actions += AreaActionBuilder(name, area).apply(builder).build() +} + +/** + * Registers an [AreaAction] for the specified [Area] using the builder. + * + * @param predicate The predicate that determines whether or not the given [Position] is inside the [Area]. + */ +fun action(name: String, predicate: (Position) -> Boolean, builder: AreaActionBuilder.() -> Unit) { + val area = object : Area { + override fun contains(position: Position): Boolean = predicate(position) + } + + action(name, area, builder) +} + +/** + * Registers an [AreaAction] for the specified [Area] using the builder. + * + * @param x The `x` coordinate range, both ends inclusive. + * @param y The `y` coordinate range, both ends inclusive. + */ +fun action(name: String, x: IntRange, y: IntRange, height: Int = 0, builder: AreaActionBuilder.() -> Unit) { + val area = RectangularArea(x, y, height) + + action(name, area, builder) +} + +/** + * The [Set] of ([Area], [AreaAction]) [Pair]s. + */ +internal val actions = mutableSetOf>() diff --git a/game/plugin/areas/src/AreaActionBuilder.kt b/game/plugin/areas/src/AreaActionBuilder.kt new file mode 100644 index 000000000..00ba8eb64 --- /dev/null +++ b/game/plugin/areas/src/AreaActionBuilder.kt @@ -0,0 +1,42 @@ +package org.apollo.game.plugins.area + +/** + * A builder for ([Area], [AreaAction]) [Pair]s. + */ +class AreaActionBuilder internal constructor(val name: String, val area: Area) { + + private var entrance: AreaListener = { } + + private var inside: AreaListener = { } + + private var exit: AreaListener = { } + + /** + * Places the contents of this builder into an ([Area], [AreaAction]) [Pair]. + */ + internal fun build(): Pair { + return Pair(area, AreaAction(entrance, inside, exit)) + } + + /** + * The [listener] to execute when a player enters the associated [Area]. + */ + fun entrance(listener: AreaListener) { + this.entrance = listener + } + + /** + * The [listener] to execute when a player moves around inside the associated [Area]. + */ + fun inside(listener: AreaListener) { + this.inside = listener + } + + /** + * The [listener] to execute when a player moves exits the associated [Area]. + */ + fun exit(listener: AreaListener) { + this.exit = listener + } + +} \ No newline at end of file diff --git a/game/plugin/areas/src/areas.plugin.kts b/game/plugin/areas/src/Areas.plugin.kts similarity index 100% rename from game/plugin/areas/src/areas.plugin.kts rename to game/plugin/areas/src/Areas.plugin.kts diff --git a/game/plugin/areas/src/action.kt b/game/plugin/areas/src/action.kt deleted file mode 100644 index 5b965603a..000000000 --- a/game/plugin/areas/src/action.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.apollo.game.plugins.area - -/** - * Defines an area action using the DSL. - */ -fun action(@Suppress("UNUSED_PARAMETER") name: String, builder: ActionBuilder.() -> Unit) { - val listener = ActionBuilder() - builder(listener) - - actions.add(listener.build()) -} - -/** - * The [Set] of ([Area], [AreaAction]) [Pair]s. - */ -val actions = mutableSetOf>() - -class AreaAction(val entrance: AreaListener, val inside: AreaListener, val exit: AreaListener) \ No newline at end of file diff --git a/game/plugin/areas/src/area.kt b/game/plugin/areas/src/area.kt deleted file mode 100644 index a924ca44e..000000000 --- a/game/plugin/areas/src/area.kt +++ /dev/null @@ -1,94 +0,0 @@ -package org.apollo.game.plugins.area - -import org.apollo.game.model.Position -import org.apollo.game.model.entity.Player -import org.apollo.game.plugins.api.Position.component1 -import org.apollo.game.plugins.api.Position.component2 -import org.apollo.game.plugins.api.Position.component3 - -/** - * An area in the game world. - */ -interface Area { - - /** - * Returns whether or not the specified [Position] is inside this [Area]. - */ - operator fun contains(position: Position): Boolean - -} - -private class RectangularArea(val x: IntRange, val y: IntRange, val height: Int) : Area { - - override operator fun contains(position: Position): Boolean { - val (x, y, z) = position - return x in this.x && y in this.y && z == height - } - -} - -/** - * A typealias for a function that is invoked when a player enters, moves inside of, or exits an [Area]. - */ -internal typealias AreaListener = Player.(Position) -> Unit - -/** - * A builder for ([Area], [AreaAction]) [Pair]s. - */ -class ActionBuilder { - - private var area: Area? = null - - private var entrance: AreaListener = { } - - private var inside: AreaListener = { } - - private var exit: AreaListener = { } - - /** - * Places the contents of this builder into an ([Area], [AreaAction]) [Pair]. - */ - fun build(): Pair { - val area = area ?: throw UnsupportedOperationException("Area must be specified.") - return Pair(area, AreaAction(entrance, inside, exit)) - } - - /** - * Sets the [Area] to listen for movement in. - */ - fun area(contains: (Position) -> Boolean) { - this.area = object : Area { - override fun contains(position: Position): Boolean = contains.invoke(position) - } - } - - /** - * Sets the [Area] to listen for movement in. Note that [IntRange]s are (inclusive, _exclusive_), i.e. the upper - * bound is exclusive. - */ - fun area(x: IntRange, y: IntRange, height: Int = 0) { - this.area = RectangularArea(x, y, height) - } - - /** - * Executes the specified [listener] when a player enters the related [Area]. - */ - fun entrance(listener: AreaListener) { - this.entrance = listener - } - - /** - * Executes the specified [listener] when a player moves around inside the related [Area]. - */ - fun inside(listener: AreaListener) { - this.inside = listener - } - - /** - * Executes the specified [listener] when a player moves exits the related [Area]. - */ - fun exit(listener: AreaListener) { - this.exit = listener - } - -} \ No newline at end of file diff --git a/game/plugin/areas/test/AreaActionTests.kt b/game/plugin/areas/test/AreaActionTests.kt new file mode 100644 index 000000000..0fbd5e1b6 --- /dev/null +++ b/game/plugin/areas/test/AreaActionTests.kt @@ -0,0 +1,59 @@ +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugins.area.action +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class AreaActionTests { + + @TestMock + lateinit var player: Player + + @Test + fun `entrance action is triggered when a player enters the area`() { + var triggered = false + val position = Position(3222, 3222) + + action("entrance_test_action", predicate = { it == player.position }) { + triggered = true + } + + player.position = position + + assertTrue(triggered) { "entrance_test_action was not triggered." } + } + + @Test + fun `inside action is triggered when a player moves inside an area`() { + player.position = Position(3222, 3222) + var triggered = false + + action("inside_test_action", x = 3220..3224, y = 3220..3224) { + triggered = true + } + + player.position = Position(3223, 3222) + + assertTrue(triggered) { "inside_test_action was not triggered." } + } + + @Test + fun `exit action is triggered when a player exits the area`() { + player.position = Position(3222, 3222) + + var triggered = false + + action("exit_test_action", predicate = { it == player.position }) { + triggered = true + } + + player.position = Position(3221, 3221) + + assertTrue(triggered) { "exit_test_action was not triggered." } + } + +} \ No newline at end of file From 86fba62ab989e12f814bb80baeb8e91372d6b78a Mon Sep 17 00:00:00 2001 From: Major Date: Tue, 21 Aug 2018 00:47:23 +0100 Subject: [PATCH 134/209] Support npc and object definitions in plugin tests --- .../testing/junit/ApolloTestExtension.kt | 95 +++++++++++++++---- .../api/annotations/definitionAnnotations.kt | 34 ++++++- game/plugin/api/src/definitions.kt | 6 +- .../skills/mining/test/MiningActionTests.kt | 35 ++++--- .../plugin/skills/mining/test/PickaxeTests.kt | 12 ++- .../skills/mining/test/ProspectingTests.kt | 15 +-- .../skills/prayer/test/BuryBoneTests.kt | 12 ++- .../skills/woodcutting/test/AxeTests.kt | 12 ++- .../woodcutting/test/WoodcuttingTests.kt | 20 ++-- .../game/plugin/KotlinPluginEnvironment.java | 13 ++- 10 files changed, 182 insertions(+), 72 deletions(-) diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt index b36404654..defeb83f0 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt @@ -5,6 +5,8 @@ import io.mockk.slot import io.mockk.spyk import io.mockk.staticMockk import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition import org.apollo.game.message.handler.MessageHandlerChainSet import org.apollo.game.model.World import org.apollo.game.model.entity.Npc @@ -15,14 +17,25 @@ import org.apollo.game.plugin.PluginMetaData import org.apollo.game.plugin.testing.fakes.FakePluginContextFactory import org.apollo.game.plugin.testing.junit.api.ActionCapture import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions import org.apollo.game.plugin.testing.junit.mocking.StubPrototype -import org.junit.jupiter.api.extension.* -import java.util.* +import org.junit.jupiter.api.extension.AfterAllCallback +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.AfterTestExecutionCallback +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.BeforeEachCallback +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.api.extension.ParameterContext +import org.junit.jupiter.api.extension.ParameterResolver +import java.util.ArrayList +import kotlin.reflect.KFunction import kotlin.reflect.KMutableProperty +import kotlin.reflect.full.companionObject import kotlin.reflect.full.createType import kotlin.reflect.full.declaredMemberFunctions import kotlin.reflect.full.declaredMemberProperties -import kotlin.reflect.full.findAnnotation +import kotlin.reflect.jvm.isAccessible import kotlin.reflect.jvm.jvmErasure internal val supportedTestDoubleTypes = setOf( @@ -67,6 +80,25 @@ class ApolloTestingExtension : val stubHandlers = MessageHandlerChainSet() val stubWorld = spyk(World()) + context.testClass // This _must_ come before plugin environment initialisation + .map { it.kotlin.companionObject } + .ifPresent { companion -> + val companionInstance = companion.objectInstance!! + val testClassMethods = companion.declaredMemberFunctions + + createTestDefinitions( + testClassMethods, companionInstance, ItemDefinition::getId, ItemDefinition::lookup + ) + + createTestDefinitions( + testClassMethods, companionInstance, NpcDefinition::getId, NpcDefinition::lookup + ) + + createTestDefinitions( + testClassMethods, companionInstance, ObjectDefinition::getId, ObjectDefinition::lookup + ) + } + val pluginEnvironment = KotlinPluginEnvironment(stubWorld) pluginEnvironment.setContext(FakePluginContextFactory.create(stubHandlers)) pluginEnvironment.load(ArrayList()) @@ -77,22 +109,8 @@ class ApolloTestingExtension : } override fun beforeEach(context: ExtensionContext) { - val testClass = context.requiredTestClass.kotlin val testClassInstance = context.requiredTestInstance - val testClassProps = testClass.declaredMemberProperties - val testClassMethods = context.testClass.map { it.kotlin.declaredMemberFunctions }.orElse(emptyList()) - val testClassItemDefs = testClassMethods.asSequence() - .mapNotNull { it.findAnnotation()?.let { anno -> it to anno } } - .flatMap { (it.first.call(context.requiredTestInstance as Any) as Collection).asSequence() } - .map { it.id to it } - .toMap() - - if (testClassItemDefs.isNotEmpty()) { - val itemIdSlot = slot() - - staticMockk().mock() - every { ItemDefinition.lookup(capture(itemIdSlot)) } answers { testClassItemDefs[itemIdSlot.captured] } - } + val testClassProps = context.requiredTestClass.kotlin.declaredMemberProperties val store = context.getStore(namespace) val state = store.get(ApolloTestState::class) as ApolloTestState @@ -101,10 +119,10 @@ class ApolloTestingExtension : .mapNotNull { it as? KMutableProperty<*> } .filter { supportedTestDoubleTypes.contains(it.returnType) } - propertyStubSites.forEach { - it.setter.call( + propertyStubSites.forEach { property -> + property.setter.call( testClassInstance, - state.createStub(StubPrototype(it.returnType.jvmErasure, it.annotations)) + state.createStub(StubPrototype(property.returnType.jvmErasure, property.annotations)) ) } } @@ -124,4 +142,39 @@ class ApolloTestingExtension : return testState.createStub(StubPrototype(paramType, param.annotations.toList())) } + + /** + * Mocks the definition class of type [D] for any function with the attached annotation [A]. + * + * @param testClassMethods All of the methods in the class being tested. + * @param idMapper The map function that returns an id given a definition [D]. + * @param lookup The lookup function that returns an instance of [D] given a definition id. + */ + private inline fun createTestDefinitions( + testClassMethods: Collection>, + companionObjectInstance: Any?, + crossinline idMapper: (D) -> Int, + crossinline lookup: (Int) -> D + ) { + val testDefinitions = testClassMethods.asSequence() + .filter { method -> method.annotations.any { it is A } } + .flatMap { method -> + @Suppress("UNCHECKED_CAST") + method as? KFunction> ?: throw RuntimeException("${method.name} is annotated with " + + "${A::class.simpleName} but does not return Collection<${D::class.simpleName}." + ) + + method.isAccessible = true // lets us call methods in private companion objects + method.call(companionObjectInstance).asSequence() + } + .associateBy(idMapper) + + if (testDefinitions.isNotEmpty()) { + val idSlot = slot() + + staticMockk().mock() + every { lookup(capture(idSlot)) } answers { testDefinitions[idSlot.captured]!! } + } + } + } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt index 484d0b2c9..b730b277b 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt @@ -1,5 +1,37 @@ package org.apollo.game.plugin.testing.junit.api.annotations +/** + * Specifies that the the ItemDefinitions returned by the annotated function should be inserted into the definition + * table. + * + * The annotated function **must**: + * - Be inside a **companion object** inside an apollo test class (a regular object will not work). + * - Return a `Collection`. + */ @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) -annotation class ItemDefinitions \ No newline at end of file +annotation class ItemDefinitions + +/** + * Specifies that the the NpcDefinitions returned by the annotated function should be inserted into the definition + * table. + * + * The annotated function **must**: + * - Be inside a **companion object** inside an apollo test class (a regular object will not work). + * - Return a `Collection`. + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class NpcDefinitions + +/** + * Specifies that the the ObjectDefinitions returned by the annotated function should be inserted into the definition + * table. + * + * The annotated function **must**: + * - Be inside a **companion object** inside an apollo test class (a regular object will not work). + * - Return a `Collection`. + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class ObjectDefinitions \ No newline at end of file diff --git a/game/plugin/api/src/definitions.kt b/game/plugin/api/src/definitions.kt index b2f826e5f..9e64e460b 100644 --- a/game/plugin/api/src/definitions.kt +++ b/game/plugin/api/src/definitions.kt @@ -22,7 +22,11 @@ object Definitions { } fun npc(id: Int): NpcDefinition? { - return NpcDefinition.lookup(id) + try { + return NpcDefinition.lookup(id) + } catch (e: NullPointerException) { + throw RuntimeException("Failed to find npc $id: count=${NpcDefinition.count()}") + } } fun npc(name: String): NpcDefinition? { diff --git a/game/plugin/skills/mining/test/MiningActionTests.kt b/game/plugin/skills/mining/test/MiningActionTests.kt index a378f0ca3..f9fe0319b 100644 --- a/game/plugin/skills/mining/test/MiningActionTests.kt +++ b/game/plugin/skills/mining/test/MiningActionTests.kt @@ -12,13 +12,13 @@ import org.apollo.game.plugin.skills.mining.Ore import org.apollo.game.plugin.skills.mining.Pickaxe import org.apollo.game.plugin.skills.mining.TIN_OBJECTS import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.assertions.verifyAfter import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.ActionCapture import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.apollo.game.plugin.testing.junit.api.interactions.spawnObject -import org.apollo.game.plugin.testing.assertions.contains import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test @@ -26,14 +26,6 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(ApolloTestingExtension::class) class MiningActionTests { - private val TIN_OBJ_IDS = TIN_OBJECTS.entries.first() - - @ItemDefinitions - fun ores() = Ore.values() - .map { ItemDefinition(it.id).also { it.name = "" } } - - @ItemDefinitions - fun pickaxes() = listOf(ItemDefinition(Pickaxe.BRONZE.id)) @TestMock lateinit var world: World @@ -50,8 +42,12 @@ class MiningActionTests { val target = spyk(MiningTarget(obj.id, obj.position, Ore.TIN)) every { target.skillRequirementsMet(player) } returns false + player.startAction(MiningAction(player, Pickaxe.BRONZE, target)) - verifyAfter(action.complete()) { player.sendMessage(contains("do not have the required level")) } + + verifyAfter(action.complete()) { + player.sendMessage(contains("do not have the required level")) + } } @Test @@ -63,12 +59,15 @@ class MiningActionTests { every { target.skillRequirementsMet(player) } returns true every { target.isSuccessful(player, any()) } returns true - every { world.expireObject(obj, any(), any()) } answers {} + every { world.expireObject(obj, any(), any()) } answers { } player.skillSet.setCurrentLevel(Skill.MINING, Ore.TIN.level) player.startAction(MiningAction(player, Pickaxe.BRONZE, target)) - verifyAfter(action.ticks(1)) { player.sendMessage(contains("You swing your pick")) } + verifyAfter(action.ticks(1)) { + player.sendMessage(contains("You swing your pick")) + } + after(action.complete()) { verify { player.sendMessage("You manage to mine some ") } verify { world.expireObject(obj, expiredTinId, Ore.TIN.respawn) } @@ -77,4 +76,16 @@ class MiningActionTests { assertEquals(player.skillSet.getExperience(Skill.MINING), Ore.TIN.exp) } } + + private companion object { + private val TIN_OBJ_IDS = TIN_OBJECTS.entries.first() + + @ItemDefinitions + fun ores() = Ore.values() + .map { ItemDefinition(it.id).apply { name = "" } } + + @ItemDefinitions + fun pickaxes() = listOf(ItemDefinition(Pickaxe.BRONZE.id)) + } + } \ No newline at end of file diff --git a/game/plugin/skills/mining/test/PickaxeTests.kt b/game/plugin/skills/mining/test/PickaxeTests.kt index 15198c0d1..69e375395 100644 --- a/game/plugin/skills/mining/test/PickaxeTests.kt +++ b/game/plugin/skills/mining/test/PickaxeTests.kt @@ -13,11 +13,6 @@ import org.junit.jupiter.params.provider.EnumSource @ExtendWith(ApolloTestingExtension::class) class PickaxeTests { - @ItemDefinitions - fun pickaxes() = Pickaxe.values().map { - ItemDefinition(it.id).apply { isStackable = false } - } - @TestMock lateinit var player: Player @@ -72,4 +67,11 @@ class PickaxeTests { assertEquals(pickaxe, Pickaxe.bestFor(player)) } + private companion object { + @ItemDefinitions + fun pickaxes() = Pickaxe.values().map { + ItemDefinition(it.id).apply { isStackable = false } + } + } + } \ No newline at end of file diff --git a/game/plugin/skills/mining/test/ProspectingTests.kt b/game/plugin/skills/mining/test/ProspectingTests.kt index 0274951d8..2bbc07665 100644 --- a/game/plugin/skills/mining/test/ProspectingTests.kt +++ b/game/plugin/skills/mining/test/ProspectingTests.kt @@ -2,13 +2,13 @@ import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.entity.Player import org.apollo.game.plugin.skills.mining.Ore +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.assertions.verifyAfter import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.ActionCapture import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.apollo.game.plugin.testing.junit.api.interactions.interactWithObject -import org.apollo.game.plugin.testing.assertions.contains import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ArgumentsSource @@ -16,11 +16,6 @@ import org.junit.jupiter.params.provider.ArgumentsSource @ExtendWith(ApolloTestingExtension::class) class ProspectingTests { - @ItemDefinitions - fun ores() = Ore.values().map { - ItemDefinition(it.id).also { it.name = "" } - } - @TestMock lateinit var player: Player @@ -43,4 +38,12 @@ class ProspectingTests { verifyAfter(action.complete()) { player.sendMessage(contains("no ore available in this rock")) } } + + private companion object { + @ItemDefinitions + fun ores() = Ore.values().map { + ItemDefinition(it.id).also { it.name = "" } + } + } + } \ No newline at end of file diff --git a/game/plugin/skills/prayer/test/BuryBoneTests.kt b/game/plugin/skills/prayer/test/BuryBoneTests.kt index d5aaae14b..6d485334b 100644 --- a/game/plugin/skills/prayer/test/BuryBoneTests.kt +++ b/game/plugin/skills/prayer/test/BuryBoneTests.kt @@ -26,11 +26,6 @@ class BuryBoneTests { @TestMock lateinit var action: ActionCapture - @ItemDefinitions - fun bones(): Collection { - return Bone.values().map { ItemDefinition(it.id) } - } - @ParameterizedTest @EnumSource(value = Bone::class) fun `Burying a bone should send a message`(bone: Bone) { @@ -69,4 +64,11 @@ class BuryBoneTests { } } + private companion object { + @ItemDefinitions + fun bones(): Collection { + return Bone.values().map { ItemDefinition(it.id) } + } + } + } \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/test/AxeTests.kt b/game/plugin/skills/woodcutting/test/AxeTests.kt index 2b2d3a2b6..cbbedb551 100644 --- a/game/plugin/skills/woodcutting/test/AxeTests.kt +++ b/game/plugin/skills/woodcutting/test/AxeTests.kt @@ -13,11 +13,6 @@ import org.junit.jupiter.params.provider.EnumSource @ExtendWith(ApolloTestingExtension::class) class AxeTests { - @ItemDefinitions - fun axes() = Axe.values().map { - ItemDefinition(it.id).apply { isStackable = false } - } - @TestMock lateinit var player: Player @@ -69,4 +64,11 @@ class AxeTests { assertEquals(axe, Axe.bestFor(player)) } + private companion object { + @ItemDefinitions + fun axes() = Axe.values().map { + ItemDefinition(it.id).apply { isStackable = false } + } + } + } \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt b/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt index 8c8f1cd47..c1a6e1ad3 100644 --- a/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt +++ b/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt @@ -20,19 +20,11 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ArgumentsSource -import java.util.* +import java.util.Random @ExtendWith(ApolloTestingExtension::class) class WoodcuttingTests { - @ItemDefinitions - fun logs() = woodcuttingTestData().map { - ItemDefinition(it.tree.id).also { it.name = "" } - } - - @ItemDefinitions - fun tools() = listOf(ItemDefinition(Axe.BRONZE.id)) - @TestMock lateinit var action: ActionCapture @@ -85,4 +77,14 @@ class WoodcuttingTests { assertEquals(1, player.inventory.getAmount(data.tree.id)) } } + + private companion object { + @ItemDefinitions + fun logs() = woodcuttingTestData().map { + ItemDefinition(it.tree.id).also { it.name = "" } + } + + @ItemDefinitions + fun tools() = listOf(ItemDefinition(Axe.BRONZE.id)) + } } \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java index d86cd0edd..7e8d61fa7 100644 --- a/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java +++ b/game/src/main/java/org/apollo/game/plugin/KotlinPluginEnvironment.java @@ -1,5 +1,11 @@ package org.apollo.game.plugin; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ClassInfoList; @@ -7,12 +13,6 @@ import org.apollo.game.model.World; import org.apollo.game.plugin.kotlin.KotlinPluginScript; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.logging.Logger; - public class KotlinPluginEnvironment implements PluginEnvironment { private static final Logger logger = Logger.getLogger(KotlinPluginEnvironment.class.getName()); @@ -28,7 +28,6 @@ public KotlinPluginEnvironment(World world) { @Override public void load(Collection plugins) { List pluginScripts = new ArrayList<>(); - List> pluginClasses = new ArrayList<>(); ClassGraph classGraph = new ClassGraph().enableAllInfo(); From 7e6039356d3887ebdab597b890f73d701f9e6dc7 Mon Sep 17 00:00:00 2001 From: Major- Date: Mon, 20 Aug 2018 18:35:54 +0100 Subject: [PATCH 135/209] Throw custom exception on missing plugin dependency --- .../build/plugin/ApolloPluginExtension.groovy | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy index aa554e478..a89ff51db 100644 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy @@ -68,9 +68,25 @@ class ApolloPluginExtension { def setDependencies(List dependencies) { dependencies.each { - project.dependencies.add('compile', project.findProject(":game:plugin:$it")) + def project = project.findProject(":game:plugin:$it") + if (project == null) { + throw new MissingPluginDependencyException(name, it) + } + + this.project.dependencies.add('compile', project) } this.dependencies = dependencies } } + +/** + * A {@link RuntimeException} thrown when a plugin dependency was missing. + */ +class MissingPluginDependencyException extends RuntimeException { + + MissingPluginDependencyException(String plugin, String dependency) { + super("Missing dependency in the `$plugin` plugin: failed to resolve `$dependency`.") + } + +} \ No newline at end of file From ae73453e1a377bff8f43533c07a5ffa7b7567cc2 Mon Sep 17 00:00:00 2001 From: Major- Date: Mon, 20 Aug 2018 18:55:14 +0100 Subject: [PATCH 136/209] Remove (empty) util plugin The contents of this plugin have mostly been moved into the api plugin, or removed entirely. --- game/plugin/skills/mining/build.gradle | 2 +- game/plugin/util/lookup/build.gradle | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 game/plugin/util/lookup/build.gradle diff --git a/game/plugin/skills/mining/build.gradle b/game/plugin/skills/mining/build.gradle index 3ea6934ed..71bc90208 100644 --- a/game/plugin/skills/mining/build.gradle +++ b/game/plugin/skills/mining/build.gradle @@ -10,5 +10,5 @@ plugin { "tlf30" ] - dependencies = ["api", "util:lookup"] + dependencies = ["api"] } \ No newline at end of file diff --git a/game/plugin/util/lookup/build.gradle b/game/plugin/util/lookup/build.gradle deleted file mode 100644 index e2d4a3625..000000000 --- a/game/plugin/util/lookup/build.gradle +++ /dev/null @@ -1,3 +0,0 @@ -plugin { - name = "entity_lookup" -} \ No newline at end of file From d4de32c82c7613e8528866116081887aab72337d Mon Sep 17 00:00:00 2001 From: Major- Date: Mon, 20 Aug 2018 20:41:27 +0100 Subject: [PATCH 137/209] Rename npc_spawn function to spawnNpc --- game/plugin/entity/spawn/src/spawn.kt | 20 +- .../locations/al-kharid/src/npcs.plugin.kts | 128 +++---- .../locations/edgeville/src/npcs.plugin.kts | 80 ++--- .../locations/falador/src/npcs.plugin.kts | 286 +++++++-------- .../locations/lumbridge/src/npcs.plugin.kts | 22 +- .../tutorial-island/src/npcs.plugin.kts | 44 +-- .../locations/varrock/src/npcs.plugin.kts | 330 +++++++++--------- .../skills/fishing/src/spots.plugin.kts | 258 +++++++------- 8 files changed, 587 insertions(+), 581 deletions(-) diff --git a/game/plugin/entity/spawn/src/spawn.kt b/game/plugin/entity/spawn/src/spawn.kt index f21f7d20a..f70c9a285 100644 --- a/game/plugin/entity/spawn/src/spawn.kt +++ b/game/plugin/entity/spawn/src/spawn.kt @@ -5,13 +5,19 @@ import org.apollo.game.model.Direction import org.apollo.game.model.Graphic import org.apollo.game.model.Position -data class Spawn(val id: Int?, val name: String, val position: Position, val facing: Direction, - val spawnAnimation: Animation? = null, val spawnGraphic: Graphic? = null) - -object Spawns { - val list = mutableListOf() +fun spawnNpc(name: String, x: Int, y: Int, z: Int = 0, id: Int? = null, facing: Direction = Direction.NORTH) { + Spawns.list += Spawn(id, name, Position(x, y, z), facing) } -fun npc_spawn(name: String, x: Int, y: Int, z: Int = 0, id: Int? = null, facing: Direction = Direction.NORTH) { - Spawns.list.add(Spawn(id, name, Position(x, y, z), facing)) +internal data class Spawn( + val id: Int?, + val name: String, + val position: Position, + val facing: Direction, + val spawnAnimation: Animation? = null, + val spawnGraphic: Graphic? = null +) + +internal object Spawns { + val list = mutableListOf() } diff --git a/game/plugin/locations/al-kharid/src/npcs.plugin.kts b/game/plugin/locations/al-kharid/src/npcs.plugin.kts index 71fa6ce03..79b74471c 100644 --- a/game/plugin/locations/al-kharid/src/npcs.plugin.kts +++ b/game/plugin/locations/al-kharid/src/npcs.plugin.kts @@ -1,114 +1,114 @@ package org.apollo.plugin.locations.alKharid import org.apollo.game.model.Direction -import org.apollo.game.plugin.entity.spawn.npc_spawn +import org.apollo.game.plugin.entity.spawn.spawnNpc // Generic npcs -npc_spawn("man", x = 3276, y = 3186) -npc_spawn("man", x = 3282, y = 3197) +spawnNpc("man", x = 3276, y = 3186) +spawnNpc("man", x = 3282, y = 3197) -npc_spawn("man", id = 3, x = 3301, y = 3200) -npc_spawn("man", id = 3, x = 3300, y = 3208) +spawnNpc("man", id = 3, x = 3301, y = 3200) +spawnNpc("man", id = 3, x = 3300, y = 3208) -npc_spawn("man", id = 2, x = 3297, y = 3196) +spawnNpc("man", id = 2, x = 3297, y = 3196) -npc_spawn("man", id = 16, x = 3294, y = 3204) +spawnNpc("man", id = 16, x = 3294, y = 3204) -npc_spawn("spider", x = 3319, y = 3145) -npc_spawn("spider", x = 3319, y = 3140) -npc_spawn("spider", x = 3323, y = 3138) +spawnNpc("spider", x = 3319, y = 3145) +spawnNpc("spider", x = 3319, y = 3140) +spawnNpc("spider", x = 3323, y = 3138) -npc_spawn("scorpion", x = 3282, y = 3149) +spawnNpc("scorpion", x = 3282, y = 3149) // Camels -npc_spawn("cam_the_camel", x = 3295, y = 3232) -npc_spawn("elly_the_camel", x = 3312, y = 3210) -npc_spawn("camel", x = 3285, y = 3198) -npc_spawn("ollie_the_camel", x = 3291, y = 3209) -npc_spawn("al_the_camel", x = 3275, y = 3162) +spawnNpc("cam_the_camel", x = 3295, y = 3232) +spawnNpc("elly_the_camel", x = 3312, y = 3210) +spawnNpc("camel", x = 3285, y = 3198) +spawnNpc("ollie_the_camel", x = 3291, y = 3209) +spawnNpc("al_the_camel", x = 3275, y = 3162) // Quest npc -npc_spawn("osman", x = 3286, y = 3180, facing = Direction.EAST) +spawnNpc("osman", x = 3286, y = 3180, facing = Direction.EAST) -npc_spawn("hassan", x = 3302, y = 3163) +spawnNpc("hassan", x = 3302, y = 3163) -npc_spawn("father_reen", x = 3272, y = 3158) +spawnNpc("father_reen", x = 3272, y = 3158) -npc_spawn("man", id = 663, x = 3297, y = 3287) +spawnNpc("man", id = 663, x = 3297, y = 3287) // Boarder guards -npc_spawn("border_guard", x = 3268, y = 3226) -npc_spawn("border_guard", x = 3267, y = 3226) -npc_spawn("border_guard", x = 3268, y = 3229, facing = Direction.SOUTH) -npc_spawn("border_guard", x = 3267, y = 3229, facing = Direction.SOUTH) +spawnNpc("border_guard", x = 3268, y = 3226) +spawnNpc("border_guard", x = 3267, y = 3226) +spawnNpc("border_guard", x = 3268, y = 3229, facing = Direction.SOUTH) +spawnNpc("border_guard", x = 3267, y = 3229, facing = Direction.SOUTH) // Palace guards -npc_spawn("Al-Kharid warrior", x = 3285, y = 3174) -npc_spawn("Al-Kharid warrior", x = 3283, y = 3168) -npc_spawn("Al-Kharid warrior", x = 3285, y = 3169) -npc_spawn("Al-Kharid warrior", x = 3290, y = 3162) -npc_spawn("Al-Kharid warrior", x = 3295, y = 3170) -npc_spawn("Al-Kharid warrior", x = 3300, y = 3175) -npc_spawn("Al-Kharid warrior", x = 3300, y = 3171) -npc_spawn("Al-Kharid warrior", x = 3301, y = 3168) +spawnNpc("Al-Kharid warrior", x = 3285, y = 3174) +spawnNpc("Al-Kharid warrior", x = 3283, y = 3168) +spawnNpc("Al-Kharid warrior", x = 3285, y = 3169) +spawnNpc("Al-Kharid warrior", x = 3290, y = 3162) +spawnNpc("Al-Kharid warrior", x = 3295, y = 3170) +spawnNpc("Al-Kharid warrior", x = 3300, y = 3175) +spawnNpc("Al-Kharid warrior", x = 3300, y = 3171) +spawnNpc("Al-Kharid warrior", x = 3301, y = 3168) // Shanty pass -npc_spawn("shantay_guard", x = 3301, y = 3120) -npc_spawn("shantay_guard", x = 3302, y = 3126) -npc_spawn("shantay_guard", x = 3306, y = 3126) -npc_spawn("shantay_guard", id = 838, x = 3303, y = 3118) +spawnNpc("shantay_guard", x = 3301, y = 3120) +spawnNpc("shantay_guard", x = 3302, y = 3126) +spawnNpc("shantay_guard", x = 3306, y = 3126) +spawnNpc("shantay_guard", id = 838, x = 3303, y = 3118) // Mine -npc_spawn("scorpion", x = 3296, y = 3294) -npc_spawn("scorpion", x = 3298, y = 3280) -npc_spawn("scorpion", x = 3299, y = 3299) -npc_spawn("scorpion", x = 3299, y = 3309) -npc_spawn("scorpion", x = 3300, y = 3287) -npc_spawn("scorpion", x = 3300, y = 3315) -npc_spawn("scorpion", x = 3301, y = 3305) -npc_spawn("scorpion", x = 3301, y = 3312) +spawnNpc("scorpion", x = 3296, y = 3294) +spawnNpc("scorpion", x = 3298, y = 3280) +spawnNpc("scorpion", x = 3299, y = 3299) +spawnNpc("scorpion", x = 3299, y = 3309) +spawnNpc("scorpion", x = 3300, y = 3287) +spawnNpc("scorpion", x = 3300, y = 3315) +spawnNpc("scorpion", x = 3301, y = 3305) +spawnNpc("scorpion", x = 3301, y = 3312) // Functional npcs -npc_spawn("gnome_pilot", x = 3279, y = 3213) +spawnNpc("gnome_pilot", x = 3279, y = 3213) -npc_spawn("banker", id = 496, x = 3267, y = 3164, facing = Direction.EAST) -npc_spawn("banker", id = 496, x = 3267, y = 3167, facing = Direction.EAST) -npc_spawn("banker", id = 496, x = 3267, y = 3169, facing = Direction.EAST) +spawnNpc("banker", id = 496, x = 3267, y = 3164, facing = Direction.EAST) +spawnNpc("banker", id = 496, x = 3267, y = 3167, facing = Direction.EAST) +spawnNpc("banker", id = 496, x = 3267, y = 3169, facing = Direction.EAST) -npc_spawn("banker", id = 497, x = 3267, y = 3166, facing = Direction.EAST) -npc_spawn("banker", id = 497, x = 3267, y = 3168, facing = Direction.EAST) +spawnNpc("banker", id = 497, x = 3267, y = 3166, facing = Direction.EAST) +spawnNpc("banker", id = 497, x = 3267, y = 3168, facing = Direction.EAST) -npc_spawn("gem_trader", x = 3287, y = 3210) +spawnNpc("gem_trader", x = 3287, y = 3210) -npc_spawn("zeke", x = 3289, y = 3189) +spawnNpc("zeke", x = 3289, y = 3189) -npc_spawn("shantay", x = 3304, y = 3124) +spawnNpc("shantay", x = 3304, y = 3124) -npc_spawn("rug_merchant", id = 2296, x = 3311, y = 3109, facing = Direction.WEST) +spawnNpc("rug_merchant", id = 2296, x = 3311, y = 3109, facing = Direction.WEST) -npc_spawn("ranael", x = 3315, y = 3163) +spawnNpc("ranael", x = 3315, y = 3163) -npc_spawn("shop_keeper", id = 524, x = 3315, y = 3178) -npc_spawn("shop_assistant", id = 525, x = 3315, y = 3180, facing = Direction.WEST) +spawnNpc("shop_keeper", id = 524, x = 3315, y = 3178) +spawnNpc("shop_assistant", id = 525, x = 3315, y = 3180, facing = Direction.WEST) -npc_spawn("louie_legs", x = 3316, y = 3175, facing = Direction.WEST) +spawnNpc("louie_legs", x = 3316, y = 3175, facing = Direction.WEST) -npc_spawn("ellis", x = 3274, y = 3192) +spawnNpc("ellis", x = 3274, y = 3192) -npc_spawn("dommik", x = 3321, y = 3193) +spawnNpc("dommik", x = 3321, y = 3193) -npc_spawn("tool_leprechaun", x = 3319, y = 3204) +spawnNpc("tool_leprechaun", x = 3319, y = 3204) -npc_spawn("ali_morrisane", x = 3304, y = 3211, facing = Direction.EAST) +spawnNpc("ali_morrisane", x = 3304, y = 3211, facing = Direction.EAST) -npc_spawn("silk_trader", x = 3300, y = 3203) +spawnNpc("silk_trader", x = 3300, y = 3203) -npc_spawn("karim", x = 3273, y = 3180) \ No newline at end of file +spawnNpc("karim", x = 3273, y = 3180) \ No newline at end of file diff --git a/game/plugin/locations/edgeville/src/npcs.plugin.kts b/game/plugin/locations/edgeville/src/npcs.plugin.kts index 2fa94f88a..7419b2b20 100644 --- a/game/plugin/locations/edgeville/src/npcs.plugin.kts +++ b/game/plugin/locations/edgeville/src/npcs.plugin.kts @@ -1,54 +1,54 @@ package org.apollo.plugin.locations.edgeville import org.apollo.game.model.Direction -import org.apollo.game.plugin.entity.spawn.npc_spawn +import org.apollo.game.plugin.entity.spawn.spawnNpc // Generic npcs -npc_spawn("man", x = 3095, y = 3508) -npc_spawn("man", x = 3095, y = 3511) -npc_spawn("man", x = 3098, y = 3509) -npc_spawn("man", id = 2, x = 3093, y = 3511) -npc_spawn("man", id = 3, x = 3097, y = 3508) -npc_spawn("man", id = 3, x = 3092, y = 3508) -npc_spawn("man", id = 3, x = 3097, y = 3512) - -npc_spawn("guard", x = 3086, y = 3516) -npc_spawn("guard", x = 3094, y = 3518) -npc_spawn("guard", x = 3108, y = 3514) -npc_spawn("guard", x = 3110, y = 3514) -npc_spawn("guard", x = 3113, y = 3514) -npc_spawn("guard", x = 3113, y = 3516) - -npc_spawn("sheep", id = 43, x = 3050, y = 3516) -npc_spawn("sheep", id = 43, x = 3051, y = 3514) -npc_spawn("sheep", id = 43, x = 3056, y = 3517) -npc_spawn("ram", id = 3673, x = 3048, y = 3515) - -npc_spawn("monk", x = 3044, y = 3491) -npc_spawn("monk", x = 3045, y = 3483) -npc_spawn("monk", x = 3045, y = 3497) -npc_spawn("monk", x = 3050, y = 3490) -npc_spawn("monk", x = 3054, y = 3490) -npc_spawn("monk", x = 3058, y = 3497) +spawnNpc("man", x = 3095, y = 3508) +spawnNpc("man", x = 3095, y = 3511) +spawnNpc("man", x = 3098, y = 3509) +spawnNpc("man", id = 2, x = 3093, y = 3511) +spawnNpc("man", id = 3, x = 3097, y = 3508) +spawnNpc("man", id = 3, x = 3092, y = 3508) +spawnNpc("man", id = 3, x = 3097, y = 3512) + +spawnNpc("guard", x = 3086, y = 3516) +spawnNpc("guard", x = 3094, y = 3518) +spawnNpc("guard", x = 3108, y = 3514) +spawnNpc("guard", x = 3110, y = 3514) +spawnNpc("guard", x = 3113, y = 3514) +spawnNpc("guard", x = 3113, y = 3516) + +spawnNpc("sheep", id = 43, x = 3050, y = 3516) +spawnNpc("sheep", id = 43, x = 3051, y = 3514) +spawnNpc("sheep", id = 43, x = 3056, y = 3517) +spawnNpc("ram", id = 3673, x = 3048, y = 3515) + +spawnNpc("monk", x = 3044, y = 3491) +spawnNpc("monk", x = 3045, y = 3483) +spawnNpc("monk", x = 3045, y = 3497) +spawnNpc("monk", x = 3050, y = 3490) +spawnNpc("monk", x = 3054, y = 3490) +spawnNpc("monk", x = 3058, y = 3497) // Functional npcs -npc_spawn("richard", x = 3098, y = 3516) -npc_spawn("doris", x = 3079, y = 3491) -npc_spawn("brother_jered", x = 3045, y = 3488) -npc_spawn("brother_althric", x = 3054, y = 3504) +spawnNpc("richard", x = 3098, y = 3516) +spawnNpc("doris", x = 3079, y = 3491) +spawnNpc("brother_jered", x = 3045, y = 3488) +spawnNpc("brother_althric", x = 3054, y = 3504) -npc_spawn("abbot_langley", x = 3059, y = 3484) -npc_spawn("oziach", x = 3067, y = 3518, facing = Direction.EAST) +spawnNpc("abbot_langley", x = 3059, y = 3484) +spawnNpc("oziach", x = 3067, y = 3518, facing = Direction.EAST) -npc_spawn("shop_keeper", id = 528, x = 3079, y = 3509) -npc_spawn("shop_assistant", id = 529, x = 3082, y = 3513) +spawnNpc("shop_keeper", id = 528, x = 3079, y = 3509) +spawnNpc("shop_assistant", id = 529, x = 3082, y = 3513) -npc_spawn("banker", x = 3096, y = 3489, facing = Direction.WEST) -npc_spawn("banker", x = 3096, y = 3491, facing = Direction.WEST) -npc_spawn("banker", x = 3096, y = 3492) -npc_spawn("banker", x = 3098, y = 3492) +spawnNpc("banker", x = 3096, y = 3489, facing = Direction.WEST) +spawnNpc("banker", x = 3096, y = 3491, facing = Direction.WEST) +spawnNpc("banker", x = 3096, y = 3492) +spawnNpc("banker", x = 3098, y = 3492) -npc_spawn("mage_of_zamorak", x = 3106, y = 3560) \ No newline at end of file +spawnNpc("mage_of_zamorak", x = 3106, y = 3560) \ No newline at end of file diff --git a/game/plugin/locations/falador/src/npcs.plugin.kts b/game/plugin/locations/falador/src/npcs.plugin.kts index 68b676f2e..9136f9c09 100644 --- a/game/plugin/locations/falador/src/npcs.plugin.kts +++ b/game/plugin/locations/falador/src/npcs.plugin.kts @@ -1,171 +1,171 @@ package org.apollo.plugin.locations.falador -import org.apollo.game.plugin.entity.spawn.npc_spawn +import org.apollo.game.plugin.entity.spawn.spawnNpc // Generic npcs -npc_spawn("chicken", x = 2965, y = 3345) - -npc_spawn("duck", x = 2988, y = 3383) -npc_spawn("duck", x = 2992, y = 3383) -npc_spawn("duck", x = 2993, y = 3385) - -npc_spawn("drunken_man", x = 2957, y = 3368, z = 1) - -npc_spawn("dwarf", id = 118, x = 3023, y = 3334) -npc_spawn("dwarf", id = 118, x = 3027, y = 3341) -npc_spawn("dwarf", id = 118, x = 3012, y = 3341) -npc_spawn("dwarf", id = 118, x = 3017, y = 3346, z = 1) -npc_spawn("dwarf", id = 118, x = 3011, y = 3341, z = 1) - -npc_spawn("dwarf", id = 121, x = 3027, y = 3341) - -npc_spawn("dwarf", id = 382, x = 3017, y = 3340) - -npc_spawn("dwarf", id = 3294, x = 3022, y = 3338) -npc_spawn("dwarf", id = 3295, x = 3021, y = 3341) - -npc_spawn("gardener", x = 2998, y = 3385) -npc_spawn("gardener", x = 3019, y = 3369) -npc_spawn("gardener", id = 3234, x = 3016, y = 3386) - -npc_spawn("guard", x = 2965, y = 3394) -npc_spawn("guard", x = 2964, y = 3396) -npc_spawn("guard", x = 2966, y = 3397) -npc_spawn("guard", x = 2964, y = 3384) -npc_spawn("guard", x = 2963, y = 3380) -npc_spawn("guard", x = 3006, y = 3325) -npc_spawn("guard", x = 3008, y = 3320) -npc_spawn("guard", x = 3006, y = 3322) -npc_spawn("guard", x = 3038, y = 3356) - -npc_spawn("guard", id = 10, x = 2942, y = 3375) -npc_spawn("guard", id = 10, x = 3040, y = 3352) - -npc_spawn("guard", id = 3230, x = 2967, y = 3395) -npc_spawn("guard", id = 3230, x = 2966, y = 3392) -npc_spawn("guard", id = 3230, x = 2963, y = 3376) -npc_spawn("guard", id = 3230, x = 2954, y = 3382) -npc_spawn("guard", id = 3230, x = 2950, y = 3377) -npc_spawn("guard", id = 3230, x = 2968, y = 3381) - -npc_spawn("guard", id = 3231, x = 3033, y = 3389, z = 1) -npc_spawn("guard", id = 3231, x = 3041, y = 3388, z = 1) -npc_spawn("guard", id = 3231, x = 3048, y = 3389, z = 1) -npc_spawn("guard", id = 3231, x = 3056, y = 3389, z = 1) -npc_spawn("guard", id = 3231, x = 3062, y = 3386, z = 1) -npc_spawn("guard", id = 3231, x = 3058, y = 3329, z = 1) -npc_spawn("guard", id = 3231, x = 3050, y = 3329, z = 1) -npc_spawn("guard", id = 3231, x = 3038, y = 3329, z = 1) -npc_spawn("guard", id = 3231, x = 3029, y = 3329, z = 1) - -npc_spawn("swan", x = 2960, y = 3359) -npc_spawn("swan", x = 2963, y = 3360) -npc_spawn("swan", x = 2968, y = 3359) -npc_spawn("swan", x = 2971, y = 3360) -npc_spawn("swan", x = 2976, y = 3358) -npc_spawn("swan", x = 2989, y = 3384) - -npc_spawn("man", id = 3223, x = 2991, y = 3365) -npc_spawn("man", id = 3225, x = 3037, y = 3345, z = 1) - -npc_spawn("white_knight", x = 2983, y = 3343) -npc_spawn("white_knight", x = 2981, y = 3334) -npc_spawn("white_knight", x = 2988, y = 3335) -npc_spawn("white_knight", x = 2996, y = 3342) -npc_spawn("white_knight", x = 2960, y = 3340) -npc_spawn("white_knight", x = 2962, y = 3336) -npc_spawn("white_knight", x = 2974, y = 3342) -npc_spawn("white_knight", x = 2972, y = 3345) -npc_spawn("white_knight", x = 2977, y = 3348) - -npc_spawn("white_knight", id = 3348, x = 2971, y = 3340) -npc_spawn("white_knight", id = 3348, x = 2978, y = 3350) - -npc_spawn("white_knight", x = 2964, y = 3330, z = 1) -npc_spawn("white_knight", x = 2968, y = 3334, z = 1) -npc_spawn("white_knight", x = 2969, y = 3339, z = 1) -npc_spawn("white_knight", x = 2978, y = 3332, z = 1) -npc_spawn("white_knight", x = 2958, y = 3340, z = 1) -npc_spawn("white_knight", x = 2960, y = 3343, z = 1) - -npc_spawn("white_knight", id = 3348, x = 2987, y = 3334, z = 1) -npc_spawn("white_knight", id = 3348, x = 2983, y = 3336, z = 1) -npc_spawn("white_knight", id = 3348, x = 2987, y = 3334, z = 1) -npc_spawn("white_knight", id = 3348, x = 2979, y = 3348, z = 1) -npc_spawn("white_knight", id = 3348, x = 2964, y = 3337, z = 1) - -npc_spawn("white_knight", id = 3349, x = 2989, y = 3344, z = 1) - -npc_spawn("white_knight", x = 2985, y = 3342, z = 2) - -npc_spawn("white_knight", id = 3348, x = 2979, y = 3348, z = 2) -npc_spawn("white_knight", id = 3348, x = 2974, y = 3329, z = 2) -npc_spawn("white_knight", id = 3348, x = 2982, y = 3341, z = 2) - -npc_spawn("white_knight", id = 3349, x = 2990, y = 3341, z = 2) -npc_spawn("white_knight", id = 3349, x = 2971, y = 3330, z = 2) -npc_spawn("white_knight", id = 3349, x = 2965, y = 3350, z = 2) -npc_spawn("white_knight", id = 3349, x = 2965, y = 3329, z = 2) - -npc_spawn("white_knight", id = 3350, x = 2961, y = 3347, z = 2) - -npc_spawn("white_knight", id = 3349, x = 2962, y = 3339, z = 3) - -npc_spawn("white_knight", id = 3350, x = 2960, y = 3336, z = 3) -npc_spawn("white_knight", id = 3350, x = 2984, y = 3349, z = 3) - -npc_spawn("woman", id = 3226, x = 2991, y = 3384) +spawnNpc("chicken", x = 2965, y = 3345) + +spawnNpc("duck", x = 2988, y = 3383) +spawnNpc("duck", x = 2992, y = 3383) +spawnNpc("duck", x = 2993, y = 3385) + +spawnNpc("drunken_man", x = 2957, y = 3368, z = 1) + +spawnNpc("dwarf", id = 118, x = 3023, y = 3334) +spawnNpc("dwarf", id = 118, x = 3027, y = 3341) +spawnNpc("dwarf", id = 118, x = 3012, y = 3341) +spawnNpc("dwarf", id = 118, x = 3017, y = 3346, z = 1) +spawnNpc("dwarf", id = 118, x = 3011, y = 3341, z = 1) + +spawnNpc("dwarf", id = 121, x = 3027, y = 3341) + +spawnNpc("dwarf", id = 382, x = 3017, y = 3340) + +spawnNpc("dwarf", id = 3294, x = 3022, y = 3338) +spawnNpc("dwarf", id = 3295, x = 3021, y = 3341) + +spawnNpc("gardener", x = 2998, y = 3385) +spawnNpc("gardener", x = 3019, y = 3369) +spawnNpc("gardener", id = 3234, x = 3016, y = 3386) + +spawnNpc("guard", x = 2965, y = 3394) +spawnNpc("guard", x = 2964, y = 3396) +spawnNpc("guard", x = 2966, y = 3397) +spawnNpc("guard", x = 2964, y = 3384) +spawnNpc("guard", x = 2963, y = 3380) +spawnNpc("guard", x = 3006, y = 3325) +spawnNpc("guard", x = 3008, y = 3320) +spawnNpc("guard", x = 3006, y = 3322) +spawnNpc("guard", x = 3038, y = 3356) + +spawnNpc("guard", id = 10, x = 2942, y = 3375) +spawnNpc("guard", id = 10, x = 3040, y = 3352) + +spawnNpc("guard", id = 3230, x = 2967, y = 3395) +spawnNpc("guard", id = 3230, x = 2966, y = 3392) +spawnNpc("guard", id = 3230, x = 2963, y = 3376) +spawnNpc("guard", id = 3230, x = 2954, y = 3382) +spawnNpc("guard", id = 3230, x = 2950, y = 3377) +spawnNpc("guard", id = 3230, x = 2968, y = 3381) + +spawnNpc("guard", id = 3231, x = 3033, y = 3389, z = 1) +spawnNpc("guard", id = 3231, x = 3041, y = 3388, z = 1) +spawnNpc("guard", id = 3231, x = 3048, y = 3389, z = 1) +spawnNpc("guard", id = 3231, x = 3056, y = 3389, z = 1) +spawnNpc("guard", id = 3231, x = 3062, y = 3386, z = 1) +spawnNpc("guard", id = 3231, x = 3058, y = 3329, z = 1) +spawnNpc("guard", id = 3231, x = 3050, y = 3329, z = 1) +spawnNpc("guard", id = 3231, x = 3038, y = 3329, z = 1) +spawnNpc("guard", id = 3231, x = 3029, y = 3329, z = 1) + +spawnNpc("swan", x = 2960, y = 3359) +spawnNpc("swan", x = 2963, y = 3360) +spawnNpc("swan", x = 2968, y = 3359) +spawnNpc("swan", x = 2971, y = 3360) +spawnNpc("swan", x = 2976, y = 3358) +spawnNpc("swan", x = 2989, y = 3384) + +spawnNpc("man", id = 3223, x = 2991, y = 3365) +spawnNpc("man", id = 3225, x = 3037, y = 3345, z = 1) + +spawnNpc("white_knight", x = 2983, y = 3343) +spawnNpc("white_knight", x = 2981, y = 3334) +spawnNpc("white_knight", x = 2988, y = 3335) +spawnNpc("white_knight", x = 2996, y = 3342) +spawnNpc("white_knight", x = 2960, y = 3340) +spawnNpc("white_knight", x = 2962, y = 3336) +spawnNpc("white_knight", x = 2974, y = 3342) +spawnNpc("white_knight", x = 2972, y = 3345) +spawnNpc("white_knight", x = 2977, y = 3348) + +spawnNpc("white_knight", id = 3348, x = 2971, y = 3340) +spawnNpc("white_knight", id = 3348, x = 2978, y = 3350) + +spawnNpc("white_knight", x = 2964, y = 3330, z = 1) +spawnNpc("white_knight", x = 2968, y = 3334, z = 1) +spawnNpc("white_knight", x = 2969, y = 3339, z = 1) +spawnNpc("white_knight", x = 2978, y = 3332, z = 1) +spawnNpc("white_knight", x = 2958, y = 3340, z = 1) +spawnNpc("white_knight", x = 2960, y = 3343, z = 1) + +spawnNpc("white_knight", id = 3348, x = 2987, y = 3334, z = 1) +spawnNpc("white_knight", id = 3348, x = 2983, y = 3336, z = 1) +spawnNpc("white_knight", id = 3348, x = 2987, y = 3334, z = 1) +spawnNpc("white_knight", id = 3348, x = 2979, y = 3348, z = 1) +spawnNpc("white_knight", id = 3348, x = 2964, y = 3337, z = 1) + +spawnNpc("white_knight", id = 3349, x = 2989, y = 3344, z = 1) + +spawnNpc("white_knight", x = 2985, y = 3342, z = 2) + +spawnNpc("white_knight", id = 3348, x = 2979, y = 3348, z = 2) +spawnNpc("white_knight", id = 3348, x = 2974, y = 3329, z = 2) +spawnNpc("white_knight", id = 3348, x = 2982, y = 3341, z = 2) + +spawnNpc("white_knight", id = 3349, x = 2990, y = 3341, z = 2) +spawnNpc("white_knight", id = 3349, x = 2971, y = 3330, z = 2) +spawnNpc("white_knight", id = 3349, x = 2965, y = 3350, z = 2) +spawnNpc("white_knight", id = 3349, x = 2965, y = 3329, z = 2) + +spawnNpc("white_knight", id = 3350, x = 2961, y = 3347, z = 2) + +spawnNpc("white_knight", id = 3349, x = 2962, y = 3339, z = 3) + +spawnNpc("white_knight", id = 3350, x = 2960, y = 3336, z = 3) +spawnNpc("white_knight", id = 3350, x = 2984, y = 3349, z = 3) + +spawnNpc("woman", id = 3226, x = 2991, y = 3384) // Functional npcs -npc_spawn("apprentice_workman", id = 3235, x = 2971, y = 3369, z = 1) +spawnNpc("apprentice_workman", id = 3235, x = 2971, y = 3369, z = 1) -npc_spawn("banker", id = 495, x = 2945, y = 3366) -npc_spawn("banker", id = 495, x = 2946, y = 3366) -npc_spawn("banker", id = 495, x = 2947, y = 3366) -npc_spawn("banker", id = 495, x = 2948, y = 3366) +spawnNpc("banker", id = 495, x = 2945, y = 3366) +spawnNpc("banker", id = 495, x = 2946, y = 3366) +spawnNpc("banker", id = 495, x = 2947, y = 3366) +spawnNpc("banker", id = 495, x = 2948, y = 3366) -npc_spawn("banker", x = 2949, y = 3366) +spawnNpc("banker", x = 2949, y = 3366) -npc_spawn("banker", x = 3015, y = 3353) -npc_spawn("banker", x = 3014, y = 3353) -npc_spawn("banker", x = 3013, y = 3353) -npc_spawn("banker", x = 3012, y = 3353) -npc_spawn("banker", x = 3011, y = 3353) -npc_spawn("banker", x = 3010, y = 3353) +spawnNpc("banker", x = 3015, y = 3353) +spawnNpc("banker", x = 3014, y = 3353) +spawnNpc("banker", x = 3013, y = 3353) +spawnNpc("banker", x = 3012, y = 3353) +spawnNpc("banker", x = 3011, y = 3353) +spawnNpc("banker", x = 3010, y = 3353) -npc_spawn("cassie", x = 2976, y = 3383) +spawnNpc("cassie", x = 2976, y = 3383) -npc_spawn("emily", x = 2954, y = 3372) +spawnNpc("emily", x = 2954, y = 3372) -npc_spawn("flynn", x = 2950, y = 3387) +spawnNpc("flynn", x = 2950, y = 3387) -npc_spawn("hairdresser", x = 2944, y = 3380) +spawnNpc("hairdresser", x = 2944, y = 3380) -npc_spawn("herquin", x = 2945, y = 3335) +spawnNpc("herquin", x = 2945, y = 3335) -npc_spawn("heskel", x = 3007, y = 3374) +spawnNpc("heskel", x = 3007, y = 3374) -npc_spawn("kaylee", x = 2957, y = 3372) +spawnNpc("kaylee", x = 2957, y = 3372) -npc_spawn("tina", x = 2955, y = 3371, z = 1) +spawnNpc("tina", x = 2955, y = 3371, z = 1) -npc_spawn("tool_leprechaun", x = 3005, y = 3370) +spawnNpc("tool_leprechaun", x = 3005, y = 3370) -npc_spawn("squire", x = 2977, y = 3343) +spawnNpc("squire", x = 2977, y = 3343) -npc_spawn("sir_tiffy_cashien", x = 2997, y = 3373) +spawnNpc("sir_tiffy_cashien", x = 2997, y = 3373) -npc_spawn("sir_amik_varze", x = 2960, y = 3336, z = 2) +spawnNpc("sir_amik_varze", x = 2960, y = 3336, z = 2) -npc_spawn("sir_vyvin", x = 2983, y = 3335, z = 2) +spawnNpc("sir_vyvin", x = 2983, y = 3335, z = 2) -npc_spawn("shop_keeper", id = 524, x = 2955, y = 3389) -npc_spawn("shop_assistant", id = 525, x = 2957, y = 3387) +spawnNpc("shop_keeper", id = 524, x = 2955, y = 3389) +spawnNpc("shop_assistant", id = 525, x = 2957, y = 3387) -npc_spawn("wayne", x = 2972, y = 3312) +spawnNpc("wayne", x = 2972, y = 3312) -npc_spawn("workman", id = 3236, x = 2975, y = 3369, z = 1) +spawnNpc("workman", id = 3236, x = 2975, y = 3369, z = 1) -npc_spawn("wyson_the_gardener", x = 3028, y = 3381) \ No newline at end of file +spawnNpc("wyson_the_gardener", x = 3028, y = 3381) \ No newline at end of file diff --git a/game/plugin/locations/lumbridge/src/npcs.plugin.kts b/game/plugin/locations/lumbridge/src/npcs.plugin.kts index 28b055058..03094618d 100644 --- a/game/plugin/locations/lumbridge/src/npcs.plugin.kts +++ b/game/plugin/locations/lumbridge/src/npcs.plugin.kts @@ -1,15 +1,15 @@ package org.apollo.plugin.locations.lumbridge -import org.apollo.game.plugin.entity.spawn.npc_spawn +import org.apollo.game.plugin.entity.spawn.spawnNpc -npc_spawn("woman", id = 4, x = 3232, y = 3207) -npc_spawn("man", id = 1, x = 3231, y = 3237) -npc_spawn("man", id = 2, x = 3224, y = 3240) -npc_spawn("woman", id = 5, x = 3229, y = 2329) +spawnNpc("woman", id = 4, x = 3232, y = 3207) +spawnNpc("man", id = 1, x = 3231, y = 3237) +spawnNpc("man", id = 2, x = 3224, y = 3240) +spawnNpc("woman", id = 5, x = 3229, y = 2329) -npc_spawn("hans", x = 3221, y = 3221) -npc_spawn("father aereck", x = 3243, y = 3210) -npc_spawn("bob", x = 3231, y = 3203) -npc_spawn("shop keeper", x = 3212, y = 3247) -npc_spawn("shop assistant", x = 3211, y = 3245) -npc_spawn("lumbridge guide", x = 323, y = 3229) +spawnNpc("hans", x = 3221, y = 3221) +spawnNpc("father aereck", x = 3243, y = 3210) +spawnNpc("bob", x = 3231, y = 3203) +spawnNpc("shop keeper", x = 3212, y = 3247) +spawnNpc("shop assistant", x = 3211, y = 3245) +spawnNpc("lumbridge guide", x = 323, y = 3229) diff --git a/game/plugin/locations/tutorial-island/src/npcs.plugin.kts b/game/plugin/locations/tutorial-island/src/npcs.plugin.kts index f3165e697..5ec51c09b 100644 --- a/game/plugin/locations/tutorial-island/src/npcs.plugin.kts +++ b/game/plugin/locations/tutorial-island/src/npcs.plugin.kts @@ -1,44 +1,44 @@ package org.apollo.plugin.locations.tutorialIsland import org.apollo.game.model.Direction -import org.apollo.game.plugin.entity.spawn.npc_spawn +import org.apollo.game.plugin.entity.spawn.spawnNpc // Functional npcs // 'Above-ground' npcs -npc_spawn("master_chef", x = 3076, y = 3085) -npc_spawn("quest_guide", x = 3086, y = 3122) -npc_spawn("financial_advisor", x = 3127, y = 3124, facing = Direction.WEST) -npc_spawn("brother_brace", x = 3124, y = 3107, facing = Direction.EAST) -npc_spawn("magic_instructor", x = 3140, y = 3085) +spawnNpc("master_chef", x = 3076, y = 3085) +spawnNpc("quest_guide", x = 3086, y = 3122) +spawnNpc("financial_advisor", x = 3127, y = 3124, facing = Direction.WEST) +spawnNpc("brother_brace", x = 3124, y = 3107, facing = Direction.EAST) +spawnNpc("magic_instructor", x = 3140, y = 3085) // 'Below-ground' npcs // Note: They aren't actually on a different plane, they're just in a different location that // pretends to be underground. -npc_spawn("mining_instructor", x = 3081, y = 9504) -npc_spawn("combat_instructor", x = 3104, y = 9506) +spawnNpc("mining_instructor", x = 3081, y = 9504) +spawnNpc("combat_instructor", x = 3104, y = 9506) // Non-humanoid npcs -npc_spawn("fishing_spot", id = 316, x = 3102, y = 3093) +spawnNpc("fishing_spot", id = 316, x = 3102, y = 3093) -npc_spawn("chicken", x = 3140, y = 3095) -npc_spawn("chicken", x = 3140, y = 3093) -npc_spawn("chicken", x = 3138, y = 3092) -npc_spawn("chicken", x = 3137, y = 3094) -npc_spawn("chicken", x = 3138, y = 3095) +spawnNpc("chicken", x = 3140, y = 3095) +spawnNpc("chicken", x = 3140, y = 3093) +spawnNpc("chicken", x = 3138, y = 3092) +spawnNpc("chicken", x = 3137, y = 3094) +spawnNpc("chicken", x = 3138, y = 3095) // 'Below-ground' npcs // Note: They aren't actually on a different plane, they're just in a different location that // pretends to be underground. -npc_spawn("giant_rat", id = 87, x = 3105, y = 9514) -npc_spawn("giant_rat", id = 87, x = 3105, y = 9517) -npc_spawn("giant_rat", id = 87, x = 3106, y = 9514) -npc_spawn("giant_rat", id = 87, x = 3104, y = 9514) -npc_spawn("giant_rat", id = 87, x = 3105, y = 9519) -npc_spawn("giant_rat", id = 87, x = 3109, y = 9516) -npc_spawn("giant_rat", id = 87, x = 3108, y = 9520) -npc_spawn("giant_rat", id = 87, x = 3102, y = 9517) \ No newline at end of file +spawnNpc("giant_rat", id = 87, x = 3105, y = 9514) +spawnNpc("giant_rat", id = 87, x = 3105, y = 9517) +spawnNpc("giant_rat", id = 87, x = 3106, y = 9514) +spawnNpc("giant_rat", id = 87, x = 3104, y = 9514) +spawnNpc("giant_rat", id = 87, x = 3105, y = 9519) +spawnNpc("giant_rat", id = 87, x = 3109, y = 9516) +spawnNpc("giant_rat", id = 87, x = 3108, y = 9520) +spawnNpc("giant_rat", id = 87, x = 3102, y = 9517) \ No newline at end of file diff --git a/game/plugin/locations/varrock/src/npcs.plugin.kts b/game/plugin/locations/varrock/src/npcs.plugin.kts index 4ffecf07b..1e5c9f0cc 100644 --- a/game/plugin/locations/varrock/src/npcs.plugin.kts +++ b/game/plugin/locations/varrock/src/npcs.plugin.kts @@ -1,270 +1,270 @@ package org.apollo.plugin.locations.varrock import org.apollo.game.model.Direction -import org.apollo.game.plugin.entity.spawn.npc_spawn +import org.apollo.game.plugin.entity.spawn.spawnNpc -npc_spawn("barbarian_woman", x = 3222, y = 3399) +spawnNpc("barbarian_woman", x = 3222, y = 3399) -npc_spawn("bear", id = 106, x = 3289, y = 3351) +spawnNpc("bear", id = 106, x = 3289, y = 3351) -npc_spawn("black_knight", x = 3238, y = 3514) -npc_spawn("black_knight", x = 3227, y = 3518) -npc_spawn("black_knight", x = 3279, y = 3502) +spawnNpc("black_knight", x = 3238, y = 3514) +spawnNpc("black_knight", x = 3227, y = 3518) +spawnNpc("black_knight", x = 3279, y = 3502) -npc_spawn("dark_wizard", id = 174, x = 3230, y = 3366) +spawnNpc("dark_wizard", id = 174, x = 3230, y = 3366) -npc_spawn("dark_wizard", id = 174, x = 3228, y = 3368) -npc_spawn("dark_wizard", id = 174, x = 3225, y = 3367) -npc_spawn("dark_wizard", id = 174, x = 3226, y = 3365) -npc_spawn("dark_wizard", id = 174, x = 3226, y = 3372) -npc_spawn("dark_wizard", id = 174, x = 3231, y = 3371) +spawnNpc("dark_wizard", id = 174, x = 3228, y = 3368) +spawnNpc("dark_wizard", id = 174, x = 3225, y = 3367) +spawnNpc("dark_wizard", id = 174, x = 3226, y = 3365) +spawnNpc("dark_wizard", id = 174, x = 3226, y = 3372) +spawnNpc("dark_wizard", id = 174, x = 3231, y = 3371) -npc_spawn("dark_wizard", id = 172, x = 3229, y = 3372) -npc_spawn("dark_wizard", id = 172, x = 3224, y = 3370) -npc_spawn("dark_wizard", id = 172, x = 3228, y = 3366) -npc_spawn("dark_wizard", id = 172, x = 3232, y = 3368) -npc_spawn("dark_wizard", id = 172, x = 3226, y = 3369) +spawnNpc("dark_wizard", id = 172, x = 3229, y = 3372) +spawnNpc("dark_wizard", id = 172, x = 3224, y = 3370) +spawnNpc("dark_wizard", id = 172, x = 3228, y = 3366) +spawnNpc("dark_wizard", id = 172, x = 3232, y = 3368) +spawnNpc("dark_wizard", id = 172, x = 3226, y = 3369) -npc_spawn("giant_rat", id = 87, x = 3292, y = 3375) -npc_spawn("giant_rat", id = 87, x = 3265, y = 3384) -npc_spawn("giant_rat", id = 87, x = 3267, y = 3381) +spawnNpc("giant_rat", id = 87, x = 3292, y = 3375) +spawnNpc("giant_rat", id = 87, x = 3265, y = 3384) +spawnNpc("giant_rat", id = 87, x = 3267, y = 3381) -npc_spawn("guard", id = 368, x = 3263, y = 3407, facing = Direction.SOUTH) +spawnNpc("guard", id = 368, x = 3263, y = 3407, facing = Direction.SOUTH) -npc_spawn("jeremy_clerksin", x = 3253, y = 3477) -npc_spawn("martina_scorsby", x = 3256, y = 3481) +spawnNpc("jeremy_clerksin", x = 3253, y = 3477) +spawnNpc("martina_scorsby", x = 3256, y = 3481) -npc_spawn("man", x = 3281, y = 3500) -npc_spawn("man", x = 3193, y = 3394) -npc_spawn("man", x = 3159, y = 3429) -npc_spawn("man", x = 3245, y = 3394) -npc_spawn("man", x = 3283, y = 3492, z = 1) +spawnNpc("man", x = 3281, y = 3500) +spawnNpc("man", x = 3193, y = 3394) +spawnNpc("man", x = 3159, y = 3429) +spawnNpc("man", x = 3245, y = 3394) +spawnNpc("man", x = 3283, y = 3492, z = 1) -npc_spawn("man", id = 2, x = 3283, y = 3492, z = 1) -npc_spawn("man", id = 2, x = 3263, y = 3400) +spawnNpc("man", id = 2, x = 3283, y = 3492, z = 1) +spawnNpc("man", id = 2, x = 3263, y = 3400) -npc_spawn("man", id = 3, x = 3227, y = 3395, z = 1) -npc_spawn("man", id = 3, x = 3231, y = 3399, z = 1) +spawnNpc("man", id = 3, x = 3227, y = 3395, z = 1) +spawnNpc("man", id = 3, x = 3231, y = 3399, z = 1) -npc_spawn("mugger", x = 3251, y = 3390) -npc_spawn("mugger", x = 3177, y = 3363) +spawnNpc("mugger", x = 3251, y = 3390) +spawnNpc("mugger", x = 3177, y = 3363) -npc_spawn("tramp", id = 2792, x = 3177, y = 3363) +spawnNpc("tramp", id = 2792, x = 3177, y = 3363) -npc_spawn("woman", x = 3221, y = 3396) +spawnNpc("woman", x = 3221, y = 3396) -npc_spawn("woman", id = 5, x = 3279, y = 3497) -npc_spawn("woman", id = 25, x = 3278, y = 3492) +spawnNpc("woman", id = 5, x = 3279, y = 3497) +spawnNpc("woman", id = 25, x = 3278, y = 3492) -npc_spawn("thief", x = 3285, y = 3500) -npc_spawn("thief", x = 3234, y = 3389) -npc_spawn("thief", x = 3188, y = 3383) -npc_spawn("thief", x = 3184, y = 3390) -npc_spawn("thief", x = 3188, y = 3394) +spawnNpc("thief", x = 3285, y = 3500) +spawnNpc("thief", x = 3234, y = 3389) +spawnNpc("thief", x = 3188, y = 3383) +spawnNpc("thief", x = 3184, y = 3390) +spawnNpc("thief", x = 3188, y = 3394) -npc_spawn("unicorn", x = 3286, y = 3342) -npc_spawn("unicorn", x = 3279, y = 3345) +spawnNpc("unicorn", x = 3286, y = 3342) +spawnNpc("unicorn", x = 3279, y = 3345) // North Guards -npc_spawn("guard", x = 3244, y = 3500) -npc_spawn("guard", x = 3247, y = 3503) +spawnNpc("guard", x = 3244, y = 3500) +spawnNpc("guard", x = 3247, y = 3503) // East Guards -npc_spawn("guard", x = 3271, y = 3431) -npc_spawn("guard", x = 3270, y = 3425) -npc_spawn("guard", x = 3274, y = 3421) -npc_spawn("guard", x = 3274, y = 3427) +spawnNpc("guard", x = 3271, y = 3431) +spawnNpc("guard", x = 3270, y = 3425) +spawnNpc("guard", x = 3274, y = 3421) +spawnNpc("guard", x = 3274, y = 3427) // South Guards -npc_spawn("guard", x = 3210, y = 3382) -npc_spawn("guard", x = 3212, y = 3380) -npc_spawn("guard", x = 3207, y = 3376) +spawnNpc("guard", x = 3210, y = 3382) +spawnNpc("guard", x = 3212, y = 3380) +spawnNpc("guard", x = 3207, y = 3376) // West Guards -npc_spawn("guard", x = 3174, y = 3427) -npc_spawn("guard", x = 3176, y = 3430) -npc_spawn("guard", x = 3176, y = 3427) -npc_spawn("guard", x = 3180, y = 3399) -npc_spawn("guard", x = 3175, y = 3415, z = 1) -npc_spawn("guard", x = 3174, y = 3403, z = 1) +spawnNpc("guard", x = 3174, y = 3427) +spawnNpc("guard", x = 3176, y = 3430) +spawnNpc("guard", x = 3176, y = 3427) +spawnNpc("guard", x = 3180, y = 3399) +spawnNpc("guard", x = 3175, y = 3415, z = 1) +spawnNpc("guard", x = 3174, y = 3403, z = 1) // Varrock Palace -npc_spawn("guard", x = 3210, y = 3461) -npc_spawn("guard", x = 3211, y = 3465) -npc_spawn("guard", x = 3214, y = 3462) -npc_spawn("guard", x = 3216, y = 3464) -npc_spawn("guard", x = 3220, y = 3461) -npc_spawn("guard", x = 3206, y = 3461) -npc_spawn("guard", x = 3204, y = 3495) - -npc_spawn("guard", x = 3204, y = 3495, z = 1) -npc_spawn("guard", x = 3205, y = 3492, z = 1) -npc_spawn("guard", x = 3203, y = 3492, z = 1) -npc_spawn("guard", x = 3205, y = 3497, z = 1) - -npc_spawn("guard", x = 3221, y = 3471, z = 2) -npc_spawn("guard", x = 3214, y = 3474, z = 2) -npc_spawn("guard", x = 3215, y = 3471, z = 2) -npc_spawn("guard", x = 3211, y = 3471, z = 2) -npc_spawn("guard", x = 3209, y = 3473, z = 2) -npc_spawn("guard", x = 3212, y = 3475, z = 2) -npc_spawn("guard", x = 3207, y = 3477, z = 2) -npc_spawn("guard", x = 3203, y = 3476, z = 2) -npc_spawn("guard", x = 3205, y = 3479, z = 2) -npc_spawn("guard", x = 3203, y = 3483, z = 2) -npc_spawn("guard", x = 3221, y = 3485, z = 2) - -npc_spawn("monk_of_zamorak", id = 189, x = 3213, y = 3476) - -npc_spawn("warrior_woman", x = 3203, y = 3490) -npc_spawn("warrior_woman", x = 3205, y = 3493) +spawnNpc("guard", x = 3210, y = 3461) +spawnNpc("guard", x = 3211, y = 3465) +spawnNpc("guard", x = 3214, y = 3462) +spawnNpc("guard", x = 3216, y = 3464) +spawnNpc("guard", x = 3220, y = 3461) +spawnNpc("guard", x = 3206, y = 3461) +spawnNpc("guard", x = 3204, y = 3495) + +spawnNpc("guard", x = 3204, y = 3495, z = 1) +spawnNpc("guard", x = 3205, y = 3492, z = 1) +spawnNpc("guard", x = 3203, y = 3492, z = 1) +spawnNpc("guard", x = 3205, y = 3497, z = 1) + +spawnNpc("guard", x = 3221, y = 3471, z = 2) +spawnNpc("guard", x = 3214, y = 3474, z = 2) +spawnNpc("guard", x = 3215, y = 3471, z = 2) +spawnNpc("guard", x = 3211, y = 3471, z = 2) +spawnNpc("guard", x = 3209, y = 3473, z = 2) +spawnNpc("guard", x = 3212, y = 3475, z = 2) +spawnNpc("guard", x = 3207, y = 3477, z = 2) +spawnNpc("guard", x = 3203, y = 3476, z = 2) +spawnNpc("guard", x = 3205, y = 3479, z = 2) +spawnNpc("guard", x = 3203, y = 3483, z = 2) +spawnNpc("guard", x = 3221, y = 3485, z = 2) + +spawnNpc("monk_of_zamorak", id = 189, x = 3213, y = 3476) + +spawnNpc("warrior_woman", x = 3203, y = 3490) +spawnNpc("warrior_woman", x = 3205, y = 3493) // Varrock/Lumbridge Pen -npc_spawn("swan", x = 3261, y = 3354) -npc_spawn("swan", x = 3260, y = 3356) +spawnNpc("swan", x = 3261, y = 3354) +spawnNpc("swan", x = 3260, y = 3356) -npc_spawn("ram", id = 3673, x = 3238, y = 3346) -npc_spawn("ram", id = 3673, x = 3248, y = 3352) -npc_spawn("ram", id = 3673, x = 3260, y = 3348) +spawnNpc("ram", id = 3673, x = 3238, y = 3346) +spawnNpc("ram", id = 3673, x = 3248, y = 3352) +spawnNpc("ram", id = 3673, x = 3260, y = 3348) -npc_spawn("sheep", id = 42, x = 3263, y = 3347) -npc_spawn("sheep", id = 42, x = 3268, y = 3350) -npc_spawn("sheep", id = 42, x = 3252, y = 3352) -npc_spawn("sheep", id = 42, x = 3243, y = 3344) -npc_spawn("sheep", id = 42, x = 3235, y = 3347) +spawnNpc("sheep", id = 42, x = 3263, y = 3347) +spawnNpc("sheep", id = 42, x = 3268, y = 3350) +spawnNpc("sheep", id = 42, x = 3252, y = 3352) +spawnNpc("sheep", id = 42, x = 3243, y = 3344) +spawnNpc("sheep", id = 42, x = 3235, y = 3347) -npc_spawn("sheep", id = 3579, x = 3234, y = 3344) -npc_spawn("sheep", id = 3579, x = 3241, y = 3347) -npc_spawn("sheep", id = 3579, x = 3257, y = 3350) +spawnNpc("sheep", id = 3579, x = 3234, y = 3344) +spawnNpc("sheep", id = 3579, x = 3241, y = 3347) +spawnNpc("sheep", id = 3579, x = 3257, y = 3350) // Champions Guild -npc_spawn("chicken", x = 3195, y = 3359) -npc_spawn("chicken", x = 3198, y = 3356) -npc_spawn("chicken", x = 3195, y = 3355) +spawnNpc("chicken", x = 3195, y = 3359) +spawnNpc("chicken", x = 3198, y = 3356) +spawnNpc("chicken", x = 3195, y = 3355) -npc_spawn("chicken", id = 1017, x = 3196, y = 3353) -npc_spawn("chicken", id = 1017, x = 3197, y = 3356) +spawnNpc("chicken", id = 1017, x = 3196, y = 3353) +spawnNpc("chicken", id = 1017, x = 3197, y = 3356) -npc_spawn("evil_chicken", x = 3198, y = 3359) +spawnNpc("evil_chicken", x = 3198, y = 3359) // Function Npc -npc_spawn("apothecary", x = 3196, y = 3403) +spawnNpc("apothecary", x = 3196, y = 3403) -npc_spawn("captain_rovin", x = 3204, y = 3496, z = 2) +spawnNpc("captain_rovin", x = 3204, y = 3496, z = 2) -npc_spawn("curator", x = 3256, y = 3447) +spawnNpc("curator", x = 3256, y = 3447) -npc_spawn("dimintheis", x = 3280, y = 3403) +spawnNpc("dimintheis", x = 3280, y = 3403) -npc_spawn("dr_harlow", x = 3224, y = 3398) +spawnNpc("dr_harlow", x = 3224, y = 3398) -npc_spawn("ellamaria", x = 3228, y = 3475) +spawnNpc("ellamaria", x = 3228, y = 3475) -npc_spawn("father_lawrence", x = 3253, y = 3484) +spawnNpc("father_lawrence", x = 3253, y = 3484) -npc_spawn("guidors_wife", id = 342, x = 3280, y = 3382) +spawnNpc("guidors_wife", id = 342, x = 3280, y = 3382) -npc_spawn("guidor", x = 3284, y = 3381, facing = Direction.SOUTH) +spawnNpc("guidor", x = 3284, y = 3381, facing = Direction.SOUTH) -npc_spawn("guild_master", x = 3189, y = 3360) +spawnNpc("guild_master", x = 3189, y = 3360) -npc_spawn("gypsy", x = 3203, y = 3423) +spawnNpc("gypsy", x = 3203, y = 3423) -npc_spawn("hooknosed_jack", x = 3268, y = 3400) +spawnNpc("hooknosed_jack", x = 3268, y = 3400) -npc_spawn("jonny_the_beard", x = 3223, y = 3395) +spawnNpc("jonny_the_beard", x = 3223, y = 3395) -npc_spawn("johnathon", x = 3278, y = 3503, z = 1) +spawnNpc("johnathon", x = 3278, y = 3503, z = 1) -npc_spawn("katrine", x = 3185, y = 3386) +spawnNpc("katrine", x = 3185, y = 3386) -npc_spawn("king_roald", x = 3223, y = 3473) +spawnNpc("king_roald", x = 3223, y = 3473) -npc_spawn("master_farmer", x = 3243, y = 3349) +spawnNpc("master_farmer", x = 3243, y = 3349) -npc_spawn("pox", x = 3267, y = 3399) +spawnNpc("pox", x = 3267, y = 3399) -npc_spawn("reldo", x = 3210, y = 3492) +spawnNpc("reldo", x = 3210, y = 3492) -npc_spawn("romeo", x = 3211, y = 3423) +spawnNpc("romeo", x = 3211, y = 3423) -npc_spawn("shilop", x = 3211, y = 3435) +spawnNpc("shilop", x = 3211, y = 3435) -npc_spawn("sir_prysin", x = 3204, y = 3472) +spawnNpc("sir_prysin", x = 3204, y = 3472) -npc_spawn("tarquin", x = 3203, y = 3344, facing = Direction.SOUTH) +spawnNpc("tarquin", x = 3203, y = 3344, facing = Direction.SOUTH) -npc_spawn("tool_leprechaun", x = 3182, y = 3355) +spawnNpc("tool_leprechaun", x = 3182, y = 3355) -npc_spawn("tool_leprechaun", x = 3229, y = 3455) +spawnNpc("tool_leprechaun", x = 3229, y = 3455) -npc_spawn("tramp", id = 641, x = 3207, y = 3392) +spawnNpc("tramp", id = 641, x = 3207, y = 3392) -npc_spawn("wilough", x = 3222, y = 3437) +spawnNpc("wilough", x = 3222, y = 3437) // Shop Npc -npc_spawn("aubury", x = 3253, y = 3401) +spawnNpc("aubury", x = 3253, y = 3401) -npc_spawn("baraek", x = 3217, y = 3434) +spawnNpc("baraek", x = 3217, y = 3434) -npc_spawn("bartender", x = 3226, y = 3400) +spawnNpc("bartender", x = 3226, y = 3400) -npc_spawn("bartender", id = 1921, x = 3277, y = 3487) +spawnNpc("bartender", id = 1921, x = 3277, y = 3487) -npc_spawn("fancy_dress_shop_owner", x = 3281, y = 3398) +spawnNpc("fancy_dress_shop_owner", x = 3281, y = 3398) -npc_spawn("horvik", x = 3229, y = 3438) +spawnNpc("horvik", x = 3229, y = 3438) -npc_spawn("lowe", x = 3233, y = 3421) +spawnNpc("lowe", x = 3233, y = 3421) -npc_spawn("scavvo", x = 3192, y = 3353, z = 1) +spawnNpc("scavvo", x = 3192, y = 3353, z = 1) -npc_spawn("shop_keeper", id = 551, x = 3206, y = 3399) -npc_spawn("shop_assistant", id = 552, x = 3207, y = 3396) +spawnNpc("shop_keeper", id = 551, x = 3206, y = 3399) +spawnNpc("shop_assistant", id = 552, x = 3207, y = 3396) -npc_spawn("shop_keeper", id = 522, x = 3216, y = 3414) -npc_spawn("shop_assistant", id = 523, x = 3216, y = 3417) +spawnNpc("shop_keeper", id = 522, x = 3216, y = 3414) +spawnNpc("shop_assistant", id = 523, x = 3216, y = 3417) -npc_spawn("tea_seller", x = 3271, y = 3411) +spawnNpc("tea_seller", x = 3271, y = 3411) -npc_spawn("thessalia", x = 3206, y = 3417) +spawnNpc("thessalia", x = 3206, y = 3417) -npc_spawn("zaff", x = 3203, y = 3434) +spawnNpc("zaff", x = 3203, y = 3434) // Juliet House -npc_spawn("draul_leptoc", x = 3228, y = 3475) -npc_spawn("juliet", x = 3159, y = 3425, z = 1) -npc_spawn("phillipa", x = 3160, y = 3429, z = 1) +spawnNpc("draul_leptoc", x = 3228, y = 3475) +spawnNpc("juliet", x = 3159, y = 3425, z = 1) +spawnNpc("phillipa", x = 3160, y = 3429, z = 1) // Gertrude House -npc_spawn("gertrude", x = 3153, y = 3413) -npc_spawn("kanel", x = 3155, y = 3405, facing = Direction.EAST) -npc_spawn("philop", x = 3150, y = 3405, facing = Direction.SOUTH) +spawnNpc("gertrude", x = 3153, y = 3413) +spawnNpc("kanel", x = 3155, y = 3405, facing = Direction.EAST) +spawnNpc("philop", x = 3150, y = 3405, facing = Direction.SOUTH) // Small Bank -npc_spawn("banker", id = 495, x = 3252, y = 3418) -npc_spawn("banker", id = 494, x = 3252, y = 3418) -npc_spawn("banker", id = 494, x = 3252, y = 3418) -npc_spawn("banker", id = 494, x = 3252, y = 3418) +spawnNpc("banker", id = 495, x = 3252, y = 3418) +spawnNpc("banker", id = 494, x = 3252, y = 3418) +spawnNpc("banker", id = 494, x = 3252, y = 3418) +spawnNpc("banker", id = 494, x = 3252, y = 3418) // Big Bank -npc_spawn("banker", id = 494, x = 3187, y = 3436, facing = Direction.WEST) -npc_spawn("banker", id = 494, x = 3187, y = 3440, facing = Direction.WEST) -npc_spawn("banker", id = 494, x = 3187, y = 3444, facing = Direction.WEST) -npc_spawn("banker", id = 495, x = 3187, y = 3438, facing = Direction.WEST) -npc_spawn("banker", id = 495, x = 3187, y = 3442, facing = Direction.WEST) \ No newline at end of file +spawnNpc("banker", id = 494, x = 3187, y = 3436, facing = Direction.WEST) +spawnNpc("banker", id = 494, x = 3187, y = 3440, facing = Direction.WEST) +spawnNpc("banker", id = 494, x = 3187, y = 3444, facing = Direction.WEST) +spawnNpc("banker", id = 495, x = 3187, y = 3438, facing = Direction.WEST) +spawnNpc("banker", id = 495, x = 3187, y = 3442, facing = Direction.WEST) \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/spots.plugin.kts b/game/plugin/skills/fishing/src/spots.plugin.kts index 8aa824b6f..e874ad859 100644 --- a/game/plugin/skills/fishing/src/spots.plugin.kts +++ b/game/plugin/skills/fishing/src/spots.plugin.kts @@ -1,181 +1,181 @@ - import org.apollo.game.model.Direction import org.apollo.game.model.Position -import org.apollo.game.plugin.entity.spawn.Spawn -import org.apollo.game.plugin.entity.spawn.Spawns +import org.apollo.game.plugin.entity.spawn.spawnNpc import org.apollo.game.plugin.skills.fishing.FishingSpot -import org.apollo.game.plugin.skills.fishing.FishingSpot.* +import org.apollo.game.plugin.skills.fishing.FishingSpot.CAGE_HARPOON +import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_HARPOON +import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_ROD +import org.apollo.game.plugin.skills.fishing.FishingSpot.ROD // Al-Kharid -register(NET_ROD, x = 3267, y = 3148) -register(NET_ROD, x = 3268, y = 3147) -register(NET_ROD, x = 3277, y = 3139) -register(CAGE_HARPOON, x = 3350, y = 3817) -register(CAGE_HARPOON, x = 3347, y = 3814) -register(CAGE_HARPOON, x = 3363, y = 3816) -register(CAGE_HARPOON, x = 3368, y = 3811) +NET_ROD at Position(3267, 3148) +NET_ROD at Position(3268, 3147) +NET_ROD at Position(3277, 3139) +CAGE_HARPOON at Position(3350, 3817) +CAGE_HARPOON at Position(3347, 3814) +CAGE_HARPOON at Position(3363, 3816) +CAGE_HARPOON at Position(3368, 3811) // Ardougne -register(ROD, x = 2561, y = 3374) -register(ROD, x = 2562, y = 3374) -register(ROD, x = 2568, y = 3365) +ROD at Position(2561, 3374) +ROD at Position(2562, 3374) +ROD at Position(2568, 3365) // Bandit camp -register(NET_ROD, x = 3047, y = 3703) -register(NET_ROD, x = 3045, y = 3702) +NET_ROD at Position(3047, 3703) +NET_ROD at Position(3045, 3702) // Baxtorian falls -register(ROD, x = 2527, y = 3412) -register(ROD, x = 2530, y = 3412) -register(ROD, x = 2533, y = 3410) +ROD at Position(2527, 3412) +ROD at Position(2530, 3412) +ROD at Position(2533, 3410) // Burgh de Rott -register(NET_HARPOON, x = 3497, y = 3175) -register(NET_HARPOON, x = 3496, y = 3178) -register(NET_HARPOON, x = 3499, y = 3178) -register(NET_HARPOON, x = 3489, y = 3184) -register(NET_HARPOON, x = 3496, y = 3176) -register(NET_HARPOON, x = 3486, y = 3184) -register(NET_HARPOON, x = 3479, y = 3189) -register(NET_HARPOON, x = 3476, y = 3191) -register(NET_HARPOON, x = 3472, y = 3196) -register(NET_HARPOON, x = 3496, y = 3180) -register(NET_HARPOON, x = 3512, y = 3178) -register(NET_HARPOON, x = 3515, y = 3180) -register(NET_HARPOON, x = 3518, y = 3177) -register(NET_HARPOON, x = 3528, y = 3172) -register(NET_HARPOON, x = 3531, y = 3169) -register(NET_HARPOON, x = 3531, y = 3172) -register(NET_HARPOON, x = 3531, y = 3167) +NET_HARPOON at Position(3497, 3175) +NET_HARPOON at Position(3496, 3178) +NET_HARPOON at Position(3499, 3178) +NET_HARPOON at Position(3489, 3184) +NET_HARPOON at Position(3496, 3176) +NET_HARPOON at Position(3486, 3184) +NET_HARPOON at Position(3479, 3189) +NET_HARPOON at Position(3476, 3191) +NET_HARPOON at Position(3472, 3196) +NET_HARPOON at Position(3496, 3180) +NET_HARPOON at Position(3512, 3178) +NET_HARPOON at Position(3515, 3180) +NET_HARPOON at Position(3518, 3177) +NET_HARPOON at Position(3528, 3172) +NET_HARPOON at Position(3531, 3169) +NET_HARPOON at Position(3531, 3172) +NET_HARPOON at Position(3531, 3167) // Camelot -register(ROD, x = 2726, y = 3524) -register(ROD, x = 2727, y = 3524) +ROD at Position(2726, 3524) +ROD at Position(2727, 3524) // Castle wars -register(ROD, x = 2461, y = 3151) -register(ROD, x = 2461, y = 3150) -register(ROD, x = 2462, y = 3145) -register(ROD, x = 2472, y = 3156) +ROD at Position(2461, 3151) +ROD at Position(2461, 3150) +ROD at Position(2462, 3145) +ROD at Position(2472, 3156) // Catherby 1 -register(NET_ROD, x = 2838, y = 3431) -register(CAGE_HARPOON, x = 2837, y = 3431) -register(CAGE_HARPOON, x = 2836, y = 3431) -register(NET_ROD, x = 2846, y = 3429) -register(NET_ROD, x = 2844, y = 3429) -register(CAGE_HARPOON, x = 2845, y = 3429) -register(NET_HARPOON, x = 2853, y = 3423) -register(NET_HARPOON, x = 2855, y = 3423) -register(NET_HARPOON, x = 2859, y = 3426) +NET_ROD at Position(2838, 3431) +CAGE_HARPOON at Position(2837, 3431) +CAGE_HARPOON at Position(2836, 3431) +NET_ROD at Position(2846, 3429) +NET_ROD at Position(2844, 3429) +CAGE_HARPOON at Position(2845, 3429) +NET_HARPOON at Position(2853, 3423) +NET_HARPOON at Position(2855, 3423) +NET_HARPOON at Position(2859, 3426) // Draynor village -register(NET_ROD, x = 3085, y = 3230) -register(NET_ROD, x = 3085, y = 3231) -register(NET_ROD, x = 3086, y = 3227) +NET_ROD at Position(3085, 3230) +NET_ROD at Position(3085, 3231) +NET_ROD at Position(3086, 3227) // Elf camp -register(ROD, x = 2210, y = 3243) -register(ROD, x = 2216, y = 3236) -register(ROD, x = 2222, y = 3241) +ROD at Position(2210, 3243) +ROD at Position(2216, 3236) +ROD at Position(2222, 3241) // Entrana -register(NET_ROD, x = 2843, y = 3359) -register(NET_ROD, x = 2842, y = 3359) -register(NET_ROD, x = 2847, y = 3361) -register(NET_ROD, x = 2848, y = 3361) -register(NET_ROD, x = 2840, y = 3356) -register(NET_ROD, x = 2845, y = 3356) -register(NET_ROD, x = 2875, y = 3342) -register(NET_ROD, x = 2876, y = 3342) -register(NET_ROD, x = 2877, y = 3342) +NET_ROD at Position(2843, 3359) +NET_ROD at Position(2842, 3359) +NET_ROD at Position(2847, 3361) +NET_ROD at Position(2848, 3361) +NET_ROD at Position(2840, 3356) +NET_ROD at Position(2845, 3356) +NET_ROD at Position(2875, 3342) +NET_ROD at Position(2876, 3342) +NET_ROD at Position(2877, 3342) // Fishing guild -register(CAGE_HARPOON, x = 2612, y = 3411) -register(CAGE_HARPOON, x = 2607, y = 3410) -register(NET_HARPOON, x = 2612, y = 3414) -register(NET_HARPOON, x = 2612, y = 3415) -register(NET_HARPOON, x = 2609, y = 3416) -register(CAGE_HARPOON, x = 2604, y = 3417) -register(NET_HARPOON, x = 2605, y = 3416) -register(NET_HARPOON, x = 2602, y = 3411) -register(NET_HARPOON, x = 2602, y = 3412) -register(CAGE_HARPOON, x = 2602, y = 3414) -register(NET_HARPOON, x = 2603, y = 3417) -register(NET_HARPOON, x = 2599, y = 3419) -register(NET_HARPOON, x = 2601, y = 3422) -register(NET_HARPOON, x = 2605, y = 3421) -register(CAGE_HARPOON, x = 2602, y = 3426) -register(NET_HARPOON, x = 2604, y = 3426) -register(CAGE_HARPOON, x = 2605, y = 3425) +CAGE_HARPOON at Position(2612, 3411) +CAGE_HARPOON at Position(2607, 3410) +NET_HARPOON at Position(2612, 3414) +NET_HARPOON at Position(2612, 3415) +NET_HARPOON at Position(2609, 3416) +CAGE_HARPOON at Position(2604, 3417) +NET_HARPOON at Position(2605, 3416) +NET_HARPOON at Position(2602, 3411) +NET_HARPOON at Position(2602, 3412) +CAGE_HARPOON at Position(2602, 3414) +NET_HARPOON at Position(2603, 3417) +NET_HARPOON at Position(2599, 3419) +NET_HARPOON at Position(2601, 3422) +NET_HARPOON at Position(2605, 3421) +CAGE_HARPOON at Position(2602, 3426) +NET_HARPOON at Position(2604, 3426) +CAGE_HARPOON at Position(2605, 3425) // Fishing platform -register(NET_ROD, x = 2791, y = 3279) -register(NET_ROD, x = 2795, y = 3279) -register(NET_ROD, x = 2790, y = 3273) +NET_ROD at Position(2791, 3279) +NET_ROD at Position(2795, 3279) +NET_ROD at Position(2790, 3273) // Grand Tree -register(ROD, x = 2393, y = 3419) -register(ROD, x = 2391, y = 3421) -register(ROD, x = 2389, y = 3423) -register(ROD, x = 2388, y = 3423) -register(ROD, x = 2385, y = 3422) -register(ROD, x = 2384, y = 3419) -register(ROD, x = 2383, y = 3417) +ROD at Position(2393, 3419) +ROD at Position(2391, 3421) +ROD at Position(2389, 3423) +ROD at Position(2388, 3423) +ROD at Position(2385, 3422) +ROD at Position(2384, 3419) +ROD at Position(2383, 3417) // Karamja -register(NET_ROD, x = 2921, y = 3178) -register(CAGE_HARPOON, x = 2923, y = 3179) -register(CAGE_HARPOON, x = 2923, y = 3180) -register(NET_ROD, x = 2924, y = 3181) -register(NET_ROD, x = 2926, y = 3180) -register(CAGE_HARPOON, x = 2926, y = 3179) +NET_ROD at Position(2921, 3178) +CAGE_HARPOON at Position(2923, 3179) +CAGE_HARPOON at Position(2923, 3180) +NET_ROD at Position(2924, 3181) +NET_ROD at Position(2926, 3180) +CAGE_HARPOON at Position(2926, 3179) // Lumbridge -register(ROD, x = 3239, y = 3244) -register(NET_ROD, x = 3238, y = 3252) +ROD at Position(3239, 3244) +NET_ROD at Position(3238, 3252) // Miscellenia -register(CAGE_HARPOON, x = 2580, y = 3851) -register(CAGE_HARPOON, x = 2581, y = 3851) -register(CAGE_HARPOON, x = 2582, y = 3851) -register(CAGE_HARPOON, x = 2583, y = 3852) -register(CAGE_HARPOON, x = 2583, y = 3853) +CAGE_HARPOON at Position(2580, 3851) +CAGE_HARPOON at Position(2581, 3851) +CAGE_HARPOON at Position(2582, 3851) +CAGE_HARPOON at Position(2583, 3852) +CAGE_HARPOON at Position(2583, 3853) // Rellekka -register(NET_ROD, x = 2633, y = 3691) -register(NET_ROD, x = 2633, y = 3689) -register(CAGE_HARPOON, x = 2639, y = 3698) -register(CAGE_HARPOON, x = 2639, y = 3697) -register(CAGE_HARPOON, x = 2639, y = 3695) -register(NET_HARPOON, x = 2642, y = 3694) -register(NET_HARPOON, x = 2642, y = 3697) -register(NET_HARPOON, x = 2644, y = 3709) +NET_ROD at Position(2633, 3691) +NET_ROD at Position(2633, 3689) +CAGE_HARPOON at Position(2639, 3698) +CAGE_HARPOON at Position(2639, 3697) +CAGE_HARPOON at Position(2639, 3695) +NET_HARPOON at Position(2642, 3694) +NET_HARPOON at Position(2642, 3697) +NET_HARPOON at Position(2644, 3709) // Rimmington -register(NET_ROD, x = 2990, y = 3169) -register(NET_ROD, x = 2986, y = 3176) +NET_ROD at Position(2990, 3169) +NET_ROD at Position(2986, 3176) // Shilo Village -register(ROD, x = 2855, y = 2974) -register(ROD, x = 2865, y = 2972) -register(ROD, x = 2860, y = 2972) -register(ROD, x = 2835, y = 2974) -register(ROD, x = 2859, y = 2976) +ROD at Position(2855, 2974) +ROD at Position(2865, 2972) +ROD at Position(2860, 2972) +ROD at Position(2835, 2974) +ROD at Position(2859, 2976) // Tirannwn -register(ROD, x = 2266, y = 3253) -register(ROD, x = 2265, y = 3258) -register(ROD, x = 2264, y = 3258) +ROD at Position(2266, 3253) +ROD at Position(2265, 3258) +ROD at Position(2264, 3258) // Tutorial island -register(NET_ROD, x = 3101, y = 3092) -register(NET_ROD, x = 3103, y = 3092) +NET_ROD at Position(3101, 3092) +NET_ROD at Position(3103, 3092) /** * Registers the [FishingSpot] at the specified position. */ -fun register(spot: FishingSpot, x: Int, y: Int, z: Int = 0) { - val position = Position(x, y, z) - Spawns.list.add(Spawn(spot.npc, "", position, Direction.NORTH)) +infix fun FishingSpot.at(position: Position) { + spawnNpc("", position.x, position.y, position.height, id = npc, facing = Direction.NORTH) } \ No newline at end of file From 2080e1e700551c929099e4f9817d64598ad15d58 Mon Sep 17 00:00:00 2001 From: Major- Date: Mon, 20 Aug 2018 22:01:09 +0100 Subject: [PATCH 138/209] Add tests for player actions --- .../entity/following/src/following.plugin.kts | 3 +- .../src/{player_action.kt => PlayerAction.kt} | 26 ++++++-------- .../player-action/src/PlayerActionType.kt | 8 +++++ ...on.plugin.kts => PlayerActions.plugin.kts} | 6 ++-- .../player-action/test/PlayerActionTests.kt | 34 +++++++++++++++++++ .../message/impl/SetPlayerActionMessage.java | 22 ++++++++++-- 6 files changed, 76 insertions(+), 23 deletions(-) rename game/plugin/entity/player-action/src/{player_action.kt => PlayerAction.kt} (67%) create mode 100644 game/plugin/entity/player-action/src/PlayerActionType.kt rename game/plugin/entity/player-action/src/{player_action.plugin.kts => PlayerActions.plugin.kts} (66%) create mode 100644 game/plugin/entity/player-action/test/PlayerActionTests.kt diff --git a/game/plugin/entity/following/src/following.plugin.kts b/game/plugin/entity/following/src/following.plugin.kts index 3fc65c1fb..25e97d82e 100644 --- a/game/plugin/entity/following/src/following.plugin.kts +++ b/game/plugin/entity/following/src/following.plugin.kts @@ -1,7 +1,8 @@ +import org.apollo.game.plugin.entity.player_action.PlayerActionEvent import org.apollo.game.plugin.entity.player_action.PlayerActionType import org.apollo.plugin.entity.following.FollowAction -on_player_event { org.apollo.game.plugin.entity.player_action.PlayerActionEvent::class } +on_player_event { PlayerActionEvent::class } .where { action == PlayerActionType.FOLLOW } .then { FollowAction.start(it, target) diff --git a/game/plugin/entity/player-action/src/player_action.kt b/game/plugin/entity/player-action/src/PlayerAction.kt similarity index 67% rename from game/plugin/entity/player-action/src/player_action.kt rename to game/plugin/entity/player-action/src/PlayerAction.kt index 2b5c230de..22026b62a 100644 --- a/game/plugin/entity/player-action/src/player_action.kt +++ b/game/plugin/entity/player-action/src/PlayerAction.kt @@ -3,35 +3,29 @@ package org.apollo.game.plugin.entity.player_action import org.apollo.game.message.impl.SetPlayerActionMessage import org.apollo.game.model.entity.Player import org.apollo.game.model.event.PlayerEvent -import java.util.EnumSet - -enum class PlayerActionType(val displayName: String, val slot: Int, val primary: Boolean = true) { - ATTACK("Attack", 2), - CHALLENGE("Challenge", 2), - FOLLOW("Follow", 4), - TRADE("Trade with", 5) -} +import java.util.* class PlayerActionEvent(player: Player, val target: Player, val action: PlayerActionType) : PlayerEvent(player) -private val playerActionsMap = mutableMapOf>() -private val Player.actions: EnumSet - get() = playerActionsMap.computeIfAbsent(this, { EnumSet.noneOf(PlayerActionType::class.java) }) - fun Player.enableAction(action: PlayerActionType) { send(SetPlayerActionMessage(action.displayName, action.slot, action.primary)) - actions.add(action) + actions += action } fun Player.disableAction(action: PlayerActionType) { send(SetPlayerActionMessage("null", action.slot, action.primary)) - actions.remove(action) + actions -= action } fun Player.actionEnabled(action: PlayerActionType): Boolean { - return actions.contains(action) + return action in actions } fun Player.actionAt(slot: Int): PlayerActionType? { return actions.find { it.slot == slot } -} \ No newline at end of file +} + +private val playerActionsMap = mutableMapOf>() + +private val Player.actions: EnumSet + get() = playerActionsMap.computeIfAbsent(this) { EnumSet.noneOf(PlayerActionType::class.java) } diff --git a/game/plugin/entity/player-action/src/PlayerActionType.kt b/game/plugin/entity/player-action/src/PlayerActionType.kt new file mode 100644 index 000000000..b4ac185f6 --- /dev/null +++ b/game/plugin/entity/player-action/src/PlayerActionType.kt @@ -0,0 +1,8 @@ +package org.apollo.game.plugin.entity.player_action + +enum class PlayerActionType(val displayName: String, val slot: Int, val primary: Boolean = true) { + ATTACK("Attack", 2), + CHALLENGE("Challenge", 2), + FOLLOW("Follow", 4), + TRADE("Trade with", 5) +} \ No newline at end of file diff --git a/game/plugin/entity/player-action/src/player_action.plugin.kts b/game/plugin/entity/player-action/src/PlayerActions.plugin.kts similarity index 66% rename from game/plugin/entity/player-action/src/player_action.plugin.kts rename to game/plugin/entity/player-action/src/PlayerActions.plugin.kts index b3859a79a..6b4a0fe40 100644 --- a/game/plugin/entity/player-action/src/player_action.plugin.kts +++ b/game/plugin/entity/player-action/src/PlayerActions.plugin.kts @@ -1,9 +1,7 @@ +package org.apollo.game.plugin.entity.player_action + import org.apollo.game.message.impl.PlayerActionMessage import org.apollo.game.model.event.impl.LoginEvent -import org.apollo.game.plugin.entity.player_action.PlayerActionEvent -import org.apollo.game.plugin.entity.player_action.PlayerActionType -import org.apollo.game.plugin.entity.player_action.actionAt -import org.apollo.game.plugin.entity.player_action.enableAction on { PlayerActionMessage::class } .then { diff --git a/game/plugin/entity/player-action/test/PlayerActionTests.kt b/game/plugin/entity/player-action/test/PlayerActionTests.kt new file mode 100644 index 000000000..4c1dc248f --- /dev/null +++ b/game/plugin/entity/player-action/test/PlayerActionTests.kt @@ -0,0 +1,34 @@ +package org.apollo.game.plugin.entity.player_action + +import io.mockk.verify +import org.apollo.game.message.impl.SetPlayerActionMessage +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +@ExtendWith(ApolloTestingExtension::class) +class PlayerActionTests { + + @TestMock + lateinit var player: Player + + @ParameterizedTest + @EnumSource(PlayerActionType::class) + fun `enabling and disabling PlayerActions sends SetPlayerActionMessages`(type: PlayerActionType) { + player.enableAction(type) + + verify { player.send(eq(SetPlayerActionMessage(type.displayName, type.slot, type.primary))) } + assertTrue(player.actionEnabled(type)) { "Action $type should have been enabled, but was not." } + + player.disableAction(type) + + verify { player.send(eq(SetPlayerActionMessage("null", type.slot, type.primary))) } + assertFalse(player.actionEnabled(type)) { "Action $type should not have been enabled, but was." } + } + +} \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/message/impl/SetPlayerActionMessage.java b/game/src/main/java/org/apollo/game/message/impl/SetPlayerActionMessage.java index 4ebae8c32..4db7ceefc 100644 --- a/game/src/main/java/org/apollo/game/message/impl/SetPlayerActionMessage.java +++ b/game/src/main/java/org/apollo/game/message/impl/SetPlayerActionMessage.java @@ -2,6 +2,8 @@ import org.apollo.net.message.Message; +import java.util.Objects; + /** * A {@link Message} sent by the client to add an action to the menu when a player right-clicks another. * @@ -37,8 +39,8 @@ public SetPlayerActionMessage(String text, int slot) { /** * Creates the set player action message. * - * @param text The action text. - * @param slot The menu slot. + * @param text The action text. + * @param slot The menu slot. * @param primaryInteraction Whether or not the action is the primary action. */ public SetPlayerActionMessage(String text, int slot, boolean primaryInteraction) { @@ -75,4 +77,20 @@ public boolean isPrimaryAction() { return primaryAction; } + @Override + public boolean equals(Object o) { + if (o instanceof SetPlayerActionMessage) { + SetPlayerActionMessage other = (SetPlayerActionMessage) o; + return slot == other.slot && primaryAction == other.primaryAction && Objects.equals(text, other.text); + + } + + return false; + } + + @Override + public int hashCode() { + return Objects.hash(text, slot, primaryAction); + } + } \ No newline at end of file From 0b0f75d62294ac68bcc16a376852d4ed00b52b57 Mon Sep 17 00:00:00 2001 From: Arham4 Date: Thu, 26 Jul 2018 01:41:59 -0500 Subject: [PATCH 139/209] Added all shops in Lumbridge, Falador, Edgeville, and Al-Kharid --- game/plugin/locations/al-kharid/build.gradle | 5 +- .../locations/al-kharid/src/shops.plugin.kts | 144 ++++++++++++++++++ game/plugin/locations/edgeville/build.gradle | 5 +- .../locations/edgeville/src/shops.plugin.kts | 29 ++++ game/plugin/locations/falador/build.gradle | 5 +- .../locations/falador/src/shops.plugin.kts | 74 +++++++++ game/plugin/locations/lumbridge/build.gradle | 5 +- .../locations/lumbridge/src/shops.plugin.kts | 40 +++++ 8 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 game/plugin/locations/al-kharid/src/shops.plugin.kts create mode 100644 game/plugin/locations/edgeville/src/shops.plugin.kts create mode 100644 game/plugin/locations/falador/src/shops.plugin.kts create mode 100644 game/plugin/locations/lumbridge/src/shops.plugin.kts diff --git a/game/plugin/locations/al-kharid/build.gradle b/game/plugin/locations/al-kharid/build.gradle index a587f4fee..3be3eb4f1 100644 --- a/game/plugin/locations/al-kharid/build.gradle +++ b/game/plugin/locations/al-kharid/build.gradle @@ -1,9 +1,10 @@ plugin { - name = "al_kharid_npc_spawns" + name = "al_kharid" authors = [ "Jesse W", + "Arham 4" ] dependencies = [ - "entity:spawn", + "entity:spawn", "shops" ] } \ No newline at end of file diff --git a/game/plugin/locations/al-kharid/src/shops.plugin.kts b/game/plugin/locations/al-kharid/src/shops.plugin.kts new file mode 100644 index 000000000..d679700e6 --- /dev/null +++ b/game/plugin/locations/al-kharid/src/shops.plugin.kts @@ -0,0 +1,144 @@ +import org.apollo.game.plugin.shops.shop + +shop("Al-Kharid General Store") { + operated by "Shop keeper"(524) and "Shop assistant"(525) + buys any items + + sell(5) of "Pot" + sell(2) of "Jug" + sell(2) of "Shears" + sell(3) of "Bucket" + sell(2) of "Bowl" + sell(2) of "Cake tin" + sell(2) of "Tinderbox" + sell(2) of "Chisel" + sell(5) of "Hammer" + sell(5) of "Newcomer map" +} + +/** + * TODO add a way to "unlock" items, as more of Ali Morrisane's items are unlocked by completing certain parts of + * the Rogue Trader minigame progressively. + * + * TODO this shop can be accessed only through dialogue, so support for that should be added. + */ +/*shop("Ali's Discount Wares") { + operated by "Ali Morrisane" + + sell(3) of "Pot" + sell(2) of "Jug" + sell(10) of { "Waterskin"(1825) } + sell(3) of "Desert shirt" + sell(2) of "Desert boots" + sell(19) of "Bucket" + sell(11) of "Fake beard" + sell(12) of "Karidian headpiece" + sell(50) of "Papyrus" + sell(5) of "Knife" + sell(11) of "Tinderbox" + sell(23) of "Bronze pickaxe" + sell(15) of "Raw chicken" +}*/ + +shop("Dommik's Crafting Store") { + operated by "Dommik" + + sell(2) of "Chisel" + category("mould") { + sell(10) of "Ring" + sell(2) of "Necklace" + sell(10) of "Amulet" + } + sell(3) of "Needle" + sell(100) of "Thread" + category("mould") { + sell(3) of "Holy" + sell(10) of "Sickle" + sell(10) of "Tiara" + } +} + +shop("Gem Trader") { + operated by "Gem trader" + + category("uncut", affix = prefix) { + sell(1) of { + -"Sapphire" + -"Emerald" + } + sell(0) of { + -"Ruby" + -"Diamond" + } + } + + sell(1) of { + -"Sapphire" + -"Emerald" + } + sell(0) of { + -"Ruby" + -"Diamond" + } +} + +shop("Louie's Armoured Legs Bazaar") { + operated by "Louie Legs" + + category("platelegs", depluralise = false) { + sell(5) of "Bronze" + sell(3) of "Iron" + sell(2) of "Steel" + sell(1) of "Black" + sell(1) of "Mithril" + sell(1) of "Adamant" + } +} + +shop("Ranael's Super Skirt Store") { + operated by "Ranael" + + category("plateskirt") { + sell(5) of "Bronze" + sell(3) of "Iron" + sell(2) of "Steel" + sell(1) of "Black" + sell(1) of "Mithril" + sell(1) of "Adamant" + } +} + +shop("Shantay Pass Shop") { + operated by "Shantay" + + sell(100) of { "Waterskin"(1823) } + sell(100) of { "Waterskin"(1831) } + sell(10) of "Jug of water" + sell(10) of "Bowl of water" + sell(10) of "Bucket of water" + sell(10) of "Knife" + category("desert", affix = prefix) { + sell(10) of "shirt" + sell(10) of "robe" + sell(10) of "boots" + } + sell(10) of "Bronze bar" + sell(500) of "Feather" + sell(10) of "Hammer" + sell(0) of "Bucket" + sell(0) of "Bowl" + sell(0) of "Jug" + sell(500) of "Shantay pass" + sell(20) of "Rope" +} + +shop("Zeke's Superior Scimitars") { + operated by "Zeke" + + category("scimitar") { + sell(5) of "Bronze" + sell(3) of "Iron" + sell(2) of "Steel" + sell(1) of "Mithril" + } +} \ No newline at end of file diff --git a/game/plugin/locations/edgeville/build.gradle b/game/plugin/locations/edgeville/build.gradle index 6c9023e3d..0f2de3218 100644 --- a/game/plugin/locations/edgeville/build.gradle +++ b/game/plugin/locations/edgeville/build.gradle @@ -1,9 +1,10 @@ plugin { - name = "edgeville_npc_spawns" + name = "edgeville" authors = [ "Jesse W", + "Arham 4" ] dependencies = [ - "entity:spawn", + "entity:spawn", "shops" ] } \ No newline at end of file diff --git a/game/plugin/locations/edgeville/src/shops.plugin.kts b/game/plugin/locations/edgeville/src/shops.plugin.kts new file mode 100644 index 000000000..1a619dc10 --- /dev/null +++ b/game/plugin/locations/edgeville/src/shops.plugin.kts @@ -0,0 +1,29 @@ +import org.apollo.game.plugin.shops.shop + +shop("Edgeville General Store") { + operated by "Shop keeper"(528) and "Shop assistant"(529) + buys any items + + sell(5) of "Pot" + sell(2) of "Jug" + sell(2) of "Shears" + sell(3) of "Bucket" + sell(2) of "Bowl" + sell(2) of "Cake tin" + sell(2) of "Tinderbox" + sell(2) of "Chisel" + sell(5) of "Hammer" + sell(5) of "Newcomer map" +} + +/** + * TODO make a way to have requirements to open shops. Players have to have finished Dragon Slayer to access + * "Oziach's Armour" + */ +shop("Oziach's Armour") { + operated by "Oziach" + + sell(2) of "Rune platebody" + sell(2) of "Green d'hide body" + sell(35) of "Anti-dragon shield" +} \ No newline at end of file diff --git a/game/plugin/locations/falador/build.gradle b/game/plugin/locations/falador/build.gradle index c599f40ca..9af8dd9e0 100644 --- a/game/plugin/locations/falador/build.gradle +++ b/game/plugin/locations/falador/build.gradle @@ -1,9 +1,10 @@ plugin { - name = "falador_npc_spawns" + name = "falador" authors = [ "Jesse W", + "Arham 4" ] dependencies = [ - "entity:spawn", + "entity:spawn", "shops" ] } \ No newline at end of file diff --git a/game/plugin/locations/falador/src/shops.plugin.kts b/game/plugin/locations/falador/src/shops.plugin.kts new file mode 100644 index 000000000..dde292f2e --- /dev/null +++ b/game/plugin/locations/falador/src/shops.plugin.kts @@ -0,0 +1,74 @@ +import org.apollo.game.plugin.shops.shop + +shop("Falador General Store") { + operated by "Shop keeper"(524) and "Shop assistant"( 525) + buys any items + + sell(5) of "Pot" + sell(2) of "Jug" + sell(2) of "Shears" + sell(3) of "Bucket" + sell(2) of "Bowl" + sell(2) of "Cake tin" + sell(2) of "Tinderbox" + sell(2) of "Chisel" + sell(5) of "Hammer" + sell(5) of "Newcomer map" +} + +shop("Cassie's Shield Shop") { + operated by "Cassie" + + sell(5) of "Wooden shield" + sell(3) of "Bronze sq shield" + sell(3) of "Bronze kiteshield" + sell(2) of "Iron sq shield" + sell(0) of "Iron kiteshield" + sell(0) of "Steel sq shield" + sell(0) of "Steel kiteshield" + sell(0) of "Mithril sq shield" +} + +shop("Flynn's Mace Market") { + operated by "Flynn" + + category("mace") { + sell(5) of "Bronze" + sell(4) of "Iron" + sell(3) of "Mithril" + sell(2) of "Adamant" + } +} + +shop("Herquin's Gems") { + operated by "Herquin" + + category("uncut", affix = prefix) { + sell(1) of "Sapphire" + sell(0) of { + -"Emerald" + -"Ruby" + -"Diamond" + } + } + + sell(1) of "Sapphire" + sell(0) of { + -"Emerald" + -"Ruby" + -"Diamond" + } +} + +shop("Wayne's Chains - Chainmail Specialist") { + operated by "Wayne" + + category("chainbody") { + sell(3) of "Bronze" + sell(2) of "Iron" + sell(1) of "Steel" + sell(1) of "Black" + sell(1) of "Mithril" + sell(1) of "Adamant" + } +} \ No newline at end of file diff --git a/game/plugin/locations/lumbridge/build.gradle b/game/plugin/locations/lumbridge/build.gradle index 60f39625d..97bdf6868 100644 --- a/game/plugin/locations/lumbridge/build.gradle +++ b/game/plugin/locations/lumbridge/build.gradle @@ -1,9 +1,10 @@ plugin { - name = "lumbridge_npc_spawns" + name = "lumbridge" authors = [ "Gary Tierney", + "Arham 4" ] dependencies = [ - "entity:spawn", + "entity:spawn", "shops" ] } \ No newline at end of file diff --git a/game/plugin/locations/lumbridge/src/shops.plugin.kts b/game/plugin/locations/lumbridge/src/shops.plugin.kts new file mode 100644 index 000000000..dd12f2861 --- /dev/null +++ b/game/plugin/locations/lumbridge/src/shops.plugin.kts @@ -0,0 +1,40 @@ +import org.apollo.game.plugin.shops.shop + +shop("Lumbridge General Store") { + operated by "Shop keeper" and "Shop assistant" + buys any items + + sell(5) of "Pot" + sell(2) of "Jug" + sell(2) of "Shears" + sell(3) of "Bucket" + sell(2) of "Bowl" + sell(2) of "Cake tin" + sell(2) of "Tinderbox" + sell(2) of "Chisel" + sell(5) of "Hammer" + sell(5) of "Newcomer map" +} + +shop("Bob's Brilliant Axes") { + operated by "Bob" + + category("pickaxe") { + sell(5) of "Bronze" + } + + category("axe") { + sell(10) of "Bronze" + sell(5) of "Iron" + sell(3) of "Steel" + } + + category("battleaxe") { + sell(5) of "Iron" + sell(2) of "Steel" + sell(1) of "Mithril" + } +} + +// TODO find out how to make objects be able to open stores for the Culinaromancer's Chest. Also links to TODO in +// Al-Kharid's shops plugin for "unlockable" items. \ No newline at end of file From c2724236a2bd96460409f9997f310005e7f158ab Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 21:21:58 +0100 Subject: [PATCH 140/209] Add Gradle wrapper --- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 +++++++++++++++++++++++ gradlew.bat | 84 +++++++++++ 4 files changed, 261 insertions(+) create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..0d4a9516871afd710a9d84d89e31ba77745607bd GIT binary patch literal 54413 zcmafaV|Zr4wq`oEZQHiZj%|LijZQlLf{tz5M#r{o+fI6V=G-$g=gzrzeyqLskF}nv zRZs0&c;EUi2L_G~0s;*U0szbL-0C3_3~ zRZ#mYf6f1oqJoH`jHHCB8l!^by~4z}yc`4LEP@;Z?bO6{g9`Hk+s@(L1jC5Tq{1Yf z4E;CQvrx0-gF+peRxFC*gF=&$zNYjO?K|gN=WqXMz`tYs@0o%B{dRD+{C_6(f9t^g zhmNJQv6-#;f2)f2uc{u-#*U8W&i{|ewYN^n_1~cv|1J!}zc&$eaBy{T{cEpa46s*q zHFkD2cV;xTHFj}{*3kBt*FgS4A5SI|$F%$gB@It9FlC}D3y`sbZG{2P6gGwC$U`6O zb_cId9AhQl#A<&=x>-xDD%=Ppt$;y71@Lwsl{x943#T@8*?cbR<~d`@@}4V${+r$jICUIOzgZJy_9I zu*eA(F)$~J07zX%tmQN}1^wj+RM|9bbwhQA=xrPE*{vB_P!pPYT5{Or^m*;Qz#@Bl zRywCG_RDyM6bf~=xn}FtiFAw|rrUxa1+z^H`j6e|GwKDuq}P)z&@J>MEhsVBvnF|O zOEm)dADU1wi8~mX(j_8`DwMT_OUAnjbWYer;P*^Uku_qMu3}qJU zTAkza-K9aj&wcsGuhQ>RQoD?gz~L8RwCHOZDzhBD$az*$TQ3!uygnx_rsXG`#_x5t zn*lb(%JI3%G^MpYp-Y(KI4@_!&kBRa3q z|Fzn&3R%ZsoMNEn4pN3-BSw2S_{IB8RzRv(eQ1X zyBQZHJ<(~PfUZ~EoI!Aj`9k<+Cy z2DtI<+9sXQu!6&-Sk4SW3oz}?Q~mFvy(urUy<)x!KQ>#7yIPC)(ORhKl7k)4eSy~} z7#H3KG<|lt68$tk^`=yjev%^usOfpQ#+Tqyx|b#dVA(>fPlGuS@9ydo z!Cs#hse9nUETfGX-7lg;F>9)+ml@M8OO^q|W~NiysX2N|2dH>qj%NM`=*d3GvES_# zyLEHw&1Fx<-dYxCQbk_wk^CI?W44%Q9!!9aJKZW-bGVhK?N;q`+Cgc*WqyXcxZ%U5QXKu!Xn)u_dxeQ z;uw9Vysk!3OFzUmVoe)qt3ifPin0h25TU zrG*03L~0|aaBg7^YPEW^Yq3>mSNQgk-o^CEH?wXZ^QiPiuH}jGk;75PUMNquJjm$3 zLcXN*uDRf$Jukqg3;046b;3s8zkxa_6yAlG{+7{81O3w96i_A$KcJhD&+oz1<>?lun#C3+X0q zO4JxN{qZ!e#FCl@e_3G?0I^$CX6e$cy7$BL#4<`AA)Lw+k`^15pmb-447~5lkSMZ` z>Ce|adKhb-F%yy!vx>yQbXFgHyl(an=x^zi(!-~|k;G1=E(e@JgqbAF{;nv`3i)oi zDeT*Q+Mp{+NkURoabYb9@#Bi5FMQnBFEU?H{~9c;g3K%m{+^hNe}(MdpPb?j9`?2l z#%AO!|2QxGq7-2Jn2|%atvGb(+?j&lmP509i5y87`9*BSY++<%%DXb)kaqG0(4Eft zj|2!Od~2TfVTi^0dazAIeVe&b#{J4DjN6;4W;M{yWj7#+oLhJyqeRaO;>?%mX>Ec{Mp~;`bo}p;`)@5dA8fNQ38FyMf;wUPOdZS{U*8SN6xa z-kq3>*Zos!2`FMA7qjhw-`^3ci%c91Lh`;h{qX1r;x1}eW2hYaE*3lTk4GwenoxQ1kHt1Lw!*N8Z%DdZSGg5~Bw}+L!1#d$u+S=Bzo7gi zqGsBV29i)Jw(vix>De)H&PC; z-t2OX_ak#~eSJ?Xq=q9A#0oaP*dO7*MqV;dJv|aUG00UX=cIhdaet|YEIhv6AUuyM zH1h7fK9-AV)k8sr#POIhl+?Z^r?wI^GE)ZI=H!WR<|UI(3_YUaD#TYV$Fxd015^mT zpy&#-IK>ahfBlJm-J(n(A%cKV;)8&Y{P!E|AHPtRHk=XqvYUX?+9po4B$0-6t74UUef${01V{QLEE8gzw* z5nFnvJ|T4dlRiW9;Ed_yB{R@)fC=zo4hCtD?TPW*WJmMXYxN_&@YQYg zBQ$XRHa&EE;YJrS{bn7q?}Y&DH*h;){5MmE(9A6aSU|W?{3Ox%5fHLFScv7O-txuRbPG1KQtI`Oay=IcEG=+hPhlnYC;`wSHeo|XGio0aTS6&W($E$ z?N&?TK*l8;Y^-xPl-WVZwrfdiQv10KdsAb9u-*1co*0-Z(h#H)k{Vc5CT!708cs%sExvPC+7-^UY~jTfFq=cj z!Dmy<+NtKp&}}$}rD{l?%MwHdpE(cPCd;-QFPk1`E5EVNY2i6E`;^aBlx4}h*l42z zpY#2cYzC1l6EDrOY*ccb%kP;k8LHE3tP>l3iK?XZ%FI<3666yPw1rM%>eCgnv^JS_ zK7c~;g7yXt9fz@(49}Dj7VO%+P!eEm& z;z8UXs%NsQ%@2S5nve)@;yT^61BpVlc}=+i6{ZZ9r7<({yUYqe==9*Z+HguP3`sA& z{`inI4G)eLieUQ*pH9M@)u7yVnWTQva;|xq&-B<>MoP(|xP(HqeCk1&h>DHNLT>Zi zQ$uH%s6GoPAi0~)sC;`;ngsk+StYL9NFzhFEoT&Hzfma1f|tEnL0 zMWdX4(@Y*?*tM2@H<#^_l}BC&;PYJl%~E#veQ61{wG6!~nyop<^e)scV5#VkGjYc2 z$u)AW-NmMm%T7WschOnQ!Hbbw&?`oMZrJ&%dVlN3VNra1d0TKfbOz{dHfrCmJ2Jj= zS#Gr}JQcVD?S9X!u|oQ7LZ+qcq{$40 ziG5=X^+WqeqxU00YuftU7o;db=K+Tq!y^daCZgQ)O=M} zK>j*<3oxs=Rcr&W2h%w?0Cn3);~vqG>JO_tTOzuom^g&^vzlEjkx>Sv!@NNX%_C!v zaMpB>%yVb}&ND9b*O>?HxQ$5-%@xMGe4XKjWh7X>CYoRI2^JIwi&3Q5UM)?G^k8;8 zmY$u;(KjZx>vb3fe2zgD7V;T2_|1KZQW$Yq%y5Ioxmna9#xktcgVitv7Sb3SlLd6D zfmBM9Vs4rt1s0M}c_&%iP5O{Dnyp|g1(cLYz^qLqTfN6`+o}59Zlu%~oR3Q3?{Bnr zkx+wTpeag^G12fb_%SghFcl|p2~<)Av?Agumf@v7y-)ecVs`US=q~=QG%(_RTsqQi z%B&JdbOBOmoywgDW|DKR5>l$1^FPhxsBrja<&}*pfvE|5dQ7j-wV|ur%QUCRCzBR3q*X`05O3U@?#$<>@e+Zh&Z&`KfuM!0XL& zI$gc@ZpM4o>d&5)mg7+-Mmp98K^b*28(|Ew8kW}XEV7k^vnX-$onm9OtaO@NU9a|as7iA%5Wrw9*%UtJYacltplA5}gx^YQM` zVkn`TIw~avq)mIQO0F0xg)w$c)=8~6Jl|gdqnO6<5XD)&e7z7ypd3HOIR+ss0ikSVrWar?548HFQ*+hC)NPCq*;cG#B$7 z!n?{e9`&Nh-y}v=nK&PR>PFdut*q&i81Id`Z<0vXUPEbbJ|<~_D!)DJMqSF~ly$tN zygoa)um~xdYT<7%%m!K8+V(&%83{758b0}`b&=`))Tuv_)OL6pf=XOdFk&Mfx9y{! z6nL>V?t=#eFfM$GgGT8DgbGRCF@0ZcWaNs_#yl+6&sK~(JFwJmN-aHX{#Xkpmg;!} zgNyYYrtZdLzW1tN#QZAh!z5>h|At3m+ryJ-DFl%V>w?cmVTxt^DsCi1ZwPaCe*D{) z?#AZV6Debz{*D#C2>44Czy^yT3y92AYDcIXtZrK{L-XacVl$4i=X2|K=Fy5vAzhk{ zu3qG=qSb_YYh^HirWf~n!_Hn;TwV8FU9H8+=BO)XVFV`nt)b>5yACVr!b98QlLOBDY=^KS<*m9@_h3;64VhBQzb_QI)gbM zSDto2i*iFrvxSmAIrePB3i`Ib>LdM8wXq8(R{-)P6DjUi{2;?}9S7l7bND4w%L2!; zUh~sJ(?Yp}o!q6)2CwG*mgUUWlZ;xJZo`U`tiqa)H4j>QVC_dE7ha0)nP5mWGB268 zn~MVG<#fP#R%F=Ic@(&Va4dMk$ysM$^Avr1&hS!p=-7F>UMzd(M^N9Ijb|364}qcj zcIIh7suk$fQE3?Z^W4XKIPh~|+3(@{8*dSo&+Kr(J4^VtC{z*_{2}ld<`+mDE2)S| zQ}G#Q0@ffZCw!%ZGc@kNoMIdQ?1db%N1O0{IPPesUHI;(h8I}ETudk5ESK#boZgln z(0kvE`&6z1xH!s&={%wQe;{^&5e@N0s7IqR?L*x%iXM_czI5R1aU?!bA7)#c4UN2u zc_LZU+@elD5iZ=4*X&8%7~mA;SA$SJ-8q^tL6y)d150iM)!-ry@TI<=cnS#$kJAS# zq%eK**T*Wi2OlJ#w+d_}4=VN^A%1O+{?`BK00wkm)g8;u?vM;RR+F1G?}({ENT3i= zQsjJkp-dmJ&3-jMNo)wrz0!g*1z!V7D(StmL(A}gr^H-CZ~G9u?*Uhcx|x7rb`v^X z9~QGx;wdF4VcxCmEBp$F#sms@MR?CF67)rlpMxvwhEZLgp2?wQq|ci#rLtrYRV~iR zN?UrkDDTu114&d~Utjcyh#tXE_1x%!dY?G>qb81pWWH)Ku@Kxbnq0=zL#x@sCB(gs zm}COI(!{6-XO5li0>1n}Wz?w7AT-Sp+=NQ1aV@fM$`PGZjs*L+H^EW&s!XafStI!S zzgdntht=*p#R*o8-ZiSb5zf6z?TZr$^BtmIfGAGK;cdg=EyEG)fc*E<*T=#a?l=R5 zv#J;6C(umoSfc)W*EODW4z6czg3tXIm?x8{+8i^b;$|w~k)KLhJQnNW7kWXcR^sol z1GYOp?)a+}9Dg*nJ4fy*_riThdkbHO37^csfZRGN;CvQOtRacu6uoh^gg%_oEZKDd z?X_k67s$`|Q&huidfEonytrq!wOg07H&z@`&BU6D114p!rtT2|iukF}>k?71-3Hk< zs6yvmsMRO%KBQ44X4_FEYW~$yx@Y9tKrQ|rC1%W$6w}-9!2%4Zk%NycTzCB=nb)r6*92_Dg+c0;a%l1 zsJ$X)iyYR2iSh|%pIzYV1OUWER&np{w1+RXb~ zMUMRymjAw*{M)UtbT)T!kq5ZAn%n=gq3ssk3mYViE^$paZ;c^7{vXDJ`)q<}QKd2?{r9`X3mpZ{AW^UaRe2^wWxIZ$tuyKzp#!X-hXkHwfD zj@2tA--vFi3o_6B?|I%uwD~emwn0a z+?2Lc1xs(`H{Xu>IHXpz=@-84uw%dNV;{|c&ub|nFz(=W-t4|MME(dE4tZQi?0CE|4_?O_dyZj1)r zBcqB8I^Lt*#)ABdw#yq{OtNgf240Jvjm8^zdSf40 z;H)cp*rj>WhGSy|RC5A@mwnmQ`y4{O*SJ&S@UFbvLWyPdh)QnM=(+m3p;0&$^ysbZ zJt!ZkNQ%3hOY*sF2_~-*`aP|3Jq7_<18PX*MEUH*)t{eIx%#ibC|d&^L5FwoBN}Oe z?!)9RS@Zz%X1mqpHgym75{_BM4g)k1!L{$r4(2kL<#Oh$Ei7koqoccI3(MN1+6cDJ zp=xQhmilz1?+ZjkX%kfn4{_6K_D{wb~rdbkh!!k!Z@cE z^&jz55*QtsuNSlGPrU=R?}{*_8?4L7(+?>?(^3Ss)f!ou&{6<9QgH>#2$?-HfmDPN z6oIJ$lRbDZb)h-fFEm^1-v?Slb8udG{7GhbaGD_JJ8a9f{6{TqQN;m@$&)t81k77A z?{{)61za|e2GEq2)-OqcEjP`fhIlUs_Es-dfgX-3{S08g`w=wGj2{?`k^GD8d$}6Z zBT0T1lNw~fuwjO5BurKM593NGYGWAK%UCYiq{$p^GoYz^Uq0$YQ$j5CBXyog8(p_E znTC+$D`*^PFNc3Ih3b!2Lu|OOH6@46D)bbvaZHy%-9=$cz}V^|VPBpmPB6Ivzlu&c zPq6s7(2c4=1M;xlr}bkSmo9P`DAF>?Y*K%VPsY`cVZ{mN&0I=jagJ?GA!I;R)i&@{ z0Gl^%TLf_N`)`WKs?zlWolWvEM_?{vVyo(!taG$`FH2bqB`(o50pA=W34kl-qI62lt z1~4LG_j%sR2tBFteI{&mOTRVU7AH>>-4ZCD_p6;-J<=qrod`YFBwJz(Siu(`S}&}1 z6&OVJS@(O!=HKr-Xyzuhi;swJYK*ums~y1ePdX#~*04=b9)UqHHg;*XJOxnS6XK#j zG|O$>^2eW2ZVczP8#$C`EpcWwPFX4^}$omn{;P(fL z>J~%-r5}*D3$Kii z34r@JmMW2XEa~UV{bYP=F;Y5=9miJ+Jw6tjkR+cUD5+5TuKI`mSnEaYE2=usXNBs9 zac}V13%|q&Yg6**?H9D620qj62dM+&&1&a{NjF}JqmIP1I1RGppZ|oIfR}l1>itC% zl>ed${{_}8^}m2^br*AIX$L!Vc?Sm@H^=|LnpJg`a7EC+B;)j#9#tx-o0_e4!F5-4 zF4gA;#>*qrpow9W%tBzQ89U6hZ9g=-$gQpCh6Nv_I0X7t=th2ajJ8dBbh{i)Ok4{I z`Gacpl?N$LjC$tp&}7Sm(?A;;Nb0>rAWPN~@3sZ~0_j5bR+dz;Qs|R|k%LdreS3Nn zp*36^t#&ASm=jT)PIjNqaSe4mTjAzlAFr*@nQ~F+Xdh$VjHWZMKaI+s#FF#zjx)BJ zufxkW_JQcPcHa9PviuAu$lhwPR{R{7CzMUi49=MaOA%ElpK;A)6Sgsl7lw)D$8FwE zi(O6g;m*86kcJQ{KIT-Rv&cbv_SY4 zpm1|lSL*o_1LGOlBK0KuU2?vWcEcQ6f4;&K=&?|f`~X+s8H)se?|~2HcJo{M?Ity) zE9U!EKGz2^NgB6Ud;?GcV*1xC^1RYIp&0fr;DrqWLi_Kts()-#&3|wz{wFQsKfnnsC||T?oIgUp z{O(?Df7&vW!i#_~*@naguLLjDAz+)~*_xV2iz2?(N|0y8DMneikrT*dG`mu6vdK`% z=&nX5{F-V!Reau}+w_V3)4?}h@A@O)6GCY7eXC{p-5~p8x{cH=hNR;Sb{*XloSZ_%0ZKYG=w<|!vy?spR4!6mF!sXMUB5S9o_lh^g0!=2m55hGR; z-&*BZ*&;YSo474=SAM!WzrvjmNtq17L`kxbrZ8RN419e=5CiQ-bP1j-C#@@-&5*(8 zRQdU~+e(teUf}I3tu%PB1@Tr{r=?@0KOi3+Dy8}+y#bvgeY(FdN!!`Kb>-nM;7u=6 z;0yBwOJ6OdWn0gnuM{0`*fd=C(f8ASnH5aNYJjpbY1apTAY$-%)uDi$%2)lpH=#)=HH z<9JaYwPKil@QbfGOWvJ?cN6RPBr`f+jBC|-dO|W@x_Vv~)bmY(U(!cs6cnhe0z31O z>yTtL4@KJ*ac85u9|=LFST22~!lb>n7IeHs)_(P_gU}|8G>{D_fJX)8BJ;Se? z67QTTlTzZykb^4!{xF!=C}VeFd@n!9E)JAK4|vWVwWop5vSWcD<;2!88v-lS&ve7C zuYRH^85#hGKX(Mrk};f$j_V&`Nb}MZy1mmfz(e`nnI4Vpq(R}26pZx?fq%^|(n~>* z5a5OFtFJJfrZmgjyHbj1`9||Yp?~`p2?4NCwu_!!*4w8K`&G7U_|np&g7oY*-i;sI zu)~kYH;FddS{7Ri#Z5)U&X3h1$Mj{{yk1Q6bh4!7!)r&rqO6K~{afz@bis?*a56i& zxi#(Ss6tkU5hDQJ0{4sKfM*ah0f$>WvuRL zunQ-eOqa3&(rv4kiQ(N4`FO6w+nko_HggKFWx@5aYr}<~8wuEbD(Icvyl~9QL^MBt zSvD)*C#{2}!Z55k1ukV$kcJLtW2d~%z$t0qMe(%2qG`iF9K_Gsae7OO%Tf8E>ooch ztAw01`WVv6?*14e1w%Wovtj7jz_)4bGAqqo zvTD|B4)Ls8x7-yr6%tYp)A7|A)x{WcI&|&DTQR&2ir(KGR7~_RhNOft)wS<+vQ*|sf;d>s zEfl&B^*ZJp$|N`w**cXOza8(ARhJT{O3np#OlfxP9Nnle4Sto)Fv{w6ifKIN^f1qO*m8+MOgA1^Du!=(@MAh8)@wU8t=Ymh!iuT_lzfm za~xEazL-0xwy9$48!+?^lBwMV{!Gx)N>}CDi?Jwax^YX@_bxl*+4itP;DrTswv~n{ zZ0P>@EB({J9ZJ(^|ptn4ks^Z2UI&87d~J_^z0&vD2yb%*H^AE!w= zm&FiH*c%vvm{v&i3S>_hacFH${|(2+q!`X~zn4$aJDAry>=n|{C7le(0a)nyV{kAD zlud4-6X>1@-XZd`3SKKHm*XNn_zCyKHmf*`C_O509$iy$Wj`Sm3y?nWLCDy>MUx1x zl-sz7^{m(&NUk*%_0(G^>wLDnXW90FzNi$Tu6* z<+{ePBD`%IByu977rI^x;gO5M)Tfa-l*A2mU-#IL2?+NXK-?np<&2rlF;5kaGGrx2 zy8Xrz`kHtTVlSSlC=nlV4_oCsbwyVHG4@Adb6RWzd|Otr!LU=% zEjM5sZ#Ib4#jF(l!)8Na%$5VK#tzS>=05GpV?&o* z3goH1co0YR=)98rPJ~PuHvkA59KUi#i(Mq_$rApn1o&n1mUuZfFLjx@3;h`0^|S##QiTP8rD`r8P+#D@gvDJh>amMIl065I)PxT6Hg(lJ?X7*|XF2Le zv36p8dWHCo)f#C&(|@i1RAag->5ch8TY!LJ3(+KBmLxyMA%8*X%_ARR*!$AL66nF= z=D}uH)D)dKGZ5AG)8N-;Il*-QJ&d8u30&$_Q0n1B58S0ykyDAyGa+BZ>FkiOHm1*& zNOVH;#>Hg5p?3f(7#q*dL74;$4!t?a#6cfy#}9H3IFGiCmevir5@zXQj6~)@zYrWZ zRl*e66rjwksx-)Flr|Kzd#Bg>We+a&E{h7bKSae9P~ z(g|zuXmZ zD?R*MlmoZ##+0c|cJ(O{*h(JtRdA#lChYhfsx25(Z`@AK?Q-S8_PQqk z>|Z@Ki1=wL1_c6giS%E4YVYD|Y-{^ZzFwB*yN8-4#+TxeQ`jhks7|SBu7X|g=!_XL z`mY=0^chZfXm%2DYHJ4z#soO7=NONxn^K3WX={dV>$CTWSZe@<81-8DVtJEw#Uhd3 zxZx+($6%4a&y_rD8a&E`4$pD6-_zZJ%LEE*1|!9uOm!kYXW< zOBXZAowsX-&$5C`xgWkC43GcnY)UQt2Qkib4!!8Mh-Q!_M%5{EC=Gim@_;0+lP%O^ zG~Q$QmatQk{Mu&l{q~#kOD;T-{b1P5u7)o-QPPnqi?7~5?7%IIFKdj{;3~Hu#iS|j z)Zoo2wjf%+rRj?vzWz(6JU`=7H}WxLF*|?WE)ci7aK?SCmd}pMW<{#1Z!_7BmVP{w zSrG>?t}yNyCR%ZFP?;}e8_ zRy67~&u11TN4UlopWGj6IokS{vB!v!n~TJYD6k?~XQkpiPMUGLG2j;lh>Eb5bLTkX zx>CZlXdoJsiPx=E48a4Fkla>8dZYB%^;Xkd(BZK$z3J&@({A`aspC6$qnK`BWL;*O z-nRF{XRS`3Y&b+}G&|pE1K-Ll_NpT!%4@7~l=-TtYRW0JJ!s2C-_UsRBQ=v@VQ+4> z*6jF0;R@5XLHO^&PFyaMDvyo?-lAD(@H61l-No#t@at@Le9xOgTFqkc%07KL^&iss z!S2Ghm)u#26D(e1Q7E;L`rxOy-N{kJ zTgfw}az9=9Su?NEMMtpRlYwDxUAUr8F+P=+9pkX4%iA4&&D<|=B|~s*-U+q6cq`y* zIE+;2rD7&D5X;VAv=5rC5&nP$E9Z3HKTqIFCEV%V;b)Y|dY?8ySn|FD?s3IO>VZ&&f)idp_7AGnwVd1Z znBUOBA}~wogNpEWTt^1Rm-(YLftB=SU|#o&pT7vTr`bQo;=ZqJHIj2MP{JuXQPV7% z0k$5Ha6##aGly<}u>d&d{Hkpu?ZQeL_*M%A8IaXq2SQl35yW9zs4^CZheVgHF`%r= zs(Z|N!gU5gj-B^5{*sF>;~fauKVTq-Ml2>t>E0xl9wywD&nVYZfs1F9Lq}(clpNLz z4O(gm_i}!k`wUoKr|H#j#@XOXQ<#eDGJ=eRJjhOUtiKOG;hym-1Hu)1JYj+Kl*To<8( za1Kf4_Y@Cy>eoC59HZ4o&xY@!G(2p^=wTCV>?rQE`Upo^pbhWdM$WP4HFdDy$HiZ~ zRUJFWTII{J$GLVWR?miDjowFk<1#foE3}C2AKTNFku+BhLUuT>?PATB?WVLzEYyu+ zM*x((pGdotzLJ{}R=OD*jUexKi`mb1MaN0Hr(Wk8-Uj0zA;^1w2rmxLI$qq68D>^$ zj@)~T1l@K|~@YJ6+@1vlWl zHg5g%F{@fW5K!u>4LX8W;ua(t6YCCO_oNu}IIvI6>Fo@MilYuwUR?9p)rKNzDmTAN zzN2d>=Za&?Z!rJFV*;mJ&-sBV80%<-HN1;ciLb*Jk^p?u<~T25%7jjFnorfr={+wm zzl5Q6O>tsN8q*?>uSU6#xG}FpAVEQ_++@}G$?;S7owlK~@trhc#C)TeIYj^N(R&a} zypm~c=fIs;M!YQrL}5{xl=tUU-Tfc0ZfhQuA-u5(*w5RXg!2kChQRd$Fa8xQ0CQIU zC`cZ*!!|O!*y1k1J^m8IIi|Sl3R}gm@CC&;4840^9_bb9%&IZTRk#=^H0w%`5pMDCUef5 zYt-KpWp2ijh+FM`!zZ35>+7eLN;s3*P!bp%-oSx34fdTZ14Tsf2v7ZrP+mitUx$rS zW(sOi^CFxe$g3$x45snQwPV5wpf}>5OB?}&Gh<~i(mU&ss#7;utaLZ!|KaTHniGO9 zVC9OTzuMKz)afey_{93x5S*Hfp$+r*W>O^$2ng|ik!<`U1pkxm3*)PH*d#>7md1y} zs7u^a8zW8bvl92iN;*hfOc-=P7{lJeJ|3=NfX{(XRXr;*W3j845SKG&%N zuBqCtDWj*>KooINK1 zFPCsCWr!-8G}G)X*QM~34R*k zmRmDGF*QE?jCeNfc?k{w<}@29e}W|qKJ1K|AX!htt2|B`nL=HkC4?1bEaHtGBg}V( zl(A`6z*tck_F$4;kz-TNF%7?=20iqQo&ohf@S{_!TTXnVh}FaW2jxAh(DI0f*SDG- z7tqf5X@p#l?7pUNI(BGi>n_phw=lDm>2OgHx-{`T>KP2YH9Gm5ma zb{>7>`tZ>0d5K$j|s2!{^sFWQo3+xDb~#=9-jp(1ydI3_&RXGB~rxWSMgDCGQG)oNoc#>)td zqE|X->35U?_M6{^lB4l(HSN|`TC2U*-`1jSQeiXPtvVXdN-?i1?d#;pw%RfQuKJ|e zjg75M+Q4F0p@8I3ECpBhGs^kK;^0;7O@MV=sX^EJLVJf>L;GmO z3}EbTcoom7QbI(N8ad!z(!6$!MzKaajSRb0c+ZDQ($kFT&&?GvXmu7+V3^_(VJx1z zP-1kW_AB&_A;cxm*g`$ z#Pl@Cg{siF0ST2-w)zJkzi@X)5i@)Z;7M5ewX+xcY36IaE0#flASPY2WmF8St0am{ zV|P|j9wqcMi%r-TaU>(l*=HxnrN?&qAyzimA@wtf;#^%{$G7i4nXu=Pp2#r@O~wi)zB>@25A*|axl zEclXBlXx1LP3x0yrSx@s-kVW4qlF+idF+{M7RG54CgA&soDU-3SfHW@-6_ z+*;{n_SixmGCeZjHmEE!IF}!#aswth_{zm5Qhj0z-@I}pR?cu=P)HJUBClC;U+9;$#@xia30o$% zDw%BgOl>%vRenxL#|M$s^9X}diJ9q7wI1-0n2#6>@q}rK@ng(4M68(t52H_Jc{f&M9NPxRr->vj-88hoI?pvpn}llcv_r0`;uN>wuE{ z&TOx_i4==o;)>V4vCqG)A!mW>dI^Ql8BmhOy$6^>OaUAnI3>mN!Zr#qo4A>BegYj` zNG_)2Nvy2Cqxs1SF9A5HHhL7sai#Umw%K@+riaF+q)7&MUJvA&;$`(w)+B@c6!kX@ zzuY;LGu6|Q2eu^06PzSLspV2v4E?IPf`?Su_g8CX!75l)PCvyWKi4YRoRThB!-BhG zubQ#<7oCvj@z`^y&mPhSlbMf0<;0D z?5&!I?nV-jh-j1g~&R(YL@c=KB_gNup$8abPzXZN`N|WLqxlN)ZJ+#k4UWq#WqvVD z^|j+8f5uxTJtgcUscKTqKcr?5g-Ih3nmbvWvvEk})u-O}h$=-p4WE^qq7Z|rLas0$ zh0j&lhm@Rk(6ZF0_6^>Rd?Ni-#u1y`;$9tS;~!ph8T7fLlYE{P=XtWfV0Ql z#z{_;A%p|8+LhbZT0D_1!b}}MBx9`R9uM|+*`4l3^O(>Mk%@ha>VDY=nZMMb2TnJ= zGlQ+#+pmE98zuFxwAQcVkH1M887y;Bz&EJ7chIQQe!pgWX>(2ruI(emhz@_6t@k8Z zqFEyJFX2PO`$gJ6p$=ku{7!vR#u+$qo|1r;orjtp9FP^o2`2_vV;W&OT)acRXLN^m zY8a;geAxg!nbVu|uS8>@Gvf@JoL&GP`2v4s$Y^5vE32&l;2)`S%e#AnFI-YY7_>d#IKJI!oL6e z_7W3e=-0iz{bmuB*HP+D{Nb;rn+RyimTFqNV9Bzpa0?l`pWmR0yQOu&9c0S*1EPr1 zdoHMYlr>BycjTm%WeVuFd|QF8I{NPT&`fm=dITj&3(M^q ze2J{_2zB;wDME%}SzVWSW6)>1QtiX)Iiy^p2eT}Ii$E9w$5m)kv(3wSCNWq=#DaKZ zs%P`#^b7F-J0DgQ1?~2M`5ClYtYN{AlU|v4pEg4z03=g6nqH`JjQuM{k`!6jaIL_F zC;sn?1x?~uMo_DFg#ypNeie{3udcm~M&bYJ1LI zE%y}P9oCX3I1Y9yhF(y9Ix_=8L(p)EYr&|XZWCOb$7f2qX|A4aJ9bl7pt40Xr zXUT#NMBB8I@xoIGSHAZkYdCj>eEd#>a;W-?v4k%CwBaR5N>e3IFLRbDQTH#m_H+4b zk2UHVymC`%IqwtHUmpS1!1p-uQB`CW1Y!+VD!N4TT}D8(V0IOL|&R&)Rwj@n8g@=`h&z9YTPDT+R9agnwPuM!JW~=_ya~% zIJ*>$Fl;y7_`B7G4*P!kcy=MnNmR`(WS5_sRsvHF42NJ;EaDram5HwQ4Aw*qbYn0j;#)bh1lyKLg#dYjN*BMlh+fxmCL~?zB;HBWho;20WA==ci0mAqMfyG>1!HW zO7rOga-I9bvut1Ke_1eFo9tbzsoPTXDW1Si4}w3fq^Z|5LGf&egnw%DV=b11$F=P~ z(aV+j8S}m=CkI*8=RcrT>GmuYifP%hCoKY22Z4 zmu}o08h3YhcXx-v-QC??8mDn<+}+*X{+gZH-I;G^|7=1fBveS?J$27H&wV5^V^P$! z84?{UeYSmZ3M!@>UFoIN?GJT@IroYr;X@H~ax*CQ>b5|Xi9FXt5j`AwUPBq`0sWEJ z3O|k+g^JKMl}L(wfCqyMdRj9yS8ncE7nI14Tv#&(?}Q7oZpti{Q{Hw&5rN-&i|=fWH`XTQSu~1jx(hqm$Ibv zRzFW9$xf@oZAxL~wpj<0ZJ3rdPAE=0B>G+495QJ7D>=A&v^zXC9)2$$EnxQJ<^WlV zYKCHb1ZzzB!mBEW2WE|QG@&k?VXarY?umPPQ|kziS4{EqlIxqYHP!HN!ncw6BKQzKjqk!M&IiOJ9M^wc~ZQ1xoaI z;4je%ern~?qi&J?eD!vTl__*kd*nFF0n6mGEwI7%dI9rzCe~8vU1=nE&n4d&8}pdL zaz`QAY?6K@{s2x%Sx%#(y+t6qLw==>2(gb>AksEebXv=@ht>NBpqw=mkJR(c?l7vo z&cV)hxNoYPGqUh9KAKT)kc(NqekzE6(wjjotP(ac?`DJF=Sb7^Xet-A3PRl%n&zKk zruT9cS~vV1{%p>OVm1-miuKr<@rotj*5gd$?K`oteNibI&K?D63RoBjw)SommJ5<4 zus$!C8aCP{JHiFn2>XpX&l&jI7E7DcTjzuLYvON2{rz<)#$HNu(;ie-5$G<%eLKnTK7QXfn(UR(n+vX%aeS6!q6kv z!3nzY76-pdJp339zsl_%EI|;ic_m56({wdc(0C5LvLULW=&tWc5PW-4;&n+hm1m`f zzQV0T>OPSTjw=Ox&UF^y< zarsYKY8}YZF+~k70=olu$b$zdLaozBE|QE@H{_R21QlD5BilYBTOyv$D5DQZ8b1r- zIpSKX!SbA0Pb5#cT)L5!KpxX+x+8DRy&`o-nj+nmgV6-Gm%Fe91R1ca3`nt*hRS|^ z<&we;TJcUuPDqkM7k0S~cR%t7a`YP#80{BI$e=E!pY}am)2v3-Iqk2qvuAa1YM>xj#bh+H2V z{b#St2<;Gg>$orQ)c2a4AwD5iPcgZ7o_}7xhO86(JSJ(q(EWKTJDl|iBjGEMbX8|P z4PQHi+n(wZ_5QrX0?X_J)e_yGcTM#E#R^u_n8pK@l5416`c9S=q-e!%0RjoPyTliO zkp{OC@Ep^#Ig-n!C)K0Cy%8~**Vci8F1U(viN{==KU0nAg2(+K+GD_Gu#Bx!{tmUm zCwTrT(tCr6X8j43_n96H9%>>?4akSGMvgd+krS4wRexwZ1JxrJy!Uhz#yt$-=aq?A z@?*)bRZxjG9OF~7d$J0cwE_^CLceRK=LvjfH-~{S><^D;6B2&p-02?cl?|$@>`Qt$ zP*iaOxg<+(rbk>34VQDQpNQ|a9*)wScu!}<{oXC87hRPqyrNWpo?#=;1%^D2n2+C* zKKQH;?rWn-@%Y9g%NHG&lHwK9pBfV1a`!TqeU_Fv8s6_(@=RHua7`VYO|!W&WL*x= zIWE9eQaPq3zMaXuf)D0$V`RIZ74f)0P73xpeyk4)-?8j;|K%pD$eq4j2%tL=;&+E91O(2p91K|85b)GQcbRe&u6Ilu@SnE={^{Ix1Eqgv8D z4=w65+&36|;5WhBm$!n*!)ACCwT9Sip#1_z&g~E1kB=AlEhO0lu`Ls@6gw*a)lzc# zKx!fFP%eSBBs)U>xIcQKF(r_$SWD3TD@^^2Ylm=kC*tR+I@X>&SoPZdJ2fT!ysjH% z-U%|SznY8Fhsq7Vau%{Ad^Pvbf3IqVk{M2oD+w>MWimJA@VSZC$QooAO3 zC=DplXdkyl>mSp^$zk7&2+eoGQ6VVh_^E#Z3>tX7Dmi<2aqlM&YBmK&U}m>a%8)LQ z8v+c}a0QtXmyd%Kc2QNGf8TK?_EK4wtRUQ*VDnf5jHa?VvH2K(FDZOjAqYufW8oIZ z31|o~MR~T;ZS!Lz%8M0*iVARJ>_G2BXEF8(}6Dmn_rFV~5NI`lJjp`Mi~g7~P%H zO`S&-)Fngo3VXDMo7ImlaZxY^s!>2|csKca6!|m7)l^M0SQT1_L~K29%x4KV8*xiu zwP=GlyIE9YPSTC0BV`6|#)30=hJ~^aYeq7d6TNfoYUkk-^k0!(3qp(7Mo-$|48d8Z2d zrsfsRM)y$5)0G`fNq!V?qQ+nh0xwFbcp{nhW%vZ?h);=LxvM(pWd9FG$Bg1;@Bv)mKDW>AP{ol zD(R~mLzdDrBv$OSi{E%OD`Ano=F^vwc)rNb*Bg3-o)bbAgYE=M7Gj2OHY{8#pM${_^ zwkU|tnTKawxUF7vqM9UfcQ`V49zg78V%W)$#5ssR}Rj7E&p(4_ib^?9luZPJ%iJTvW&-U$nFYky>KJwHpEHHx zVEC;!ETdkCnO|${Vj#CY>LLut_+c|(hpWk8HRgMGRY%E--%oKh@{KnbQ~0GZd}{b@ z`J2qHBcqqjfHk^q=uQL!>6HSSF3LXL*cCd%opM|k#=xTShX~qcxpHTW*BI!c3`)hQq{@!7^mdUaG7sFsFYnl1%blslM;?B8Q zuifKqUAmR=>33g~#>EMNfdye#rz@IHgpM$~Z7c5@bO@S>MyFE3_F}HVNLnG0TjtXU zJeRWH^j5w_qXb$IGs+E>daTa}XPtrUnnpTRO9NEx4g6uaFEfHP9gW;xZnJi{oqAH~ z5dHS(ch3^hbvkv@u3QPLuWa}ImaElDrmIc%5HN<^bwej}3+?g) z-ai7D&6Iq_P(}k`i^4l?hRLbCb>X9iq2UYMl=`9U9Rf=3Y!gnJbr?eJqy>Zpp)m>Ae zcQ4Qfs&AaE?UDTODcEj#$_n4KeERZHx-I+E5I~E#L_T3WI3cj$5EYR75H7hy%80a8Ej?Y6hv+fR6wHN%_0$-xL!eI}fdjOK7(GdFD%`f%-qY@-i@fTAS&ETI99jUVg8 zslPSl#d4zbOcrgvopvB2c2A6r^pEr&Sa5I5%@1~BpGq`Wo|x=&)WnnQjE+)$^U-wW zr2Kv?XJby(8fcn z8JgPn)2_#-OhZ+;72R6PspMfCVvtLxFHeb7d}fo(GRjm_+R(*?9QRBr+yPF(iPO~ zA4Tp1<0}#fa{v0CU6jz}q9;!3Pew>ikG1qh$5WPRTQZ~ExQH}b1hDuzRS1}65uydS z~Te*3@?o8fih=mZ`iI!hL5iv3?VUBLQv0X zLtu58MIE7Jbm?)NFUZuMN2_~eh_Sqq*56yIo!+d_zr@^c@UwR&*j!fati$W<=rGGN zD$X`$lI%8Qe+KzBU*y3O+;f-Csr4$?3_l+uJ=K@dxOfZ?3APc5_x2R=a^kLFoxt*_ z4)nvvP+(zwlT5WYi!4l7+HKqzmXKYyM9kL5wX$dTSFSN&)*-&8Q{Q$K-})rWMin8S zy*5G*tRYNqk7&+v;@+>~EIQgf_SB;VxRTQFcm5VtqtKZ)x=?-f+%OY(VLrXb^6*aP zP&0Nu@~l2L!aF8i2!N~fJiHyxRl?I1QNjB)`uP_DuaU?2W;{?0#RGKTr2qH5QqdhK zP__ojm4WV^PUgmrV)`~f>(769t3|13DrzdDeXxqN6XA|_GK*;zHU()a(20>X{y-x| z2P6Ahq;o=)Nge`l+!+xEwY`7Q(8V=93A9C+WS^W%p&yR)eiSX+lp)?*7&WSYSh4i> zJa6i5T9o;Cd5z%%?FhB?J{l+t_)c&_f86gZMU{HpOA=-KoU5lIL#*&CZ_66O5$3?# ztgjGLo`Y7bj&eYnK#5x1trB_6tpu4$EomotZLb*9l6P(JmqG`{z$?lNKgq?GAVhkA zvw!oFhLyX=$K=jTAMwDQ)E-8ZW5$X%P2$YB5aq!VAnhwGv$VR&;Ix#fu%xlG{|j_K zbEYL&bx%*YpXcaGZj<{Y{k@rsrFKh7(|saspt?OxQ~oj_6En(&!rTZPa7fLCEU~mA zB7tbVs=-;cnzv*#INgF_9f3OZhp8c5yk!Dy1+`uA7@eJfvd~g34~wKI1PW%h(y&nA zRwMni12AHEw36)C4Tr-pt6s82EJa^8N#bjy??F*rg4fS@?6^MbiY3;7x=gd~G|Hi& zwmG+pAn!aV>>nNfP7-Zn8BLbJm&7}&ZX+$|z5*5{{F}BRSxN=JKZTa#{ut$v0Z0Fs za@UjXo#3!wACv+p9k*^9^n+(0(YKIUFo`@ib@bjz?Mh8*+V$`c%`Q>mrc5bs4aEf4 zh0qtL1qNE|xQ9JrM}qE>X>Y@dQ?%` zBx(*|1FMzVY&~|dE^}gHJ37O9bjnk$d8vKipgcf+As(kt2cbxAR3^4d0?`}}hYO*O z{+L&>G>AYaauAxE8=#F&u#1YGv%`d*v+EyDcU2TnqvRE33l1r}p#Vmcl%n>NrYOqV z2Car_^^NsZ&K=a~bj%SZlfxzHAxX$>=Q|Zi;E0oyfhgGgqe1Sd5-E$8KV9=`!3jWZCb2crb;rvQ##iw}xm7Da za!H${ls5Ihwxkh^D)M<4Yy3bp<-0a+&KfV@CVd9X6Q?v)$R3*rfT@jsedSEhoV(vqv?R1E8oWV;_{l_+_6= zLjV^-bZU$D_ocfSpRxDGk*J>n4G6s-e>D8JK6-gA>aM^Hv8@)txvKMi7Pi#DS5Y?r zK0%+L;QJdrIPXS2 ztjWAxkSwt2xG$L)Zb7F??cjs!KCTF+D{mZ5e0^8bdu_NLgFHTnO*wx!_8#}NO^mu{FaYeCXGjnUgt_+B-Ru!2_Ue-0UPg2Y)K3phLmR<4 zqUCWYX!KDU!jYF6c?k;;vF@Qh^q(PWwp1ez#I+0>d7V(u_h|L+kX+MN1f5WqMLn!L z!c(pozt7tRQi&duH8n=t-|d)c^;%K~6Kpyz(o53IQ_J+aCapAif$Ek#i0F9U>i+94 zFb=OH5(fk-o`L(o|DyQ(hlozl*2cu#)Y(D*zgNMi1Z!DTex#w#)x(8A-T=S+eByJW z%-k&|XhdZOWjJ&(FTrZNWRm^pHEot_MRQ_?>tKQ&MB~g(&D_e>-)u|`Ot(4j=UT6? zQ&YMi2UnCKlBpwltP!}8a2NJ`LlfL=k8SQf69U)~=G;bq9<2GU&Q#cHwL|o4?ah1` z;fG)%t0wMC;DR?^!jCoKib_iiIjsxCSxRUgJDCE%0P;4JZhJCy)vR1%zRl>K?V6#) z2lDi*W3q9rA zo;yvMujs+)a&00~W<-MNj=dJ@4%tccwT<@+c$#CPR%#aE#Dra+-5eSDl^E>is2v^~ z8lgRwkpeU$|1LW4yFwA{PQ^A{5JY!N5PCZ=hog~|FyPPK0-i;fCl4a%1 z?&@&E-)b4cK)wjXGq|?Kqv0s7y~xqvSj-NpOImt{Riam*Z!wz-coZIMuQU>M%6ben z>P@#o^W;fizVd#?`eeEPs#Gz^ySqJn+~`Pq%-Ee6*X+E>!PJGU#rs6qu0z5{+?`-N zxf1#+JNk7e6AoJTdQwxs&GMTq?Djch_8^xL^A;9XggtGL>!@0|BRuIdE&j$tzvt7I zr@I@0<0io%lpF697s1|qNS|BsA>!>-9DVlgGgw2;;k;=7)3+&t!);W3ulPgR>#JiV zUerO;WxuJqr$ghj-veVGfKF?O7si#mzX@GVt+F&atsB@NmBoV4dK|!owGP005$7LN7AqCG(S+={YA- zn#I{UoP_$~Epc=j78{(!2NLN)3qSm-1&{F&1z4Dz&7Mj_+SdlR^Q5{J=r822d4A@?Rj~xATaWewHUOus{*C|KoH`G zHB8SUT06GpSt)}cFJ18!$Kp@r+V3tE_L^^J%9$&fcyd_AHB)WBghwqBEWW!oh@StV zDrC?ttu4#?Aun!PhC4_KF1s2#kvIh~zds!y9#PIrnk9BWkJpq}{Hlqi+xPOR&A1oP zB0~1tV$Zt1pQuHpJw1TAOS=3$Jl&n{n!a+&SgYVe%igUtvE>eHqKY0`e5lwAf}2x( zP>9Wz+9uirp7<7kK0m2&Y*mzArUx%$CkV661=AIAS=V=|xY{;$B7cS5q0)=oq0uXU z_roo90&gHSfM6@6kmB_FJZ)3y_tt0}7#PA&pWo@_qzdIMRa-;U*Dy>Oo#S_n61Fn! z%mrH%tRmvQvg%UqN_2(C#LSxgQ>m}FKLGG=uqJQuSkk=S@c~QLi4N+>lr}QcOuP&% zQCP^cRk&rk-@lpa0^Lcvdu`F*qE)-0$TnxJlwZf|dP~s8cjhL%>^+L~{umxl5Xr6@ z^7zVKiN1Xg;-h+kr4Yt2BzjZs-Mo54`pDbLc}fWq{34=6>U9@sBP~iWZE`+FhtU|x zTV}ajn*Hc}Y?3agQ+bV@oIRm=qAu%|zE;hBw7kCcDx{pm!_qCxfPX3sh5^B$k_2d` z6#rAeUZC;e-LuMZ-f?gHeZogOa*mE>ffs+waQ+fQl4YKoAyZii_!O0;h55EMzD{;) z8lSJvv((#UqgJ?SCQFqJ-UU?2(0V{;7zT3TW`u6GH6h4m3}SuAAj_K(raGBu>|S&Q zZGL?r9@caTbmRm7p=&Tv?Y1)60*9At38w)$(1c?4cpFY2RLyw9c<{OwQE{b@WI}FQ zTT<2HOF4222d%k70yL~x_d#6SNz`*%@4++8gYQ8?yq0T@w~bF@aOHL2)T4xj`AVps9k z?m;<2ClJh$B6~fOYTWIV*T9y1BpB1*C?dgE{%lVtIjw>4MK{wP6OKTb znbPWrkZjYCbr`GGa%Xo0h;iFPNJBI3fK5`wtJV?wq_G<_PZ<`eiKtvN$IKfyju*^t zXc}HNg>^PPZ16m6bfTpmaW5=qoSsj>3)HS}teRa~qj+Y}mGRE?cH!qMDBJ8 zJB!&-=MG8Tb;V4cZjI_#{>ca0VhG_P=j0kcXVX5)^Sdpk+LKNv#yhpwC$k@v^Am&! z_cz2^4Cc{_BC!K#zN!KEkPzviUFPJ^N_L-kHG6}(X#$>Q=9?!{$A(=B3)P?PkxG9gs#l! zo6TOHo$F|IvjTC3MW%XrDoc7;m-6wb9mL(^2(>PQXY53hE?%4FW$rTHtN`!VgH72U zRY)#?Y*pMA<)x3B-&fgWQ(TQ6S6nUeSY{9)XOo_k=j$<*mA=f+ghSALYwBw~!Egn!jtjubOh?6Cb-Zi3IYn*fYl()^3u zRiX0I{5QaNPJ9w{yh4(o#$geO7b5lSh<5ZaRg9_=aFdZjxjXv(_SCv^v-{ZKQFtAA}kw=GPC7l81GY zeP@0Da{aR#{6`lbI0ON0y#K=t|L*}MG_HSl$e{U;v=BSs{SU3(e*qa(l%rD;(zM^3 zrRgN3M#Sf(Cr9>v{FtB`8JBK?_zO+~{H_0$lLA!l{YOs9KQd4Zt<3*Ns7dVbT{1Ut z?N9{XkN(96?r(4BH~3qeiJ_CAt+h1}O_4IUF$S(5EyTyo=`{^16P z=VhDY!NxkDukQz>T`0*H=(D3G7Np*2P`s(6M*(*ZJa;?@JYj&_z`d5bap=KK37p3I zr5#`%aC)7fUo#;*X5k7g&gQjxlC9CF{0dz*m2&+mf$Sc1LnyXn9lpZ!!Bl!@hnsE5px};b-b-`qne0Kh;hziNC zXV|zH%+PE!2@-IrIq!HM2+ld;VyNUZiDc@Tjt|-1&kq}>muY;TA3#Oy zWdYGP3NOZWSWtx6?S6ES@>)_Yz%%nLG3P>Z7`SrhkZ?shTfrHkYI;2zAn8h65wV3r z^{4izW-c9!MTge3eN=~r5aTnz6*6l#sD68kJ7Nv2wMbL~Ojj0H;M`mAvk*`Q!`KI? z7nCYBqbu$@MSNd+O&_oWdX()8Eh|Z&v&dJPg*o-sOBb2hriny)< zd(o&&kZM^NDtV=hufp8L zCkKu7)k`+czHaAU567$?GPRGdkb4$37zlIuS&<&1pgArURzoWCbyTEl9OiXZBn4p<$48-Gekh7>e)v*?{9xBt z=|Rx!@Y3N@ffW5*5!bio$jhJ7&{!B&SkAaN`w+&3x|D^o@s{ZAuqNss8K;211tUWIi1B!%-ViYX+Ys6w)Q z^o1{V=hK#+tt&aC(g+^bt-J9zNRdv>ZYm9KV^L0y-yoY7QVZJ_ivBS02I|mGD2;9c zR%+KD&jdXjPiUv#t1VmFOM&=OUE2`SNm4jm&a<;ZH`cYqBZoAglCyixC?+I+}*ScG#;?SEAFob{v0ZKw{`zw*tX}<2k zoH(fNh!>b5w8SWSV}rQ*E24cO=_eQHWy8J!5;Y>Bh|p;|nWH|nK9+ol$k`A*u*Y^Uz^%|h4Owu}Cb$zhIxlVJ8XJ0xtrErT zcK;34CB;ohd|^NfmVIF=XlmB5raI}nXjFz;ObQ4Mpl_`$dUe7sj!P3_WIC~I`_Xy@ z>P5*QE{RSPpuV=3z4p3}dh>Dp0=We@fdaF{sJ|+_E*#jyaTrj-6Y!GfD@#y@DUa;& zu4Iqw5(5AamgF!2SI&WT$rvChhIB$RFFF|W6A>(L9XT{0%DM{L`knIQPC$4F`8FWb zGlem_>>JK-Fib;g*xd<-9^&_ue95grYH>5OvTiM;#uT^LVmNXM-n8chJBD2KeDV7t zbnv3CaiyN>w(HfGv86K5MEM{?f#BTR7**smpNZ}ftm+gafRSt=6fN$(&?#6m3hF!>e$X)hFyCF++Qvx(<~q3esTI zH#8Sv!WIl2<&~=B)#sz1x2=+KTHj=0v&}iAi8eD=M->H|a@Qm|CSSzH#eVIR3_Tvu zG8S**NFbz%*X?DbDuP(oNv2;Lo@#_y4k$W+r^#TtJ8NyL&&Rk;@Q}~24`BB)bgwcp z=a^r(K_NEukZ*|*7c2JKrm&h&NP)9<($f)eTN}3|Rt`$5uB0|!$Xr4Vn#i;muSljn zxG?zbRD(M6+8MzGhbOn%C`M#OcRK!&ZHihwl{F+OAnR>cyg~No44>vliu$8^T!>>*vYQJCJg=EF^lJ*3M^=nGCw`Yg@hCmP(Gq^=eCEE1!t-2>%Al{w@*c% zUK{maww*>K$tu;~I@ERb9*uU@LsIJ|&@qcb!&b zsWIvDo4#9Qbvc#IS%sV1_4>^`newSxEcE08c9?rHY2%TRJfK2}-I=Fq-C)jc`gzV( zCn?^noD(9pAf2MP$>ur0;da`>Hr>o>N@8M;X@&mkf;%2A*2CmQBXirsJLY zlX21ma}mKH_LgYUM-->;tt;6F?E5=fUWDwQhp*drQ%hH0<5t2m)rFP%=6aPIC0j$R znGI0hcV~}vk?^&G`v~YCKc7#DrdMM3TcPBmxx#XUC_JVEt@k=%3-+7<3*fTcQ>f~?TdLjv96nb66xj=wVQfpuCD(?kzs~dUV<}P+Fpd)BOTO^<*E#H zeE80(b~h<*Qgez(iFFOkl!G!6#9NZAnsxghe$L=Twi^(Q&48 zD0ohTj)kGLD){xu%pm|}f#ZaFPYpHtg!HB30>F1c=cP)RqzK2co`01O5qwAP zUJm0jS0#mci>|Nu4#MF@u-%-4t>oUTnn_#3K09Hrwnw13HO@9L;wFJ*Z@=gCgpA@p zMswqk;)PTXWuMC-^MQxyNu8_G-i3W9!MLd2>;cM+;Hf&w| zLv{p*hArp9+h2wsMqT5WVqkkc0>1uokMox{AgAvDG^YJebD-czexMB!lJKWllLoBI zetW2;;FKI1xNtA(ZWys!_un~+834+6y|uV&Lo%dKwhcoDzRADYM*peh{o`-tHvwWIBIXW`PKwS3|M>CW37Z2dr!uJWNFS5UwY4;I zNIy1^sr+@8Fob%DHRNa&G{lm?KWU7sV2x9(Ft5?QKsLXi!v6@n&Iyaz5&U*|hCz+d z9vu60IG<v6+^ZmBs_aN!}p|{f(ikVl&LcB+UY;PPz* zj84Tm>g5~-X=GF_4JrVmtEtm=3mMEL1#z+pc~t^Iify^ft~cE=R0TymXu*iQL+XLX zdSK$~5pglr3f@Lrcp`>==b5Z6r7c=p=@A5nXNacsPfr(5m;~ks@*Wu7A z%WyY$Pt*RAKHz_7cghHuQqdU>hq$vD?plol_1EU(Fkgyo&Q2&2e?FT3;H%!|bhU~D z>VX4-6}JLQz8g3%Bq}n^NhfJur~v5H0dbB^$~+7lY{f3ES}E?|JnoLsAG%l^%eu_PM zEl0W(sbMRB3rFeYG&tR~(i2J0)RjngE`N_Jvxx!UAA1mc7J>9)`c=`}4bVbm8&{A` z3sMPU-!r-8de=P(C@7-{GgB<5I%)x{WfzJwEvG#hn3ict8@mexdoTz*(XX!C&~}L* z^%3eYQ8{Smsmq(GIM4d5ilDUk{t@2@*-aevxhy7yk(wH?8yFz%gOAXRbCYzm)=AsM z?~+vo2;{-jkA%Pqwq&co;|m{=y}y2lN$QPK>G_+jP`&?U&Ubq~T`BzAj1TlC`%8+$ zzdwNf<3suPnbh&`AI7RAYuQ<#!sD|A=ky2?hca{uHsB|0VqShI1G3lG5g}9~WSvy4 zX3p~Us^f5AfXlBZ0hA;mR6aj~Q8yb^QDaS*LFQwg!!<|W!%WX9Yu}HThc7>oC9##H zEW`}UQ%JQ38UdsxEUBrA@=6R-v1P6IoIw8$8fw6F{OSC7`cOr*u?p_0*Jvj|S)1cd z-9T);F8F-Y_*+h-Yt9cQQq{E|y^b@r&6=Cd9j0EZL}Pj*RdyxgJentY49AyC@PM<< zl&*aq_ubX%*pqUkQ^Zsi@DqhIeR&Ad)slJ2g zmeo&+(g!tg$z1ao1a#Qq1J022mH4}y?AvWboI4H028;trScqDQrB36t!gs|uZS9}KG0}DD$ zf2xF}M*@VJSzEJ5>ucf+L_AtN-Ht=34g&C?oPP>W^bwoigIncKUyf61!ce!2zpcNT zj&;rPGI~q2!Sy>Q7_lRX*DoIs-1Cei=Cd=+Xv4=%bn#Yqo@C=V`|QwlF0Y- zONtrwpHQ##4}VCL-1ol(e<~KU9-ja^kryz!g!})y-2S5z2^gE$Isj8l{%tF=Rzy`r z^RcP7vu`jHgHLKUE957n3j+BeE(bf;f)Zw($XaU6rZ26Upl#Yv28=8Y`hew{MbH>* z-sGI6dnb5D&dUCUBS`NLAIBP!Vi!2+~=AU+)^X^IpOEAn#+ab=`7c z%7B|mZ>wU+L;^&abXKan&N)O;=XI#dTV|9OMYxYqLbtT#GY8PP$45Rm2~of+J>>HIKIVn(uQf-rp09_MwOVIp@6!8bKV(C#(KxcW z;Pesq(wSafCc>iJNV8sg&`!g&G55<06{_1pIoL`2<7hPvAzR1+>H6Rx0Ra%4j7H-<-fnivydlm{TBr06;J-Bq8GdE^Amo)ptV>kS!Kyp*`wUx=K@{3cGZnz53`+C zLco1jxLkLNgbEdU)pRKB#Pq(#(Jt>)Yh8M?j^w&RPUueC)X(6`@@2R~PV@G(8xPwO z^B8^+`qZnQr$8AJ7<06J**+T8xIs)XCV6E_3W+al18!ycMqCfV>=rW0KBRjC* zuJkvrv;t&xBpl?OB3+Li(vQsS(-TPZ)Pw2>s8(3eF3=n*i0uqv@RM^T#Ql7(Em{(~%f2Fw|Reg@eSCey~P zBQlW)_DioA*yxxDcER@_=C1MC{UswPMLr5BQ~T6AcRyt0W44ffJG#T~Fk}wU^aYoF zYTayu-s?)<`2H(w+1(6X&I4?m3&8sok^jpXBB<|ZENso#?v@R1^DdVvKoD?}3%@{}}_E7;wt9USgrfR3(wabPRhJ{#1es81yP!o4)n~CGsh2_Yj2F^z|t zk((i&%nDLA%4KFdG96pQR26W>R2^?C1X4+a*hIzL$L=n4M7r$NOTQEo+k|2~SUI{XL{ynLSCPe%gWMMPFLO{&VN2pom zBUCQ(30qj=YtD_6H0-ZrJ46~YY*A;?tmaGvHvS^H&FXUG4)%-a1K~ly6LYaIn+4lG zt=wuGLw!%h=Pyz?TP=?6O-K-sT4W%_|Nl~;k~YA^_`gqfe{Xw=PWn#9f1mNz)sFuL zJbrevo(DPgpirvGMb6ByuEPd=Rgn}fYXqeUKyM+!n(cKeo|IY%p!#va6`D8?A*{u3 zEeWw0*oylJ1X!L#OCKktX2|>-z3#>`9xr~azOH+2dXHRwdfnpri9|xmK^Q~AuY!Fg z`9Xx?hxkJge~)NVkPQ(VaW(Ce2pXEtgY*cL8i4E)mM(iz_vdm|f@%cSb*Lw{WbShh41VGuplex9E^VvW}irx|;_{VK=N_WF39^ zH4<*peWzgc)0UQi4fBk2{FEzldDh5+KlRd!$_*@eYRMMRb1gU~9lSO_>Vh-~q|NTD zL}X*~hgMj$*Gp5AEs~>Bbjjq7G>}>ki1VxA>@kIhLe+(EQS0mjNEP&eXs5)I;7m1a zmK0Ly*!d~Dk4uxRIO%iZ!1-ztZxOG#W!Q_$M7_DKND0OwI+uC;PQCbQ#k#Y=^zQve zTZVepdX>5{JSJb;DX3%3g42Wz2D@%rhIhLBaFmx#ZV8mhya}jo1u{t^tzoiQy=jJp zjY2b7D2f$ZzJx)8fknqdD6fd5-iF8e(V}(@xe)N=fvS%{X$BRvW!N3TS8jn=P%;5j zShSbzsLs3uqycFi3=iSvqH~}bQn1WQGOL4?trj(kl?+q2R23I42!ipQ&`I*&?G#i9 zWvNh8xoGKDt>%@i0+}j?Ykw&_2C4!aYEW0^7)h2Hi7$;qgF3;Go?bs=v)kHmvd|`R z%(n94LdfxxZ)zh$ET8dH1F&J#O5&IcPH3=8o;%>OIT6w$P1Yz4S!}kJHNhMQ1(prc zM-jSA-7Iq=PiqxKSWb+YbLB-)lSkD6=!`4VL~`ExISOh2ud=TI&SKfR4J08Bad&rj zcXxMpcNgOB?w$~L7l^wPcXxw$0=$oV?)`I44)}b#ChS`_lBQhvb6ks?HDr3tFgkg&td19?b8=!sETXtp=&+3T$cCwZe z0nAET-7561gsbBws$TVjP7QxY(NuBYXVn9~9%vyN-B#&tJhWgtL1B<%BTS*-2$xB` zO)cMDHoWsm%JACZF--Pa7oP;f!n%p`*trlpvZ!HKoB={l+-(8O;;eYv2A=ra z3U7rSMCkP_6wAy`l|Se(&5|AefXvV1E#XA(LT!% zjj4|~xlZ-kPLNeQLFyXb%$K}YEfCBvHA-Znw#dZSI6V%3YD{Wj2@utT5Hieyofp6Qi+lz!u)htnI1GWzvQsA)baEuw9|+&(E@p8M+#&fsX@Kf`_YQ>VM+40YLv`3-(!Z7HKYg@+l00WGr779i-%t`kid%e zDtbh8UfBVT3|=8FrNian@aR3*DTUy&u&05x%(Lm3yNoBZXMHWS7OjdqHp>cD>g!wK z#~R{1`%v$IP;rBoP0B0P><;dxN9Xr+fp*s_EK3{EZ94{AV0#Mtv?;$1YaAdEiq5)g zYME;XN9cZs$;*2p63Q9^x&>PaA1p^5m7|W?hrXp2^m;B@xg0bD?J;wIbm6O~Nq^^K z2AYQs@7k)L#tgUkTOUHsh&*6b*EjYmwngU}qesKYPWxU-z_D> zDWr|K)XLf_3#k_9Rd;(@=P^S^?Wqlwert#9(A$*Y$s-Hy)BA0U0+Y58zs~h=YtDKxY0~BO^0&9{?6Nny;3=l59(6ec9j(79M?P1cE zex!T%$Ta-KhjFZLHjmPl_D=NhJULC}i$}9Qt?nm6K6-i8&X_P+i(c*LI3mtl3 z*B+F+7pnAZ5}UU_eImDj(et;Khf-z^4uHwrA7dwAm-e4 zwP1$Ov3NP5ts+e(SvM)u!3aZMuFQq@KE-W;K6 zag=H~vzsua&4Sb$4ja>&cSJ)jjVebuj+?ivYqrwp3!5>ul`B*4hJGrF;!`FaE+wKo z#};5)euvxC1zX0-G;AV@R(ZMl=q_~u8mQ5OYl;@BAkt)~#PynFX#c1K zUQ1^_N8g+IZwUl*n0Bb-vvliVtM=zuMGU-4a8|_8f|2GEd(2zSV?aSHUN9X^GDA8M zgTZW06m*iAy@7l>F3!7+_Y3mj^vjBsAux3$%U#d$BT^fTf-7{Y z_W0l=7$ro5IDt7jp;^cWh^Zl3Ga1qFNrprdu#g=n9=KH!CjLF#ucU5gy6*uASO~|b z7gcqm90K@rqe({P>;ww_q%4}@bq`ST8!0{V08YXY)5&V!>Td)?j7#K}HVaN4FU4DZ z%|7OppQq-h`HJ;rw-BAfH* z1H$ufM~W{%+b@9NK?RAp-$(P0N=b<(;wFbBN0{u5vc+>aoZ|3&^a866X@el7E8!E7 z=9V(Ma**m_{DKZit2k;ZOINI~E$|wO99by=HO{GNc1t?nl8soP@gxk8)WfxhIoxTP zoO`RA0VCaq)&iRDN9yh_@|zqF+f07Esbhe!e-j$^PS57%mq2p=+C%0KiwV#t^%_hH zoO?{^_yk5x~S)haR6akK6d|#2TN& zfWcN zc7QAWl)E9`!KlY>7^DNw$=yYmmRto>w0L(~fe?|n6k2TBsyG@sI)goigj=mn)E)I* z4_AGyEL7?(_+2z=1N@D}9$7FYdTu;%MFGP_mEJXc2OuXEcY1-$fpt8m_r2B|<~Xfs zX@3RQi`E-1}^9N{$(|YS@#{ZWuCxo)91{k>ESD54g_LYhm~vlOK_CAJHeYFfuIVB^%cqCfvpy#sU8Do8u}# z>>%PLKOZ^+$H54o@brtL-hHorSKcsjk_ZibBKBgyHt~L z=T6?e0oLX|h!Z3lbkPMO27MM?xn|uZAJwvmX?Yvp#lE3sQFY)xqet>`S2Y@1t)Z*& z;*I3;Ha8DFhk=YBt~{zp=%%*fEC}_8?9=(-k7HfFeN^GrhNw4e?vx*#oMztnO*&zY zmRT9dGI@O)t^=Wj&Og1R3b%(m*kb&yc;i`^-tqY9(0t!eyOkH<$@~1lXmm!SJllE_ zr~{a&w|8*LI>Z^h!m%YLgKv06Js7j7RaoX}ZJGYirR<#4Mghd{#;38j3|V+&=ZUq#1$ zgZb-7kV)WJUko?{R`hpSrC;w2{qa`(Z4gM5*ZL`|#8szO=PV^vpSI-^K_*OQji^J2 zZ_1142N}zG$1E0fI%uqHOhV+7%Tp{9$bAR=kRRs4{0a`r%o%$;vu!_Xgv;go)3!B#;hC5qD-bcUrKR&Sc%Zb1Y($r78T z=eG`X#IpBzmXm(o6NVmZdCQf6wzqawqI63v@e%3TKuF!cQ#NQbZ^?6K-3`_b=?ztW zA>^?F#dvVH=H-r3;;5%6hTN_KVZ=ps4^YtRk>P1i>uLZ)Ii2G7V5vy;OJ0}0!g>j^ z&TY&E2!|BDIf1}U(+4G5L~X6sQ_e7In0qJmWYpn!5j|2V{1zhjZt9cdKm!we6|Pp$ z07E+C8=tOwF<<}11VgVMzV8tCg+cD_z?u+$sBjwPXl^(Ge7y8-=c=fgNg@FxI1i5Y-HYQMEH z_($je;nw`Otdhd1G{Vn*w*u@j8&T=xnL;X?H6;{=WaFY+NJfB2(xN`G)LW?4u39;x z6?eSh3Wc@LR&yA2tJj;0{+h6rxF zKyHo}N}@004HA(adG~0solJ(7>?LoXKoH0~bm+xItnZ;3)VJt!?ue|~2C=ylHbPP7 zv2{DH()FXXS_ho-sbto)gk|2V#;BThoE}b1EkNYGT8U#0ItdHG>vOZx8JYN*5jUh5Fdr9#12^ zsEyffqFEQD(u&76zA^9Jklbiz#S|o1EET$ujLJAVDYF znX&4%;vPm-rT<8fDutDIPC@L=zskw49`G%}q#l$1G3atT(w70lgCyfYkg7-=+r7$%E`G?1NjiH)MvnKMWo-ivPSQHbk&_l5tedNp|3NbU^wk0SSXF9ohtM zUqXiOg*8ERKx{wO%BimK)=g^?w=pxB1Vu_x<9jKOcU7N;(!o3~UxyO+*ZCw|jy2}V*Z22~KhmvxoTszc+#EMWXTM6QF*ks% zW47#2B~?wS)6>_ciKe1Fu!@Tc6oN7e+6nriSU;qT7}f@DJiDF@P2jXUv|o|Wh1QPf zLG31d>@CpThA+Ex#y)ny8wkC4x-ELYCXGm1rFI=1C4`I5qboYgDf322B_Nk@#eMZ% znluCKW2GZ{r9HR@VY`>sNgy~s+D_GkqFyz6jgXKD)U|*eKBkJRRIz{gm3tUd*yXmR z(O4&#ZA*us6!^O*TzpKAZ#}B5@}?f=vdnqnRmG}xyt=)2o%<9jj>-4wLP1X-bI{(n zD9#|rN#J;G%LJ&$+Gl2eTRPx6BQC6Uc~YK?nMmktvy^E8#Y*6ZJVZ>Y(cgsVnd!tV z!%twMNznd)?}YCWyy1-#P|2Fu%~}hcTGoy>_uawRTVl=(xo5!%F#A38L109wyh@wm zdy+S8E_&$Gjm=7va-b7@Hv=*sNo0{i8B7=n4ex-mfg`$!n#)v@xxyQCr3m&O1Jxg! z+FXX^jtlw=utuQ+>Yj$`9!E<5-c!|FX(~q`mvt6i*K!L(MHaqZBTtuSA9V~V9Q$G? zC8wAV|#XY=;TQD#H;;dcHVb9I7Vu2nI0hHo)!_{qIa@|2}9d ztpC*Q{4Py~2;~6URN^4FBCBip`QDf|O_Y%iZyA0R`^MQf$ce0JuaV(_=YA`knEMXw zP6TbjYSGXi#B4eX=QiWqb3bEw-N*a;Yg?dsVPpeYFS*&AsqtW1j2D$h$*ZOdEb$8n0 zGET4Igs^cMTXWG{2#A7w_usx=KMmNfi4oAk8!MA8Y=Rh9^*r>jEV(-{I0=rc);`Y) zm+6KHz-;MIy|@2todN&F+Yv1e&b&ZvycbTHpDoZ>FIiUn+M-=%A2C(I*^Yx@VKf(Z zxJOny&WoWcyKodkeN^5))aV|-UBFw{?AGo?;NNFFcKzk+6|gYfA#FR=y@?;3IoQ zUMI=7lwo9gV9fRvYi}Nd)&gQw7(K3=a0#p27u6Q)7JlP#A)piUUF8B3Li&38Xk$@| z9OR+tU~qgd3T3322E))eV)hAAHYIj$TmhH#R+C-&E-}5Qd{3B}gD{MXnsrS;{Erv1 z6IyQ=S2qD>Weqqj#Pd65rDSdK54%boN+a?=CkR|agnIP6;INm0A*4gF;G4PlA^3%b zN{H%#wYu|!3fl*UL1~f+Iu|;cqDax?DBkZWSUQodSDL4Es@u6zA>sIm>^Aq-&X#X8 zI=#-ucD|iAodfOIY4AaBL$cFO@s(xJ#&_@ZbtU+jjSAW^g;_w`FK%aH_hAY=!MTjI zwh_OEJ_25zTQv$#9&u0A11x_cGd92E74AbOrD`~f6Ir9ENNQAV2_J2Ig~mHWhaO5a zc>fYG$zke^S+fBupw+klDkiljJAha z6DnTemhkf>hv`8J*W_#wBj-2w(cVtXbkWWtE(3j@!A-IfF?`r$MhVknTs3D1N`rYN zKth9jZtX#>v#%U@^DVN!;ni#n1)U&H_uB{6pcq7$TqXJX!Q0P7U*JUZyclb~)l*DS zOLpoQfW_3;a0S$#V0SOwVeeqE$Hd^L`$;l_~2giLYd?7!gUYIpOs!jqSL~pI)4`YuB_692~A z^T#YYQ_W3Rakk}$SL&{`H8mc{>j+3eKprw6BK`$vSSIn;s31M~YlJLApJ)+Gi1{^- zw96WnT9M0Vr_D=e=a}${raR{(35Q!g+8`}vOFj1e&Or(_wp2U2aVQP0_jP57 z2(R4E(E$n!xl<}Zx38wO;27wuQ`P#_j!}L2 z2qr;As4D4n2X$-Jd_-!fsbu_D(64i;c4cJnP576x_>Q4WNushFwkBV!kVd(AYFXe{ zaqO5`Qfr!#ETmE(B;u_&FITotv~W}QYFCI!&ENKIb1p4fg*Yv1)EDMb==EjHHWM#{ zGMpqb2-LXdHB@D~pE3|+B392Gh4q)y9jBd$a^&cJM60VEUnLtHQD5i-X6PVF>9m_k zDvG3P(?CzdaIrC8s4cu~N9MEb!Tt(g*GK~gIp1Gyeaw3b7#YPx_1T6i zRi#pAMr~PJKe9P~I+ARa$a!K~)t(4LaVbjva1yd;b1Yz2$7MMc`aLmMl(a^DgN(u? zq2o9&Gif@Tq~Yq+qDfx^F*nCnpuPv%hRFc$I!p74*quLt^M}D_rwl10uMTr!)(*=7 zSC5ea@#;l(h87k4T4x)(o^#l76P-GYJA(pOa&F9YT=fS<*O{4agzba^dIrh0hjls<~APlIz9{ zgRY{OMv2s|`;VCoYVj?InYoq^QWuA&*VDyOn@pPvK8l~g#1~~MGVVvtLDt}>id_Z` zn(ihfL?Y}Y4YX335m*Xx(y+bbukchHrM zycIGp#1*K3$!(tgTsMD2VyUSg^yvCwB8*V~sACE(yq2!MS6f+gsxv^GR|Q7R_euYx z&X+@@H?_oQddGxJYS&ZG-9O(X+l{wcw;W7srpYjZZvanY(>Q1utSiyuuonkjh5J0q zGz6`&meSuxixIPt{UoHVupUbFKIA+3V5(?ijn}(C(v>=v?L*lJF8|yRjl-m#^|krg zLVbFV6+VkoEGNz6he;EkP!Z6|a@n8?yCzX9>FEzLnp21JpU0x!Qee}lwVKA})LZJq zlI|C??|;gZ8#fC3`gzDU%7R87KZyd)H__0c^T^$zo@TBKTP*i{)Gp3E0TZ}s3mKSY zix@atp^j#QnSc5K&LsU38#{lUdwj%xF zcx&l^?95uq9on1m*0gp$ruu||5MQo)XaN>|ngV5Jb#^wWH^5AdYcn_1>H~XtNwJd3 zd9&?orMSSuj=lhO?6)Ay7;gdU#E}pTBa5wFu`nejq##Xd71BHzH2XqLA5 zeLEo;9$}~u0pEu@(?hXB_l;{jQ=7m?~mwj-ME~Tw-OHPrR7K2Xq9eCNwQO$hR z3_A?=`FJctNXA#yQEorVoh{RWxJbdQga zU%K##XEPgy?E|K(=o#IPgnbk7E&5%J=VHube|2%!Qp}@LznjE%VQhJ?L(XJOmFVY~ zo-az+^5!Ck7Lo<7b~XC6JFk>17*_dY;=z!<0eSdFD2L?CSp_XB+?;N+(5;@=_Ss3& zXse>@sA7hpq;IAeIp3hTe9^$DVYf&?)={zc9*hZAV)|UgKoD!1w{UVo8D)Htwi8*P z%#NAn+8sd@b{h=O)dy9EGKbpyDtl@NBZw0}+Wd=@65JyQ2QgU}q2ii;ot1OsAj zUI&+Pz+NvuRv#8ugesT<<@l4L$zso0AQMh{we$tkeG*mpLmOTiy8|dNYhsqhp+q*yfZA`Z)UC*(oxTNPfOFk3RXkbzAEPofVUy zZ3A%mO?WyTRh@WdXz+zD!ogo}gbUMV!YtTNhr zrt@3PcP%5F;_SQ>Ui`Gq-lUe&taU4*h2)6RDh@8G1$o!){k~3)DT87%tQeHYdO?B` zAmoJvG6wWS?=0(Cj?Aqj59`p(SIEvYyPGJ^reI z`Hr?3#U2zI7k0=UmqMD35l`>3xMcWlDv$oo6;b`dZq3d!~)W z=4Qk)lE8&>#HV>?kRLOHZYz83{u7?^KoXmM^pazj8`7OwQ=5I!==; zA!uN`Q#n=Drmzg}@^nG!mJp9ml3ukWk96^6*us*;&>s+7hWfLXtl?a}(|-#=P12>A zon1}yqh^?9!;on?tRd6Fk0knQSLl4vBGb87A_kJNDGyrnpmn48lz_%P{* z_G*3D#IR<2SS54L5^h*%=)4D9NPpji7DZ5&lHD|99W86QN_(|aJ<5C~PX%YB`Qt_W z>jF_Os@kI6R!ub4n-!orS(G6~mKL7()1g=Lf~{D!LR7#wRHfLxTjYr{*c{neyhz#U zbm@WBKozE+kTd+h-mgF+ELWqTKin57P;0b){ zii5=(B%S(N!Z=rAFGnM6iePtvpxB_Q9-oq_xH!URn2_d-H~i;lro8r{-g!k-Ydb6_w5K@FOV?zPF_hi z%rlxBv$lQi%bjsu^7KT~@u#*c$2-;AkuP)hVEN?W5MO8C9snj*EC&|M!aK6o12q3+ z8e?+dH17E!A$tRlbJW~GtMDkMPT=m1g-v67q{sznnWOI$`g(8E!Pf!#KpO?FETxLK z2b^8^@mE#AR1z(DT~R3!nnvq}LG2zDGoE1URR=A2SA z%lN$#V@#E&ip_KZL}Q6mvm(dsS?oHoRf8TWL~1)4^5<3JvvVbEsQqSa3(lF*_mA$g zv`LWarC79G)zR0J+#=6kB`SgjQZ2460W zN%lZt%M@=EN>Wz4I;eH>C0VnDyFe)DBS_2{h6=0ZJ*w%s)QFxLq+%L%e~UQ0mM9ud zm&|r){_<*Om%vlT(K9>dE(3AHjSYro5Y1I?ZjMqWyHzuCE0nyCn`6eq%MEt(aY=M2rIzHeMds)4^Aub^iTIT|%*izG4YH;sT`D9MR(eND-SB+e66LZT z2VX)RJsn${O{D48aUBl|(>ocol$1@glsxisc#GE*=DXHXA?|hJT#{;X{i$XibrA}X zFHJa+ssa2$F_UC(o2k2Z0vwx%Wb(<6_bdDO#=a$0gK2NoscCr;vyx?#cF)JjM%;a| z$^GIlIzvz%Hx3WVU481}_e4~aWcyC|j&BZ@uWW1`bH1y9EWXOxd~f-VE5DpueNofN zv7vZeV<*!A^|36hUE;`#x%MHhL(~?eZ5fhA9Ql3KHTWoAeO-^7&|2)$IcD1r5X#-u zN~N0$6pHPhop@t1_d`dO3#TC0>y5jm>8;$F5_A2& zt#=^IDfYv?JjPPTPNx2TL-Lrl82VClQSLWW_$3=XPbH}xM34)cyW5@lnxy=&h%eRq zv29&h^fMoxjsDnmua(>~OnX{Cq!7vM0M4Mr@_18|YuSKPBKUTV$s^So zc}JlAW&bVz|JY#Eyup6Ny{|P_s0Pq;5*tinH+>5Xa--{ z2;?2PBs((S4{g=G`S?B3Ien`o#5DmUVwzpGuABthYG~OKIY`2ms;33SN9u^I8i_H5`BQ%yOfW+N3r|ufHS_;U;TWT5z;b14n1gX%Pn`uuO z6#>Vl)L0*8yl|#mICWQUtgzeFp9$puHl~m&O+vj3Ox#SxQUa?fY*uK?A;00RiFg(G zK?g=7b5~U4QIK`C*um%=Sw=OJ1eeaV@WZ%hh-3<=lR#(Xesk%?)l4p(EpTwPvN99V@TT)!A8SeFTV+frN=r|5l?K#odjijx2nFgc3kI zC$hVs1S-!z9>xn9MZcRk0YXdYlf~8*LfH$IHKD59H&gLz%6 z#mAYSRJufbRi~LRadwM*G!O2>&U<^d`@<)otXZJJxT@G}4kTx0zPDVhVXwiU)$}5Y z`0iV`8EEh&GlUk&VY9m0Mqr*U&|^Bc?FB`<%{x-o0ATntwIA%(YDcxWs$C)%a%d_@ z?fx!Co+@3p7ha$|pWYD}p6#(PG%_h8K7sQjT_P~|3ZEH0DRxa3~bP&&lPMj3C~!H2QD zq>(f^RUFSqf6K3BMBFy$jiuoSE+DhEq$xLDb7{57 z0B|1pSjYJ5F@cHG%qDZ{ogL$P!BK&sR%zD`gbK#9gRZX17EtAJxN% zys^gb2=X9=7HP}N(iRqt(tot2yyeE%s;L}AcMh;~-W~s_eAe!gIUYdQz5j~T)0trh z>#1U$uOyyl%!Pi(gD&)uHe9Q^27_kHyFCC}n^-KL(=OxHqUfex1YS__RJh0m-S>eM zqAk`aSev*z1lI&-?CycgDm=bdQCp}RqS0_d-4Mf&>u2KyGFxKe8JM1N{GNWw0n$FL z1UDp(h0(1I2Jh9I`?IS}h4R~n zRwRz>8?$fFMB2{UPe^$Ifl;Oc>}@Q9`|8DCeR{?LUQLPfaMsxs8ps=D_aAXORZH~< zdcIOca-F;+D3~M+)Vi4h)I4O3<)$65yI)goQ_vk#fb;Uim>UI4Dv9#2b1;N_Wg>-F zNwKeMKY+su#~NL0uE%_$mw1%ddX2Qs2P!ncM+>wnz}OCQX1!q~oS?OqYU;&ESAAwP z452QWL0&u^mraF#=j_ZeBWhm&F|d!QjwRl^7=Bl7@(43=BkN=3{BRv#QHIk>Umc_w zvP>q|q{lJ=zs|W9%a@8%W>C@MYN1D5{(=Af31+pR#kB`cd0-YlQQTg}+ zL|_h=F9JQ|Gux5c0ehaffHNYLf8VwF+qnM6IjBEI_eceee;o;FY@#~FFVsZjBSp!j z8V*Bgmn{RK!!zqGc;jy)z@Zjo>5{%m1?K}fLEL$l6Dl4f=ye0wNI#)2L=^K(&18Gb zJoj8@WBB;P^T#V)I0`aDSy?$rJU{+-5472NyFp>;Vw43j@3Z=;D2eSfyw5*0Q+&ML zsV&&*3c3$pa`qcaGbEB0*CA~Wp3%PkF?B87FV&rWNb|@GU$LB;l|;YutU*k za1hjUL_BX%G^s;BuzRi4Hl?eqC2z&ZrKh1tZDwnufG$g$LX(j!h%F5(n8D@in3lnX z(*8+3ZT6TVYRcSpM1eMeCps=Fz8q%gyM&B=a7(Vf`4k3dN$IM+`BO^_7HZq4BR|7w z+5kOJ;9_$X%-~arA@qmXSzD|+NMh--%5-9u6t(M=f%&z$<_V#Y_lzn{E$MZZG)+A> zu2E`_Y(MBJ2l*AqvCUmU;yBT}#oQ{V=((mC-QGJwsCOH*a;{1JRTKv7DBNG+M!XL7(^jbv&Qy-o9HNFrmN)-`D3WFtXs>1vBOJpI(=x; zKhJlFdfMf^G#oU(w1+ucMKYPZaDp>$kt=wiYsBCjUY-uz<4JziB>6fXDSLH*2Y z&Px5y`#3!fF=c4>fCMdg-tX582pemU@ZxyFbznL8-=TTo1Sybg9>7h*J^9^~XxXJO z`k9v~=4amxl<;FCV9h2k%?^-ZUzQy^#{JleyH23o1S{r<+t#z6jKS<9rbAM96^1iY zi6{IjauB)UwBhC-_L(MzGCxhhv`?ryc zja_Uwi7$8l!}*vjJppGyp#Wz=*?;jC*xQ&J894rql5A$2giJRtV&DWQh#(+Vs3-5_ z69_tj(>8%z1VtVp>a74r5}j2rG%&;uaTQ|fr&r%ew-HO}76i8`&ki%#)~}q4Y|d$_ zfNp9uc#$#OEca>>MaY6rF`dB|5#S)bghf>>TmmE&S~IFw;PF0UztO6+R-0!TSC?QP z{b(RA_;q3QAPW^XN?qQqu{h<}Vfiv}Rr!lA$C79^1=U>+ng9Dh>v{`?AOZt>CrQ=o zI}=mSnR))8fJpO->rcX?H);oqSQUZ?sR!fH2SoFdcPm5*2y<_u;4h;BqcF*XbwWSv zcJN%!g|L(22Xp!^1?c;T&qm%rpkP&2EQC3JF+SENm$+@7#e!UKD1uQ{TDw43?!b!3 zUooS_rt=xJfa&h?c^hfV>YwQXre3qosz_^c#)FO~d!<)2o}Oxz5HWtr<)1Yw012v4 zhv0w(RfJspDnA^-6Jmr;GkWt%{mAYOm6yPb&Vl&rv@D^K&;#?=X{kaK5FhScNJ_3> z#5u(Saisq2(~pVlrfG#@kLM#Ot~5rZZc%B&h1=gen?R+#t^1bYKf zVvtefX=D$*)39e^2@!~A_}9c${Gf0?1;dk=!Itp#s%0>Io%k`9(bDeI-udd&E6Zfu zcaiv(h`DM3W3Mfda)fYwhB=8RAPkotVt5-z21Ij~Ot9A^SK-1u*zFVK&mF?q1;|wy zrF+XWs^5Q-%Z6I62gTwrRe#F>riVM#fv_TihxSJ6to1X7NVszgivoTa!fPfBBYj94 zuc2m zL_k-<1FoORng1aL{Zx(P7JmUiH zlmTHdzkn75=mS{V=o$V;gzhEaunoJzJ3uq>0_w~77eID^U*w+v0po_N8=sS-DL~!V z%-~rL<0V7PCEWPCpNgpfsein`Fr)+8=N}mUn2x=K`z%efnhSs#23&N1fjdO`M>s%z zP3(;v93%lLq>ZfqBi#QI-aCXAP8-may8x5s`G)KA;{HSYe2szWINWf^b*fc{jl0KecD zRTle?)%_YzJJcVb>;VJ>P?3Lu2S)vCJZlF>Jxj~~X2U5-NNNy(H?8%XD~yFUxNKs&hwWx^)iF@ zGmEv<|7Q7hGrY_+`iz+d_=^9c(_c}UCzq2#%A0|5WjzCXjZUOxOX zU&-^smw$iwKPe;r`&{rP{L35^&+wk6f2-Sn;D2Ww@sjAJj{Gwbp4H!o{#5_}qALFq z{-q%LGklZvKf%A4D!+t%sRRBDi(>mvuz&V4yu^GdD*KFy?fg%ef5ZU%w=d&M`POGt zNSEJ0{qJI~FRTAjlJc1-+x>Tm{%D?m3sk-&cq#w)OpxI98wCF#2KbWcrAXK_(}M4B zF#VQf*h|irx=+uXZUMi+`A;fPFR5M%Wjs^Wh5rWCKgedhWO^w|@XS;b^&3oom;>K0 zB??|ry^IBarYem6Z7RU`#rDs-ZZAn*hSollv?csD$sh0QpTtI9vb>Dpd}e7*`fZj! zM|8d{~YM@vfW-r0z8vJ z<^6B6Ur(}L?ms_c9@hO0^Iy&J_uc51^?d33e#Y!-``?)VG)BGjCq5$&0G8A*r!2qk zUHscGc;VxE=1KqbH=dW%&Ogl({>L!>((m$2W8M9KQ@a1=h51jN|KoG{v(x0K&*iy% e1c3cF4~(n?C}6GmGu)3JNC)6=LGAhZ*Z%`+-T+_# literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a95009c3b --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..cccdd3d51 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## 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="" + +# 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="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, switch paths to Windows format before running java +if $cygwin ; 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/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@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= + +@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 From d8c7cdff61035498f6693d719a48985b5c902bf9 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 21:22:39 +0100 Subject: [PATCH 141/209] Add Appyveyor configuration --- appveyor.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..6af61b3d1 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,20 @@ +version: "{branch} {build}" + +build: + verbosity: detailed + +build_script: +- gradlew.bat assemble --info --no-daemon + +test_script: +- gradlew.bat check --info --no-daemon + +cache: +- C:\Users\appveyor\.gradle + +environment: + matrix: + - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 + +matrix: + fast_finish: true \ No newline at end of file From c3cdbdf75eb74025e952f624addbaf629111ae54 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 21:26:37 +0100 Subject: [PATCH 142/209] Create zip file distributions for each AppVeyor build --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6af61b3d1..b00ccfac7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,4 +17,8 @@ environment: - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 matrix: - fast_finish: true \ No newline at end of file + fast_finish: true + +artifacts: +- path: 'game\build\distributions\game-0.0.1.zip' + name: Apollo Server Distribution From 6198e305208ac678f438f0d8cb9c1ef4f7cc7789 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 21:28:56 +0100 Subject: [PATCH 143/209] Remove Gradle wrapper hack from Travis config --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3e1191abd..fd2718227 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,6 @@ jdk: after_success: - ./gradlew jacocoTestReport - bash <(curl -s https://codecov.io/bash) -before_install: - - gradle -b gradle/wrapper.gradle wrapper - - mv gradle/gradlew gradle/gradlew.bat . - - mv gradle/gradle/wrapper gradle/ before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ From 51cfe1cd36533afeceacd008af6b51f02ab8023c Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 22:00:39 +0100 Subject: [PATCH 144/209] Add WalkingQueue tests --- .../game/model/entity/WalkingQueueTests.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 game/src/test/java/org/apollo/game/model/entity/WalkingQueueTests.java diff --git a/game/src/test/java/org/apollo/game/model/entity/WalkingQueueTests.java b/game/src/test/java/org/apollo/game/model/entity/WalkingQueueTests.java new file mode 100644 index 000000000..51dd4d60c --- /dev/null +++ b/game/src/test/java/org/apollo/game/model/entity/WalkingQueueTests.java @@ -0,0 +1,82 @@ +package org.apollo.game.model.entity; + +import org.apollo.game.model.Position; +import org.apollo.game.model.World; +import org.apollo.game.model.area.Region; +import org.apollo.game.model.area.RegionRepository; +import org.apollo.game.model.area.collision.CollisionManager; +import org.apollo.util.security.PlayerCredentials; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.spy; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({World.class, CollisionManager.class}) +public class WalkingQueueTests { + private static final Position START_POSITION = new Position(1, 1); + private static final Position END_WALK_POSITION = new Position(2, 1); + private static final Position END_RUN_POSITION = new Position(3, 1); + + private World createFakeWorld(boolean traversable) { + World world = spy(World.class); + CollisionManager collisionManager = mock(CollisionManager.class); + when(collisionManager.traversable(any(), any(), any())).thenReturn(traversable); + when(world.getCollisionManager()).thenReturn(collisionManager); + + return world; + } + + private Player createFakePlayer(World world) { + PlayerCredentials credentials = new PlayerCredentials("test", "test", -1, -1, "0.0.0.0"); + Player player = new Player(world, credentials, START_POSITION); + + Region region = world.getRegionRepository().fromPosition(START_POSITION); + region.addEntity(player); + + return player; + } + + @Test + public void doesntMoveWhenTileIsBlocked() { + World world = createFakeWorld(false); + Player player = createFakePlayer(world); + + WalkingQueue walkingQueue = new WalkingQueue(player); + walkingQueue.addStep(END_WALK_POSITION); + walkingQueue.pulse(); + + assertEquals(START_POSITION, player.getPosition()); + } + + @Test + public void movesOneTileWhenWalking() throws Exception { + World world = createFakeWorld(true); + Player player = createFakePlayer(world); + + WalkingQueue walkingQueue = new WalkingQueue(player); + walkingQueue.addStep(END_WALK_POSITION); + walkingQueue.pulse(); + + assertEquals(END_WALK_POSITION, player.getPosition()); + } + + @Test + public void movesTwoTilesWhenRunning() throws Exception { + World world = createFakeWorld(true); + Player player = createFakePlayer(world); + + WalkingQueue walkingQueue = new WalkingQueue(player); + walkingQueue.setRunning(true); + walkingQueue.addStep(END_RUN_POSITION); + walkingQueue.pulse(); + + assertEquals(END_RUN_POSITION, player.getPosition()); + } +} \ No newline at end of file From d97b6274c64901a37709e706c0de2f2e2c7867a9 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 22:13:16 +0100 Subject: [PATCH 145/209] Include default configuratio in app distribution --- game/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/game/build.gradle b/game/build.gradle index a357a982a..53407a749 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -35,3 +35,9 @@ dependencies { } } } + +applicationDistribution.from("$rootDir/data") { + include '*.dat' + include '*.xml' + into "data/" +} \ No newline at end of file From eaa6ff6f2f540b1b5e149fc65b8b6c38690c62ef Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 22:59:25 +0100 Subject: [PATCH 146/209] Add ktlint Gradle plugin --- build.gradle | 1 + gradle/kotlin.gradle | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 899294782..d349e5361 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'org.jetbrains.kotlin.jvm' version "1.2.60" apply(false) + id 'org.jmailen.kotlinter' version '1.16.0' apply(false) } allprojects { diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle index 0851617ec..88332919d 100644 --- a/gradle/kotlin.gradle +++ b/gradle/kotlin.gradle @@ -1,5 +1,20 @@ allprojects { - plugins.withId('kotlin') { + if (it.pluginManager.hasPlugin('kotlin') || it.pluginManager.hasPlugin('apollo-plugin')) { + + } +} + +gradle.projectsEvaluated { + configure(subprojects.findAll { it.pluginManager.hasPlugin('kotlin') }) { + apply plugin: 'org.jmailen.kotlinter' + + kotlinter { + ignoreFailures = true + indentSize = 4 + continuationIndentSize = 4 + reporters = ['checkstyle', 'plain'] + } + kotlin { experimental { coroutines 'enable' } } } -} \ No newline at end of file +} From 96e11dfe27b9590767fb5e7c378fa34655892283 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 23:00:17 +0100 Subject: [PATCH 147/209] Remove empty allprojects block --- gradle/kotlin.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle index 88332919d..e5e7156ad 100644 --- a/gradle/kotlin.gradle +++ b/gradle/kotlin.gradle @@ -1,9 +1,3 @@ -allprojects { - if (it.pluginManager.hasPlugin('kotlin') || it.pluginManager.hasPlugin('apollo-plugin')) { - - } -} - gradle.projectsEvaluated { configure(subprojects.findAll { it.pluginManager.hasPlugin('kotlin') }) { apply plugin: 'org.jmailen.kotlinter' From ba5ff2b765c1238152899e040ee658e12d50d281 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Wed, 22 Aug 2018 23:16:53 +0100 Subject: [PATCH 148/209] Fix inclusion of ktlint for check tasks --- build.gradle | 1 - game/build.gradle | 1 + game/plugin-testing/build.gradle | 1 + game/plugin/build.gradle | 1 + gradle/kotlin.gradle | 20 ++++++++------------ 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index d349e5361..511dba9fa 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,5 @@ allprojects { } apply from: 'gradle/properties.gradle' -apply from: 'gradle/kotlin.gradle' apply from: 'gradle/jacoco.gradle' apply from: 'gradle/wrapper.gradle' \ No newline at end of file diff --git a/game/build.gradle b/game/build.gradle index 53407a749..a5eb72e8e 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'application' apply plugin: 'org.jetbrains.kotlin.jvm' +apply from: "$rootDir/gradle/kotlin.gradle" description = 'Apollo Game' mainClassName = 'org.apollo.Server' diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index 9e26f3b54..ae3a276c2 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'java-library' apply plugin: 'org.jetbrains.kotlin.jvm' +apply from: "$rootDir/gradle/kotlin.gradle" dependencies { test.useJUnitPlatform() diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index 90c96c9a6..6d254617a 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,6 +1,7 @@ subprojects { subproj -> if (subproj.buildFile.exists()) { apply plugin: 'apollo-plugin' + apply from: "$rootDir/gradle/kotlin.gradle" test { useJUnitPlatform() diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle index e5e7156ad..01ae102ed 100644 --- a/gradle/kotlin.gradle +++ b/gradle/kotlin.gradle @@ -1,14 +1,10 @@ -gradle.projectsEvaluated { - configure(subprojects.findAll { it.pluginManager.hasPlugin('kotlin') }) { - apply plugin: 'org.jmailen.kotlinter' +apply plugin: 'org.jmailen.kotlinter' - kotlinter { - ignoreFailures = true - indentSize = 4 - continuationIndentSize = 4 - reporters = ['checkstyle', 'plain'] - } - - kotlin { experimental { coroutines 'enable' } } - } +kotlinter { + ignoreFailures = true + indentSize = 4 + continuationIndentSize = 4 + reporters = ['checkstyle', 'plain'] } + +kotlin { experimental { coroutines 'enable' } } From 4689ba9db613d1db1f4620bdf9e2b06228b95fea Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 23 Aug 2018 19:49:47 +0100 Subject: [PATCH 149/209] Add SonarCloud scans to Travis runs --- .travis.yml | 4 ++++ build.gradle | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd2718227..79e382bf6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,10 @@ language: java jdk: - oraclejdk8 after_success: + - ./gradlew sonarqube \ + -Dsonar.organization=github-apollo-rsps \ + -Dsonar.host.url=https://sonarcloud.io \ + -Dsonar.login="$SONARCLOUD_TOKEN" - ./gradlew jacocoTestReport - bash <(curl -s https://codecov.io/bash) before_cache: diff --git a/build.gradle b/build.gradle index 511dba9fa..cd99f5459 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,8 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version "1.2.60" apply(false) + id 'org.jetbrains.kotlin.jvm' version '1.2.60' apply(false) + id 'org.jetbrains.intellij' version '0.3.6' apply(false) id 'org.jmailen.kotlinter' version '1.16.0' apply(false) + id 'org.sonarqube' version '2.6.2' } allprojects { From cfddd054991a87ba5dd162f29099149c22951e7e Mon Sep 17 00:00:00 2001 From: Major- Date: Thu, 23 Aug 2018 18:29:36 +0100 Subject: [PATCH 150/209] Repackage api plugin --- .../apollo/game/plugin/api}/definitions.kt | 18 ++--- .../apollo/game/plugin/api}/player.kt | 0 .../game/{plugins => plugin}/api/position.kt | 2 +- .../{ => org/apollo/game/plugin/api}/util.kt | 2 +- .../{ => org/apollo/game/plugin/api}/world.kt | 37 +++++----- game/plugin/areas/src/Area.kt | 6 +- game/plugin/cmd/src/teleport-cmd.plugin.kts | 68 +++++++++---------- game/plugin/navigation/door/src/door.kt | 17 ++--- game/plugin/skills/mining/src/mining.kt | 18 ++--- .../woodcutting/src/woodcutting.plugin.kts | 9 +-- 10 files changed, 83 insertions(+), 94 deletions(-) rename game/plugin/api/src/{ => org/apollo/game/plugin/api}/definitions.kt (78%) rename game/plugin/api/src/{ => org/apollo/game/plugin/api}/player.kt (100%) rename game/plugin/api/src/org/apollo/game/{plugins => plugin}/api/position.kt (88%) rename game/plugin/api/src/{ => org/apollo/game/plugin/api}/util.kt (81%) rename game/plugin/api/src/{ => org/apollo/game/plugin/api}/world.kt (72%) diff --git a/game/plugin/api/src/definitions.kt b/game/plugin/api/src/org/apollo/game/plugin/api/definitions.kt similarity index 78% rename from game/plugin/api/src/definitions.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/definitions.kt index 9e64e460b..2512d72c1 100644 --- a/game/plugin/api/src/definitions.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/definitions.kt @@ -3,6 +3,7 @@ package org.apollo.game.plugin.api import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition +import java.lang.IllegalArgumentException object Definitions { fun item(id: Int): ItemDefinition? { @@ -22,11 +23,7 @@ object Definitions { } fun npc(id: Int): NpcDefinition? { - try { - return NpcDefinition.lookup(id) - } catch (e: NullPointerException) { - throw RuntimeException("Failed to find npc $id: count=${NpcDefinition.count()}") - } + return NpcDefinition.lookup(id) } fun npc(name: String): NpcDefinition? { @@ -43,11 +40,16 @@ object Definitions { nameSupplier: T.() -> String, name: String ): T? { - val definitions = definitionsProvider.invoke() + val definitions = definitionsProvider() if (ID_REGEX matches name) { - val id = name.substring(name.lastIndexOf('_') + 1, name.length).toInt() - return definitions.getOrNull(id) + val id = name.substring(name.lastIndexOf('_') + 1, name.length).toIntOrNull() + + if (id == null || id >= definitions.size) { + throw IllegalArgumentException("Error while searching for definition: invalid id suffix in $name.") + } + + return definitions[id] } val normalizedName = name.replace('_', ' ') diff --git a/game/plugin/api/src/player.kt b/game/plugin/api/src/org/apollo/game/plugin/api/player.kt similarity index 100% rename from game/plugin/api/src/player.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/player.kt diff --git a/game/plugin/api/src/org/apollo/game/plugins/api/position.kt b/game/plugin/api/src/org/apollo/game/plugin/api/position.kt similarity index 88% rename from game/plugin/api/src/org/apollo/game/plugins/api/position.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/position.kt index 59e6d3deb..35f901427 100644 --- a/game/plugin/api/src/org/apollo/game/plugins/api/position.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/position.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugins.api +package org.apollo.game.plugin.api import org.apollo.game.model.Position diff --git a/game/plugin/api/src/util.kt b/game/plugin/api/src/org/apollo/game/plugin/api/util.kt similarity index 81% rename from game/plugin/api/src/util.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/util.kt index 663aa3de5..a8d538264 100644 --- a/game/plugin/api/src/util.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/util.kt @@ -2,7 +2,7 @@ package org.apollo.game.plugin.api import java.util.* -public val RAND = Random() +val RAND = Random() fun rand(bounds: Int): Int { return RAND.nextInt(bounds) diff --git a/game/plugin/api/src/world.kt b/game/plugin/api/src/org/apollo/game/plugin/api/world.kt similarity index 72% rename from game/plugin/api/src/world.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/world.kt index 6dd75879b..36ab48592 100644 --- a/game/plugin/api/src/world.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/world.kt @@ -10,23 +10,34 @@ import org.apollo.game.model.entity.EntityType.STATIC_OBJECT import org.apollo.game.model.entity.obj.DynamicGameObject import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.scheduling.ScheduledTask -import java.util.Optional -import java.util.stream.Stream -fun Region.find(position: Position, predicate: (T) -> Boolean, vararg types: EntityType): Stream { - val result = getEntities(position, *types) - return result.stream().filter(predicate::invoke) +fun Region.find(position: Position, predicate: (T) -> Boolean, vararg types: EntityType): Sequence { + return getEntities(position, *types).asSequence().filter(predicate) } -fun Region.findObjects(position: Position, id: Int): Stream { +fun Region.findObjects(position: Position, id: Int): Sequence { return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) } -fun Region.findObject(position: Position, id: Int): Optional { - return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) - .findFirst() +fun Region.findObject(position: Position, id: Int): GameObject? { + return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT).firstOrNull() } +fun World.findObject(position: Position, objectId: Int): GameObject? { + return regionRepository.fromPosition(position).findObject(position, objectId) +} + +fun World.findObjects(position: Position, id: Int): Sequence { + return regionRepository.fromPosition(position).findObjects(position, id) +} + +fun World.expireObject(obj: GameObject, replacement: Int, respawnDelay: Int) { + val replacementObj = DynamicGameObject.createPublic(this, replacement, obj.position, obj.type, obj.orientation) + + schedule(ExpireObjectTask(this, obj, replacementObj, respawnDelay)) +} + + class ExpireObjectTask( private val world: World, private val existing: GameObject, @@ -49,10 +60,4 @@ class ExpireObjectTask( stop() } } -} - -fun World.expireObject(obj: GameObject, replacement: Int, respawnDelay: Int) { - val replacementObj = DynamicGameObject.createPublic(this, replacement, obj.position, obj.type, obj.orientation) - - schedule(ExpireObjectTask(this, obj, replacementObj, respawnDelay)) -} +} \ No newline at end of file diff --git a/game/plugin/areas/src/Area.kt b/game/plugin/areas/src/Area.kt index 6efdae069..376ce33a8 100644 --- a/game/plugin/areas/src/Area.kt +++ b/game/plugin/areas/src/Area.kt @@ -1,9 +1,9 @@ package org.apollo.game.plugins.area import org.apollo.game.model.Position -import org.apollo.game.plugins.api.Position.component1 -import org.apollo.game.plugins.api.Position.component2 -import org.apollo.game.plugins.api.Position.component3 +import org.apollo.game.plugin.api.Position.component1 +import org.apollo.game.plugin.api.Position.component2 +import org.apollo.game.plugin.api.Position.component3 /** * An area in the game world. diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index 381118a45..4d1dabb75 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -2,9 +2,9 @@ import com.google.common.primitives.Ints import org.apollo.game.model.Position import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugins.api.Position.component1 -import org.apollo.game.plugins.api.Position.component2 -import org.apollo.game.plugins.api.Position.component3 +import org.apollo.game.plugin.api.Position.component1 +import org.apollo.game.plugin.api.Position.component2 +import org.apollo.game.plugin.api.Position.component3 /** * Sends the player's position. @@ -75,35 +75,35 @@ on_command("tele", PrivilegeLevel.ADMINISTRATOR) } } -private val TELEPORT_DESTINATIONS = listOf( - "alkharid" to Position(3292, 3171, 0), - "ardougne" to Position(2662, 3304, 0), - "barrows" to Position(3565, 3314, 0), - "brimhaven" to Position(2802, 3179, 0), - "burthorpe" to Position(2898, 3545, 0), - "camelot" to Position(2757, 3478, 0), - "canifis" to Position(3493, 3489, 0), - "cw" to Position(2442, 3090, 0), - "draynor" to Position(3082, 3249, 0), - "duelarena" to Position(3370, 3267, 0), - "edgeville" to Position(3087, 3504, 0), - "entrana" to Position(2827, 3343, 0), - "falador" to Position(2965, 3379, 0), - "ge" to Position(3164, 3476, 0), - "kbd" to Position(2273, 4680, 0), - "keldagrim" to Position(2845, 10210, 0), - "kq" to Position(3507, 9494, 0), - "lumbridge" to Position(3222, 3219, 0), - "lunar" to Position(2113, 3915, 0), - "misc" to Position(2515, 3866, 0), - "neit" to Position(2332, 3804, 0), - "pc" to Position(2658, 2660, 0), - "rellekka" to Position(2660, 3657, 0), - "shilo" to Position(2852, 2955, 0), - "taverley" to Position(2895, 3443, 0), - "tutorial" to Position(3094, 3107, 0), - "tzhaar" to Position(2480, 5175, 0), - "varrock" to Position(3212, 3423, 0), - "yanille" to Position(2605, 3096, 0), - "zanaris" to Position(2452, 4473, 0) +internal val TELEPORT_DESTINATIONS = listOf( + "alkharid" to Position(3292, 3171), + "ardougne" to Position(2662, 3304), + "barrows" to Position(3565, 3314), + "brimhaven" to Position(2802, 3179), + "burthorpe" to Position(2898, 3545), + "camelot" to Position(2757, 3478), + "canifis" to Position(3493, 3489), + "cw" to Position(2442, 3090), + "draynor" to Position(3082, 3249), + "duelarena" to Position(3370, 3267), + "edgeville" to Position(3087, 3504), + "entrana" to Position(2827, 3343), + "falador" to Position(2965, 3379), + "ge" to Position(3164, 3476), + "kbd" to Position(2273, 4680), + "keldagrim" to Position(2845, 10210), + "kq" to Position(3507, 9494), + "lumbridge" to Position(3222, 3219), + "lunar" to Position(2113, 3915), + "misc" to Position(2515, 3866), + "neit" to Position(2332, 3804), + "pc" to Position(2658, 2660), + "rellekka" to Position(2660, 3657), + "shilo" to Position(2852, 2955), + "taverley" to Position(2895, 3443), + "tutorial" to Position(3094, 3107), + "tzhaar" to Position(2480, 5175), + "varrock" to Position(3212, 3423), + "yanille" to Position(2605, 3096), + "zanaris" to Position(2452, 4473) ) \ No newline at end of file diff --git a/game/plugin/navigation/door/src/door.kt b/game/plugin/navigation/door/src/door.kt index afc8f14dc..d7255cb7c 100644 --- a/game/plugin/navigation/door/src/door.kt +++ b/game/plugin/navigation/door/src/door.kt @@ -10,7 +10,7 @@ import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.api.findObject import org.apollo.net.message.Message -import java.util.Objects +import java.util.* enum class DoorType { LEFT, RIGHT, NOT_SUPPORTED @@ -34,7 +34,7 @@ class Door(private val gameObject: GameObject) { Direction.EAST to Direction.SOUTH ) - val toggledDoors: HashMap = hashMapOf() + val toggledDoors = hashMapOf() val LEFT_HINGED = setOf(1516, 1536, 1533) @@ -47,13 +47,7 @@ class Door(private val gameObject: GameObject) { * @param objectId The [GameObject] id of the door */ fun find(world: World, position: Position, objectId: Int): Door? { - val region = world.regionRepository.fromPosition(position) - val gameObject = region.findObject(position, objectId).orElseGet(null) - return if (gameObject == null) { - null - } else { - Door(gameObject) - } + return world.findObject(position, objectId)?.let(::Door) } } @@ -88,7 +82,7 @@ class Door(private val gameObject: GameObject) { regionRepository.fromPosition(gameObject.position).removeEntity(gameObject) - val originalDoor: GameObject? = toggledDoors[gameObject] + val originalDoor = toggledDoors[gameObject] if (originalDoor == null) { val position = movePosition() @@ -98,7 +92,7 @@ class Door(private val gameObject: GameObject) { orientation) regionRepository.fromPosition(position).addEntity(toggledDoor) - toggledDoors.put(toggledDoor, gameObject) + toggledDoors[toggledDoor] = gameObject } else { toggledDoors.remove(gameObject) regionRepository.fromPosition(originalDoor.position).addEntity(originalDoor) @@ -119,6 +113,7 @@ class Door(private val gameObject: GameObject) { */ private fun translateDirection(): Direction? { val direction = Direction.WNES[gameObject.orientation] + return when (type()) { DoorType.LEFT -> LEFT_HINGE_ORIENTATION[direction] DoorType.RIGHT -> RIGHT_HINGE_ORIENTATION[direction] diff --git a/game/plugin/skills/mining/src/mining.kt b/game/plugin/skills/mining/src/mining.kt index 0dc0f778c..c98dd8a80 100644 --- a/game/plugin/skills/mining/src/mining.kt +++ b/game/plugin/skills/mining/src/mining.kt @@ -4,7 +4,6 @@ import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position import org.apollo.game.model.World import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.plugin.api.* import org.apollo.game.plugin.skills.mining.Ore import org.apollo.game.plugin.skills.mining.Pickaxe @@ -88,22 +87,14 @@ class MiningAction( data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { - /** - * Get the [GameObject] represented by this target. - * - * @todo: api: shouldn't be as verbose - */ - private fun getObject(world: World): GameObject? { - val region = world.regionRepository.fromPosition(position) - return region.findObject(position, objectId).orElse(null) - } - /** * Deplete this mining resource from the [World], and schedule it to be respawned * in a number of ticks specified by the [Ore]. */ fun deplete(world: World) { - world.expireObject(getObject(world)!!, ore.objects[objectId]!!, ore.respawn) + val obj = world.findObject(position, objectId)!! + + world.expireObject(obj, ore.objects[objectId]!!, ore.respawn) } /** @@ -117,7 +108,7 @@ data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) /** * Check if this target is still valid in the [World] (i.e. has not been [deplete]d). */ - fun isValid(world: World) = getObject(world) != null + fun isValid(world: World) = world.findObject(position, objectId) != null /** * Get the normalized name of the [Ore] represented by this target. @@ -142,5 +133,6 @@ data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) * this [MiningTarget]. */ fun skillRequirementsMet(mob: Player) = mob.mining.current < ore.level + } diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index f14e5b73f..bdb0b0328 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -7,11 +7,7 @@ import org.apollo.game.model.Position import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.plugin.api.Definitions -import org.apollo.game.plugin.api.expireObject -import org.apollo.game.plugin.api.findObject -import org.apollo.game.plugin.api.rand -import org.apollo.game.plugin.api.woodcutting +import org.apollo.game.plugin.api.* import org.apollo.game.plugin.skills.woodcutting.Axe import org.apollo.game.plugin.skills.woodcutting.Tree import java.util.concurrent.TimeUnit @@ -30,8 +26,7 @@ class WoodcuttingTarget(private val objectId: Int, val position: Position, val t * Get the tree object in the world */ fun getObject(world: World): GameObject? { - val region = world.regionRepository.fromPosition(position) - return region.findObject(position, objectId).orElse(null) + return world.findObject(position, objectId) } /** From 0a2d94ffbee3ed9cecf8b8fee9ff0239b18a283f Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 23 Aug 2018 20:22:13 +0100 Subject: [PATCH 151/209] Fix order of gradle arguments in sonarqube run --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 79e382bf6..0089c8415 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,11 @@ language: java jdk: - oraclejdk8 after_success: - - ./gradlew sonarqube \ + - ./gradlew \ -Dsonar.organization=github-apollo-rsps \ -Dsonar.host.url=https://sonarcloud.io \ - -Dsonar.login="$SONARCLOUD_TOKEN" + -Dsonar.login="$SONARCLOUD_TOKEN" \ + sonarqube - ./gradlew jacocoTestReport - bash <(curl -s https://codecov.io/bash) before_cache: From 03786a63143882e7d992c48cc3a33fdd7bb5a40d Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 23 Aug 2018 20:36:44 +0100 Subject: [PATCH 152/209] Run Sonarqube after generating JaCoCo report --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0089c8415..a7729fe3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,13 +2,9 @@ language: java jdk: - oraclejdk8 after_success: - - ./gradlew \ - -Dsonar.organization=github-apollo-rsps \ - -Dsonar.host.url=https://sonarcloud.io \ - -Dsonar.login="$SONARCLOUD_TOKEN" \ - sonarqube - ./gradlew jacocoTestReport - bash <(curl -s https://codecov.io/bash) + - ./gradlew -Dsonar.organization=github-apollo-rsps -Dsonar.host.url=https://sonarcloud.io -Dsonar.login="$SONARCLOUD_TOKEN" sonarqube before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ From 5346eab529e41703bd5a9d0426fb2b5785023aff Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 23 Aug 2018 22:55:44 +0100 Subject: [PATCH 153/209] Use travis built-in SonarCloud support --- .travis.yml | 8 +++++++- build.gradle | 2 +- gradle/{jacoco.gradle => quality-gate.gradle} | 18 ++++++++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) rename gradle/{jacoco.gradle => quality-gate.gradle} (74%) diff --git a/.travis.yml b/.travis.yml index a7729fe3e..e1fddb4e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,16 @@ language: java jdk: - oraclejdk8 + +addons: + sonarcloud: + organization: "github-apollo-rsps" + after_success: - ./gradlew jacocoTestReport - bash <(curl -s https://codecov.io/bash) - - ./gradlew -Dsonar.organization=github-apollo-rsps -Dsonar.host.url=https://sonarcloud.io -Dsonar.login="$SONARCLOUD_TOKEN" sonarqube + - git fetch --unshallow + - ./gradlew -Dsonar.host.url=https://sonarcloud.io -Dsonar.login="$SONAR_TOKEN" sonarqube before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ diff --git a/build.gradle b/build.gradle index cd99f5459..5cee3c2ea 100644 --- a/build.gradle +++ b/build.gradle @@ -17,5 +17,5 @@ allprojects { } apply from: 'gradle/properties.gradle' -apply from: 'gradle/jacoco.gradle' +apply from: 'gradle/quality-gate.gradle' apply from: 'gradle/wrapper.gradle' \ No newline at end of file diff --git a/gradle/jacoco.gradle b/gradle/quality-gate.gradle similarity index 74% rename from gradle/jacoco.gradle rename to gradle/quality-gate.gradle index 4fee3f85c..bd2a50900 100644 --- a/gradle/jacoco.gradle +++ b/gradle/quality-gate.gradle @@ -5,7 +5,6 @@ def testedProjects() { } gradle.projectsEvaluated { - configure(testedProjects()) { apply plugin: 'jacoco' @@ -19,11 +18,17 @@ gradle.projectsEvaluated { } test { + reports { + junitXml.enabled = true + html.enabled = false + } + jacoco { append = false destinationFile = file("$buildDir/jacoco/jacocoTest.exec") classDumpDir = file("$buildDir/jacoco/classpathdumps") } + } } @@ -35,7 +40,7 @@ gradle.projectsEvaluated { reports { xml.enabled = true - html.enabled = true + html.enabled = false } testedProjects().each { subproject -> @@ -54,5 +59,14 @@ gradle.projectsEvaluated { executionData = execData } + sonarqube { + properties { + property "sonar.organization", "github-apollo-rsps" + property "sonar.projectKey", "apollo:org.apollo" + property "sonar.projectName", "Apollo RSPS" + property "sonar.kotlin.file.suffixes", ".kt,.kts" + } + } + project.tasks["sonarqube"].dependsOn(jacocoTestReport) } \ No newline at end of file From 754343afec10e07a6d59e62694852e21f3704f2b Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 23 Aug 2018 23:08:30 +0100 Subject: [PATCH 154/209] Move shop plugins to unique packages --- game/plugin/locations/al-kharid/src/shops.plugin.kts | 2 ++ game/plugin/locations/edgeville/src/shops.plugin.kts | 2 ++ game/plugin/locations/falador/src/shops.plugin.kts | 2 ++ game/plugin/locations/lumbridge/src/shops.plugin.kts | 2 ++ game/plugin/locations/varrock/src/shops.plugin.kts | 2 ++ 5 files changed, 10 insertions(+) diff --git a/game/plugin/locations/al-kharid/src/shops.plugin.kts b/game/plugin/locations/al-kharid/src/shops.plugin.kts index d679700e6..ec55c37a5 100644 --- a/game/plugin/locations/al-kharid/src/shops.plugin.kts +++ b/game/plugin/locations/al-kharid/src/shops.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.alKharid + import org.apollo.game.plugin.shops.shop shop("Al-Kharid General Store") { diff --git a/game/plugin/locations/edgeville/src/shops.plugin.kts b/game/plugin/locations/edgeville/src/shops.plugin.kts index 1a619dc10..cb43fa596 100644 --- a/game/plugin/locations/edgeville/src/shops.plugin.kts +++ b/game/plugin/locations/edgeville/src/shops.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.edgeville + import org.apollo.game.plugin.shops.shop shop("Edgeville General Store") { diff --git a/game/plugin/locations/falador/src/shops.plugin.kts b/game/plugin/locations/falador/src/shops.plugin.kts index dde292f2e..c79007e6b 100644 --- a/game/plugin/locations/falador/src/shops.plugin.kts +++ b/game/plugin/locations/falador/src/shops.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.falador + import org.apollo.game.plugin.shops.shop shop("Falador General Store") { diff --git a/game/plugin/locations/lumbridge/src/shops.plugin.kts b/game/plugin/locations/lumbridge/src/shops.plugin.kts index dd12f2861..e67a4c8a3 100644 --- a/game/plugin/locations/lumbridge/src/shops.plugin.kts +++ b/game/plugin/locations/lumbridge/src/shops.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.lumbridge + import org.apollo.game.plugin.shops.shop shop("Lumbridge General Store") { diff --git a/game/plugin/locations/varrock/src/shops.plugin.kts b/game/plugin/locations/varrock/src/shops.plugin.kts index 9406e91f5..4ee6c7e63 100644 --- a/game/plugin/locations/varrock/src/shops.plugin.kts +++ b/game/plugin/locations/varrock/src/shops.plugin.kts @@ -1,3 +1,5 @@ +package org.apollo.plugin.locations.varrock + import org.apollo.game.plugin.shops.shop shop("Aubury's Rune Shop.") { From dc0690f82dc9002eea9be211647aa3818dbc1876 Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 24 Aug 2018 15:04:37 +0100 Subject: [PATCH 155/209] Make plugins target java 8 --- game/plugin/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index 6d254617a..0fd76d26e 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -7,6 +7,12 @@ subprojects { subproj -> useJUnitPlatform() } + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = "1.8" + } + } + dependencies { test.useJUnitPlatform() implementation group: 'com.google.guava', name: 'guava', version: guavaVersion From fd52ee602686067b5137b38a154f5945b5ec9b70 Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 24 Aug 2018 23:06:36 +0100 Subject: [PATCH 156/209] Add @DefinitionSource annotations Allows parameterized tests to use Item, Npc, and Object definitions as @ArgumentSources. This commit also adds support for using @ItemDefinitions etc on properties as well as functions. --- game/plugin-testing/build.gradle | 6 ++ .../testing/junit/ApolloTestExtension.kt | 79 ++++++++------ ...nnotations.kt => DefinitionAnnotations.kt} | 6 +- .../junit/params/DefinitionProviders.kt | 100 ++++++++++++++++++ .../testing/junit/params/DefinitionSource.kt | 54 ++++++++++ .../api/{definitions.kt => Definitions.kt} | 0 6 files changed, 207 insertions(+), 38 deletions(-) rename game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/{definitionAnnotations.kt => DefinitionAnnotations.kt} (86%) create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionSource.kt rename game/plugin/api/src/org/apollo/game/plugin/api/{definitions.kt => Definitions.kt} (100%) diff --git a/game/plugin-testing/build.gradle b/game/plugin-testing/build.gradle index ae3a276c2..0f2dc14d1 100644 --- a/game/plugin-testing/build.gradle +++ b/game/plugin-testing/build.gradle @@ -19,4 +19,10 @@ dependencies { api group: 'com.willowtreeapps.assertk', name: 'assertk', version: assertkVersion implementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion +} + +tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = "1.8" + } } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt index defeb83f0..c9942e418 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt @@ -13,23 +13,14 @@ import org.apollo.game.model.entity.Npc import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.plugin.KotlinPluginEnvironment -import org.apollo.game.plugin.PluginMetaData import org.apollo.game.plugin.testing.fakes.FakePluginContextFactory import org.apollo.game.plugin.testing.junit.api.ActionCapture import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions import org.apollo.game.plugin.testing.junit.mocking.StubPrototype -import org.junit.jupiter.api.extension.AfterAllCallback -import org.junit.jupiter.api.extension.AfterEachCallback -import org.junit.jupiter.api.extension.AfterTestExecutionCallback -import org.junit.jupiter.api.extension.BeforeAllCallback -import org.junit.jupiter.api.extension.BeforeEachCallback -import org.junit.jupiter.api.extension.ExtensionContext -import org.junit.jupiter.api.extension.ParameterContext -import org.junit.jupiter.api.extension.ParameterResolver -import java.util.ArrayList -import kotlin.reflect.KFunction +import org.junit.jupiter.api.extension.* +import kotlin.reflect.KCallable import kotlin.reflect.KMutableProperty import kotlin.reflect.full.companionObject import kotlin.reflect.full.createType @@ -58,7 +49,7 @@ class ApolloTestingExtension : private fun cleanup(context: ExtensionContext) { val store = context.getStore(namespace) - val state = store.get(ApolloTestState::class) as ApolloTestState + val state = store[ApolloTestState::class] as ApolloTestState try { state.actionCapture?.runAction() @@ -84,27 +75,32 @@ class ApolloTestingExtension : .map { it.kotlin.companionObject } .ifPresent { companion -> val companionInstance = companion.objectInstance!! - val testClassMethods = companion.declaredMemberFunctions + val callables: List> = companion.declaredMemberFunctions + companion.declaredMemberProperties createTestDefinitions( - testClassMethods, companionInstance, ItemDefinition::getId, ItemDefinition::lookup + callables, companionInstance, ItemDefinition::getId, ItemDefinition::lookup, + ItemDefinition::getDefinitions ) createTestDefinitions( - testClassMethods, companionInstance, NpcDefinition::getId, NpcDefinition::lookup + callables, companionInstance, NpcDefinition::getId, NpcDefinition::lookup, + NpcDefinition::getDefinitions ) createTestDefinitions( - testClassMethods, companionInstance, ObjectDefinition::getId, ObjectDefinition::lookup + callables, companionInstance, ObjectDefinition::getId, ObjectDefinition::lookup, + ObjectDefinition::getDefinitions ) } - val pluginEnvironment = KotlinPluginEnvironment(stubWorld) - pluginEnvironment.setContext(FakePluginContextFactory.create(stubHandlers)) - pluginEnvironment.load(ArrayList()) + KotlinPluginEnvironment(stubWorld).apply { + setContext(FakePluginContextFactory.create(stubHandlers)) + load(emptyList()) + } - val state = ApolloTestState(stubHandlers, stubWorld) val store = context.getStore(namespace) + val state = ApolloTestState(stubHandlers, stubWorld) + store.put(ApolloTestState::class, state) } @@ -151,30 +147,43 @@ class ApolloTestingExtension : * @param lookup The lookup function that returns an instance of [D] given a definition id. */ private inline fun createTestDefinitions( - testClassMethods: Collection>, + testClassMethods: Collection>, companionObjectInstance: Any?, crossinline idMapper: (D) -> Int, - crossinline lookup: (Int) -> D + crossinline lookup: (Int) -> D?, + crossinline getAll: () -> Array ) { - val testDefinitions = testClassMethods.asSequence() - .filter { method -> method.annotations.any { it is A } } - .flatMap { method -> - @Suppress("UNCHECKED_CAST") - method as? KFunction> ?: throw RuntimeException("${method.name} is annotated with " + - "${A::class.simpleName} but does not return Collection<${D::class.simpleName}." - ) - - method.isAccessible = true // lets us call methods in private companion objects - method.call(companionObjectInstance).asSequence() - } + val testDefinitions = findTestDefinitions(testClassMethods, companionObjectInstance) .associateBy(idMapper) if (testDefinitions.isNotEmpty()) { val idSlot = slot() - staticMockk().mock() - every { lookup(capture(idSlot)) } answers { testDefinitions[idSlot.captured]!! } + + every { lookup(capture(idSlot)) } answers { testDefinitions[idSlot.captured] } + every { getAll() } answers { testDefinitions.values.sortedBy(idMapper).toTypedArray() } } } + companion object { + + inline fun findTestDefinitions( + callables: Collection>, + companionObjectInstance: Any? + ): List { + return callables + .filter { method -> method.annotations.any { it is A } } + .flatMap { method -> + @Suppress("UNCHECKED_CAST") + method as? KCallable> ?: throw RuntimeException("${method.name} is annotated with " + + "${A::class.simpleName} but does not return Collection<${D::class.simpleName}>." + ) + + method.isAccessible = true // lets us call methods in private companion objects + method.call(companionObjectInstance) + } + } + + } + } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/DefinitionAnnotations.kt similarity index 86% rename from game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt rename to game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/DefinitionAnnotations.kt index b730b277b..b3d6c8d64 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/definitionAnnotations.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/DefinitionAnnotations.kt @@ -8,7 +8,7 @@ package org.apollo.game.plugin.testing.junit.api.annotations * - Be inside a **companion object** inside an apollo test class (a regular object will not work). * - Return a `Collection`. */ -@Target(AnnotationTarget.FUNCTION) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) annotation class ItemDefinitions @@ -20,7 +20,7 @@ annotation class ItemDefinitions * - Be inside a **companion object** inside an apollo test class (a regular object will not work). * - Return a `Collection`. */ -@Target(AnnotationTarget.FUNCTION) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) annotation class NpcDefinitions @@ -32,6 +32,6 @@ annotation class NpcDefinitions * - Be inside a **companion object** inside an apollo test class (a regular object will not work). * - Return a `Collection`. */ -@Target(AnnotationTarget.FUNCTION) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) annotation class ObjectDefinitions \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt new file mode 100644 index 000000000..5edfd5eb6 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt @@ -0,0 +1,100 @@ +package org.apollo.game.plugin.testing.junit.params + +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension.Companion.findTestDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import org.junit.jupiter.params.support.AnnotationConsumer +import java.util.stream.Stream +import kotlin.reflect.KCallable +import kotlin.reflect.full.companionObject +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.full.declaredMemberProperties + +/** + * An [ArgumentsProvider] for a definition of type `D`. + */ +abstract class DefinitionsProvider( + private val definitionProvider: (methods: Collection>, companionObjectInstance: Any) -> List +) : ArgumentsProvider { + + protected lateinit var sourceNames: Set + + override fun provideArguments(context: ExtensionContext): Stream { + val companion = context.requiredTestClass.kotlin.companionObject + ?: throw RuntimeException("${context.requiredTestMethod.name} is annotated with a DefinitionsProvider," + + " but does not contain a companion object to search for Definitions in." + ) + + val companionInstance = companion.objectInstance!! // safe + val callables: List> = companion.declaredMemberFunctions + companion.declaredMemberProperties + + val filtered = if (sourceNames.isEmpty()) { + callables + } else { + callables.filter { it.name in sourceNames } + } + + return definitionProvider(filtered, companionInstance).map { Arguments.of(it) }.stream() + } +} + +// These providers are separate because of a JUnit bug in its use of ArgumentsSource and AnnotationConsumer - +// the reflection code that invokes the AnnotationConsumer searches for an accept() method that takes an +// Annotation parameter, prohibiting usage of the actual `Annotation` type as the parameter - meaning +// DefinitionsProvider cannot abstract over different annotation implementations (i.e. over ItemDefinitionSource, +// NpcDefinitionSource, and ObjectDefinitionSource). + +/** + * An [ArgumentsProvider] for [ItemDefinition]s. + * + * Test authors should not need to utilise this class, and should instead annotate their function with + * [@ItemDefinitionSource][ItemDefinitionSource]. + */ +object ItemDefinitionsProvider : DefinitionsProvider( + { methods, companion -> findTestDefinitions(methods, companion) } +), AnnotationConsumer { + + override fun accept(source: ItemDefinitionSource) { + sourceNames = source.sourceNames.toHashSet() + } + +} + +/** + * An [ArgumentsProvider] for [NpcDefinition]s. + * + * Test authors should not need to utilise this class, and should instead annotate their function with + * [@NpcDefinitionSource][NpcDefinitionSource]. + */ +object NpcDefinitionsProvider : DefinitionsProvider( + { methods, companion -> findTestDefinitions(methods, companion) } +), AnnotationConsumer { + + override fun accept(source: NpcDefinitionSource) { + sourceNames = source.sourceNames.toHashSet() + } + +} + +/** + * An [ArgumentsProvider] for [ObjectDefinition]s. + * + * Test authors should not need to utilise this class, and should instead annotate their function with + * [@ObjectDefinitionSource][ObjectDefinitionSource]. + */ +object ObjectDefinitionsProvider : DefinitionsProvider( + { methods, companion -> findTestDefinitions(methods, companion) } +), AnnotationConsumer { + + override fun accept(source: ObjectDefinitionSource) { + sourceNames = source.sourceNames.toHashSet() + } + +} diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionSource.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionSource.kt new file mode 100644 index 000000000..c97fc9ca1 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionSource.kt @@ -0,0 +1,54 @@ +package org.apollo.game.plugin.testing.junit.params + +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition +import org.junit.jupiter.params.provider.ArgumentsSource + +/** + * `@ItemDefinitionSource` is an [ArgumentsSource] for [ItemDefinition]s. + * + * @param sourceNames The names of the properties or functions annotated with `@ItemDefinitions` to use as sources of + * [ItemDefinition]s for the test with this annotation. Every property/function must return + * `Collection`. If no [sourceNames] are provided, every property and function annotated with + * `@ItemDefinitions` (in this class's companion object) will be used. + * + * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedTest + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +@ArgumentsSource(ItemDefinitionsProvider::class) +annotation class ItemDefinitionSource(vararg val sourceNames: String) + +/** + * `@NpcDefinitionSource` is an [ArgumentsSource] for [NpcDefinition]s. + * + * @param sourceNames The names of the properties or functions annotated with `@NpcDefinitions` to use as sources of + * [NpcDefinition]s for the test with this annotation. Every property/function must return + * `Collection`. If no [sourceNames] are provided, every property and function annotated with + * `@NpcDefinitions` (in this class's companion object) will be used. + * + * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedTest + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +@ArgumentsSource(NpcDefinitionsProvider::class) +annotation class NpcDefinitionSource(vararg val sourceNames: String) + +/** + * `@ObjectDefinitionSource` is an [ArgumentsSource] for [ObjectDefinition]s. + * + * @param sourceNames The names of the properties or functions annotated with `@ObjectDefinitions` to use as sources of + * [ObjectDefinition]s for the test with this annotation. Every property/function must return + * `Collection`. If no [sourceNames] are provided, every property and function annotated with + * `@ObjectDefinitions` (in this class's companion object) will be used. + * + * @see org.junit.jupiter.params.provider.ArgumentsSource + * @see org.junit.jupiter.params.ParameterizedTest + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +@ArgumentsSource(ObjectDefinitionsProvider::class) +annotation class ObjectDefinitionSource(vararg val sourceNames: String) diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/definitions.kt b/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt similarity index 100% rename from game/plugin/api/src/org/apollo/game/plugin/api/definitions.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt From f4aa3aae4ed3957201644e52ecd58a50802c2dd0 Mon Sep 17 00:00:00 2001 From: Major- Date: Sat, 25 Aug 2018 01:14:56 +0100 Subject: [PATCH 157/209] Add tests for api plugin --- .../org/apollo/game/plugin/api/Definitions.kt | 52 +++++++- .../game/plugin/api/{player.kt => Player.kt} | 21 ++- .../plugin/api/{position.kt => Position.kt} | 0 .../game/plugin/api/{util.kt => Random.kt} | 0 .../src/org/apollo/game/plugin/api/World.kt | 104 +++++++++++++++ .../src/org/apollo/game/plugin/api/world.kt | 63 --------- .../game/plugin/api/DefinitionsTests.kt | 94 +++++++++++++ .../org/apollo/game/plugin/api/PlayerTests.kt | 123 ++++++++++++++++++ .../apollo/game/plugin/api/PositionTests.kt | 26 ++++ game/plugin/skills/fishing/src/fishing.kt | 6 +- game/plugin/skills/mining/src/mining.kt | 4 +- .../skills/mining/test/MiningActionTests.kt | 6 +- .../woodcutting/src/woodcutting.plugin.kts | 4 +- 13 files changed, 422 insertions(+), 81 deletions(-) rename game/plugin/api/src/org/apollo/game/plugin/api/{player.kt => Player.kt} (85%) rename game/plugin/api/src/org/apollo/game/plugin/api/{position.kt => Position.kt} (100%) rename game/plugin/api/src/org/apollo/game/plugin/api/{util.kt => Random.kt} (100%) create mode 100644 game/plugin/api/src/org/apollo/game/plugin/api/World.kt delete mode 100644 game/plugin/api/src/org/apollo/game/plugin/api/world.kt create mode 100644 game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt create mode 100644 game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt create mode 100644 game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt b/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt index 2512d72c1..d083dc9cb 100644 --- a/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt @@ -5,27 +5,73 @@ import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition import java.lang.IllegalArgumentException +/** + * Provides plugins with access to item, npc, and object definitions + */ object Definitions { - fun item(id: Int): ItemDefinition? { + + /** + * Returns the [ItemDefinition] with the specified [id]. Callers of this function must perform bounds checking on + * the [id] prior to invoking this method (i.e. verify that `id >= 0 && id < ItemDefinition.count()`). + * + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + fun item(id: Int): ItemDefinition { return ItemDefinition.lookup(id) } + /** + * Returns the [ItemDefinition] with the specified name, performing case-insensitive matching. If multiple items + * share the same name, the item with the lowest id is returned. + * + * The name may be suffixed with an explicit item id (as a way to disambiguate in the above case), by ending the + * name with `_id`, e.g. `monks_robe_42`. If an explicit id is attached, it must be bounds checked (in the same + * manner as [item(id: Int)][item]). + */ fun item(name: String): ItemDefinition? { return findEntity(ItemDefinition::getDefinitions, ItemDefinition::getName, name) } - fun obj(id: Int): ObjectDefinition? { + /** + * Returns the [ObjectDefinition] with the specified [id]. Callers of this function must perform bounds checking on + * the [id] prior to invoking this method (i.e. verify that `id >= 0 && id < ObjectDefinition.count()`). + * + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + fun obj(id: Int): ObjectDefinition { return ObjectDefinition.lookup(id) } + /** + * Returns the [ObjectDefinition] with the specified name, performing case-insensitive matching. If multiple objects + * share the same name, the object with the lowest id is returned. + * + * The name may be suffixed with an explicit object id (as a way to disambiguate in the above case), by ending the + * name with `_id`, e.g. `man_2`. If an explicit id is attached, it must be bounds checked (in the same + * manner as [object(id: Int)][object]). + */ fun obj(name: String): ObjectDefinition? { return findEntity(ObjectDefinition::getDefinitions, ObjectDefinition::getName, name) } - fun npc(id: Int): NpcDefinition? { + /** + * Returns the [NpcDefinition] with the specified [id]. Callers of this function must perform bounds checking on + * the [id] prior to invoking this method (i.e. verify that `id >= 0 && id < NpcDefinition.count()`). + * + * @throws IndexOutOfBoundsException If the id is out of bounds. + */ + fun npc(id: Int): NpcDefinition { return NpcDefinition.lookup(id) } + /** + * Returns the [NpcDefinition] with the specified name, performing case-insensitive matching. If multiple npcs + * share the same name, the npc with the lowest id is returned. + * + * The name may be suffixed with an explicit npc id (as a way to disambiguate in the above case), by ending the + * name with `_id`, e.g. `man_2`. If an explicit id is attached, it must be bounds checked (in the same + * manner as [npc(id: Int)][npc]). + */ fun npc(name: String): NpcDefinition? { return findEntity(NpcDefinition::getDefinitions, NpcDefinition::getName, name) } diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/player.kt b/game/plugin/api/src/org/apollo/game/plugin/api/Player.kt similarity index 85% rename from game/plugin/api/src/org/apollo/game/plugin/api/player.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/Player.kt index 069ffe972..9205bc0b4 100644 --- a/game/plugin/api/src/org/apollo/game/plugin/api/player.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/Player.kt @@ -53,26 +53,37 @@ class SkillProxy(private val skills: SkillSet, private val skill: Int) { } /** - * Boosts the current level of this skill by [amount], if possible (i.e. if `current + amount <= maximum + amount`). + * Boosts the current level of this skill by [amount], if possible. */ fun boost(amount: Int) { - val new = Math.min(current + amount, maximum + amount) + require(amount >= 1) { "Can only boost skills by positive values." } + + val new = if (current - maximum > amount) { + current + } else { + Math.min(current + amount, maximum + amount) + } + skills.setCurrentLevel(skill, new) } /** - * Drains the current level of this skill by [amount], if possible (i.e. if `current - amount >= 0`). + * Drains the current level of this skill by [amount], if possible. */ fun drain(amount: Int) { + require(amount >= 1) { "Can only drain skills by positive values." } + val new = Math.max(current - amount, 0) skills.setCurrentLevel(skill, new) } /** - * Restores the current level of this skill by [amount], if possible (i.e. if `current + amount < maximum`). + * Restores the current level of this skill by [amount], if possible. */ fun restore(amount: Int) { - val new = Math.max(current + amount, maximum) + require(amount >= 1) { "Can only restore skills by positive values." } + + val new = Math.min(current + amount, maximum) skills.setCurrentLevel(skill, new) } diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/position.kt b/game/plugin/api/src/org/apollo/game/plugin/api/Position.kt similarity index 100% rename from game/plugin/api/src/org/apollo/game/plugin/api/position.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/Position.kt diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/util.kt b/game/plugin/api/src/org/apollo/game/plugin/api/Random.kt similarity index 100% rename from game/plugin/api/src/org/apollo/game/plugin/api/util.kt rename to game/plugin/api/src/org/apollo/game/plugin/api/Random.kt diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/World.kt b/game/plugin/api/src/org/apollo/game/plugin/api/World.kt new file mode 100644 index 000000000..a44163c1b --- /dev/null +++ b/game/plugin/api/src/org/apollo/game/plugin/api/World.kt @@ -0,0 +1,104 @@ +package org.apollo.game.plugin.api + +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.area.Region +import org.apollo.game.model.entity.Entity +import org.apollo.game.model.entity.EntityType +import org.apollo.game.model.entity.EntityType.DYNAMIC_OBJECT +import org.apollo.game.model.entity.EntityType.STATIC_OBJECT +import org.apollo.game.model.entity.obj.DynamicGameObject +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.scheduling.ScheduledTask + +/** + * Finds all of the [Entities][Entity] with the specified [EntityTypes][EntityType] at the specified [position], that + * match the provided [predicate]. + * + * ``` + * const val GOLD_COINS = 995 + * ... + * + * val allCoins: Sequence = region.find(position, EntityType.GROUND_ITEM) { item -> item.id == GOLD_COINS } + * ``` + */ +fun Region.find(position: Position, vararg types: EntityType, predicate: (T) -> Boolean): Sequence { + return getEntities(position, *types).asSequence().filter(predicate) +} + +/** + * Finds the first [GameObject]s with the specified [id] at the specified [position]. + * + * Note that the iteration order of entities in a [Region] is not defined - this function should not be used if there + * may be more than [GameObject] with the specified [id] (see [Region.findObjects]). + */ +fun Region.findObject(position: Position, id: Int): GameObject? { + return find(position, DYNAMIC_OBJECT, STATIC_OBJECT) { it.id == id } + .firstOrNull() +} + +/** + * Finds **all** [GameObject]s with the specified [id] at the specified [position]. + */ +fun Region.findObjects(position: Position, id: Int): Sequence { + return find(position, DYNAMIC_OBJECT, STATIC_OBJECT) { it.id == id } +} + +/** + * Finds the first [GameObject]s with the specified [id] at the specified [position]. + * + * Note that the iteration order of entities in a [Region] is not defined - this function should not be used if there + * may be more than [GameObject] with the specified [id] (see [World.findObjects]). + */ +fun World.findObject(position: Position, id: Int): GameObject? { + return regionRepository.fromPosition(position).findObject(position, id) +} + +/** + * Finds **all** [GameObject]s with the specified [id] at the specified [position]. + */ +fun World.findObjects(position: Position, id: Int): Sequence { + return regionRepository.fromPosition(position).findObjects(position, id) +} + +/** + * Removes the specified [GameObject] from the world, replacing it with [replacement] object for [delay] **pulses**. + */ +fun World.replaceObject(obj: GameObject, replacement: Int, delay: Int) { + val replacementObj = DynamicGameObject.createPublic(this, replacement, obj.position, obj.type, obj.orientation) + + schedule(ExpireObjectTask(this, obj, replacementObj, delay)) +} + +/** + * A [ScheduledTask] that temporarily replaces the [existing] [GameObject] with the [replacement] [GameObject] for the + * specified [duration]. + * + * @param existing The [GameObject] that already exists and should be replaced. + * @param replacement The [GameObject] to replace the [existing] object with. + * @param duration The time, in **pulses**, for the [replacement] object to exist in the game world. + */ +private class ExpireObjectTask( + private val world: World, + private val existing: GameObject, + private val replacement: GameObject, + private val duration: Int +) : ScheduledTask(0, true) { + + private var respawning: Boolean = false + + override fun execute() { + val region = world.regionRepository.fromPosition(existing.position) + + if (!respawning) { + world.spawn(replacement) + respawning = true + setDelay(duration) + } else { + region.removeEntity(replacement) + world.spawn(existing) + stop() + } + } + +} \ No newline at end of file diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/world.kt b/game/plugin/api/src/org/apollo/game/plugin/api/world.kt deleted file mode 100644 index 36ab48592..000000000 --- a/game/plugin/api/src/org/apollo/game/plugin/api/world.kt +++ /dev/null @@ -1,63 +0,0 @@ -package org.apollo.game.plugin.api - -import org.apollo.game.model.Position -import org.apollo.game.model.World -import org.apollo.game.model.area.Region -import org.apollo.game.model.entity.Entity -import org.apollo.game.model.entity.EntityType -import org.apollo.game.model.entity.EntityType.DYNAMIC_OBJECT -import org.apollo.game.model.entity.EntityType.STATIC_OBJECT -import org.apollo.game.model.entity.obj.DynamicGameObject -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.scheduling.ScheduledTask - -fun Region.find(position: Position, predicate: (T) -> Boolean, vararg types: EntityType): Sequence { - return getEntities(position, *types).asSequence().filter(predicate) -} - -fun Region.findObjects(position: Position, id: Int): Sequence { - return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT) -} - -fun Region.findObject(position: Position, id: Int): GameObject? { - return find(position, { it.id == id }, DYNAMIC_OBJECT, STATIC_OBJECT).firstOrNull() -} - -fun World.findObject(position: Position, objectId: Int): GameObject? { - return regionRepository.fromPosition(position).findObject(position, objectId) -} - -fun World.findObjects(position: Position, id: Int): Sequence { - return regionRepository.fromPosition(position).findObjects(position, id) -} - -fun World.expireObject(obj: GameObject, replacement: Int, respawnDelay: Int) { - val replacementObj = DynamicGameObject.createPublic(this, replacement, obj.position, obj.type, obj.orientation) - - schedule(ExpireObjectTask(this, obj, replacementObj, respawnDelay)) -} - - -class ExpireObjectTask( - private val world: World, - private val existing: GameObject, - private val replacement: GameObject, - private val respawnDelay: Int -) : ScheduledTask(0, true) { - - private var respawning: Boolean = false - - override fun execute() { - val region = world.regionRepository.fromPosition(existing.position) - - if (!respawning) { - world.spawn(replacement) - respawning = true - setDelay(respawnDelay) - } else { - region.removeEntity(replacement) - world.spawn(existing) - stop() - } - } -} \ No newline at end of file diff --git a/game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt b/game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt new file mode 100644 index 000000000..43af94858 --- /dev/null +++ b/game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt @@ -0,0 +1,94 @@ +package org.apollo.game.plugin.api + +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions +import org.apollo.game.plugin.testing.junit.params.ItemDefinitionSource +import org.apollo.game.plugin.testing.junit.params.NpcDefinitionSource +import org.apollo.game.plugin.testing.junit.params.ObjectDefinitionSource +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest + +@ExtendWith(ApolloTestingExtension::class) +class DefinitionsTests { + + @Test + fun `can find an ItemDefinition directly using its id`() { + val searched = Definitions.item(0) + assertEquals(items.first().id, searched.id) + } + + @Test + fun `can find an ItemDefinition using its name`() { + val searched = Definitions.item("item_two") + assertEquals(items[2].id, searched?.id) + } + + @ParameterizedTest + @ItemDefinitionSource + fun `can find ItemDefinitions directly using id suffixing`(item: ItemDefinition) { + val searched = Definitions.item("${item.name}_${item.id}") + assertEquals(item.id, searched?.id) + } + + @Test + fun `can find an NpcDefinition directly using its id`() { + val searched = Definitions.npc(0) + assertEquals(npcs.first().id, searched.id) + } + + @Test + fun `can find an NpcDefinition using its name`() { + val searched = Definitions.npc("npc_two") + assertEquals(items[2].id, searched?.id) + } + + @ParameterizedTest + @NpcDefinitionSource + fun `can find NpcDefinitions directly using id suffixing`(npc: NpcDefinition) { + val searched = Definitions.npc("${npc.name}_${npc.id}") + assertEquals(npc.id, searched?.id) + } + + @Test + fun `can find an ObjectDefinition directly using its id`() { + val searched = Definitions.obj(0) + assertEquals(objs.first().id, searched.id) + } + + @Test + fun `can find an ObjectDefinition using its name`() { + val searched = Definitions.obj("obj_two") + assertEquals(items[2].id, searched?.id) + } + + @ParameterizedTest + @ObjectDefinitionSource + fun `can find ObjectDefinitions directly using id suffixing`(obj: ObjectDefinition) { + val searched = Definitions.obj("${obj.name}_${obj.id}") + assertEquals(obj.id, searched?.id) + } + + private companion object { + + @ItemDefinitions + val items = listOf("item zero", "item one", "item two", "item duplicate name", "item duplicate name") + .mapIndexed { id, name -> ItemDefinition(id).also { it.name = name } } + + @NpcDefinitions + val npcs = listOf("npc zero", "npc one", "npc two", "npc duplicate name", "npc duplicate name") + .mapIndexed { id, name -> NpcDefinition(id).also { it.name = name } } + + @ObjectDefinitions + val objs = listOf("obj zero", "obj one", "obj two", "obj duplicate name", "obj duplicate name") + .mapIndexed { id, name -> ObjectDefinition(id).also { it.name = name } } + + } + +} \ No newline at end of file diff --git a/game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt b/game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt new file mode 100644 index 000000000..a1b1f3b78 --- /dev/null +++ b/game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt @@ -0,0 +1,123 @@ +package org.apollo.game.plugin.api + +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class PlayerTests { + + @TestMock + lateinit var player: Player + + @BeforeEach + fun setHitpointsLevel() { + player.skillSet.setSkill(Skill.HITPOINTS, Skill(1_154.0, 10, 10)) + } + + @Test + fun `can boost skill above maximum level`() { + player.apply { + hitpoints.boost(5) + + assertEquals(15, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `boosts to the same skill do not accumulate`() { + player.apply { + hitpoints.boost(5) + hitpoints.boost(4) + + assertEquals(15, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `greater boosts can override earlier boosts`() { + player.apply { + hitpoints.boost(5) + hitpoints.boost(7) + + assertEquals(17, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `can drain skills`() { + player.apply { + hitpoints.drain(5) + + assertEquals(5, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `repeated drains on the same skill accumulate`() { + player.apply { + hitpoints.drain(4) + hitpoints.drain(5) + + assertEquals(1, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `cannot drain skills below zero`() { + player.apply { + hitpoints.drain(99) + + assertEquals(0, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `can restore previously-drained skills`() { + player.skillSet.setCurrentLevel(Skill.HITPOINTS, 1) + + player.apply { + hitpoints.restore(5) + + assertEquals(6, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `repeated restores on the same skill accumulate`() { + player.skillSet.setCurrentLevel(Skill.HITPOINTS, 1) + + player.apply { + hitpoints.restore(3) + hitpoints.restore(4) + + assertEquals(8, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + + @Test + fun `cannot restore skills above their maximum level`() { + player.skillSet.setCurrentLevel(Skill.HITPOINTS, 1) + + player.apply { + hitpoints.restore(99) + + assertEquals(10, hitpoints.current) + assertEquals(10, hitpoints.maximum) + } + } + +} \ No newline at end of file diff --git a/game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt b/game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt new file mode 100644 index 000000000..452d2f00a --- /dev/null +++ b/game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt @@ -0,0 +1,26 @@ +package org.apollo.game.plugin.api + +import org.apollo.game.model.Position +import org.apollo.game.plugin.api.Position.component1 +import org.apollo.game.plugin.api.Position.component2 +import org.apollo.game.plugin.api.Position.component3 +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class PositionTests { + + @Test + fun `Positions are destructured in the correct order`() { + val x = 10 + val y = 20 + val z = 1 + + val position = Position(x, y, z) + val (x2, y2, z2) = position + + assertEquals(x, x2) { "x coordinate mismatch in Position destructuring." } + assertEquals(y, y2) { "y coordinate mismatch in Position destructuring." } + assertEquals(z, z2) { "z coordinate mismatch in Position destructuring." } + } + +} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/fishing.kt b/game/plugin/skills/fishing/src/fishing.kt index 807ac994d..ccf584556 100644 --- a/game/plugin/skills/fishing/src/fishing.kt +++ b/game/plugin/skills/fishing/src/fishing.kt @@ -28,9 +28,9 @@ enum class Fish(val id: Int, val level: Int, val experience: Double, catchSuffix /** * The name of this fish, formatted so it can be inserted into a message. */ - val catchMessage = "You catch ${catchSuffix ?: "a ${catchName()}."}" + val catchMessage by lazy { "You catch ${catchSuffix ?: "a ${catchName()}."}" } - private fun catchName() = Definitions.item(id)!!.name.toLowerCase().removePrefix("raw ") + private fun catchName() = Definitions.item(id).name.toLowerCase().removePrefix("raw ") } @@ -59,7 +59,7 @@ enum class FishingTool( /** * The name of this tool, formatted so it can be inserted into a message. */ - val formattedName = Definitions.item(id)!!.name.toLowerCase() + val formattedName by lazy { Definitions.item(id).name.toLowerCase() } } diff --git a/game/plugin/skills/mining/src/mining.kt b/game/plugin/skills/mining/src/mining.kt index c98dd8a80..c3b773f23 100644 --- a/game/plugin/skills/mining/src/mining.kt +++ b/game/plugin/skills/mining/src/mining.kt @@ -94,7 +94,7 @@ data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) fun deplete(world: World) { val obj = world.findObject(position, objectId)!! - world.expireObject(obj, ore.objects[objectId]!!, ore.respawn) + world.replaceObject(obj, ore.objects[objectId]!!, ore.respawn) } /** @@ -113,7 +113,7 @@ data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) /** * Get the normalized name of the [Ore] represented by this target. */ - fun oreName() = Definitions.item(ore.id)!!.name.toLowerCase() + fun oreName() = Definitions.item(ore.id).name.toLowerCase() /** * Reward a [player] with experience and ore if they have the inventory capacity to take a new ore. diff --git a/game/plugin/skills/mining/test/MiningActionTests.kt b/game/plugin/skills/mining/test/MiningActionTests.kt index f9fe0319b..2bd964f5b 100644 --- a/game/plugin/skills/mining/test/MiningActionTests.kt +++ b/game/plugin/skills/mining/test/MiningActionTests.kt @@ -7,7 +7,7 @@ import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill -import org.apollo.game.plugin.api.expireObject +import org.apollo.game.plugin.api.replaceObject import org.apollo.game.plugin.skills.mining.Ore import org.apollo.game.plugin.skills.mining.Pickaxe import org.apollo.game.plugin.skills.mining.TIN_OBJECTS @@ -59,7 +59,7 @@ class MiningActionTests { every { target.skillRequirementsMet(player) } returns true every { target.isSuccessful(player, any()) } returns true - every { world.expireObject(obj, any(), any()) } answers { } + every { world.replaceObject(obj, any(), any()) } answers { } player.skillSet.setCurrentLevel(Skill.MINING, Ore.TIN.level) player.startAction(MiningAction(player, Pickaxe.BRONZE, target)) @@ -70,7 +70,7 @@ class MiningActionTests { after(action.complete()) { verify { player.sendMessage("You manage to mine some ") } - verify { world.expireObject(obj, expiredTinId, Ore.TIN.respawn) } + verify { world.replaceObject(obj, expiredTinId, Ore.TIN.respawn) } assertTrue(player.inventory.contains(Ore.TIN.id)) assertEquals(player.skillSet.getExperience(Skill.MINING), Ore.TIN.exp) diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts index bdb0b0328..2966914ed 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -88,7 +88,7 @@ class WoodcuttingAction( val obj = target.getObject(mob.world) ?: stop() if (mob.inventory.add(target.tree.id)) { - val logName = Definitions.item(target.tree.id)!!.name.toLowerCase() + val logName = Definitions.item(target.tree.id).name.toLowerCase() mob.sendMessage("You managed to cut some $logName.") mob.woodcutting.experience += target.tree.exp } @@ -97,7 +97,7 @@ class WoodcuttingAction( // respawn time: http://runescape.wikia.com/wiki/Trees val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY - mob.world.expireObject(obj, target.tree.stump, respawn.toInt()) + mob.world.replaceObject(obj, target.tree.stump, respawn.toInt()) stop() } } From 4af28a171770d55ade327d65888c37cb7e92f3e9 Mon Sep 17 00:00:00 2001 From: Major- Date: Sat, 25 Aug 2018 18:16:53 +0100 Subject: [PATCH 158/209] Add tests for spawn plugin --- .../apollo/game/plugin/entity/spawn/Spawn.kt} | 4 + .../game/plugin/entity/spawn/Spawn.plugin.kts | 20 +++ game/plugin/entity/spawn/src/spawn.plugin.kts | 19 --- .../game/plugin/entity/spawn/SpawnTests.kt | 143 ++++++++++++++++++ 4 files changed, 167 insertions(+), 19 deletions(-) rename game/plugin/entity/spawn/src/{spawn.kt => org/apollo/game/plugin/entity/spawn/Spawn.kt} (80%) create mode 100644 game/plugin/entity/spawn/src/org/apollo/game/plugin/entity/spawn/Spawn.plugin.kts delete mode 100644 game/plugin/entity/spawn/src/spawn.plugin.kts create mode 100644 game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt diff --git a/game/plugin/entity/spawn/src/spawn.kt b/game/plugin/entity/spawn/src/org/apollo/game/plugin/entity/spawn/Spawn.kt similarity index 80% rename from game/plugin/entity/spawn/src/spawn.kt rename to game/plugin/entity/spawn/src/org/apollo/game/plugin/entity/spawn/Spawn.kt index f70c9a285..3e7732691 100644 --- a/game/plugin/entity/spawn/src/spawn.kt +++ b/game/plugin/entity/spawn/src/org/apollo/game/plugin/entity/spawn/Spawn.kt @@ -9,6 +9,10 @@ fun spawnNpc(name: String, x: Int, y: Int, z: Int = 0, id: Int? = null, facing: Spawns.list += Spawn(id, name, Position(x, y, z), facing) } +fun spawnNpc(name: String, position: Position, id: Int? = null, facing: Direction = Direction.NORTH) { + Spawns.list += Spawn(id, name, position, facing) +} + internal data class Spawn( val id: Int?, val name: String, diff --git a/game/plugin/entity/spawn/src/org/apollo/game/plugin/entity/spawn/Spawn.plugin.kts b/game/plugin/entity/spawn/src/org/apollo/game/plugin/entity/spawn/Spawn.plugin.kts new file mode 100644 index 000000000..7d9fb4ce8 --- /dev/null +++ b/game/plugin/entity/spawn/src/org/apollo/game/plugin/entity/spawn/Spawn.plugin.kts @@ -0,0 +1,20 @@ +package org.apollo.game.plugin.entity.spawn + +import org.apollo.game.model.entity.Npc +import org.apollo.game.plugin.api.Definitions + +start { world -> + for ((id, name, position, facing, animation, graphic) in Spawns.list) { + val definition = requireNotNull(id?.let(Definitions::npc) ?: Definitions.npc(name)) { + "Could not find an Npc named $name to spawn." + } + + val npc = Npc(world, definition.id, position).apply { + turnTo(position.step(1, facing)) + animation?.let(::playAnimation) + graphic?.let(::playGraphic) + } + + world.register(npc) + } +} diff --git a/game/plugin/entity/spawn/src/spawn.plugin.kts b/game/plugin/entity/spawn/src/spawn.plugin.kts deleted file mode 100644 index 87e3bb51c..000000000 --- a/game/plugin/entity/spawn/src/spawn.plugin.kts +++ /dev/null @@ -1,19 +0,0 @@ - -import org.apollo.game.model.entity.Npc -import org.apollo.game.plugin.api.Definitions -import org.apollo.game.plugin.entity.spawn.Spawns - -start { world -> - Spawns.list.forEach { spawn -> - val definition = spawn.id?.let(Definitions::npc) ?: Definitions.npc(spawn.name) - ?: throw IllegalArgumentException("Invalid NPC name or ID ${spawn.name}, ${spawn.id}") - - val npc = Npc(world, definition.id, spawn.position) - npc.turnTo(spawn.position.step(1, spawn.facing)) - - spawn.spawnAnimation?.let(npc::playAnimation) - spawn.spawnGraphic?.let(npc::playGraphic) - - world.register(npc) - } -} diff --git a/game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt b/game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt new file mode 100644 index 000000000..9e434b296 --- /dev/null +++ b/game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt @@ -0,0 +1,143 @@ +package org.apollo.game.plugin.entity.spawn + +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.model.* +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource + +@ExtendWith(ApolloTestingExtension::class) +class SpawnTests { + + @TestMock + lateinit var world: World + + @BeforeEach + fun addNewNpcs() { + var previousSize: Int + + do { + previousSize = world.npcRepository.size() + world.pulse() + } while (previousSize != world.npcRepository.size()) + } + + @MethodSource("npcs spawned by id") + @ParameterizedTest(name = "spawning {1} at {2} (id = {0})") + fun `spawned npcs are in the correct position`(id: Int, name: String, spawn: Position) { + val npc = world.npcRepository.find { it.id == id } + + assertEquals(spawn, npc?.position) { "Failed to find npc $name with id $id." } + } + + @MethodSource("npcs spawned by id with directions") + @ParameterizedTest(name = "spawning {1} with direction {3} (id = {0})") + fun `spawned npcs are facing the correct direction`(id: Int, name: String, spawn: Position, direction: Direction) { + val npc = requireNotNull(world.npcRepository.find { it.id == id }) { "Failed to find npc $name with id $id." } + val facing = spawn.step(1, direction) + + assertEquals(facing, npc.facingPosition) + } + + @Disabled("Currently no way to test if the animation was played") + @MethodSource("npcs spawned by id with animations") + @ParameterizedTest(name = "spawning {1} with animation {3} (id = {0})") + fun `spawned npcs are playing the correct animation`(id: Int, name: String, spawn: Position, animation: Animation) { + val npc = requireNotNull(world.npcRepository.find { it.id == id }) { "Failed to find npc $name with id $id." } + + TODO("How to verify that npc.playAnimation was called with $animation.") + } + + @Disabled("Currently no way to test if the graphic was played") + @MethodSource("npcs spawned by id with graphics") + @ParameterizedTest(name = "spawning {1} with graphic {3} (id = {0})") + fun `spawned npcs are playing the correct graphic`(id: Int, name: String, spawn: Position, graphic: Graphic) { + val npc = requireNotNull(world.npcRepository.find { it.id == id }) { "Failed to find npc $name with id $id." } + + TODO("How to verify that npc.playGraphic was called with $graphic.") + } + + @MethodSource("npcs spawned by name") + @ParameterizedTest(name = "spawning {0}") + fun `spawns are looked up by name if the id is unspecified`(name: String) { + val npc = world.npcRepository.find { it.definition.name === name }!! + val expectedId = name.substringAfterLast("_").toInt() + + assertEquals(expectedId, npc.id) + } + + companion object { + + // This test class has multiple (hidden) order dependencies because of the nature of the spawn + // plugin, where npcs are inserted into the world immediately after world initialisation. + // + // All npcs that should be spawned by the test must be passed to `spawnNpc` _before_ the test world + // is created by the ApolloTestingExtension - which means they must be done inside the initialisation + // block of this companion object. + // + // When npcs are created, however, they look up their NpcDefinition - so all of the definitions must + // be created (via `@NpcDefinitions`) before the initialisation block is executed. + // + // The world must also be pulsed after the spawn plugin executes, so that npcs are registered (i.e. moved + // out of the queue). + + @JvmStatic + fun `npcs spawned by id`(): List { + return npcs.filterNot { it.id == null } + .map { (id, name, position) -> Arguments.of(id, name, position) } + } + + @JvmStatic + fun `npcs spawned by id with directions`(): List { + return npcs.filterNot { it.id == null } + .map { (id, name, position, direction) -> Arguments.of(id, name, position, direction) } + } + + @JvmStatic + fun `npcs spawned by id with animations`(): List { + return npcs.filterNot { it.id == null } + .map { (id, name, position, _, animation) -> Arguments.of(id, name, position, animation) } + } + + @JvmStatic + fun `npcs spawned by id with graphics`(): List { + return npcs.filterNot { it.id == null } + .map { (id, name, position, _, _, graphic) -> Arguments.of(id, name, position, graphic) } + } + + @JvmStatic + fun `npcs spawned by name`(): List { + return npcs.filter { it.id == null } + .map { (_, name) -> Arguments.of(name) } + } + + private val npcs = listOf( + Spawn(0, "hans", Position(1000, 1000, 0), facing = Direction.NORTH, spawnAnimation = Animation(10, 100)), + Spawn(1, "man", Position(1000, 1000, 0), facing = Direction.NORTH, spawnGraphic = Graphic(154, 0, 100)), + Spawn(null, "man_2", Position(1000, 1000, 2), facing = Direction.NORTH), + Spawn(null, "man_3", Position(1000, 1000, 3), facing = Direction.SOUTH), + Spawn(6, "fakename123", Position(1500, 1500, 3), facing = Direction.EAST, spawnAnimation = Animation(112)), + Spawn(12, "fakename123", Position(1500, 1500, 3), facing = Direction.WEST, spawnGraphic = Graphic(964)) + ) + + @NpcDefinitions + val definitions = npcs.map { (id, name) -> + val definitionId = id ?: name.substringAfterLast("_").toInt() + NpcDefinition(definitionId).also { it.name = name } + } + + init { // Must come after NpcDef initialisation, before mocked World initialisation + for ((id, name, position, direction) in npcs) { + spawnNpc(name, position.x, position.y, position.height, id, direction) + } + } + } + +} From b6c21029d4cb56febc13f8e40fd5718403c3e360 Mon Sep 17 00:00:00 2001 From: Major Date: Sun, 26 Aug 2018 00:44:48 +0100 Subject: [PATCH 159/209] Add tests for fishing plugin --- .../skills/fishing/src/fishing.plugin.kts | 128 ------------------ .../apollo/game/plugin/skills/fishing/Fish.kt | 31 +++++ .../plugin/skills/fishing/Fishing.plugin.kts | 20 +++ .../plugin/skills/fishing/FishingAction.kt | 88 ++++++++++++ .../plugin/skills/fishing/FishingSpot.kt} | 90 ++++-------- .../plugin/skills/fishing/FishingTarget.kt | 39 ++++++ .../game/plugin/skills/fishing/FishingTool.kt | 33 +++++ .../plugin/skills/fishing/Spots.plugin.kts} | 5 +- .../skills/fishing/FishingActionTests.kt | 93 +++++++++++++ 9 files changed, 331 insertions(+), 196 deletions(-) delete mode 100644 game/plugin/skills/fishing/src/fishing.plugin.kts create mode 100644 game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt create mode 100644 game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fishing.plugin.kts create mode 100644 game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt rename game/plugin/skills/fishing/src/{fishing.kt => org/apollo/game/plugin/skills/fishing/FishingSpot.kt} (51%) create mode 100644 game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt create mode 100644 game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt rename game/plugin/skills/fishing/src/{spots.plugin.kts => org/apollo/game/plugin/skills/fishing/Spots.plugin.kts} (96%) create mode 100644 game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt diff --git a/game/plugin/skills/fishing/src/fishing.plugin.kts b/game/plugin/skills/fishing/src/fishing.plugin.kts deleted file mode 100644 index 250545647..000000000 --- a/game/plugin/skills/fishing/src/fishing.plugin.kts +++ /dev/null @@ -1,128 +0,0 @@ - -import Fishing_plugin.FishingAction -import org.apollo.game.action.ActionBlock -import org.apollo.game.action.AsyncDistancedAction -import org.apollo.game.message.impl.NpcActionMessage -import org.apollo.game.model.Position -import org.apollo.game.model.entity.Player -import org.apollo.game.plugin.api.fishing -import org.apollo.game.plugin.api.rand -import org.apollo.game.plugin.skills.fishing.FishingSpot -import org.apollo.game.plugin.skills.fishing.FishingTool -import java.util.Objects - -// TODO: moving fishing spots, seaweed and caskets, evil bob - -/** - * Intercepts the [NpcActionMessage] and starts a [FishingAction] if the npc - */ -on { NpcActionMessage::class } - .where { option == 1 || option == 3 } - .then { player -> - val entity = player.world.npcRepository[index] - val spot = FishingSpot.lookup(entity.id) ?: return@then - - val option = spot.option(option) - player.startAction(FishingAction(player, entity.position, option)) - - terminate() - } - -class FishingAction(player: Player, position: Position, val option: FishingSpot.Option) : - AsyncDistancedAction(0, true, player, position, SPOT_DISTANCE) { - - /** - * The [FishingTool] used for the fishing spot. - */ - private val tool = option.tool - - override fun action(): ActionBlock = { - if (!verify()) { - stop() - } - - mob.turnTo(position) - mob.sendMessage(tool.message) - - while (isRunning) { - mob.playAnimation(tool.animation) - wait(FISHING_DELAY) - - val level = mob.fishing.current - val fish = option.sample(level) - - if (successfulCatch(level, fish.level)) { - if (tool.bait != -1) { - mob.inventory.remove(tool.bait) - } - - mob.inventory.add(fish.id) - mob.sendMessage(fish.catchMessage) - mob.fishing.experience += fish.experience - - if (mob.inventory.freeSlots() == 0) { - mob.inventory.forceCapacityExceeded() - - mob.stopAnimation() - stop() - } else if (!hasBait(mob, tool.bait)) { - mob.sendMessage("You need more ${tool.baitName} to fish at this spot.") - - mob.stopAnimation() - stop() - } - } - } - } - - /** - * Verifies that the player can gather fish from the [FishingSpot] they clicked. - */ - private fun verify(): Boolean { - val current = mob.fishing.current - - when { - current < option.level -> mob.sendMessage("You need a fishing level of ${option.level} to fish at this spot.") - !hasTool(mob, tool) -> mob.sendMessage("You need a ${tool.formattedName} to fish at this spot.") - !hasBait(mob, tool.bait) -> mob.sendMessage("You need some ${tool.baitName} to fish at this spot.") - mob.inventory.freeSlots() == 0 -> mob.inventory.forceCapacityExceeded() - else -> return true - } - - return false - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as FishingAction - return option == other.option && position == other.position && mob == other.mob - } - - override fun hashCode(): Int = Objects.hash(option, position, mob) - - private companion object { - private const val SPOT_DISTANCE = 1 - private const val FISHING_DELAY = 4 - - /** - * Returns whether or not the catch was successful. - * TODO: We need to identify the correct algorithm for this - */ - private fun successfulCatch(level: Int, req: Int): Boolean = minOf(level - req + 5, 40) > rand(100) - - /** - * Returns whether or not the [Player] has (or does not need) bait. - */ - private fun hasBait(player: Player, bait: Int): Boolean = bait == -1 || player.inventory.contains(bait) - - /** - * Returns whether or not the player has the required tool to fish at the spot. - */ - private fun hasTool(player: Player, tool: FishingTool): Boolean = player.equipment.contains(tool.id) || - player.inventory.contains(tool.id) - - } - -} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt new file mode 100644 index 000000000..1a281943f --- /dev/null +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt @@ -0,0 +1,31 @@ +package org.apollo.game.plugin.skills.fishing + +import org.apollo.game.plugin.api.Definitions + +/** + * A fish that can be gathered using the fishing skill. + */ +enum class Fish(val id: Int, val level: Int, val experience: Double, catchSuffix: String? = null) { + SHRIMPS(id = 317, level = 1, experience = 10.0, catchSuffix = "some shrimp."), + SARDINE(id = 327, level = 5, experience = 20.0), + MACKEREL(id = 353, level = 16, experience = 20.0), + HERRING(id = 345, level = 10, experience = 30.0), + ANCHOVIES(id = 321, level = 15, experience = 40.0, catchSuffix = "some anchovies."), + TROUT(id = 335, level = 20, experience = 50.0), + COD(id = 341, level = 23, experience = 45.0), + PIKE(id = 349, level = 25, experience = 60.0), + SALMON(id = 331, level = 30, experience = 70.0), + TUNA(id = 359, level = 35, experience = 80.0), + LOBSTER(id = 377, level = 40, experience = 90.0), + BASS(id = 363, level = 46, experience = 100.0), + SWORDFISH(id = 371, level = 50, experience = 100.0), + SHARK(id = 383, level = 76, experience = 110.0, catchSuffix = "a shark!"); + + /** + * The name of this fish, formatted so it can be inserted into a message. + */ + val catchMessage by lazy { "You catch ${catchSuffix ?: "a $catchName."}" } + + private val catchName by lazy { Definitions.item(id).name.toLowerCase().removePrefix("raw ") } + +} diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fishing.plugin.kts b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fishing.plugin.kts new file mode 100644 index 000000000..597058bbe --- /dev/null +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fishing.plugin.kts @@ -0,0 +1,20 @@ +package org.apollo.game.plugin.skills.fishing + +import org.apollo.game.message.impl.NpcActionMessage + +// TODO: moving fishing spots, seaweed and caskets, evil bob + +/** + * Intercepts the [NpcActionMessage] and starts a [FishingAction] if the npc + */ +on { NpcActionMessage::class } + .where { option == 1 || option == 3 } + .then { player -> + val entity = player.world.npcRepository[index] + val option = FishingSpot.lookup(entity.id)?.option(option) ?: return@then + + val target = FishingTarget(entity.position, option) + player.startAction(FishingAction(player, target)) + + terminate() + } diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt new file mode 100644 index 000000000..a02412e7a --- /dev/null +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt @@ -0,0 +1,88 @@ +package org.apollo.game.plugin.skills.fishing + +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.fishing +import java.util.Objects + +class FishingAction( + player: Player, + private val target: FishingTarget +) : AsyncDistancedAction(0, true, player, target.position, SPOT_DISTANCE) { + + /** + * The [FishingTool] used for the fishing spot. + */ + private val tool = target.option.tool + + override fun action(): ActionBlock = { + if (!target.verify(mob)) { + stop() + } + + mob.turnTo(position) + mob.sendMessage(tool.message) + + while (isRunning) { + mob.playAnimation(tool.animation) + wait(FISHING_DELAY) + + val level = mob.fishing.current + val fish = target.option.sample(level) + + if (target.isSuccessful(mob, fish.level)) { + if (tool.bait != -1) { + mob.inventory.remove(tool.bait) + } + + mob.inventory.add(fish.id) + mob.sendMessage(fish.catchMessage) + mob.fishing.experience += fish.experience + + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + + mob.stopAnimation() + stop() + } else if (!hasBait(mob, tool.bait)) { + mob.sendMessage("You need more ${tool.baitName} to fish at this spot.") + + mob.stopAnimation() + stop() + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (other is FishingAction) { + return position == other.position && target == other.target && mob == other.mob + } + + return false + } + + override fun hashCode(): Int = Objects.hash(target, position, mob) + + internal companion object { + private const val SPOT_DISTANCE = 1 + private const val FISHING_DELAY = 4 + + /** + * Returns whether or not the [Player] has (or does not need) bait. + */ + internal fun hasBait(player: Player, bait: Int): Boolean { + return bait == -1 || bait in player.inventory + } + + /** + * Returns whether or not the player has the required tool to fish at the spot. + */ + internal fun hasTool(player: Player, tool: FishingTool): Boolean { + return tool.id in player.equipment || tool.id in player.inventory + } + + } + +} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/fishing.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingSpot.kt similarity index 51% rename from game/plugin/skills/fishing/src/fishing.kt rename to game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingSpot.kt index ccf584556..54a542985 100644 --- a/game/plugin/skills/fishing/src/fishing.kt +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingSpot.kt @@ -1,76 +1,36 @@ package org.apollo.game.plugin.skills.fishing -import org.apollo.game.model.Animation -import org.apollo.game.plugin.api.Definitions import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.skills.fishing.Fish.* -import org.apollo.game.plugin.skills.fishing.FishingTool.* - -/** - * A fish that can be gathered using the fishing skill. - */ -enum class Fish(val id: Int, val level: Int, val experience: Double, catchSuffix: String? = null) { - SHRIMPS(id = 317, level = 1, experience = 10.0, catchSuffix = "some shrimp."), - SARDINE(id = 327, level = 5, experience = 20.0), - MACKEREL(id = 353, level = 16, experience = 20.0), - HERRING(id = 345, level = 10, experience = 30.0), - ANCHOVIES(id = 321, level = 15, experience = 40.0, catchSuffix = "some anchovies."), - TROUT(id = 335, level = 20, experience = 50.0), - COD(id = 341, level = 23, experience = 45.0), - PIKE(id = 349, level = 25, experience = 60.0), - SALMON(id = 331, level = 30, experience = 70.0), - TUNA(id = 359, level = 35, experience = 80.0), - LOBSTER(id = 377, level = 40, experience = 90.0), - BASS(id = 363, level = 46, experience = 100.0), - SWORDFISH(id = 371, level = 50, experience = 100.0), - SHARK(id = 383, level = 76, experience = 110.0, catchSuffix = "a shark!"); - - /** - * The name of this fish, formatted so it can be inserted into a message. - */ - val catchMessage by lazy { "You catch ${catchSuffix ?: "a ${catchName()}."}" } - - private fun catchName() = Definitions.item(id).name.toLowerCase().removePrefix("raw ") - -} - -/** - * A tool used to gather [Fish] from a [FishingSpot]. - */ -enum class FishingTool( - val message: String, - val id: Int, - animation: Int, - val bait: Int = -1, - val baitName: String? = null -) { - LOBSTER_CAGE("You attempt to catch a lobster...", id = 301, animation = 619), - SMALL_NET("You cast out your net...", id = 303, animation = 620), - BIG_NET("You cast out your net...", id = 305, animation = 620), - HARPOON("You start harpooning fish...", id = 311, animation = 618), - FISHING_ROD("You attempt to catch a fish...", id = 307, animation = 622, bait = 313, baitName = "feathers"), - FLY_FISHING_ROD("You attempt to catch a fish...", id = 309, animation = 622, bait = 314, baitName = "fishing bait"); - - /** - * The [Animation] played when fishing with this tool. - */ - val animation: Animation = Animation(animation) - - /** - * The name of this tool, formatted so it can be inserted into a message. - */ - val formattedName by lazy { Definitions.item(id).name.toLowerCase() } - -} /** * A spot that can be fished from. */ enum class FishingSpot(val npc: Int, private val first: Option, private val second: Option) { - ROD(309, Option.of(FLY_FISHING_ROD, TROUT, SALMON), Option.of(FISHING_ROD, PIKE)), - CAGE_HARPOON(312, Option.of(LOBSTER_CAGE, LOBSTER), Option.of(HARPOON, TUNA, SWORDFISH)), - NET_HARPOON(313, Option.of(BIG_NET, MACKEREL, COD), Option.of(HARPOON, BASS, SHARK)), - NET_ROD(316, Option.of(SMALL_NET, SHRIMPS, ANCHOVIES), Option.of(FISHING_ROD, SARDINE, HERRING)); + + ROD( + npc = 309, + first = Option.of(tool = FishingTool.FLY_FISHING_ROD, primary = TROUT, secondary = SALMON), + second = Option.of(tool = FishingTool.FISHING_ROD, primary = PIKE) + ), + + CAGE_HARPOON( + npc = 312, + first = Option.of(tool = FishingTool.LOBSTER_CAGE, primary = LOBSTER), + second = Option.of(tool = FishingTool.HARPOON, primary = TUNA, secondary = SWORDFISH) + ), + + NET_HARPOON( + npc = 313, + first = Option.of(tool = FishingTool.BIG_NET, primary = MACKEREL, secondary = COD), + second = Option.of(tool = FishingTool.HARPOON, primary = BASS, secondary = SHARK) + ), + + NET_ROD( + npc = 316, + first = Option.of(tool = FishingTool.SMALL_NET, primary = SHRIMPS, secondary = ANCHOVIES), + second = Option.of(tool = FishingTool.FISHING_ROD, primary = SARDINE, secondary = HERRING) + ); /** * Returns the [FishingSpot.Option] associated with the specified action id. @@ -160,4 +120,4 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco fun lookup(id: Int): FishingSpot? = FISHING_SPOTS[id] } -} +} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt new file mode 100644 index 000000000..7275ee638 --- /dev/null +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt @@ -0,0 +1,39 @@ +package org.apollo.game.plugin.skills.fishing + +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.fishing +import org.apollo.game.plugin.api.rand +import org.apollo.game.plugin.skills.fishing.FishingAction.Companion.hasBait +import org.apollo.game.plugin.skills.fishing.FishingAction.Companion.hasTool + +data class FishingTarget(val position: Position, val option: FishingSpot.Option) { + + /** + * Returns whether or not the catch was successful. + * TODO: We need to identify the correct algorithm for this + */ + fun isSuccessful(player: Player, req: Int): Boolean { + return minOf(player.fishing.current - req + 5, 40) > rand(100) + } + + /** + * Verifies that the [Player] can gather fish from their chosen [FishingSpot.Option]. + */ + fun verify(player: Player): Boolean { + val current = player.fishing.current + val required = option.level + val tool = option.tool + + when { + current < required -> player.sendMessage("You need a fishing level of $required to fish at this spot.") + hasTool(player, tool) -> player.sendMessage("You need a ${tool.formattedName} to fish at this spot.") + hasBait(player, tool.bait) -> player.sendMessage("You need some ${tool.baitName} to fish at this spot.") + player.inventory.freeSlots() == 0 -> player.inventory.forceCapacityExceeded() + else -> return true + } + + return false + } + +} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt new file mode 100644 index 000000000..41f639d0b --- /dev/null +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt @@ -0,0 +1,33 @@ +package org.apollo.game.plugin.skills.fishing + +import org.apollo.game.model.Animation +import org.apollo.game.plugin.api.Definitions + +/** + * A tool used to gather [Fish] from a [FishingSpot]. + */ +enum class FishingTool( + val message: String, + val id: Int, + animation: Int, + val bait: Int = -1, + val baitName: String? = null +) { + LOBSTER_CAGE("You attempt to catch a lobster...", id = 301, animation = 619), + SMALL_NET("You cast out your net...", id = 303, animation = 620), + BIG_NET("You cast out your net...", id = 305, animation = 620), + HARPOON("You start harpooning fish...", id = 311, animation = 618), + FISHING_ROD("You attempt to catch a fish...", id = 307, animation = 622, bait = 313, baitName = "feathers"), + FLY_FISHING_ROD("You attempt to catch a fish...", id = 309, animation = 622, bait = 314, baitName = "fishing bait"); + + /** + * The [Animation] played when fishing with this tool. + */ + val animation: Animation = Animation(animation) + + /** + * The name of this tool, formatted so it can be inserted into a message. + */ + val formattedName by lazy { Definitions.item(id).name.toLowerCase() } + +} \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/spots.plugin.kts b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Spots.plugin.kts similarity index 96% rename from game/plugin/skills/fishing/src/spots.plugin.kts rename to game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Spots.plugin.kts index e874ad859..3d162459a 100644 --- a/game/plugin/skills/fishing/src/spots.plugin.kts +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Spots.plugin.kts @@ -1,7 +1,6 @@ -import org.apollo.game.model.Direction +package org.apollo.game.plugin.skills.fishing import org.apollo.game.model.Position import org.apollo.game.plugin.entity.spawn.spawnNpc -import org.apollo.game.plugin.skills.fishing.FishingSpot import org.apollo.game.plugin.skills.fishing.FishingSpot.CAGE_HARPOON import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_HARPOON import org.apollo.game.plugin.skills.fishing.FishingSpot.NET_ROD @@ -177,5 +176,5 @@ NET_ROD at Position(3103, 3092) * Registers the [FishingSpot] at the specified position. */ infix fun FishingSpot.at(position: Position) { - spawnNpc("", position.x, position.y, position.height, id = npc, facing = Direction.NORTH) + spawnNpc("", position, id = npc) } \ No newline at end of file diff --git a/game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt b/game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt new file mode 100644 index 000000000..10f90abb9 --- /dev/null +++ b/game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt @@ -0,0 +1,93 @@ +package org.apollo.game.plugin.skills.fishing + +import io.mockk.every +import io.mockk.spyk +import io.mockk.verify +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.contains +import org.apollo.game.plugin.testing.assertions.startsWith +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.apollo.game.plugin.testing.junit.api.interactions.spawnNpc +import org.apollo.game.plugin.testing.junit.api.interactions.spawnObject +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class FishingActionTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + @Test + fun `Attempting to fish at a spot we don't have the skill to should send the player a message`() { + val obj = world.spawnObject(1, player.position) + + val option = spyk(FishingSpot.CAGE_HARPOON.option(1)) + val target = FishingTarget(obj.position, option) + + player.startAction(FishingAction(player, target)) + + every { option.level } returns Int.MAX_VALUE + + verifyAfter(action.complete()) { + player.sendMessage(contains("need a fishing level of ${Int.MAX_VALUE}")) + } + } + + @Test + fun `Fishing at a spot we have the skill to should eventually reward fish and experience`() { + val option = spyk(FishingSpot.CAGE_HARPOON.option(1)) + val obj = world.spawnNpc(FishingSpot.CAGE_HARPOON.npc, player.position) + + val target = spyk(FishingTarget(obj.position, option)) + every { target.isSuccessful(player, any()) } returns true + every { target.verify(player) } returns true + + player.skillSet.setCurrentLevel(Skill.FISHING, option.level) + player.startAction(FishingAction(player, target)) + + verifyAfter(action.ticks(1)) { + player.sendMessage(startsWith("You attempt to catch a lobster")) + } + + after(action.ticks(4)) { + verify { player.sendMessage(startsWith("You catch a .")) } + + assertTrue(player.inventory.contains(Fish.LOBSTER.id)) + assertEquals(player.skillSet.getExperience(Skill.FISHING), Fish.LOBSTER.experience) + } + } + + private companion object { + @ItemDefinitions + private val fish = Fish.values() + .map { ItemDefinition(it.id).apply { name = "" } } + + @ItemDefinitions + private val tools = FishingTool.values() + .map { ItemDefinition(it.id).apply { name = "" } } + + @NpcDefinitions + private val spots = FishingSpot.values() + .map { NpcDefinition(it.npc).apply { name = "" } } + } + +} \ No newline at end of file From 1d802c3cb029062a5bf79d4aae7ee2dfdf49ef5c Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 26 Aug 2018 14:59:09 +0100 Subject: [PATCH 160/209] Use new SonarCloud organization --- .travis.yml | 2 +- gradle/quality-gate.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e1fddb4e5..a7760a6bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ jdk: addons: sonarcloud: - organization: "github-apollo-rsps" + organization: "apollo-rsps" after_success: - ./gradlew jacocoTestReport diff --git a/gradle/quality-gate.gradle b/gradle/quality-gate.gradle index bd2a50900..28a2ddf7f 100644 --- a/gradle/quality-gate.gradle +++ b/gradle/quality-gate.gradle @@ -61,7 +61,7 @@ gradle.projectsEvaluated { sonarqube { properties { - property "sonar.organization", "github-apollo-rsps" + property "sonar.organization", "apollo-rsps" property "sonar.projectKey", "apollo:org.apollo" property "sonar.projectName", "Apollo RSPS" property "sonar.kotlin.file.suffixes", ".kt,.kts" From 46d60b425f5b34c456f55af236229ba73eb5e1d5 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 26 Aug 2018 18:35:57 +0100 Subject: [PATCH 161/209] Add herblore unit tests and clean-up plugin code --- ...erblore.plugin.kts => Herblore.plugin.kts} | 0 game/plugin/skills/herblore/src/Ingredient.kt | 2 +- .../herblore/src/MakeFinishedPotionAction.kt | 50 ------------------- ...hedPotionAction.kt => MakePotionAction.kt} | 47 +++++++++++++---- game/plugin/skills/herblore/src/Potion.kt | 13 +++-- 5 files changed, 47 insertions(+), 65 deletions(-) rename game/plugin/skills/herblore/src/{herblore.plugin.kts => Herblore.plugin.kts} (100%) delete mode 100644 game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt rename game/plugin/skills/herblore/src/{MakeUnfinishedPotionAction.kt => MakePotionAction.kt} (50%) diff --git a/game/plugin/skills/herblore/src/herblore.plugin.kts b/game/plugin/skills/herblore/src/Herblore.plugin.kts similarity index 100% rename from game/plugin/skills/herblore/src/herblore.plugin.kts rename to game/plugin/skills/herblore/src/Herblore.plugin.kts diff --git a/game/plugin/skills/herblore/src/Ingredient.kt b/game/plugin/skills/herblore/src/Ingredient.kt index 3784f0905..475436945 100644 --- a/game/plugin/skills/herblore/src/Ingredient.kt +++ b/game/plugin/skills/herblore/src/Ingredient.kt @@ -19,7 +19,7 @@ enum class CrushableIngredient(val uncrushed: Int, override val id: Int) : Ingre CHOCOLATE_BAR(uncrushed = 1973, id = 1975), BIRDS_NEST(uncrushed = 5075, id = 6693); - val uncrushedName: String = Definitions.item(uncrushed)!!.name + val uncrushedName by lazy { Definitions.item(uncrushed)!!.name } companion object { private const val PESTLE_AND_MORTAR = 233 diff --git a/game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt b/game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt deleted file mode 100644 index 37cc56d5f..000000000 --- a/game/plugin/skills/herblore/src/MakeFinishedPotionAction.kt +++ /dev/null @@ -1,50 +0,0 @@ -import org.apollo.game.action.ActionBlock -import org.apollo.game.action.AsyncAction -import org.apollo.game.model.Animation -import org.apollo.game.model.entity.Player -import org.apollo.game.plugin.api.herblore -import java.util.Objects - -class MakeFinishedPotionAction( - player: Player, - private val potion: FinishedPotion -) : AsyncAction(1, true, player) { - - override fun action(): ActionBlock = { - val level = mob.herblore.current - - if (level < potion.level) { - mob.sendMessage("You need a Herblore level of ${potion.level} to make this.") - stop() - } - - val unfinished = potion.unfinished.id - val inventory = mob.inventory - - if (inventory.contains(unfinished) && inventory.contains(potion.ingredient)) { - inventory.remove(unfinished) - inventory.remove(potion.ingredient) - - mob.playAnimation(MIXING_ANIMATION) - - inventory.add(potion.id) - mob.herblore.experience += potion.experience - - mob.sendMessage("You mix the ${potion.ingredientName} into your potion.") - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as MakeFinishedPotionAction - return mob == other.mob && potion == other.potion - } - - override fun hashCode(): Int = Objects.hash(mob, potion) - - private companion object { - private val MIXING_ANIMATION = Animation(363) - } -} \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/MakeUnfinishedPotionAction.kt b/game/plugin/skills/herblore/src/MakePotionAction.kt similarity index 50% rename from game/plugin/skills/herblore/src/MakeUnfinishedPotionAction.kt rename to game/plugin/skills/herblore/src/MakePotionAction.kt index 03bbd5a7d..46759d795 100644 --- a/game/plugin/skills/herblore/src/MakeUnfinishedPotionAction.kt +++ b/game/plugin/skills/herblore/src/MakePotionAction.kt @@ -2,12 +2,13 @@ import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncAction import org.apollo.game.model.Animation import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill import org.apollo.game.plugin.api.herblore -import java.util.Objects +import java.util.* -class MakeUnfinishedPotionAction( +abstract class MakePotionAction( player: Player, - private val potion: UnfinishedPotion + private val potion: Potion ) : AsyncAction(1, true, player) { override fun action(): ActionBlock = { @@ -20,22 +21,26 @@ class MakeUnfinishedPotionAction( val inventory = mob.inventory - if (inventory.contains(VIAL_OF_WATER) && inventory.contains(potion.herb)) { - inventory.remove(VIAL_OF_WATER) - inventory.remove(potion.herb) + if (inventory.containsAll(*ingredients)) { + ingredients.forEach { inventory.remove(it) } + inventory.add(potion.id) mob.playAnimation(MIXING_ANIMATION) - - inventory.add(potion.id) - mob.sendMessage("You put the ${potion.herbName} into the vial of water.") + mob.sendMessage(message) + reward() } } + abstract val ingredients: IntArray + abstract val message: String + + open fun reward() {} + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false - other as MakeUnfinishedPotionAction + other as MakePotionAction return mob == other.mob && potion == other.potion } @@ -44,4 +49,26 @@ class MakeUnfinishedPotionAction( private companion object { private val MIXING_ANIMATION = Animation(363) } +} + +class MakeFinishedPotionAction( + player: Player, + private val potion: FinishedPotion +) : MakePotionAction(player, potion) { + + override val ingredients = intArrayOf(potion.unfinished.id, potion.ingredient) + override val message by lazy { "You mix the ${potion.ingredientName} into your potion." } + + override fun reward() { + mob.skillSet.addExperience(Skill.HERBLORE, potion.experience) + } +} + +class MakeUnfinishedPotionAction( + player: Player, + private val potion: UnfinishedPotion +) : MakePotionAction(player, potion) { + + override val ingredients = intArrayOf(VIAL_OF_WATER, potion.herb) + override val message by lazy { "You put the ${potion.herbName} into the vial of water." } } \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/Potion.kt b/game/plugin/skills/herblore/src/Potion.kt index 299a82987..ce9053ed5 100644 --- a/game/plugin/skills/herblore/src/Potion.kt +++ b/game/plugin/skills/herblore/src/Potion.kt @@ -7,7 +7,12 @@ import org.apollo.game.plugin.api.Definitions const val VIAL_OF_WATER = 227 -enum class UnfinishedPotion(val id: Int, herb: Herb, val level: Int) { +interface Potion { + val id: Int + val level: Int +} + +enum class UnfinishedPotion(override val id: Int, herb: Herb, override val level: Int) : Potion { GUAM(id = 91, herb = Herb.GUAM_LEAF, level = 1), MARRENTILL(id = 93, herb = Herb.MARRENTILL, level = 5), TARROMIN(id = 95, herb = Herb.TARROMIN, level = 12), @@ -36,12 +41,12 @@ enum class UnfinishedPotion(val id: Int, herb: Herb, val level: Int) { } enum class FinishedPotion( - val id: Int, + override val id: Int, val unfinished: UnfinishedPotion, ingredient: Ingredient, - val level: Int, + override val level: Int, val experience: Double -) { +) : Potion { ATTACK(id = 121, unfinished = GUAM, ingredient = EYE_NEWT, level = 1, experience = 25.0), ANTIPOISON(id = 175, unfinished = MARRENTILL, ingredient = UNICORN_HORN, level = 5, experience = 37.5), STRENGTH(id = 115, unfinished = TARROMIN, ingredient = LIMPWURT_ROOT, level = 12, experience = 50.0), From d323571c39c6daa166e909e6781cf7b3a06df232 Mon Sep 17 00:00:00 2001 From: Denver Fernandes Date: Sun, 26 Aug 2018 16:58:41 +0100 Subject: [PATCH 162/209] Add command to teleport to another player Closes #410 --- game/plugin/cmd/src/teleport-cmd.plugin.kts | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index 4d1dabb75..d51a964f6 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -75,6 +75,30 @@ on_command("tele", PrivilegeLevel.ADMINISTRATOR) } } +/** + * Teleports the player to another player. + */ +on_command("teleto", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val invalidSyntax = "Invalid syntax - ::teleto [player name]" + + if (arguments.size == 1) { + val playerName = arguments[0] + val foundPlayer = player.world.getPlayer(playerName) + + if (foundPlayer == null) { + player.sendMessage("Player $playerName is currently offline or does not exist.") + return@then + } + + player.teleport(foundPlayer.position) + player.sendMessage("You have teleported to player $playerName.") + } else { + player.sendMessage(invalidSyntax) + } + } + + internal val TELEPORT_DESTINATIONS = listOf( "alkharid" to Position(3292, 3171), "ardougne" to Position(2662, 3304), From 1f7eb78ddb6ca2604aa09913de526c931fe671ad Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 26 Aug 2018 21:54:33 +0100 Subject: [PATCH 163/209] Add herblore tests --- game/plugin/skills/herblore/src/Herb.kt | 2 +- .../test/CrushIngredientActionTests.kt | 63 ++++++++++++++++++ .../herblore/test/IdentifyHerbActionTests.kt | 66 +++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 game/plugin/skills/herblore/test/CrushIngredientActionTests.kt create mode 100644 game/plugin/skills/herblore/test/IdentifyHerbActionTests.kt diff --git a/game/plugin/skills/herblore/src/Herb.kt b/game/plugin/skills/herblore/src/Herb.kt index c80e1edff..5b921f204 100644 --- a/game/plugin/skills/herblore/src/Herb.kt +++ b/game/plugin/skills/herblore/src/Herb.kt @@ -21,7 +21,7 @@ enum class Herb( DWARF_WEED(identified = 267, unidentified = 217, level = 70, experience = 13.8), TORSTOL(identified = 269, unidentified = 219, level = 75, experience = 15.0); - val identifiedName: String = Definitions.item(identified)!!.name + val identifiedName by lazy { Definitions.item(identified)!!.name } companion object { private val identified = Herb.values().map(Herb::identified).toHashSet() diff --git a/game/plugin/skills/herblore/test/CrushIngredientActionTests.kt b/game/plugin/skills/herblore/test/CrushIngredientActionTests.kt new file mode 100644 index 000000000..a81154a6d --- /dev/null +++ b/game/plugin/skills/herblore/test/CrushIngredientActionTests.kt @@ -0,0 +1,63 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.startsWith +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +internal class CrushIngredientActionTests { + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + private val ingredient = CrushableIngredient.BIRDS_NEST + + @BeforeEach + internal fun startAction() { + player.inventory.add(ingredient.uncrushed) + player.startAction(CrushIngredientAction(player, ingredient)) + } + + @Test + internal fun `Preparing an uncrushed ingredient rewards a new ingredient after 2 ticks`() { + after(action.ticks(2), "ingredient removed and new ingredient added") { + assertEquals(0, player.inventory.getAmount(ingredient.uncrushed)) + assertEquals(1, player.inventory.getAmount(ingredient.id)) + } + } + + @Test + internal fun `Preparing an uncrushed ingredient should send a message to the player after 2 ticks`() { + verifyAfter(action.ticks(2), "notification message sent to the player") { + player.sendMessage(startsWith("You carefully grind the to dust")) + } + } + + @Test + internal fun `Preparing an uncrushed ingredient should play an animation on the first tick`() { + verifyAfter(action.ticks(1), "grinding animation played") { + player.playAnimation(match { it.id == 364 }) + } + } + + private companion object { + @ItemDefinitions + private val ingredients = CrushableIngredient.values() + .map { ItemDefinition(it.uncrushed).apply { name = "" } } + + @ItemDefinitions + private val prepared = CrushableIngredient.values() + .map { ItemDefinition(it.id).apply { name = "" } } + } +} \ No newline at end of file diff --git a/game/plugin/skills/herblore/test/IdentifyHerbActionTests.kt b/game/plugin/skills/herblore/test/IdentifyHerbActionTests.kt new file mode 100644 index 000000000..b5273c184 --- /dev/null +++ b/game/plugin/skills/herblore/test/IdentifyHerbActionTests.kt @@ -0,0 +1,66 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.Item +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.startsWith +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +internal class IdentifyHerbActionTests { + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + private val herb = Herb.GUAM_LEAF + + @BeforeEach + internal fun startAction() { + player.inventory.set(0, Item(herb.unidentified)) + player.startAction(IdentifyHerbAction(player, 0, herb)) + } + + @Test + internal fun `Identifying a herb should send a message if the player doesnt have the required level`() { + player.skillSet.setCurrentLevel(Skill.HERBLORE, 0) + + verifyAfter(action.complete(), "level requirement message sent to player") { + player.sendMessage(startsWith("You need a Herblore level of")) + } + } + + @Test + internal fun `Identifying a herb should remove the undentified herb`() { + after(action.complete()) { + assertEquals(0, player.inventory.getAmount(herb.unidentified)) + } + } + + @Test + internal fun `Identifying a herb should add the identified herb to the players inventory`() { + after(action.complete()) { + assertEquals(1, player.inventory.getAmount(herb.identified)) + } + } + + private companion object { + @ItemDefinitions + val identifiedHerbs = Herb.values() + .map { ItemDefinition(it.identified).apply { name = "" } } + + @ItemDefinitions + val unidentifiedHerbs = Herb.values() + .map { ItemDefinition(it.unidentified).apply { name = "" } } + } +} \ No newline at end of file From a53929a9a848f32ac11f77bd854fa7975e98c049 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 27 Aug 2018 00:55:41 +0100 Subject: [PATCH 164/209] Remove apollo-plugin Gradle plugin Replaces the old Gradle plugin with plain Gradle buildscripts. Also cleans-up the current Gradle extensions and re-adds detekt, along with JUnit 5 support to all modules. --- build.gradle | 4 +- buildSrc/build.gradle | 10 - .../apollo/build/plugin/ApolloPlugin.groovy | 12 - .../build/plugin/ApolloPluginExtension.groovy | 92 ---- .../gradle-plugins/apollo-plugin.properties | 1 - cache/build.gradle | 6 + game/plugin/api/build.gradle | 20 +- game/plugin/areas/build.gradle | 18 +- game/plugin/bank/build.gradle | 16 +- game/plugin/build.gradle | 22 +- .../chat/private-messaging/build.gradle | 13 +- game/plugin/cmd/build.gradle | 22 +- game/plugin/consumables/build.gradle | 16 +- game/plugin/detekt.yml | 325 ------------ game/plugin/dummy/build.gradle | 16 +- game/plugin/emote-tab/build.gradle | 16 +- game/plugin/entity/following/build.gradle | 23 +- game/plugin/entity/player-action/build.gradle | 16 +- game/plugin/entity/spawn/build.gradle | 19 +- game/plugin/entity/walk-to/build.gradle | 16 +- game/plugin/locations/al-kharid/build.gradle | 23 +- game/plugin/locations/edgeville/build.gradle | 23 +- game/plugin/locations/falador/build.gradle | 23 +- game/plugin/locations/lumbridge/build.gradle | 23 +- .../locations/tutorial-island/build.gradle | 19 +- game/plugin/locations/varrock/build.gradle | 22 +- game/plugin/logout/build.gradle | 13 +- game/plugin/navigation/door/build.gradle | 18 +- game/plugin/run/build.gradle | 13 +- game/plugin/shops/build.gradle | 19 +- game/plugin/skills/fishing/build.gradle | 23 +- game/plugin/skills/herblore/build.gradle | 16 +- game/plugin/skills/mining/build.gradle | 22 +- game/plugin/skills/prayer/build.gradle | 19 +- game/plugin/skills/runecrafting/build.gradle | 20 +- game/plugin/skills/woodcutting/build.gradle | 17 +- gradle/code-quality.gradle | 24 + gradle/config/detekt.yml | 474 ++++++++++++++++++ gradle/kotlin.gradle | 9 - gradle/properties.gradle | 1 + gradle/quality-gate.gradle | 72 --- gradle/testing.gradle | 51 ++ .../wrapper/code-quality.gradle | 0 net/build.gradle | 6 +- util/build.gradle | 6 +- 45 files changed, 886 insertions(+), 753 deletions(-) delete mode 100644 buildSrc/build.gradle delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy delete mode 100644 buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy delete mode 100644 buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties delete mode 100644 game/plugin/detekt.yml create mode 100644 gradle/code-quality.gradle create mode 100644 gradle/config/detekt.yml delete mode 100644 gradle/quality-gate.gradle create mode 100644 gradle/testing.gradle rename buildSrc/settings.gradle => gradle/wrapper/code-quality.gradle (100%) diff --git a/build.gradle b/build.gradle index 5cee3c2ea..871c65d2d 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ plugins { id 'org.jetbrains.intellij' version '0.3.6' apply(false) id 'org.jmailen.kotlinter' version '1.16.0' apply(false) id 'org.sonarqube' version '2.6.2' + id "io.gitlab.arturbosch.detekt" version "1.0.0.RC8" } allprojects { @@ -17,5 +18,6 @@ allprojects { } apply from: 'gradle/properties.gradle' -apply from: 'gradle/quality-gate.gradle' +apply from: 'gradle/code-quality.gradle' +apply from: 'gradle/testing.gradle' apply from: 'gradle/wrapper.gradle' \ No newline at end of file diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle deleted file mode 100644 index 8768ea0f2..000000000 --- a/buildSrc/build.gradle +++ /dev/null @@ -1,10 +0,0 @@ -apply plugin: 'groovy' - -repositories { - mavenLocal() - maven { url "https://repo.maven.apache.org/maven2" } -} - -dependencies { - compile gradleApi() -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy deleted file mode 100644 index f8f4459bb..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPlugin.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package org.apollo.build.plugin - -import org.gradle.api.Plugin -import org.gradle.api.Project - -class ApolloPlugin implements Plugin { - - @Override - void apply(Project project) { - project.extensions.create('plugin', ApolloPluginExtension, project) - } -} diff --git a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy b/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy deleted file mode 100644 index a89ff51db..000000000 --- a/buildSrc/src/main/groovy/org/apollo/build/plugin/ApolloPluginExtension.groovy +++ /dev/null @@ -1,92 +0,0 @@ -package org.apollo.build.plugin - -import org.gradle.api.Project - -class ApolloPluginExtension { - final Project project - - /** - * The name of this plugin (defaults to the project name). - */ - String name - - /** - * An optional description of this plugin. - */ - String description = "Empty description" - - /** - * A list of other {@link ApolloPlugin}s that this plugin depends on. - */ - List dependencies = [] - - /** - * A list of others who contributed to this plugin. - */ - List authors = [] - - /** - * The directory that library files and script files are found under. - */ - final String srcDir = "src/" - - /** - * The directory that tests are found under. - */ - final String testDir = "test/" - - ApolloPluginExtension(Project project) { - this.project = project - this.name = project.name - - init() - } - - /** - * Setup the {@link Project} with the correct dependencies and tasks required to build the plugin - * and its scripts. - */ - def init() { - project.plugins.apply('kotlin') - project.dependencies { - implementation project.findProject(':game') - implementation project.findProject(':cache') - implementation project.findProject(':net') - implementation project.findProject(':util') - testImplementation project.findProject(':game:plugin-testing') - } - - project.sourceSets { - main.kotlin.srcDirs += this.srcDir - test.kotlin.srcDirs += this.testDir - } - } - - def getDependencies() { - return dependencies - } - - def setDependencies(List dependencies) { - dependencies.each { - def project = project.findProject(":game:plugin:$it") - if (project == null) { - throw new MissingPluginDependencyException(name, it) - } - - this.project.dependencies.add('compile', project) - } - - this.dependencies = dependencies - } -} - -/** - * A {@link RuntimeException} thrown when a plugin dependency was missing. - */ -class MissingPluginDependencyException extends RuntimeException { - - MissingPluginDependencyException(String plugin, String dependency) { - super("Missing dependency in the `$plugin` plugin: failed to resolve `$dependency`.") - } - -} \ No newline at end of file diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties deleted file mode 100644 index 5b546ceb9..000000000 --- a/buildSrc/src/main/resources/META-INF/gradle-plugins/apollo-plugin.properties +++ /dev/null @@ -1 +0,0 @@ -implementation-class=org.apollo.build.plugin.ApolloPlugin \ No newline at end of file diff --git a/cache/build.gradle b/cache/build.gradle index 95ef6d6a6..af79e12dd 100644 --- a/cache/build.gradle +++ b/cache/build.gradle @@ -5,4 +5,10 @@ description = 'Apollo Cache' dependencies { implementation project(':util') implementation group: 'com.google.guava', name: 'guava', version: guavaVersion + + test.useJUnitPlatform() + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitJupiterVersion + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitJupiterVersion + testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVintageVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-launcher', version: junitPlatformVersion } diff --git a/game/plugin/api/build.gradle b/game/plugin/api/build.gradle index fb25c053e..c1c8d477f 100644 --- a/game/plugin/api/build.gradle +++ b/game/plugin/api/build.gradle @@ -1,4 +1,16 @@ -plugin { - name = "Apollo Plugin API" - description = "Helpers and API for common plugin usecases" -} \ No newline at end of file +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'java' +description = 'Helpers and API for common plugin usecases' + +test { + useJUnitPlatform() +} + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/areas/build.gradle b/game/plugin/areas/build.gradle index 4a0d8ff96..22344beaa 100644 --- a/game/plugin/areas/build.gradle +++ b/game/plugin/areas/build.gradle @@ -1,6 +1,12 @@ -plugin { - name = "Area listeners" - description = "Enables plugins to listen on mobs entering, moving inside of, or leaving a rectangular area." - authors = ["Major"] - dependencies = ["api"] -} \ No newline at end of file +apply plugin: 'kotlin' + +description = 'Enables plugins to listen on mobs entering, moving inside of, or leaving a rectangular area.' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/bank/build.gradle b/game/plugin/bank/build.gradle index a8166f04e..3a9351392 100644 --- a/game/plugin/bank/build.gradle +++ b/game/plugin/bank/build.gradle @@ -1,6 +1,10 @@ -plugin { - name = "banking" - authors = [ - "Major", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/build.gradle b/game/plugin/build.gradle index 0fd76d26e..24ba2cc84 100644 --- a/game/plugin/build.gradle +++ b/game/plugin/build.gradle @@ -1,8 +1,21 @@ -subprojects { subproj -> - if (subproj.buildFile.exists()) { - apply plugin: 'apollo-plugin' +gradle.projectsEvaluated { + configure(subprojects.findAll { it.buildFile.exists() }) { subproj -> apply from: "$rootDir/gradle/kotlin.gradle" + sourceSets { + main { + kotlin { + srcDirs += "src" + } + } + + test { + kotlin { + srcDirs += "test" + } + } + } + test { useJUnitPlatform() } @@ -14,8 +27,7 @@ subprojects { subproj -> } dependencies { - test.useJUnitPlatform() implementation group: 'com.google.guava', name: 'guava', version: guavaVersion } } -} +} \ No newline at end of file diff --git a/game/plugin/chat/private-messaging/build.gradle b/game/plugin/chat/private-messaging/build.gradle index 4bd4ef678..3a9351392 100644 --- a/game/plugin/chat/private-messaging/build.gradle +++ b/game/plugin/chat/private-messaging/build.gradle @@ -1,3 +1,10 @@ -plugin { - name = "private_messaging" -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/cmd/build.gradle b/game/plugin/cmd/build.gradle index 051b171ca..4d96c9f57 100644 --- a/game/plugin/cmd/build.gradle +++ b/game/plugin/cmd/build.gradle @@ -1,12 +1,10 @@ -plugin { - name = "chat_commands" - authors = [ - "Graham", - "Major", - "lare96", - "cubeee", - ] - dependencies = [ - "api" - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/consumables/build.gradle b/game/plugin/consumables/build.gradle index 6f5139fa3..3a9351392 100644 --- a/game/plugin/consumables/build.gradle +++ b/game/plugin/consumables/build.gradle @@ -1,6 +1,10 @@ -plugin { - name = "consumables" - authors = [ - "Gary Tierney", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/detekt.yml b/game/plugin/detekt.yml deleted file mode 100644 index 0872ae9dc..000000000 --- a/game/plugin/detekt.yml +++ /dev/null @@ -1,325 +0,0 @@ -autoCorrect: true -failFast: false - -build: - warningThreshold: 5 - failThreshold: 10 - weights: - complexity: 2 - formatting: 1 - LongParameterList: 1 - comments: 1 - -processors: - active: true - exclude: - # - 'FunctionCountProcessor' - # - 'PropertyCountProcessor' - # - 'ClassCountProcessor' - # - 'PackageCountProcessor' - # - 'KtFileCountProcessor' - -console-reports: - active: true - exclude: - # - 'ProjectStatisticsReport' - # - 'ComplexityReport' - # - 'NotificationReport' - # - 'FindingsReport' - # - 'BuildFailureReport' - -output-reports: - active: true - exclude: - # - 'PlainOutputReport' - # - 'XmlOutputReport' - -potential-bugs: - active: true - DuplicateCaseInWhenExpression: - active: true - EqualsAlwaysReturnsTrueOrFalse: - active: false - EqualsWithHashCodeExist: - active: true - WrongEqualsTypeParameter: - active: false - ExplicitGarbageCollectionCall: - active: true - UnreachableCode: - active: true - LateinitUsage: - active: false - UnsafeCallOnNullableType: - active: false - UnsafeCast: - active: false - UselessPostfixExpression: - active: false - -performance: - active: true - ForEachOnRange: - active: true - SpreadOperator: - active: true - UnnecessaryTemporaryInstantiation: - active: true - -exceptions: - active: true - ExceptionRaisedInUnexpectedLocation: - active: false - methodNames: 'toString,hashCode,equals,finalize' - SwallowedException: - active: false - TooGenericExceptionCaught: - active: true - exceptions: - - ArrayIndexOutOfBoundsException - - Error - - Exception - - IllegalMonitorStateException - - IndexOutOfBoundsException - - InterruptedException - - NullPointerException - - RuntimeException - TooGenericExceptionThrown: - active: true - exceptions: - - Throwable - - ThrowError - - ThrowException - - ThrowNullPointerException - - ThrowRuntimeException - - ThrowThrowable - InstanceOfCheckForException: - active: false - IteratorNotThrowingNoSuchElementException: - active: false - PrintExceptionStackTrace: - active: false - RethrowCaughtException: - active: false - ReturnFromFinally: - active: false - ThrowingExceptionFromFinally: - active: false - ThrowingExceptionInMain: - active: false - ThrowingNewInstanceOfSameException: - active: false - -empty-blocks: - active: true - EmptyCatchBlock: - active: true - EmptyClassBlock: - active: true - EmptyDefaultConstructor: - active: true - EmptyDoWhileBlock: - active: true - EmptyElseBlock: - active: true - EmptyFinallyBlock: - active: true - EmptyForBlock: - active: true - EmptyFunctionBlock: - active: true - EmptyIfBlock: - active: true - EmptyInitBlock: - active: true - EmptySecondaryConstructor: - active: true - EmptyWhenBlock: - active: true - EmptyWhileBlock: - active: true - -complexity: - active: true - LongMethod: - threshold: 20 - LongParameterList: - threshold: 5 - LargeClass: - threshold: 150 - ComplexMethod: - threshold: 10 - TooManyFunctions: - threshold: 10 - ComplexCondition: - threshold: 3 - LabeledExpression: - active: false - StringLiteralDuplication: - active: false - threshold: 2 - ignoreAnnotation: true - excludeStringsWithLessThan5Characters: true - ignoreStringsRegex: '$^' - -code-smell: - active: true - FeatureEnvy: - threshold: 0.5 - weight: 0.45 - base: 0.5 - -formatting: - active: true - useTabs: true - Indentation: - active: false - indentSize: 4 - ConsecutiveBlankLines: - active: true - autoCorrect: true - MultipleSpaces: - active: true - autoCorrect: true - SpacingAfterComma: - active: true - autoCorrect: true - SpacingAfterKeyword: - active: true - autoCorrect: true - SpacingAroundColon: - active: true - autoCorrect: true - SpacingAroundCurlyBraces: - active: true - autoCorrect: true - SpacingAroundOperator: - active: true - autoCorrect: true - TrailingSpaces: - active: true - autoCorrect: true - UnusedImports: - active: true - autoCorrect: true - OptionalSemicolon: - active: true - autoCorrect: true - OptionalUnit: - active: true - autoCorrect: true - ExpressionBodySyntax: - active: false - autoCorrect: false - ExpressionBodySyntaxLineBreaks: - active: false - autoCorrect: false - OptionalReturnKeyword: - active: true - autoCorrect: false - -style: - active: true - ReturnCount: - active: true - max: 2 - NewLineAtEndOfFile: - active: true - OptionalAbstractKeyword: - active: true - OptionalWhenBraces: - active: false - EqualsNullCall: - active: false - ForbiddenComment: - active: true - values: 'TODO:,FIXME:,STOPSHIP:' - ForbiddenImport: - active: false - imports: '' - PackageDeclarationStyle: - active: false - ModifierOrder: - active: true - MagicNumber: - active: true - ignoreNumbers: '-1,0,1,2' - ignoreHashCodeFunction: false - ignorePropertyDeclaration: false - ignoreAnnotation: false - WildcardImport: - active: true - SafeCast: - active: true - MaxLineLength: - active: true - maxLineLength: 120 - excludePackageStatements: false - excludeImportStatements: false - PackageNaming: - active: true - packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$' - ClassNaming: - active: true - classPattern: '[A-Z$][a-zA-Z$]*' - EnumNaming: - active: true - enumEntryPattern: '^[A-Z$][a-zA-Z_$]*$' - FunctionNaming: - active: true - functionPattern: '^[a-z$][a-zA-Z$0-9]*$' - FunctionMaxLength: - active: false - maximumFunctionNameLength: 30 - FunctionMinLength: - active: false - minimumFunctionNameLength: 3 - VariableNaming: - active: true - variablePattern: '^(_)?[a-z$][a-zA-Z$0-9]*$' - ConstantNaming: - active: true - constantPattern: '^([A-Z_]*|serialVersionUID)$' - VariableMaxLength: - active: false - maximumVariableNameLength: 30 - VariableMinLength: - active: false - minimumVariableNameLength: 3 - ForbiddenClassName: - active: false - forbiddenName: '' - ProtectedMemberInFinalClass: - active: false - UnnecessaryParentheses: - active: false - DataClassContainsFunctions: - active: false - UseDataClass: - active: false - UnnecessaryAbstractClass: - active: false - -comments: - active: true - CommentOverPrivateMethod: - active: true - CommentOverPrivateProperty: - active: true - UndocumentedPublicClass: - active: false - searchInNestedClass: true - searchInInnerClass: true - searchInInnerObject: true - searchInInnerInterface: true - UndocumentedPublicFunction: - active: false - -# *experimental feature* -# Migration rules can be defined in the same config file or a new one -migration: - active: true - imports: - # your.package.Class: new.package.or.Class - # for example: - # io.gitlab.arturbosch.detekt.api.Rule: io.gitlab.arturbosch.detekt.rule.Rule diff --git a/game/plugin/dummy/build.gradle b/game/plugin/dummy/build.gradle index 46f8224a3..3a9351392 100644 --- a/game/plugin/dummy/build.gradle +++ b/game/plugin/dummy/build.gradle @@ -1,6 +1,10 @@ -plugin { - name = "training_dummy" - authors = [ - "Gary Tierney", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/emote-tab/build.gradle b/game/plugin/emote-tab/build.gradle index 04160d86f..3a9351392 100644 --- a/game/plugin/emote-tab/build.gradle +++ b/game/plugin/emote-tab/build.gradle @@ -1,6 +1,10 @@ -plugin { - name = "emote_tab" - authors = [ - "Gary Tierney", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/entity/following/build.gradle b/game/plugin/entity/following/build.gradle index a252080ec..3f43d5f07 100644 --- a/game/plugin/entity/following/build.gradle +++ b/game/plugin/entity/following/build.gradle @@ -1,10 +1,13 @@ -plugin { - name = "following" - authors = [ - "Gary Tierney", - ] - dependencies = [ - "entity:walk-to", - "entity:player-action", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + + + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:entity:walk-to') + implementation project(':game:plugin:entity:player-action') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/entity/player-action/build.gradle b/game/plugin/entity/player-action/build.gradle index 43f394f3e..3a9351392 100644 --- a/game/plugin/entity/player-action/build.gradle +++ b/game/plugin/entity/player-action/build.gradle @@ -1,6 +1,10 @@ -plugin { - name = "player_action" - authors = [ - "Gary Tierney", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/entity/spawn/build.gradle b/game/plugin/entity/spawn/build.gradle index e0bb28287..4d96c9f57 100644 --- a/game/plugin/entity/spawn/build.gradle +++ b/game/plugin/entity/spawn/build.gradle @@ -1,9 +1,10 @@ -plugin { - name = "spawning" - authors = [ - "Gary Tierney", - ] - dependencies = [ - "api", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/entity/walk-to/build.gradle b/game/plugin/entity/walk-to/build.gradle index 13ca8949f..3a9351392 100644 --- a/game/plugin/entity/walk-to/build.gradle +++ b/game/plugin/entity/walk-to/build.gradle @@ -1,6 +1,10 @@ -plugin { - name = "walkto" - authors = [ - "Gary Tierney", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/locations/al-kharid/build.gradle b/game/plugin/locations/al-kharid/build.gradle index 3be3eb4f1..7eed7d878 100644 --- a/game/plugin/locations/al-kharid/build.gradle +++ b/game/plugin/locations/al-kharid/build.gradle @@ -1,10 +1,13 @@ -plugin { - name = "al_kharid" - authors = [ - "Jesse W", - "Arham 4" - ] - dependencies = [ - "entity:spawn", "shops" - ] -} \ No newline at end of file +apply plugin: 'kotlin' + + + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:entity:spawn') + implementation project(':game:plugin:shops') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/locations/edgeville/build.gradle b/game/plugin/locations/edgeville/build.gradle index 0f2de3218..7eed7d878 100644 --- a/game/plugin/locations/edgeville/build.gradle +++ b/game/plugin/locations/edgeville/build.gradle @@ -1,10 +1,13 @@ -plugin { - name = "edgeville" - authors = [ - "Jesse W", - "Arham 4" - ] - dependencies = [ - "entity:spawn", "shops" - ] -} \ No newline at end of file +apply plugin: 'kotlin' + + + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:entity:spawn') + implementation project(':game:plugin:shops') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/locations/falador/build.gradle b/game/plugin/locations/falador/build.gradle index 9af8dd9e0..7eed7d878 100644 --- a/game/plugin/locations/falador/build.gradle +++ b/game/plugin/locations/falador/build.gradle @@ -1,10 +1,13 @@ -plugin { - name = "falador" - authors = [ - "Jesse W", - "Arham 4" - ] - dependencies = [ - "entity:spawn", "shops" - ] -} \ No newline at end of file +apply plugin: 'kotlin' + + + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:entity:spawn') + implementation project(':game:plugin:shops') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/locations/lumbridge/build.gradle b/game/plugin/locations/lumbridge/build.gradle index 97bdf6868..7eed7d878 100644 --- a/game/plugin/locations/lumbridge/build.gradle +++ b/game/plugin/locations/lumbridge/build.gradle @@ -1,10 +1,13 @@ -plugin { - name = "lumbridge" - authors = [ - "Gary Tierney", - "Arham 4" - ] - dependencies = [ - "entity:spawn", "shops" - ] -} \ No newline at end of file +apply plugin: 'kotlin' + + + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:entity:spawn') + implementation project(':game:plugin:shops') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/locations/tutorial-island/build.gradle b/game/plugin/locations/tutorial-island/build.gradle index 60631802e..24e7bbaed 100644 --- a/game/plugin/locations/tutorial-island/build.gradle +++ b/game/plugin/locations/tutorial-island/build.gradle @@ -1,9 +1,10 @@ -plugin { - name = "tutorial_island_npc_spawns" - authors = [ - "Jesse W", - ] - dependencies = [ - "entity:spawn", - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:entity:spawn') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/locations/varrock/build.gradle b/game/plugin/locations/varrock/build.gradle index f094b1bc2..6a06d7334 100644 --- a/game/plugin/locations/varrock/build.gradle +++ b/game/plugin/locations/varrock/build.gradle @@ -1,11 +1,11 @@ -plugin { - name = "varrock" - authors = [ - "Jesse W", - "Major", - "tlf30", - ] - dependencies = [ - "entity:spawn", "shops" - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:entity:spawn') + implementation project(':game:plugin:shops') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/logout/build.gradle b/game/plugin/logout/build.gradle index ae0395e62..3a9351392 100644 --- a/game/plugin/logout/build.gradle +++ b/game/plugin/logout/build.gradle @@ -1,3 +1,10 @@ -plugin { - name = "logout" -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/navigation/door/build.gradle b/game/plugin/navigation/door/build.gradle index 8ac642154..4d96c9f57 100644 --- a/game/plugin/navigation/door/build.gradle +++ b/game/plugin/navigation/door/build.gradle @@ -1,8 +1,10 @@ -plugin { - name = "door" - dependencies = ["api"] - authors = [ - "Shiver", - "Arin" - ] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/run/build.gradle b/game/plugin/run/build.gradle index 1e335cc47..3a9351392 100644 --- a/game/plugin/run/build.gradle +++ b/game/plugin/run/build.gradle @@ -1,3 +1,10 @@ -plugin { - name = "run" -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/shops/build.gradle b/game/plugin/shops/build.gradle index 369bf235d..4d96c9f57 100644 --- a/game/plugin/shops/build.gradle +++ b/game/plugin/shops/build.gradle @@ -1,11 +1,10 @@ -plugin { - name = "shops" - authors = [ - "Stuart", - "Major", - "tlf30" - ] - dependencies = [ - "api", - ] +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') } diff --git a/game/plugin/skills/fishing/build.gradle b/game/plugin/skills/fishing/build.gradle index 435281cb3..4314d6fd4 100644 --- a/game/plugin/skills/fishing/build.gradle +++ b/game/plugin/skills/fishing/build.gradle @@ -1,12 +1,13 @@ -plugin { - name = "fishing_skill" - authors = [ - "Linux", - "Major", - "tlf30" - ] - dependencies = [ - "api", - "entity:spawn", - ] +apply plugin: 'kotlin' + + + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + implementation project(':game:plugin:entity:spawn') + testImplementation project(':game:plugin-testing') } diff --git a/game/plugin/skills/herblore/build.gradle b/game/plugin/skills/herblore/build.gradle index 6dc08aac4..4d96c9f57 100644 --- a/game/plugin/skills/herblore/build.gradle +++ b/game/plugin/skills/herblore/build.gradle @@ -1,10 +1,10 @@ -plugin { - name = "herblore_skill" - authors = [ - "Chivvon", - "Chris Fletcher", - "Major" - ] +apply plugin: 'kotlin' - dependencies = ["api"] +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') } diff --git a/game/plugin/skills/mining/build.gradle b/game/plugin/skills/mining/build.gradle index 71bc90208..4d96c9f57 100644 --- a/game/plugin/skills/mining/build.gradle +++ b/game/plugin/skills/mining/build.gradle @@ -1,14 +1,10 @@ -plugin { - name = "mining-skill" - authors = [ - "Graham", - "Mikey`", - "Major", - "WH:II:DOW", - "Requa", - "Clifton", - "tlf30" - ] +apply plugin: 'kotlin' - dependencies = ["api"] -} \ No newline at end of file +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/skills/prayer/build.gradle b/game/plugin/skills/prayer/build.gradle index 5ea5c0b26..4d96c9f57 100644 --- a/game/plugin/skills/prayer/build.gradle +++ b/game/plugin/skills/prayer/build.gradle @@ -1,11 +1,10 @@ -plugin { - name = "prayer_skill" - authors = [ - "Major", - "010253", - "tlf30" - ] - dependencies = [ - "api" - ] +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') } diff --git a/game/plugin/skills/runecrafting/build.gradle b/game/plugin/skills/runecrafting/build.gradle index 74ddffb6f..4d96c9f57 100644 --- a/game/plugin/skills/runecrafting/build.gradle +++ b/game/plugin/skills/runecrafting/build.gradle @@ -1,12 +1,10 @@ -plugin { - name = "runecrafting-skill" - authors = [ - "Major", - "BugCrusher", - "tlf30" - ] +apply plugin: 'kotlin' - dependencies = [ - "api" - ] -} \ No newline at end of file +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') +} diff --git a/game/plugin/skills/woodcutting/build.gradle b/game/plugin/skills/woodcutting/build.gradle index 0da7a40d9..4d96c9f57 100644 --- a/game/plugin/skills/woodcutting/build.gradle +++ b/game/plugin/skills/woodcutting/build.gradle @@ -1,7 +1,10 @@ -plugin { - name = "woodcutting_skill" - authors = [ - "tlf30" - ] - dependencies = ["api"] -} \ No newline at end of file +apply plugin: 'kotlin' + +dependencies { + implementation project(':game') + implementation project(':cache') + implementation project(':net') + implementation project(':util') + implementation project(':game:plugin:api') + testImplementation project(':game:plugin-testing') +} diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle new file mode 100644 index 000000000..240743c86 --- /dev/null +++ b/gradle/code-quality.gradle @@ -0,0 +1,24 @@ +def detektAggregateReport = "$rootDir/reports/detekt-report.xml" + +detekt { + version = detektVersion + + defaultProfile { + output = file("$buildDir/reports") + outputName = "detekt-report" + config = file("$rootDir/gradle/config/detekt.yml") + parallel = true + } +} + +dependencies { + detekt group: 'io.gitlab.arturbosch.detekt', name: 'detekt-formatting', version: detektVersion +} + +sonarqube { + properties { + property "sonar.kotlin.detekt.reportPaths", detektAggregateReport + } +} + +tasks["sonarqube"].dependsOn(detektCheck) \ No newline at end of file diff --git a/gradle/config/detekt.yml b/gradle/config/detekt.yml new file mode 100644 index 000000000..774cafc7b --- /dev/null +++ b/gradle/config/detekt.yml @@ -0,0 +1,474 @@ +autoCorrect: true +failFast: false + +test-pattern: # Configure exclusions for test sources + active: true + patterns: # Test file regexes + - '.*/test/.*' + - '.*Test.kt' + - '.*Spec.kt' + exclude-rule-sets: + - 'comments' + exclude-rules: + - 'NamingRules' + - 'WildcardImport' + - 'MagicNumber' + - 'MaxLineLength' + - 'LateinitUsage' + - 'StringLiteralDuplication' + - 'SpreadOperator' + - 'TooManyFunctions' + - 'ForEachOnRange' + +build: + maxIssues: -1 + weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + +processors: + active: true + exclude: + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ClassCountProcessor' + # - 'PackageCountProcessor' + # - 'KtFileCountProcessor' + +console-reports: + active: true + exclude: + # - 'ProjectStatisticsReport' + # - 'ComplexityReport' + # - 'NotificationReport' + # - 'FindingsReport' + # - 'BuildFailureReport' + +output-reports: + active: true + exclude: + # - 'HtmlOutputReport' + # - 'PlainOutputReport' + # - 'XmlOutputReport' + +comments: + active: true + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + EndOfSentenceFormat: + active: false + endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!]$) + UndocumentedPublicClass: + active: false + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + UndocumentedPublicFunction: + active: false + +complexity: + active: true + ComplexCondition: + active: false + threshold: 4 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + ComplexMethod: + active: false + threshold: 10 + ignoreSingleWhenExpression: false + LabeledExpression: + active: false + LargeClass: + active: true + threshold: 150 + LongMethod: + active: false + threshold: 20 + LongParameterList: + active: false + threshold: 6 + ignoreDefaultParameters: false + MethodOverloading: + active: false + threshold: 6 + NestedBlockDepth: + active: true + threshold: 4 + StringLiteralDuplication: + active: false + threshold: 3 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: true + thresholdInFiles: 11 + thresholdInClasses: 11 + thresholdInInterfaces: 11 + thresholdInObjects: 11 + thresholdInEnums: 11 + ignoreDeprecated: false + ignorePrivate: false + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + allowedExceptionNameRegex: "^(_|(ignore|expected).*)" + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + ignoreOverriddenFunctions: false + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptyKtFile: + active: true + EmptySecondaryConstructor: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: false + methodNames: 'toString,hashCode,equals,finalize' + InstanceOfCheckForException: + active: false + NotImplementedDeclaration: + active: false + PrintStackTrace: + active: false + RethrowCaughtException: + active: false + ReturnFromFinally: + active: false + SwallowedException: + active: false + ThrowingExceptionFromFinally: + active: false + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: false + exceptions: 'IllegalArgumentException,IllegalStateException,IOException' + ThrowingNewInstanceOfSameException: + active: false + TooGenericExceptionCaught: + active: true + exceptionNames: + - ArrayIndexOutOfBoundsException + - Error + - Exception + - IllegalMonitorStateException + - NullPointerException + - IndexOutOfBoundsException + - RuntimeException + - Throwable + TooGenericExceptionThrown: + active: true + exceptionNames: + - Error + - Exception + - Throwable + - RuntimeException + +formatting: + active: true + android: false + autoCorrect: true + ChainWrapping: + active: true + autoCorrect: true + CommentSpacing: + active: true + autoCorrect: true + Filename: + active: true + FinalNewline: + active: true + autoCorrect: true + ImportOrdering: + active: true + autoCorrect: true + Indentation: + active: true + autoCorrect: true + indentSize: 4 + continuationIndentSize: 4 + MaximumLineLength: + active: false + ModifierOrdering: + active: true + autoCorrect: true + NoBlankLineBeforeRbrace: + active: true + autoCorrect: true + NoConsecutiveBlankLines: + active: true + autoCorrect: true + NoEmptyClassBody: + active: true + autoCorrect: true + NoItParamInMultilineLambda: + active: false + NoLineBreakAfterElse: + active: true + autoCorrect: true + NoLineBreakBeforeAssignment: + active: true + autoCorrect: true + NoMultipleSpaces: + active: true + autoCorrect: true + NoSemicolons: + active: true + autoCorrect: true + NoTrailingSpaces: + active: true + autoCorrect: true + NoUnitReturn: + active: true + autoCorrect: true + NoUnusedImports: + active: true + autoCorrect: true + NoWildcardImports: + active: true + autoCorrect: true + ParameterListWrapping: + active: true + autoCorrect: true + indentSize: 4 + SpacingAroundColon: + active: true + autoCorrect: true + SpacingAroundComma: + active: true + autoCorrect: true + SpacingAroundCurly: + active: true + autoCorrect: true + SpacingAroundKeyword: + active: true + autoCorrect: true + SpacingAroundOperators: + active: true + autoCorrect: true + SpacingAroundRangeOperator: + active: true + autoCorrect: true + StringTemplate: + active: true + autoCorrect: true + +naming: + active: true + ClassNaming: + active: true + classPattern: '[A-Z$][a-zA-Z0-9$]*' + EnumNaming: + active: true + enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*' + ForbiddenClassName: + active: false + forbiddenName: '' + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + FunctionNaming: + active: true + functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' + excludeClassPattern: '$^' + MatchingDeclarationName: + active: true + MemberNameEqualsClassName: + active: false + ignoreOverriddenFunction: true + ObjectPropertyNaming: + active: true + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + constantPattern: '[A-Za-z][_A-Za-z0-9]*' + PackageNaming: + active: true + packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$' + TopLevelPropertyNaming: + active: false + constantPattern: '[A-Z][_A-Z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '(_)?[A-Za-z][A-Za-z0-9]*' + VariableMaxLength: + active: false + maximumVariableNameLength: 64 + VariableMinLength: + active: false + minimumVariableNameLength: 1 + VariableNaming: + active: false + variablePattern: '[a-z][A-Za-z0-9]*' + privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + +performance: + active: true + ForEachOnRange: + active: true + SpreadOperator: + active: true + UnnecessaryTemporaryInstantiation: + active: true + +potential-bugs: + active: true + DuplicateCaseInWhenExpression: + active: true + EqualsAlwaysReturnsTrueOrFalse: + active: false + EqualsWithHashCodeExist: + active: true + ExplicitGarbageCollectionCall: + active: true + InvalidRange: + active: false + IteratorHasNextCallsNextMethod: + active: false + IteratorNotThrowingNoSuchElementException: + active: false + LateinitUsage: + active: false + excludeAnnotatedProperties: "" + ignoreOnClassesPattern: "" + UnconditionalJumpStatementInLoop: + active: false + UnreachableCode: + active: true + UnsafeCallOnNullableType: + active: false + UnsafeCast: + active: false + UselessPostfixExpression: + active: false + WrongEqualsTypeParameter: + active: false + +style: + active: true + CollapsibleIfStatements: + active: false + DataClassContainsFunctions: + active: false + conversionFunctionPrefix: 'to' + EqualsNullCall: + active: false + ExpressionBodySyntax: + active: false + includeLineWrapping: false + ForbiddenComment: + active: true + values: 'TODO:,FIXME:,STOPSHIP:' + ForbiddenImport: + active: false + imports: '' + FunctionOnlyReturningConstant: + active: false + ignoreOverridableFunction: true + excludedFunctions: 'describeContents' + LoopWithTooManyJumpStatements: + active: false + maxJumpCount: 1 + MagicNumber: + active: false + MandatoryBracesIfStatements: + active: false + MaxLineLength: + active: false + maxLineLength: 120 + excludePackageStatements: false + excludeImportStatements: false + excludeCommentStatements: false + MayBeConst: + active: false + ModifierOrder: + active: true + NestedClassesVisibility: + active: false + NewLineAtEndOfFile: + active: false + NoTabs: + active: true + OptionalAbstractKeyword: + active: true + OptionalUnit: + active: false + OptionalWhenBraces: + active: false + PreferToOverPairSyntax: + active: false + ProtectedMemberInFinalClass: + active: false + RedundantVisibilityModifierRule: + active: false + ReturnCount: + active: true + max: 2 + excludedFunctions: "equals" + SafeCast: + active: true + SerialVersionUIDInSerializableClass: + active: false + SpacingBetweenPackageAndImports: + active: false + ThrowsCount: + active: true + max: 2 + TrailingWhitespace: + active: false + UnnecessaryAbstractClass: + active: false + UnnecessaryInheritance: + active: false + UnnecessaryParentheses: + active: false + UntilInsteadOfRangeTo: + active: false + UnusedImports: + active: false + UnusedPrivateMember: + active: false + allowedNames: "(_|ignored|expected)" + UseDataClass: + active: false + excludeAnnotatedClasses: "" + UtilityClassWithPublicConstructor: + active: false + VarCouldBeVal: + active: false + WildcardImport: + active: true + excludeImports: 'java.util.*,kotlinx.android.synthetic.*' diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle index 01ae102ed..ab84ae131 100644 --- a/gradle/kotlin.gradle +++ b/gradle/kotlin.gradle @@ -1,10 +1 @@ -apply plugin: 'org.jmailen.kotlinter' - -kotlinter { - ignoreFailures = true - indentSize = 4 - continuationIndentSize = 4 - reporters = ['checkstyle', 'plain'] -} - kotlin { experimental { coroutines 'enable' } } diff --git a/gradle/properties.gradle b/gradle/properties.gradle index bf7c25579..03663a88f 100644 --- a/gradle/properties.gradle +++ b/gradle/properties.gradle @@ -16,4 +16,5 @@ ext { junitJupiterVersion = '5.1.0' mockkVersion = '1.7.15' assertkVersion = '0.9' + detektVersion = '1.0.0.RC8' } \ No newline at end of file diff --git a/gradle/quality-gate.gradle b/gradle/quality-gate.gradle deleted file mode 100644 index 28a2ddf7f..000000000 --- a/gradle/quality-gate.gradle +++ /dev/null @@ -1,72 +0,0 @@ -apply plugin: 'jacoco' - -def testedProjects() { - subprojects.findAll { subproject -> subproject.plugins.hasPlugin('java') || subproject.plugins.hasPlugin('kotlin') } -} - -gradle.projectsEvaluated { - configure(testedProjects()) { - apply plugin: 'jacoco' - - jacoco { - toolVersion = '0.8.1' - } - - jacocoTestReport { - sourceDirectories = files(sourceSets.main.allSource.srcDirs) - classDirectories = files(sourceSets.main.output) - } - - test { - reports { - junitXml.enabled = true - html.enabled = false - } - - jacoco { - append = false - destinationFile = file("$buildDir/jacoco/jacocoTest.exec") - classDumpDir = file("$buildDir/jacoco/classpathdumps") - } - - } - } - - task jacocoTestReport(type: JacocoReport) { - def tests = [] - def sourceDirs = files() - def classDirs = files() - def execData = files() - - reports { - xml.enabled = true - html.enabled = false - } - - testedProjects().each { subproject -> - sourceDirs += files(subproject.sourceSets.main.allSource.srcDirs) - classDirs += files(subproject.sourceSets.main.output) - execData += files(subproject.tasks.jacocoTestReport.executionData.findAll { - it.exists() - }) - - tests += subproject.tasks.test - } - - dependsOn tests - sourceDirectories = sourceDirs - classDirectories = classDirs - executionData = execData - } - - sonarqube { - properties { - property "sonar.organization", "apollo-rsps" - property "sonar.projectKey", "apollo:org.apollo" - property "sonar.projectName", "Apollo RSPS" - property "sonar.kotlin.file.suffixes", ".kt,.kts" - } - } - - project.tasks["sonarqube"].dependsOn(jacocoTestReport) -} \ No newline at end of file diff --git a/gradle/testing.gradle b/gradle/testing.gradle new file mode 100644 index 000000000..6e462b7be --- /dev/null +++ b/gradle/testing.gradle @@ -0,0 +1,51 @@ +apply plugin: 'jacoco' + +def jacocoCoverageAggregate = "$buildDir/jacoco/jacocoTestAll.exec" + +def testedProjects() { + subprojects.findAll { subproject -> subproject.plugins.hasPlugin('java') || subproject.plugins.hasPlugin('kotlin') } +} + +configure(testedProjects()) { + + jacoco { + toolVersion = '0.8.1' + } + + jacocoTestReport { + sourceDirectories = files(sourceSets.main.allSource.srcDirs) + classDirectories = files(sourceSets.main.output) + } + + test { + reports { + junitXml.enabled = true + html.enabled = false + } + + jacoco { + append = false + destinationFile = file("$buildDir/jacoco/jacocoTest.exec") + classDumpDir = file("$buildDir/jacoco/classpathdumps") + } + + } +} + +task jacocoMerge(type: JacocoMerge) { + destinationFile = file(jacocoCoverageAggregate) + executionData = project.fileTree(dir: '.', include: '**/build/jacoco/test.exec') +} + +sonarqube { + properties { + property "sonar.organization", "apollo-rsps" + property "sonar.projectKey", "apollo:org.apollo" + property "sonar.projectName", "Apollo RSPS" + property "sonar.kotlin.file.suffixes", ".kt,.kts" + property "sonar.jacoco.reportPaths", jacocoCoverageAggregate + } +} + +tasks["sonarqube"].dependsOn(jacocoMerge) + diff --git a/buildSrc/settings.gradle b/gradle/wrapper/code-quality.gradle similarity index 100% rename from buildSrc/settings.gradle rename to gradle/wrapper/code-quality.gradle diff --git a/net/build.gradle b/net/build.gradle index adfcb303d..939c6ff44 100644 --- a/net/build.gradle +++ b/net/build.gradle @@ -10,5 +10,9 @@ dependencies { implementation group: 'com.google.guava', name: 'guava', version: guavaVersion implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: bouncycastleVersion - testImplementation group: 'junit', name: 'junit', version: junitVersion + test.useJUnitPlatform() + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitJupiterVersion + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitJupiterVersion + testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVintageVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-launcher', version: junitPlatformVersion } diff --git a/util/build.gradle b/util/build.gradle index 6f0a0d96a..996946275 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -9,7 +9,11 @@ dependencies { implementation group: 'com.google.guava', name: 'guava', version: guavaVersion implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: bouncycastleVersion - testImplementation group: 'junit', name: 'junit', version: junitVersion + test.useJUnitPlatform() + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitJupiterVersion + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitJupiterVersion + testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVintageVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-launcher', version: junitPlatformVersion } task(genRsa, dependsOn: classes, type: JavaExec) { From 970a5b06ad95ff3aa7fcca8eb648695e3dc670d7 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 27 Aug 2018 01:20:19 +0100 Subject: [PATCH 165/209] Set input directory in detekt task --- gradle/code-quality.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle index 240743c86..cb9389f2a 100644 --- a/gradle/code-quality.gradle +++ b/gradle/code-quality.gradle @@ -7,6 +7,7 @@ detekt { output = file("$buildDir/reports") outputName = "detekt-report" config = file("$rootDir/gradle/config/detekt.yml") + input = file(".") parallel = true } } From b1a687be348f97d31b414fd0bb83968cee5fa1cc Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 27 Aug 2018 01:47:14 +0100 Subject: [PATCH 166/209] Create detekt profiles for each project --- gradle/code-quality.gradle | 41 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle index cb9389f2a..b65f3cd31 100644 --- a/gradle/code-quality.gradle +++ b/gradle/code-quality.gradle @@ -1,25 +1,32 @@ def detektAggregateReport = "$rootDir/reports/detekt-report.xml" -detekt { - version = detektVersion +gradle.projectsEvaluated { + detekt { + version = detektVersion - defaultProfile { - output = file("$buildDir/reports") - outputName = "detekt-report" - config = file("$rootDir/gradle/config/detekt.yml") - input = file(".") - parallel = true + defaultProfile { + output = file("$buildDir/reports") + outputName = "detekt-report" + config = file("$rootDir/gradle/config/detekt.yml") + parallel = true + } + + subprojects.findAll { it.pluginManager.hasPlugin('kotlin') }.forEach { proj -> + profile(proj.name) { + input = proj.sourceSets.main.kotlin + } + } } -} -dependencies { - detekt group: 'io.gitlab.arturbosch.detekt', name: 'detekt-formatting', version: detektVersion -} + dependencies { + detekt group: 'io.gitlab.arturbosch.detekt', name: 'detekt-formatting', version: detektVersion + } -sonarqube { - properties { - property "sonar.kotlin.detekt.reportPaths", detektAggregateReport + sonarqube { + properties { + property "sonar.kotlin.detekt.reportPaths", detektAggregateReport + } } -} -tasks["sonarqube"].dependsOn(detektCheck) \ No newline at end of file + tasks["sonarqube"].dependsOn(detektCheck) +} \ No newline at end of file From 0f009882af0e1b1e25d960e57b8f2a5906fe1f10 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 27 Aug 2018 02:06:04 +0100 Subject: [PATCH 167/209] Fix merging of JaCoCo reports --- gradle/testing.gradle | 65 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/gradle/testing.gradle b/gradle/testing.gradle index 6e462b7be..ec42fd68e 100644 --- a/gradle/testing.gradle +++ b/gradle/testing.gradle @@ -1,4 +1,4 @@ -apply plugin: 'jacoco' +apply plugin: "jacoco" def jacocoCoverageAggregate = "$buildDir/jacoco/jacocoTestAll.exec" @@ -6,46 +6,43 @@ def testedProjects() { subprojects.findAll { subproject -> subproject.plugins.hasPlugin('java') || subproject.plugins.hasPlugin('kotlin') } } -configure(testedProjects()) { - - jacoco { - toolVersion = '0.8.1' - } - - jacocoTestReport { - sourceDirectories = files(sourceSets.main.allSource.srcDirs) - classDirectories = files(sourceSets.main.output) - } - - test { - reports { - junitXml.enabled = true - html.enabled = false - } +gradle.projectsEvaluated { + configure(testedProjects()) { + apply plugin: "jacoco" jacoco { - append = false - destinationFile = file("$buildDir/jacoco/jacocoTest.exec") - classDumpDir = file("$buildDir/jacoco/classpathdumps") + toolVersion = '0.8.1' } + test { + reports { + junitXml.enabled = true + html.enabled = false + } + + jacoco { + append = false + destinationFile = file("$buildDir/jacoco/jacocoTest.exec") + classDumpDir = file("$buildDir/jacoco/classpathdumps") + } + } } -} -task jacocoMerge(type: JacocoMerge) { - destinationFile = file(jacocoCoverageAggregate) - executionData = project.fileTree(dir: '.', include: '**/build/jacoco/test.exec') -} + task jacocoMerge(type: JacocoMerge) { + destinationFile = file(jacocoCoverageAggregate) + executionData = project.fileTree(dir: '.', include: '**/build/jacoco/jacocoTest.exec') + } -sonarqube { - properties { - property "sonar.organization", "apollo-rsps" - property "sonar.projectKey", "apollo:org.apollo" - property "sonar.projectName", "Apollo RSPS" - property "sonar.kotlin.file.suffixes", ".kt,.kts" - property "sonar.jacoco.reportPaths", jacocoCoverageAggregate + sonarqube { + properties { + property "sonar.organization", "apollo-rsps" + property "sonar.projectKey", "apollo:org.apollo" + property "sonar.projectName", "Apollo RSPS" + property "sonar.kotlin.file.suffixes", ".kt,.kts" + property "sonar.jacoco.reportPaths", jacocoCoverageAggregate + } } -} -tasks["sonarqube"].dependsOn(jacocoMerge) + tasks["sonarqube"].dependsOn(jacocoMerge) +} From c89179825c9690c0584b21112ccc6ce15998308c Mon Sep 17 00:00:00 2001 From: Major- Date: Tue, 28 Aug 2018 18:09:33 +0100 Subject: [PATCH 168/209] Remove inline modifier from string asserts --- .../game/plugin/testing/assertions/StringAssertions.kt | 7 +++++++ .../apollo/game/plugin/testing/assertions/stringAsserts.kt | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/StringAssertions.kt delete mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/StringAssertions.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/StringAssertions.kt new file mode 100644 index 000000000..c32e88419 --- /dev/null +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/StringAssertions.kt @@ -0,0 +1,7 @@ +package org.apollo.game.plugin.testing.assertions + +import io.mockk.MockKMatcherScope + +fun MockKMatcherScope.contains(search: String) = match { it.contains(search) } +fun MockKMatcherScope.startsWith(search: String) = match { it.startsWith(search) } +fun MockKMatcherScope.endsWith(search: String) = match { it.endsWith(search) } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt deleted file mode 100644 index a21d4a498..000000000 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/stringAsserts.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.apollo.game.plugin.testing.assertions - -import io.mockk.MockKMatcherScope - -inline fun MockKMatcherScope.contains(search: String) = match { it.contains(search) } -inline fun MockKMatcherScope.startsWith(search: String) = match { it.startsWith(search) } -inline fun MockKMatcherScope.endsWith(search: String) = match { it.endsWith(search) } \ No newline at end of file From 1f539b16ab4b2b373703e8e934cec45f912d0de6 Mon Sep 17 00:00:00 2001 From: atomicint Date: Tue, 28 Aug 2018 13:38:11 -0400 Subject: [PATCH 169/209] Remove duplicate GameObject rotated checks --- .../apollo/plugin/entity/pathing/Pathing.kt | 19 +-------- .../model/area/collision/CollisionUpdate.java | 11 +---- .../game/model/entity/obj/GameObject.java | 30 ++++++++++---- .../area/collision/CollisionManagerTests.java | 41 ++++++++++++++++++- 4 files changed, 64 insertions(+), 37 deletions(-) diff --git a/game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt b/game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt index 93adb6991..963bb48ad 100644 --- a/game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt +++ b/game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt @@ -63,21 +63,4 @@ fun Mob.walkTo(target: Position, positionPredicate: ((Position) -> Boolean)? = n /** * Returns the bounding size of the specified [Entity], in [x-size, y-size] format. */ -private fun bounds(target: Entity): Pair { - return when (target) { - is GameObject -> { - val orientation = Direction.WNES[target.orientation] - val rotated = (orientation == Direction.WEST || orientation == Direction.EAST) - - val definition = target.definition - - val width = if (rotated) definition.length else definition.width - val height = if (rotated) definition.width else definition.length - - Pair(width, height) - } - is Npc -> Pair(target.definition.size, target.definition.size) - is Player -> Pair(1, 1) - else -> error("Invalid entity type") - } -} \ No newline at end of file +private fun bounds(target: Entity): Pair = Pair(target.width, target.length) \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdate.java b/game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdate.java index cd8fb73ab..1c4047842 100644 --- a/game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdate.java +++ b/game/src/main/java/org/apollo/game/model/area/collision/CollisionUpdate.java @@ -195,23 +195,16 @@ public void object(GameObject object) { } int x = position.getX(), y = position.getY(), height = position.getHeight(); - int width = definition.getWidth(), length = definition.getLength(); boolean impenetrable = definition.isImpenetrable(); int orientation = object.getOrientation(); - // north / south for walls, north east / south west for corners - if (orientation == 1 || orientation == 3) { - width = definition.getLength(); - length = definition.getWidth(); - } - if (type == FLOOR_DECORATION.getValue()) { if (definition.isInteractive() && definition.isSolid()) { tile(new Position(x, y, height), impenetrable, Direction.NESW); } } else if (type >= DIAGONAL_WALL.getValue() && type < FLOOR_DECORATION.getValue()) { - for (int dx = 0; dx < width; dx++) { - for (int dy = 0; dy < length; dy++) { + for (int dx = 0; dx < object.getWidth(); dx++) { + for (int dy = 0; dy < object.getLength(); dy++) { tile(new Position(x + dx, y + dy, height), impenetrable, Direction.NESW); } } diff --git a/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java b/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java index 0d8391bfc..1ceb76897 100644 --- a/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java +++ b/game/src/main/java/org/apollo/game/model/entity/obj/GameObject.java @@ -13,6 +13,9 @@ import com.google.common.base.MoreObjects; +import static org.apollo.game.model.entity.obj.ObjectType.RECTANGULAR_CORNER; +import static org.apollo.game.model.entity.obj.ObjectType.TRIANGULAR_CORNER; + /** * Represents an object in the game world. * @@ -86,21 +89,32 @@ public int getType() { return packed >> 2 & 0x3F; } - @Override public int getLength() { - Direction direction = Direction.WNES[getOrientation()]; - - return direction == Direction.WEST || direction == Direction.EAST ? - getDefinition().getWidth() : getDefinition().getLength(); + return isRotated() ? getDefinition().getWidth() : getDefinition().getLength(); } @Override public int getWidth() { - Direction direction = Direction.WNES[getOrientation()]; + return isRotated() ? getDefinition().getLength() : getDefinition().getWidth(); + } + + /** + * Returns whether or not this GameObject's orientation is rotated {@link Direction#WEST} or {@link Direction#EAST}. + * + * @return {@code true} iff this GameObject's orientation is rotated. + */ + public boolean isRotated() { + int orientation = getOrientation(); + int type = getType(); + Direction direction = Direction.WNES[orientation]; + + if (type == TRIANGULAR_CORNER.getValue() || type == RECTANGULAR_CORNER.getValue()) { + direction = Direction.WNES_DIAGONAL[orientation]; + } - return direction == Direction.WEST || direction == Direction.EAST ? - getDefinition().getLength() : getDefinition().getWidth(); + return direction == Direction.NORTH || direction == Direction.SOUTH + || direction == Direction.NORTH_WEST || direction == Direction.SOUTH_EAST; } @Override diff --git a/game/src/test/java/org/apollo/game/model/area/collision/CollisionManagerTests.java b/game/src/test/java/org/apollo/game/model/area/collision/CollisionManagerTests.java index d0f528975..056793e4a 100644 --- a/game/src/test/java/org/apollo/game/model/area/collision/CollisionManagerTests.java +++ b/game/src/test/java/org/apollo/game/model/area/collision/CollisionManagerTests.java @@ -85,9 +85,10 @@ public void wall() { assertUntraversable(collisionManager, back, Direction.SOUTH_EAST); } + /** - * Tests that a corner wall is untraversable from the sides that it blocks. Corners are much like walls, with - * the only difference being their orientation. Instead of {@link Direction#WNES}, they have diagonal directions. + * Tests that a corner triangular wall is untraversable from the sides that it blocks. Corners are much like walls, + * with the only difference being their orientation. Instead of {@link Direction#WNES}, they have diagonal directions. * With a corner wall at (0, 1) facing to the north-east we end up with a grid looking like this: *

*

@@ -121,6 +122,42 @@ public void cornerWall() {
 		assertUntraversable(collisionManager, back, Direction.SOUTH_WEST);
 	}
 
+	/**
+	 * Tests that a corner rectangle wall is untraversable from the sides that it blocks.  Corners are much like walls,
+	 * with the only difference being their orientation.  Instead of {@link Direction#WNES}, they have diagonal directions.
+	 * With a corner wall at (0, 1) facing to the north-east we end up with a grid looking like this:
+	 * 

+ *

+	 * (0,2) |---------|---------|
+	 *       |         |         |
+	 *       |         |         |
+	 *       |         |xxx      |
+	 * (0,1) |---------|---------|
+	 *       |      xxx|         |
+	 *       |         |         |
+	 *       |         |         |
+	 * (0,0) |---------|---------|
+	 * 	   (1,0)     (2,0)     (3,0)
+	 * 
+ *

+ * Where you can walk north and east through the tile the corner occupies, as well as south and west through the + * adjacent tile, but not north-east or south-west. + */ + @Test + public void rectangleWall() { + Position front = new Position(0, 1, 0); + Position back = front.step(1, Direction.NORTH_EAST); + + CollisionManager collisionManager = createCollisionManager( + createMapObject(WALL, front, ObjectType.RECTANGULAR_CORNER, Direction.NORTH_EAST) + ); + + assertTraversable(collisionManager, front, Direction.NORTH, Direction.EAST); + assertUntraversable(collisionManager, front, Direction.NORTH_EAST); + assertTraversable(collisionManager, back, Direction.SOUTH, Direction.WEST); + assertUntraversable(collisionManager, back, Direction.SOUTH_WEST); + } + /** * Tests that the tiles occupied by a 2x2 square object are not traversable. When an interactable object is added * to a collision update, all tiles spanning its with and length from its origin position will be marked as completely From 1a4724dcced6bf7c79b90a484acac9a23fac6894 Mon Sep 17 00:00:00 2001 From: Major- Date: Tue, 28 Aug 2018 18:50:54 +0100 Subject: [PATCH 170/209] Repackage player actions plugin --- game/plugin/entity/{player-action => actions}/build.gradle | 0 .../entity/{player-action => actions}/src/PlayerAction.kt | 2 +- .../entity/{player-action => actions}/src/PlayerActionType.kt | 2 +- .../{player-action => actions}/src/PlayerActions.plugin.kts | 2 +- .../{player-action => actions}/test/PlayerActionTests.kt | 2 +- game/plugin/entity/following/build.gradle | 4 +--- game/plugin/entity/following/src/following.plugin.kts | 4 ++-- 7 files changed, 7 insertions(+), 9 deletions(-) rename game/plugin/entity/{player-action => actions}/build.gradle (100%) rename game/plugin/entity/{player-action => actions}/src/PlayerAction.kt (95%) rename game/plugin/entity/{player-action => actions}/src/PlayerActionType.kt (80%) rename game/plugin/entity/{player-action => actions}/src/PlayerActions.plugin.kts (90%) rename game/plugin/entity/{player-action => actions}/test/PlayerActionTests.kt (96%) diff --git a/game/plugin/entity/player-action/build.gradle b/game/plugin/entity/actions/build.gradle similarity index 100% rename from game/plugin/entity/player-action/build.gradle rename to game/plugin/entity/actions/build.gradle diff --git a/game/plugin/entity/player-action/src/PlayerAction.kt b/game/plugin/entity/actions/src/PlayerAction.kt similarity index 95% rename from game/plugin/entity/player-action/src/PlayerAction.kt rename to game/plugin/entity/actions/src/PlayerAction.kt index 22026b62a..ff8fd6d2b 100644 --- a/game/plugin/entity/player-action/src/PlayerAction.kt +++ b/game/plugin/entity/actions/src/PlayerAction.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.entity.player_action +package org.apollo.game.plugin.entity.actions import org.apollo.game.message.impl.SetPlayerActionMessage import org.apollo.game.model.entity.Player diff --git a/game/plugin/entity/player-action/src/PlayerActionType.kt b/game/plugin/entity/actions/src/PlayerActionType.kt similarity index 80% rename from game/plugin/entity/player-action/src/PlayerActionType.kt rename to game/plugin/entity/actions/src/PlayerActionType.kt index b4ac185f6..049349157 100644 --- a/game/plugin/entity/player-action/src/PlayerActionType.kt +++ b/game/plugin/entity/actions/src/PlayerActionType.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.entity.player_action +package org.apollo.game.plugin.entity.actions enum class PlayerActionType(val displayName: String, val slot: Int, val primary: Boolean = true) { ATTACK("Attack", 2), diff --git a/game/plugin/entity/player-action/src/PlayerActions.plugin.kts b/game/plugin/entity/actions/src/PlayerActions.plugin.kts similarity index 90% rename from game/plugin/entity/player-action/src/PlayerActions.plugin.kts rename to game/plugin/entity/actions/src/PlayerActions.plugin.kts index 6b4a0fe40..675a8a53e 100644 --- a/game/plugin/entity/player-action/src/PlayerActions.plugin.kts +++ b/game/plugin/entity/actions/src/PlayerActions.plugin.kts @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.entity.player_action +package org.apollo.game.plugin.entity.actions import org.apollo.game.message.impl.PlayerActionMessage import org.apollo.game.model.event.impl.LoginEvent diff --git a/game/plugin/entity/player-action/test/PlayerActionTests.kt b/game/plugin/entity/actions/test/PlayerActionTests.kt similarity index 96% rename from game/plugin/entity/player-action/test/PlayerActionTests.kt rename to game/plugin/entity/actions/test/PlayerActionTests.kt index 4c1dc248f..2a6546936 100644 --- a/game/plugin/entity/player-action/test/PlayerActionTests.kt +++ b/game/plugin/entity/actions/test/PlayerActionTests.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.entity.player_action +package org.apollo.game.plugin.entity.actions import io.mockk.verify import org.apollo.game.message.impl.SetPlayerActionMessage diff --git a/game/plugin/entity/following/build.gradle b/game/plugin/entity/following/build.gradle index 3f43d5f07..e81c73d48 100644 --- a/game/plugin/entity/following/build.gradle +++ b/game/plugin/entity/following/build.gradle @@ -1,13 +1,11 @@ apply plugin: 'kotlin' - - dependencies { implementation project(':game') implementation project(':cache') implementation project(':net') implementation project(':util') implementation project(':game:plugin:entity:walk-to') - implementation project(':game:plugin:entity:player-action') + implementation project(':game:plugin:entity:actions') testImplementation project(':game:plugin-testing') } diff --git a/game/plugin/entity/following/src/following.plugin.kts b/game/plugin/entity/following/src/following.plugin.kts index 25e97d82e..26e8f2897 100644 --- a/game/plugin/entity/following/src/following.plugin.kts +++ b/game/plugin/entity/following/src/following.plugin.kts @@ -1,5 +1,5 @@ -import org.apollo.game.plugin.entity.player_action.PlayerActionEvent -import org.apollo.game.plugin.entity.player_action.PlayerActionType +import org.apollo.game.plugin.entity.actions.PlayerActionEvent +import org.apollo.game.plugin.entity.actions.PlayerActionType import org.apollo.plugin.entity.following.FollowAction on_player_event { PlayerActionEvent::class } From abc4dc3a76acdb03827afab78db900a690ce77d9 Mon Sep 17 00:00:00 2001 From: Major- Date: Tue, 28 Aug 2018 19:32:26 +0100 Subject: [PATCH 171/209] Rename walk-to to pathing --- game/plugin/entity/following/build.gradle | 2 +- .../entity/{walk-to => pathing}/build.gradle | 0 .../apollo/plugin/entity/pathing/Pathing.kt | 83 +++++++++++++++++++ game/plugin/entity/walk-to/src/walk_to.kt | 66 --------------- 4 files changed, 84 insertions(+), 67 deletions(-) rename game/plugin/entity/{walk-to => pathing}/build.gradle (100%) create mode 100644 game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt delete mode 100644 game/plugin/entity/walk-to/src/walk_to.kt diff --git a/game/plugin/entity/following/build.gradle b/game/plugin/entity/following/build.gradle index e81c73d48..4aca75d50 100644 --- a/game/plugin/entity/following/build.gradle +++ b/game/plugin/entity/following/build.gradle @@ -5,7 +5,7 @@ dependencies { implementation project(':cache') implementation project(':net') implementation project(':util') - implementation project(':game:plugin:entity:walk-to') + implementation project(':game:plugin:entity:pathing') implementation project(':game:plugin:entity:actions') testImplementation project(':game:plugin-testing') } diff --git a/game/plugin/entity/walk-to/build.gradle b/game/plugin/entity/pathing/build.gradle similarity index 100% rename from game/plugin/entity/walk-to/build.gradle rename to game/plugin/entity/pathing/build.gradle diff --git a/game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt b/game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt new file mode 100644 index 000000000..93adb6991 --- /dev/null +++ b/game/plugin/entity/pathing/src/org/apollo/plugin/entity/pathing/Pathing.kt @@ -0,0 +1,83 @@ +package org.apollo.plugin.entity.pathing + +import org.apollo.game.model.Direction +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Entity +import org.apollo.game.model.entity.Mob +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.model.entity.path.SimplePathfindingAlgorithm + +/** + * Adds a path from this [Mob] to the [target] [Entity], with the final position determined by the [facing] [Direction]. + */ +fun Mob.walkTo(target: Entity, facing: Direction? = null) { + val (width, length) = bounds(this) + val (targetWidth, targetLength) = bounds(target) + + val direction = facing ?: Direction.between(position, target.position) + val dx = direction.deltaX() + val dy = direction.deltaY() + + val targetX = if (dx <= 0) target.position.x else target.position.x + targetWidth - 1 + val targetY = if (dy <= 0) target.position.y else target.position.y + targetLength - 1 + val offsetX = if (dx < 0) -width else if (dx > 0) 1 else 0 + val offsetY = if (dy < 0) -length else if (dy > 0) 1 else 0 + + walkTo(Position(targetX + offsetX, targetY + offsetY, position.height)) +} + +/** + * Adds a path for this [Mob] to the target [Mob]s last position. + */ +fun Mob.walkBehind(target: Mob) { + walkTo(target, target.lastDirection.opposite()) +} + +/** + * Adds a path from this [Mob] to the [target] [Position], ending the path as soon as [positionPredicate] returns + * `false` (if provided). + */ +fun Mob.walkTo(target: Position, positionPredicate: ((Position) -> Boolean)? = null) { + if (position == target) { + return + } + + val pathfinder = SimplePathfindingAlgorithm(world.collisionManager) + val path = pathfinder.find(position, target) + + if (positionPredicate == null) { + path.forEach(walkingQueue::addStep) + } else { + for (step in path) { + if (!positionPredicate(step)) { + return + } + + walkingQueue.addStep(step) + } + } +} + +/** + * Returns the bounding size of the specified [Entity], in [x-size, y-size] format. + */ +private fun bounds(target: Entity): Pair { + return when (target) { + is GameObject -> { + val orientation = Direction.WNES[target.orientation] + val rotated = (orientation == Direction.WEST || orientation == Direction.EAST) + + val definition = target.definition + + val width = if (rotated) definition.length else definition.width + val height = if (rotated) definition.width else definition.length + + Pair(width, height) + } + is Npc -> Pair(target.definition.size, target.definition.size) + is Player -> Pair(1, 1) + else -> error("Invalid entity type") + } +} \ No newline at end of file diff --git a/game/plugin/entity/walk-to/src/walk_to.kt b/game/plugin/entity/walk-to/src/walk_to.kt deleted file mode 100644 index 87a1135d4..000000000 --- a/game/plugin/entity/walk-to/src/walk_to.kt +++ /dev/null @@ -1,66 +0,0 @@ -package org.apollo.plugin.entity.walkto - -import org.apollo.game.model.Direction -import org.apollo.game.model.Position -import org.apollo.game.model.entity.Entity -import org.apollo.game.model.entity.Mob -import org.apollo.game.model.entity.Npc -import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.model.entity.path.SimplePathfindingAlgorithm - -private fun bounds(target: Entity): Pair = when (target) { - is GameObject -> { - val orientation = Direction.WNES[target.orientation] - val rotated = (orientation == Direction.WEST || orientation == Direction.EAST) - - val width = if (rotated) target.definition.length else target.definition.width - val height = if (rotated) target.definition.width else target.definition.length - - Pair(width, height) - } - is Npc -> Pair(target.definition.size, target.definition.size) - is Player -> Pair(1, 1) - else -> error("Invalid entity type") -} - -fun Mob.walkTo(target: Entity, positioningDirection: Direction? = null) { - val (sourceWidth, sourceHeight) = bounds(target) - val (targetWidth, targetHeight) = bounds(target) - - val direction = positioningDirection ?: Direction.between(position, target.position) - val dx = direction.deltaX() - val dy = direction.deltaY() - - val targetX = if (dx <= 0) target.position.x else target.position.x + targetWidth - 1 - val targetY = if (dy <= 0) target.position.y else target.position.y + targetHeight - 1 - val offsetX = if (dx < 0) -sourceWidth else if (dx > 0) 1 else 0 - val offsetY = if (dy < 0) -sourceHeight else if (dy > 0) 1 else 0 - - walkTo(Position(targetX + offsetX, targetY + offsetY, position.height)) -} - -fun Mob.walkBehind(target: Mob) { - walkTo(target, target.lastDirection.opposite()) -} - -fun Mob.walkTo(target: Position, positionPredicate: ((Position) -> Boolean)? = null) { - if (position == target) { - return - } - - val pathfinder = SimplePathfindingAlgorithm(world.collisionManager) - val path = pathfinder.find(position, target) - - if (positionPredicate == null) { - path.forEach(walkingQueue::addStep) - } else { - for (step in path) { - if (!positionPredicate.invoke(step)) { - return - } - - walkingQueue.addStep(step) - } - } -} \ No newline at end of file From 68361110d9b708dc676718d5e375668755969e88 Mon Sep 17 00:00:00 2001 From: Major- Date: Tue, 28 Aug 2018 19:58:13 +0100 Subject: [PATCH 172/209] Repackage following plugin --- .../apollo/plugin/entity/following/Following.kt} | 14 ++++++-------- .../plugin/entity/following/Following.plugin.kts} | 6 ++++-- 2 files changed, 10 insertions(+), 10 deletions(-) rename game/plugin/entity/following/src/{following.kt => org/apollo/plugin/entity/following/Following.kt} (77%) rename game/plugin/entity/following/src/{following.plugin.kts => org/apollo/plugin/entity/following/Following.plugin.kts} (73%) diff --git a/game/plugin/entity/following/src/following.kt b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.kt similarity index 77% rename from game/plugin/entity/following/src/following.kt rename to game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.kt index e208229f2..2c678c283 100644 --- a/game/plugin/entity/following/src/following.kt +++ b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.kt @@ -3,13 +3,12 @@ package org.apollo.plugin.entity.following import org.apollo.game.action.Action import org.apollo.game.model.Direction import org.apollo.game.model.Position -import org.apollo.game.model.entity.Mob import org.apollo.game.model.entity.Player import org.apollo.net.message.Message -import org.apollo.plugin.entity.walkto.walkBehind -import org.apollo.plugin.entity.walkto.walkTo +import org.apollo.plugin.entity.pathing.walkBehind +import org.apollo.plugin.entity.pathing.walkTo -class FollowAction(player: Player, val target: Player) : Action(0, true, player) { +class FollowAction(player: Player, private val target: Player) : Action(0, true, player) { var lastPosition: Position? = null companion object { @@ -42,11 +41,10 @@ class FollowAction(player: Player, val target: Player) : Action(0, true, val directionOffset = (Math.random() * directions.size).toInt() mob.walkTo(target.position.step(1, directions[directionOffset])) - return + } else { + mob.walkBehind(target) + lastPosition = target.position } - - mob.walkBehind(target) - lastPosition = target.position } } \ No newline at end of file diff --git a/game/plugin/entity/following/src/following.plugin.kts b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.plugin.kts similarity index 73% rename from game/plugin/entity/following/src/following.plugin.kts rename to game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.plugin.kts index 26e8f2897..10d483ce4 100644 --- a/game/plugin/entity/following/src/following.plugin.kts +++ b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.plugin.kts @@ -1,10 +1,12 @@ +package org.apollo.plugin.entity.following + import org.apollo.game.plugin.entity.actions.PlayerActionEvent import org.apollo.game.plugin.entity.actions.PlayerActionType import org.apollo.plugin.entity.following.FollowAction on_player_event { PlayerActionEvent::class } .where { action == PlayerActionType.FOLLOW } - .then { - FollowAction.start(it, target) + .then { player -> + FollowAction.start(player, target) terminate() } \ No newline at end of file From 9a8f94df184ab3fa1e680d5c5d6c91e4ee7a331d Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Mon, 3 Sep 2018 22:40:11 +0100 Subject: [PATCH 173/209] Add runecrafting action unit tests --- .../runecrafting/src/{altar.kt => Altar.kt} | 2 + .../runecrafting/src/CreateTiaraAction.kt | 25 ++++ game/plugin/skills/runecrafting/src/Rune.kt | 66 ++++++++++ ...ing.plugin.kts => Runecrafting.plugin.kts} | 21 +++- .../runecrafting/src/RunecraftingAction.kt | 39 ++++++ .../src/{talisman.kt => Talisman.kt} | 10 +- .../runecrafting/src/TeleportToAltarAction.kt | 12 ++ .../runecrafting/src/{tiara.kt => Tiara.kt} | 6 +- game/plugin/skills/runecrafting/src/action.kt | 75 ----------- .../skills/runecrafting/src/constants.kt | 9 ++ game/plugin/skills/runecrafting/src/rune.kt | 36 ------ .../test/CreateTiaraActionTests.kt | 68 ++++++++++ .../test/RunecraftingActionTests.kt | 116 ++++++++++++++++++ 13 files changed, 364 insertions(+), 121 deletions(-) rename game/plugin/skills/runecrafting/src/{altar.kt => Altar.kt} (97%) create mode 100644 game/plugin/skills/runecrafting/src/CreateTiaraAction.kt create mode 100644 game/plugin/skills/runecrafting/src/Rune.kt rename game/plugin/skills/runecrafting/src/{runecrafting.plugin.kts => Runecrafting.plugin.kts} (80%) create mode 100644 game/plugin/skills/runecrafting/src/RunecraftingAction.kt rename game/plugin/skills/runecrafting/src/{talisman.kt => Talisman.kt} (88%) create mode 100644 game/plugin/skills/runecrafting/src/TeleportToAltarAction.kt rename game/plugin/skills/runecrafting/src/{tiara.kt => Tiara.kt} (86%) delete mode 100644 game/plugin/skills/runecrafting/src/action.kt create mode 100644 game/plugin/skills/runecrafting/src/constants.kt delete mode 100644 game/plugin/skills/runecrafting/src/rune.kt create mode 100644 game/plugin/skills/runecrafting/test/CreateTiaraActionTests.kt create mode 100644 game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt diff --git a/game/plugin/skills/runecrafting/src/altar.kt b/game/plugin/skills/runecrafting/src/Altar.kt similarity index 97% rename from game/plugin/skills/runecrafting/src/altar.kt rename to game/plugin/skills/runecrafting/src/Altar.kt index 3895a26aa..f336b2b1d 100644 --- a/game/plugin/skills/runecrafting/src/altar.kt +++ b/game/plugin/skills/runecrafting/src/Altar.kt @@ -1,3 +1,5 @@ +package org.apollo.game.plugin.skill.runecrafting + import org.apollo.game.model.Position enum class Altar(val entranceId: Int, val craftingId: Int, val portalId: Int, val entrance: Position, val exit: Position, val center: Position) { diff --git a/game/plugin/skills/runecrafting/src/CreateTiaraAction.kt b/game/plugin/skills/runecrafting/src/CreateTiaraAction.kt new file mode 100644 index 000000000..f6bcc43fe --- /dev/null +++ b/game/plugin/skills/runecrafting/src/CreateTiaraAction.kt @@ -0,0 +1,25 @@ +package org.apollo.game.plugin.skill.runecrafting + +import org.apollo.game.action.DistancedAction +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.runecraft + +class CreateTiaraAction(val player: Player, val position: Position, val tiara: Tiara, val altar: Altar) : DistancedAction(0, true, player, position, 2) { + override fun executeAction() { + if (tiara.altar != altar) { + player.sendMessage("You can't use that talisman on this altar.") + stop() + return + } + + if (player.inventory.contains(blankTiaraId)) { + player.inventory.remove(blankTiaraId) + player.inventory.add(tiara.id) + player.runecraft.experience += tiara.xp + player.playAnimation(runecraftingAnimation) + player.playGraphic(runecraftingGraphic) + stop() + } + } +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/Rune.kt b/game/plugin/skills/runecrafting/src/Rune.kt new file mode 100644 index 000000000..9d2c3991e --- /dev/null +++ b/game/plugin/skills/runecrafting/src/Rune.kt @@ -0,0 +1,66 @@ +package org.apollo.game.plugin.skill.runecrafting + +import org.apollo.game.plugin.skill.runecrafting.Altar.* + + +interface Rune { + /** + * The item id of the rune. + */ + val id: Int + + /** + * The [Altar] this rune must be crafted at. + */ + val altar: Altar + + /** + * The runecrafting level required to craft runes of this type. + */ + val level: Int + + /** + * The amount of experience rewarded from crafting a single rune of this type. + */ + val xp: Double + + /** + * Get the multiplier that is applied to the number of runes the player crafts for their runecrafting level. + * + * [playerLevel] - The players current runecrafting level. + */ + fun getBonusMultiplier(playerLevel: Int) : Double +} + +enum class DefaultRune( + override val id: Int, + override val altar: Altar, + override val level: Int, + override val xp: Double +) : Rune { + AIR_RUNE(556, AIR_ALTAR, 1, 5.0), + MIND_RUNE(558, MIND_ALTAR, 1, 5.5), + WATER_RUNE(555, WATER_ALTAR, 5, 6.0), + EARTH_RUNE(557, EARTH_ALTAR, 9, 6.5), + FIRE_RUNE(554, FIRE_ALTAR, 14, 7.0), + BODY_RUNE(559, BODY_ALTAR, 20, 7.5), + COSMIC_RUNE(564, COSMIC_ALTAR, 27, 8.0), + CHAOS_RUNE(562, CHAOS_ALTAR, 35, 8.5), + NATURE_RUNE(561, NATURE_ALTAR, 44, 9.0), + LAW_RUNE(563, LAW_ALTAR, 54, 9.5), + DEATH_RUNE(560, DEATH_ALTAR, 65, 10.0); + + override fun getBonusMultiplier(playerLevel: Int): Double = when (this) { + DefaultRune.AIR_RUNE -> (Math.floor((playerLevel / 11.0)) + 1) + DefaultRune.MIND_RUNE -> (Math.floor((playerLevel / 14.0)) + 1) + DefaultRune.WATER_RUNE -> (Math.floor((playerLevel / 19.0)) + 1) + DefaultRune.EARTH_RUNE -> (Math.floor((playerLevel / 26.0)) + 1) + DefaultRune.FIRE_RUNE -> (Math.floor((playerLevel / 35.0)) + 1) + DefaultRune.BODY_RUNE -> (Math.floor((playerLevel / 46.0)) + 1) + DefaultRune.COSMIC_RUNE -> (Math.floor((playerLevel / 59.0)) + 1) + DefaultRune.CHAOS_RUNE -> (Math.floor((playerLevel / 74.0)) + 1) + DefaultRune.NATURE_RUNE -> (Math.floor((playerLevel / 91.0)) + 1) + DefaultRune.LAW_RUNE -> 1.0 + DefaultRune.DEATH_RUNE -> 1.0 + } +} diff --git a/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts b/game/plugin/skills/runecrafting/src/Runecrafting.plugin.kts similarity index 80% rename from game/plugin/skills/runecrafting/src/runecrafting.plugin.kts rename to game/plugin/skills/runecrafting/src/Runecrafting.plugin.kts index ece21c98f..b31dbc5bf 100644 --- a/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts +++ b/game/plugin/skills/runecrafting/src/Runecrafting.plugin.kts @@ -1,9 +1,22 @@ +package org.apollo.game.plugin.skill.runecrafting + import org.apollo.game.message.impl.* import org.apollo.game.model.entity.EquipmentConstants import org.apollo.game.model.event.impl.LoginEvent private val changeAltarObjectConfigId = 491 +internal val RUNES = mutableListOf() + +fun List.findById(id: Int) : Rune? { + return find { rune -> rune.id == id } +} + + +start { + RUNES.addAll(DefaultRune.values()) +} + on_player_event { LoginEvent::class } .then { val equippedHat = player.equipment.get(EquipmentConstants.HAT) @@ -20,7 +33,7 @@ on { ObjectActionMessage::class } val hat = it.equipment.get(EquipmentConstants.HAT) ?: return@then if (hat.id == tiara.id && tiara.altar.entranceId == id) { - it.startAction(TeleportAction(it, position, 2, tiara.altar.entrance)) + it.startAction(TeleportToAltarAction(it, position, 2, tiara.altar.entrance)) terminate() } } @@ -57,7 +70,7 @@ on { ItemOnObjectMessage::class } val talisman = Talisman.findById(id) ?: return@then val altar = Altar.findByEntranceId(objectId) ?: return@then - it.startAction(TeleportAction(it, position, 2, altar.entrance)) + it.startAction(TeleportToAltarAction(it, position, 2, altar.entrance)) terminate() } @@ -66,14 +79,14 @@ on { ObjectActionMessage::class } .then { val altar = Altar.findByPortalId(id) ?: return@then - it.startAction(TeleportAction(it, altar.entrance, 1, altar.exit)) + it.startAction(TeleportToAltarAction(it, altar.entrance, 1, altar.exit)) terminate() } on { ObjectActionMessage::class } .where { option == 1 } .then { - val rune = Rune.findByAltarId(id) ?: return@then + val rune = RUNES.findById(id) ?: return@then val craftingAltar = Altar.findByCraftingId(id) ?: return@then it.startAction(RunecraftingAction(it, rune, craftingAltar)) diff --git a/game/plugin/skills/runecrafting/src/RunecraftingAction.kt b/game/plugin/skills/runecrafting/src/RunecraftingAction.kt new file mode 100644 index 000000000..371a35543 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/RunecraftingAction.kt @@ -0,0 +1,39 @@ +package org.apollo.game.plugin.skill.runecrafting + +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.api.runecraft +import org.apollo.util.LanguageUtil + +class RunecraftingAction(val player: Player, val rune: Rune, altar: Altar) : AsyncDistancedAction(0, true, player, altar.center, 3) { + override fun action(): ActionBlock = { + if (player.runecraft.current < rune.level) { + player.sendMessage("You need a runecrafting level of ${rune.level} to craft this rune.") + stop() + } + + if (!player.inventory.contains(runeEssenceId)) { + player.sendMessage("You need rune essence to craft runes.") + stop() + } + + player.turnTo(position) + player.playAnimation(runecraftingAnimation) + player.playGraphic(runecraftingGraphic) + + wait(1) + + val name = Definitions.item(rune.id).name; + val nameArticle = LanguageUtil.getIndefiniteArticle(name) + val essenceAmount = player.inventory.removeAll(runeEssenceId) + val runeAmount = essenceAmount * rune.getBonusMultiplier(player.runecraft.current) + val runesDescription = if (runeAmount > 1) "some ${name}s" else "$nameArticle $name" + + player.sendMessage("You craft the rune essence into $runesDescription") + player.inventory.add(rune.id, runeAmount.toInt()) + player.runecraft.experience += rune.xp * essenceAmount + stop() + } +} diff --git a/game/plugin/skills/runecrafting/src/talisman.kt b/game/plugin/skills/runecrafting/src/Talisman.kt similarity index 88% rename from game/plugin/skills/runecrafting/src/talisman.kt rename to game/plugin/skills/runecrafting/src/Talisman.kt index db81d9dc6..bd4cc542e 100644 --- a/game/plugin/skills/runecrafting/src/talisman.kt +++ b/game/plugin/skills/runecrafting/src/Talisman.kt @@ -1,3 +1,5 @@ +package org.apollo.game.plugin.skill.runecrafting + import org.apollo.game.model.Position import org.apollo.game.model.entity.Player @@ -22,13 +24,13 @@ enum class Talisman(val id: Int, val altar: Position) { fun sendProximityMessageTo(player: Player) { if (altar.isWithinDistance(player.position, 10)) { - player.sendMessage("Your talisman glows brightly."); + player.sendMessage("Your talisman glows brightly.") return } - var direction = if (player.position.y > altar.y) "North" else "South"; - direction += if (player.position.x > altar.x) "-East" else "-West"; + var direction = if (player.position.y > altar.y) "North" else "South" + direction += if (player.position.x > altar.x) "-East" else "-West" - player.sendMessage("The talisman pulls toward the $direction"); + player.sendMessage("The talisman pulls toward the $direction") } } \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/TeleportToAltarAction.kt b/game/plugin/skills/runecrafting/src/TeleportToAltarAction.kt new file mode 100644 index 000000000..ec6ff9a8c --- /dev/null +++ b/game/plugin/skills/runecrafting/src/TeleportToAltarAction.kt @@ -0,0 +1,12 @@ +package org.apollo.game.plugin.skill.runecrafting + +import org.apollo.game.action.DistancedAction +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player + +class TeleportToAltarAction(val player: Player, val start: Position, val distance: Int, val end: Position) : DistancedAction(0, true, player, start, distance) { + override fun executeAction() { + player.teleport(end) + stop() + } +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/tiara.kt b/game/plugin/skills/runecrafting/src/Tiara.kt similarity index 86% rename from game/plugin/skills/runecrafting/src/tiara.kt rename to game/plugin/skills/runecrafting/src/Tiara.kt index 549fe76be..d9e002c0e 100644 --- a/game/plugin/skills/runecrafting/src/tiara.kt +++ b/game/plugin/skills/runecrafting/src/Tiara.kt @@ -1,5 +1,7 @@ -import Altar.* -import Talisman.* +package org.apollo.game.plugin.skill.runecrafting + +import org.apollo.game.plugin.skill.runecrafting.Altar.* +import org.apollo.game.plugin.skill.runecrafting.Talisman.* enum class Tiara(val id: Int, val altar: Altar, val talisman: Talisman, val configId: Int, val xp: Double) { AIR_TIARA(5527, AIR_ALTAR, AIR_TALISMAN, 0, 25.0), diff --git a/game/plugin/skills/runecrafting/src/action.kt b/game/plugin/skills/runecrafting/src/action.kt deleted file mode 100644 index 6beb45704..000000000 --- a/game/plugin/skills/runecrafting/src/action.kt +++ /dev/null @@ -1,75 +0,0 @@ -import org.apollo.game.action.ActionBlock -import org.apollo.game.action.AsyncDistancedAction -import org.apollo.game.action.DistancedAction -import org.apollo.game.model.Animation -import org.apollo.game.model.Graphic -import org.apollo.game.model.Position -import org.apollo.game.model.entity.Player -import org.apollo.game.plugin.api.Definitions -import org.apollo.game.plugin.api.runecraft -import org.apollo.util.LanguageUtil - -private val blankTiaraId = 5525 -private val runecraftingAnimation = Animation(791) -private val runecraftingGraphic = Graphic(186, 0, 100) -private val runeEssenceId = 1436 - -class TeleportAction(val player: Player, val start: Position, val distance: Int, val end: Position) : DistancedAction(0, true, player, start, distance) { - override fun executeAction() { - player.teleport(end) - stop() - } -} - -class CreateTiaraAction(val player: Player, val position: Position, val tiara: Tiara, val altar: Altar) : DistancedAction(0, true, player, position, 2) { - override fun executeAction() { - if (tiara.altar != altar) { - player.sendMessage("You can't use that talisman on this altar.") - stop() - return - } - - if (player.inventory.contains(blankTiaraId)) { - player.inventory.remove(blankTiaraId) - player.inventory.add(tiara.id) - player.runecraft.experience += tiara.xp - player.playAnimation(runecraftingAnimation) - player.playGraphic(runecraftingGraphic) - stop() - } - } -} - -class RunecraftingAction(val player: Player, val rune: Rune, altar: Altar) : AsyncDistancedAction(0, true, player, altar.center, 3) { - override fun action(): ActionBlock = { - if (player.runecraft.current < rune.level) { - player.sendMessage("You need a runecrafting level of ${rune.level} to craft this rune.") - stop() - } - - if (!player.inventory.contains(runeEssenceId)) { - player.sendMessage("You need rune essence to craft runes.") - stop() - } - - player.turnTo(position) - player.playAnimation(runecraftingAnimation) - player.playGraphic(runecraftingGraphic) - - wait(1) - - val name = Definitions.item(rune.id)?.name; - val nameArticle = LanguageUtil.getIndefiniteArticle(name) - val essenceAmount = player.inventory.removeAll(runeEssenceId) - val runeAmount = essenceAmount * rune.getBonus() - val runesDescription = if (runeAmount > 1) "some ${name}s" else "$nameArticle $name" - - player.sendMessage("You craft the rune essence into $runesDescription") - player.inventory.add(rune.id, runeAmount.toInt()) - player.runecraft.experience += rune.xp - stop() - } - -} - - diff --git a/game/plugin/skills/runecrafting/src/constants.kt b/game/plugin/skills/runecrafting/src/constants.kt new file mode 100644 index 000000000..73f77cf52 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/constants.kt @@ -0,0 +1,9 @@ +package org.apollo.game.plugin.skill.runecrafting + +import org.apollo.game.model.Animation +import org.apollo.game.model.Graphic + +const val blankTiaraId = 5525 +val runecraftingAnimation = Animation(791) +val runecraftingGraphic = Graphic(186, 0, 100) +const val runeEssenceId = 1436 \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/rune.kt b/game/plugin/skills/runecrafting/src/rune.kt deleted file mode 100644 index bc94e94a3..000000000 --- a/game/plugin/skills/runecrafting/src/rune.kt +++ /dev/null @@ -1,36 +0,0 @@ -import Altar.* - -enum class Rune(val id: Int, val altar: Altar, val level: Int, val xp: Double) { - AIR_RUNE(556, AIR_ALTAR, 1, 5.0), - MIND_RUNE(558, MIND_ALTAR, 1, 5.5), - WATER_RUNE(555, WATER_ALTAR, 5, 6.0), - EARTH_RUNE(557, EARTH_ALTAR, 9, 6.5), - FIRE_RUNE(554, FIRE_ALTAR, 14, 7.0), - BODY_RUNE(559, BODY_ALTAR, 20, 7.5), - COSMIC_RUNE(564, COSMIC_ALTAR, 27, 8.0), - CHAOS_RUNE(562, CHAOS_ALTAR, 35, 8.5), - NATURE_RUNE(561, NATURE_ALTAR, 44, 9.0), - LAW_RUNE(563, LAW_ALTAR, 54, 9.5), - DEATH_RUNE(560, DEATH_ALTAR, 65, 10.0); - - companion object { - private val RUNES = Rune.values() - - fun findById(id: Int): Rune? = RUNES.find { rune -> rune.id == id } - fun findByAltarId(id: Int): Rune? = RUNES.find { rune -> rune.altar.craftingId == id } - } - - fun getBonus(): Double = when (this) { - Rune.AIR_RUNE -> (Math.floor((level / 11.0)) + 1) - Rune.MIND_RUNE -> (Math.floor((level / 14.0)) + 1) - Rune.WATER_RUNE -> (Math.floor((level / 19.0)) + 1) - Rune.EARTH_RUNE -> (Math.floor((level / 26.0)) + 1) - Rune.FIRE_RUNE -> (Math.floor((level / 35.0)) + 1) - Rune.BODY_RUNE -> (Math.floor((level / 46.0)) + 1) - Rune.COSMIC_RUNE -> (Math.floor((level / 59.0)) + 1) - Rune.CHAOS_RUNE -> (Math.floor((level / 74.0)) + 1) - Rune.NATURE_RUNE -> (Math.floor((level / 91.0)) + 1) - Rune.LAW_RUNE -> 1.0 - Rune.DEATH_RUNE -> 1.0 - } -} diff --git a/game/plugin/skills/runecrafting/test/CreateTiaraActionTests.kt b/game/plugin/skills/runecrafting/test/CreateTiaraActionTests.kt new file mode 100644 index 000000000..98af45f22 --- /dev/null +++ b/game/plugin/skills/runecrafting/test/CreateTiaraActionTests.kt @@ -0,0 +1,68 @@ +package org.apollo.game.plugin.skill.runecrafting + +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.verifyAfter +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class CreateTiaraActionTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + @Test + fun `A tiara should be rewarded after action completion`() { + player.inventory.add(blankTiaraId) + player.startAction(CreateTiaraAction(player, player.position, Tiara.AIR_TIARA, Altar.AIR_ALTAR)) + + after(action.complete(), "tiara added to inventory") { + assertEquals(1, player.inventory.getAmount(Tiara.AIR_TIARA.id)) + } + } + + @Test + fun `Tiaras can only be enchanted on compatible altars`() { + player.inventory.add(blankTiaraId) + player.startAction(CreateTiaraAction(player, player.position, Tiara.AIR_TIARA, Altar.BODY_ALTAR)) + + verifyAfter(action.complete(), "error message sent") { + player.sendMessage("You can't use that talisman on this altar.") + } + } + + @Test + fun `Experience is rewarded for enchanting tiaras`() { + player.inventory.add(blankTiaraId) + player.skillSet.setExperience(Skill.RUNECRAFT, 0.0) + player.startAction(CreateTiaraAction(player, player.position, Tiara.AIR_TIARA, Altar.AIR_ALTAR)) + + after(action.complete(), "experience gained") { + assertEquals(Tiara.AIR_TIARA.xp, player.skillSet.getExperience(Skill.RUNECRAFT)) + } + } + + companion object { + @ItemDefinitions + private val tiaras = Tiara.values() + .map { ItemDefinition(it.id).apply { name = "" } } + + @ItemDefinitions + private val blankTiara = listOf(ItemDefinition(blankTiaraId)) + } +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt b/game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt new file mode 100644 index 000000000..4e01a44bc --- /dev/null +++ b/game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt @@ -0,0 +1,116 @@ +package org.apollo.game.plugin.skill.runecrafting + +import io.mockk.verify +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class RunecraftingActionTests { + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + @BeforeEach + fun setupPlayer() { + player.position = TEST_ALTAR.center + player.inventory.add(runeEssenceId, 25) + + } + + @Test + fun `Bonus runes are rewarded depending on the multiplier returned by the rune type`() { + player.startAction(RunecraftingAction(player, `rune with 1xp and bonus multiplier of 2`, TEST_ALTAR)) + + after(action.complete()) { + assertEquals(50, player.inventory.getAmount(1)) + } + } + + @Test + fun `Experience does not stack with bonus multiplier`() { + player.skillSet.setExperience(Skill.RUNECRAFT, 0.0) + player.startAction(RunecraftingAction(player, `rune with 1xp and bonus multiplier of 2`, TEST_ALTAR)) + + after(action.complete()) { + assertEquals(25.0, player.skillSet.getExperience(Skill.RUNECRAFT)) + } + } + + @Test + fun `Experience is rewarded for each rune essence used`() { + player.skillSet.setExperience(Skill.RUNECRAFT, 0.0) + player.startAction(RunecraftingAction(player, `rune with 1xp and bonus multiplier of 1`, TEST_ALTAR)) + + after(action.complete()) { + assertEquals(25.0, player.skillSet.getExperience(Skill.RUNECRAFT)) + } + } + + @Test + fun `Cannot create runes that are too high of a level`() { + player.skillSet.setCurrentLevel(Skill.RUNECRAFT, 1) + player.startAction(RunecraftingAction(player, `rune with required level of 99`, TEST_ALTAR)) + + after(action.complete()) { + verify { player.sendMessage("You need a runecrafting level of 99 to craft this rune.") } + + assertEquals(25, player.inventory.getAmount(runeEssenceId)) + assertEquals(0, player.inventory.getAmount(1)) + } + } + + companion object { + val TEST_ALTAR = Altar.AIR_ALTAR + + val `rune with required level of 99` = object : Rune { + override val id = 1 + override val altar: Altar = TEST_ALTAR + override val level = 99 + override val xp = 1.0 + + override fun getBonusMultiplier(playerLevel: Int) = 1.0 + } + + val `rune with 1xp and bonus multiplier of 1` = object : Rune { + override val id = 1 + override val altar: Altar = TEST_ALTAR + override val level = 1 + override val xp = 1.0 + + override fun getBonusMultiplier(playerLevel: Int) = 1.0 + } + + val `rune with 1xp and bonus multiplier of 2` = object : Rune { + override val id = 1 + override val altar: Altar = TEST_ALTAR + override val level = 1 + override val xp = 1.0 + + override fun getBonusMultiplier(playerLevel: Int) = 2.0 + } + + @ItemDefinitions + private val runeEssence = listOf(ItemDefinition(runeEssenceId).apply { + isStackable = true + }) + + @ItemDefinitions + private val runes = listOf(ItemDefinition(1).apply { + name = "" + isStackable = true + }) + } +} \ No newline at end of file From 2ea0f68eb9ac2e51ec47612f6ebca359b547844d Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 00:02:00 +0100 Subject: [PATCH 174/209] Add tests for most command plugins --- .../testing/junit/ApolloTestExtension.kt | 10 ++- game/plugin/cmd/test/AnimateCommandTests.kt | 28 ++++++ game/plugin/cmd/test/BankCommandTests.kt | 27 ++++++ game/plugin/cmd/test/BroadcastCommandTests.kt | 40 +++++++++ game/plugin/cmd/test/ItemCommandTests.kt | 42 +++++++++ game/plugin/cmd/test/LookupCommandTests.kt | 88 +++++++++++++++++++ .../java/org/apollo/game/model/Animation.java | 27 ++++++ 7 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 game/plugin/cmd/test/AnimateCommandTests.kt create mode 100644 game/plugin/cmd/test/BankCommandTests.kt create mode 100644 game/plugin/cmd/test/BroadcastCommandTests.kt create mode 100644 game/plugin/cmd/test/ItemCommandTests.kt create mode 100644 game/plugin/cmd/test/LookupCommandTests.kt diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt index c9942e418..d9fbfc512 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt @@ -79,17 +79,17 @@ class ApolloTestingExtension : createTestDefinitions( callables, companionInstance, ItemDefinition::getId, ItemDefinition::lookup, - ItemDefinition::getDefinitions + ItemDefinition::getDefinitions, ItemDefinition::count ) createTestDefinitions( callables, companionInstance, NpcDefinition::getId, NpcDefinition::lookup, - NpcDefinition::getDefinitions + NpcDefinition::getDefinitions, NpcDefinition::count ) createTestDefinitions( callables, companionInstance, ObjectDefinition::getId, ObjectDefinition::lookup, - ObjectDefinition::getDefinitions + ObjectDefinition::getDefinitions, ObjectDefinition::count ) } @@ -151,7 +151,8 @@ class ApolloTestingExtension : companionObjectInstance: Any?, crossinline idMapper: (D) -> Int, crossinline lookup: (Int) -> D?, - crossinline getAll: () -> Array + crossinline getAll: () -> Array, + crossinline count: () -> Int ) { val testDefinitions = findTestDefinitions(testClassMethods, companionObjectInstance) .associateBy(idMapper) @@ -162,6 +163,7 @@ class ApolloTestingExtension : every { lookup(capture(idSlot)) } answers { testDefinitions[idSlot.captured] } every { getAll() } answers { testDefinitions.values.sortedBy(idMapper).toTypedArray() } + every { count() } answers { _ -> testDefinitions.maxBy { (id, _) -> id }?.key?.let { it + 1 } ?: 0 } } } diff --git a/game/plugin/cmd/test/AnimateCommandTests.kt b/game/plugin/cmd/test/AnimateCommandTests.kt new file mode 100644 index 000000000..a226e1a21 --- /dev/null +++ b/game/plugin/cmd/test/AnimateCommandTests.kt @@ -0,0 +1,28 @@ +import io.mockk.verify +import org.apollo.game.command.Command +import org.apollo.game.model.Animation +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class AnimateCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @Test + fun `Plays the animation provided as input`() { + player.privilegeLevel = PrivilegeLevel.MODERATOR + world.commandDispatcher.dispatch(player, Command("animate", arrayOf("1"))) + + verify { player.playAnimation(Animation(1)) } + } +} \ No newline at end of file diff --git a/game/plugin/cmd/test/BankCommandTests.kt b/game/plugin/cmd/test/BankCommandTests.kt new file mode 100644 index 000000000..4ef96051c --- /dev/null +++ b/game/plugin/cmd/test/BankCommandTests.kt @@ -0,0 +1,27 @@ +import io.mockk.verify +import org.apollo.game.command.Command +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class BankCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @Test + fun `Opens bank when used`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("bank", emptyArray())) + + verify { player.openBank() } + } +} \ No newline at end of file diff --git a/game/plugin/cmd/test/BroadcastCommandTests.kt b/game/plugin/cmd/test/BroadcastCommandTests.kt new file mode 100644 index 000000000..a8bfb9e1a --- /dev/null +++ b/game/plugin/cmd/test/BroadcastCommandTests.kt @@ -0,0 +1,40 @@ +import io.mockk.verify +import io.mockk.verifyOrder +import io.mockk.verifySequence +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.command.Command +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.startsWith +import org.apollo.game.plugin.testing.assertions.strEq +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class BroadcastCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @Test + fun `Shows basic information on an item`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("broadcast", arrayOf("msg"))) + + verify { + player.sendMessage("[Broadcast] Test: msg") + } + } +} \ No newline at end of file diff --git a/game/plugin/cmd/test/ItemCommandTests.kt b/game/plugin/cmd/test/ItemCommandTests.kt new file mode 100644 index 000000000..494b8e3d1 --- /dev/null +++ b/game/plugin/cmd/test/ItemCommandTests.kt @@ -0,0 +1,42 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.command.Command +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class ItemCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @Test + fun `Defaults to an amount of 1`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("item", arrayOf("1"))) + + assertEquals(1, player.inventory.getAmount(1)) + } + + @Test + fun `Adds item of specified amount to inventory`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("item", arrayOf("1", "10"))) + + assertEquals(10, player.inventory.getAmount(1)) + } + + companion object { + @ItemDefinitions + val items = listOf(ItemDefinition(1)) + } +} \ No newline at end of file diff --git a/game/plugin/cmd/test/LookupCommandTests.kt b/game/plugin/cmd/test/LookupCommandTests.kt new file mode 100644 index 000000000..df442a40a --- /dev/null +++ b/game/plugin/cmd/test/LookupCommandTests.kt @@ -0,0 +1,88 @@ +import io.mockk.verify +import io.mockk.verifyOrder +import io.mockk.verifySequence +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.NpcDefinition +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.command.Command +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.startsWith +import org.apollo.game.plugin.testing.assertions.strEq +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class LookupCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @Test + fun `Shows basic information on an item`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("iteminfo", arrayOf("1"))) + + verify { + player.sendMessage("Item 1 is called and is not members only.") + player.sendMessage("Its description is ``.") + } + } + + @Test + fun `Shows basic information on an npc`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("npcinfo", arrayOf("1"))) + + verify { + player.sendMessage("Npc 1 is called and has a combat level of 126.") + player.sendMessage("Its description is ``.") + } + } + + @Test + fun `Shows basic information on an object`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("objectinfo", arrayOf("1"))) + + verify { + player.sendMessage("Object 1 is called (width=1, length=1).") + player.sendMessage("Its description is ``.") + } + } + + companion object { + @ItemDefinitions + val items = listOf(ItemDefinition(1).apply { + name = "" + description = "" + isMembersOnly = false + }) + + @NpcDefinitions + val npcs = listOf(NpcDefinition(1).apply { + name = "" + combatLevel = 126 + description = "" + }) + + @ObjectDefinitions + val objects = listOf(ObjectDefinition(1).apply { + name = "" + description = "" + width = 1 + length = 1 + }) + } + +} \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/model/Animation.java b/game/src/main/java/org/apollo/game/model/Animation.java index 57df88a9b..0fe52750b 100644 --- a/game/src/main/java/org/apollo/game/model/Animation.java +++ b/game/src/main/java/org/apollo/game/model/Animation.java @@ -1,5 +1,8 @@ package org.apollo.game.model; +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; + /** * Represents an animation. * @@ -60,4 +63,28 @@ public int getId() { return id; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Animation animation = (Animation) o; + return delay == animation.delay && id == animation.id; + } + + @Override + public int hashCode() { + return Objects.hashCode(delay, id); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("delay", delay) + .add("id", id) + .toString(); + } } \ No newline at end of file From 4525eed73496507e50c644b1e53c59a68c7f1e15 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 01:16:12 +0100 Subject: [PATCH 175/209] Re-add HTML and XML code coverage reports --- build.gradle | 13 +++++++++++- gradle/code-quality.gradle | 40 +++++++++++++++---------------------- gradle/testing.gradle | 41 ++++++++++++++++++++++++++++++++++---- 3 files changed, 65 insertions(+), 29 deletions(-) diff --git a/build.gradle b/build.gradle index 871c65d2d..a5ebeebbc 100644 --- a/build.gradle +++ b/build.gradle @@ -20,4 +20,15 @@ allprojects { apply from: 'gradle/properties.gradle' apply from: 'gradle/code-quality.gradle' apply from: 'gradle/testing.gradle' -apply from: 'gradle/wrapper.gradle' \ No newline at end of file +apply from: 'gradle/wrapper.gradle' + +gradle.projectsEvaluated { + task check { + def deps = [] + deps += getTasksByName("check", true).findAll { it.project != rootProject } + deps += detektCheck + deps += jacocoReport + + dependsOn(deps) + } +} \ No newline at end of file diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle index b65f3cd31..c5f27a2e0 100644 --- a/gradle/code-quality.gradle +++ b/gradle/code-quality.gradle @@ -1,32 +1,24 @@ def detektAggregateReport = "$rootDir/reports/detekt-report.xml" -gradle.projectsEvaluated { - detekt { - version = detektVersion +detekt { + version = detektVersion - defaultProfile { - output = file("$buildDir/reports") - outputName = "detekt-report" - config = file("$rootDir/gradle/config/detekt.yml") - parallel = true - } - - subprojects.findAll { it.pluginManager.hasPlugin('kotlin') }.forEach { proj -> - profile(proj.name) { - input = proj.sourceSets.main.kotlin - } - } + profile("main") { + input = rootProject.projectDir.absolutePath + filters = ".*/resources/.*, .*/build/.*" + output = file("$buildDir/reports") + outputName = "detekt-report" + config = file("$rootDir/gradle/config/detekt.yml") + parallel = true } +} - dependencies { - detekt group: 'io.gitlab.arturbosch.detekt', name: 'detekt-formatting', version: detektVersion - } +dependencies { + detekt group: 'io.gitlab.arturbosch.detekt', name: 'detekt-formatting', version: detektVersion +} - sonarqube { - properties { - property "sonar.kotlin.detekt.reportPaths", detektAggregateReport - } +sonarqube { + properties { + property "sonar.kotlin.detekt.reportPaths", detektAggregateReport } - - tasks["sonarqube"].dependsOn(detektCheck) } \ No newline at end of file diff --git a/gradle/testing.gradle b/gradle/testing.gradle index ec42fd68e..838454d44 100644 --- a/gradle/testing.gradle +++ b/gradle/testing.gradle @@ -5,7 +5,6 @@ def jacocoCoverageAggregate = "$buildDir/jacoco/jacocoTestAll.exec" def testedProjects() { subprojects.findAll { subproject -> subproject.plugins.hasPlugin('java') || subproject.plugins.hasPlugin('kotlin') } } - gradle.projectsEvaluated { configure(testedProjects()) { apply plugin: "jacoco" @@ -31,6 +30,43 @@ gradle.projectsEvaluated { task jacocoMerge(type: JacocoMerge) { destinationFile = file(jacocoCoverageAggregate) executionData = project.fileTree(dir: '.', include: '**/build/jacoco/jacocoTest.exec') + + dependsOn(getTasksByName('test', true)) + } + + + task jacocoReport(type: JacocoReport) { + sourceDirectories = files() + classDirectories = files() + executionData = files() + + reports { + html.enabled = true + xml.enabled = true + csv.enabled = false + } + + // Work-around to allow us to build list of executionData files in doFirst + onlyIf = { + true + } + + /* + * Builds list of source dirs, class dirs, and executionData files + * when task is run, not at script evaluation time + */ + doFirst { + subprojects.findAll { subproject -> + subproject.pluginManager.hasPlugin('java') || subproject.pluginManager.hasPlugin('kotlin') + }.each { subproject -> + additionalSourceDirs files((Set) subproject.sourceSets.main.allSource.srcDirs) + additionalClassDirs((FileCollection) subproject.sourceSets.main.output) + } + + executionData = files(jacocoCoverageAggregate) + } + + dependsOn(jacocoMerge) } sonarqube { @@ -42,7 +78,4 @@ gradle.projectsEvaluated { property "sonar.jacoco.reportPaths", jacocoCoverageAggregate } } - - tasks["sonarqube"].dependsOn(jacocoMerge) } - From 274d805c553595f30d430f582eb709239bb269ab Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 01:20:30 +0100 Subject: [PATCH 176/209] Remove broken imports from command tests --- game/plugin/cmd/test/BroadcastCommandTests.kt | 11 ----------- game/plugin/cmd/test/LookupCommandTests.kt | 5 ----- 2 files changed, 16 deletions(-) diff --git a/game/plugin/cmd/test/BroadcastCommandTests.kt b/game/plugin/cmd/test/BroadcastCommandTests.kt index a8bfb9e1a..d3ba8b16f 100644 --- a/game/plugin/cmd/test/BroadcastCommandTests.kt +++ b/game/plugin/cmd/test/BroadcastCommandTests.kt @@ -1,21 +1,10 @@ import io.mockk.verify -import io.mockk.verifyOrder -import io.mockk.verifySequence -import org.apollo.cache.def.ItemDefinition -import org.apollo.cache.def.NpcDefinition -import org.apollo.cache.def.ObjectDefinition import org.apollo.game.command.Command import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.testing.assertions.startsWith -import org.apollo.game.plugin.testing.assertions.strEq import org.apollo.game.plugin.testing.junit.ApolloTestingExtension -import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions -import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions -import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.TestMock -import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith diff --git a/game/plugin/cmd/test/LookupCommandTests.kt b/game/plugin/cmd/test/LookupCommandTests.kt index df442a40a..0372d9c3a 100644 --- a/game/plugin/cmd/test/LookupCommandTests.kt +++ b/game/plugin/cmd/test/LookupCommandTests.kt @@ -1,6 +1,4 @@ import io.mockk.verify -import io.mockk.verifyOrder -import io.mockk.verifySequence import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition @@ -8,14 +6,11 @@ import org.apollo.game.command.Command import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.testing.assertions.startsWith -import org.apollo.game.plugin.testing.assertions.strEq import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.TestMock -import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith From 21fea83c8eb20d644a8be05a914255e2d3ef39c2 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 01:33:29 +0100 Subject: [PATCH 177/209] Fix Detekt report path --- gradle/code-quality.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle index c5f27a2e0..7a269657a 100644 --- a/gradle/code-quality.gradle +++ b/gradle/code-quality.gradle @@ -1,4 +1,4 @@ -def detektAggregateReport = "$rootDir/reports/detekt-report.xml" +def detektAggregateReport = "$buildDir/reports/detekt-report.xml" detekt { version = detektVersion From fc1d6f46faa880bc3ca7e2a67625ab860bf1c49c Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 02:35:35 +0100 Subject: [PATCH 178/209] Add additional command test coverage --- .../junit/api/annotations/stubAnnotations.kt | 1 + .../testing/junit/stubs/PlayerStubInfo.kt | 2 + game/plugin/cmd/src/teleport-cmd.plugin.kts | 22 +++--- game/plugin/cmd/test/AnimateCommandTests.kt | 12 ++++ game/plugin/cmd/test/ItemCommandTests.kt | 15 ++++ game/plugin/cmd/test/LookupCommandTests.kt | 14 ++++ game/plugin/cmd/test/SkillCommandTests.kt | 30 ++++++++ game/plugin/cmd/test/TeleportCommandTests.kt | 70 +++++++++++++++++++ .../cmd/test/TeleportToPlayerCommandTests.kt | 53 ++++++++++++++ gradle/config/checkstyle.xml | 0 10 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 game/plugin/cmd/test/SkillCommandTests.kt create mode 100644 game/plugin/cmd/test/TeleportCommandTests.kt create mode 100644 game/plugin/cmd/test/TeleportToPlayerCommandTests.kt create mode 100644 gradle/config/checkstyle.xml diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt index 9166616fc..2acf1636b 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/stubAnnotations.kt @@ -2,6 +2,7 @@ package org.apollo.game.plugin.testing.junit.api.annotations annotation class Id(val value: Int) annotation class Pos(val x: Int, val y: Int, val height: Int = 0) +annotation class Name(val value: String) @Target(AnnotationTarget.FIELD) @Retention(AnnotationRetention.RUNTIME) diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt index 95f4404a8..3aae860cf 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt @@ -1,6 +1,7 @@ package org.apollo.game.plugin.testing.junit.stubs import org.apollo.game.model.Position +import org.apollo.game.plugin.testing.junit.api.annotations.Name import org.apollo.game.plugin.testing.junit.api.annotations.Pos class PlayerStubInfo { @@ -10,6 +11,7 @@ class PlayerStubInfo { annotations.forEach { when (it) { + is Name -> info.name = it.value is Pos -> info.position = Position(it.x, it.y, it.height) } } diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index d51a964f6..4cc6c8ad0 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -30,6 +30,7 @@ on_command("tele", PrivilegeLevel.ADMINISTRATOR) if (results.isEmpty()) { player.sendMessage("No destinations matching '$query'.") + player.sendMessage(invalidSyntax) return@then } else if (results.size > 1) { player.sendMessage("Ambiguous query '$query' (could be $results). Please disambiguate.") @@ -84,15 +85,20 @@ on_command("teleto", PrivilegeLevel.ADMINISTRATOR) if (arguments.size == 1) { val playerName = arguments[0] - val foundPlayer = player.world.getPlayer(playerName) - - if (foundPlayer == null) { - player.sendMessage("Player $playerName is currently offline or does not exist.") - return@then + try { + val foundPlayer = player.world.getPlayer(playerName) + + if (foundPlayer == null) { + player.sendMessage("Player $playerName is currently offline or does not exist.") + return@then + } + + player.teleport(foundPlayer.position) + player.sendMessage("You have teleported to player $playerName.") + } catch (_: Exception) { + // Invalid player name syntax + player.sendMessage(invalidSyntax) } - - player.teleport(foundPlayer.position) - player.sendMessage("You have teleported to player $playerName.") } else { player.sendMessage(invalidSyntax) } diff --git a/game/plugin/cmd/test/AnimateCommandTests.kt b/game/plugin/cmd/test/AnimateCommandTests.kt index a226e1a21..c52e72bab 100644 --- a/game/plugin/cmd/test/AnimateCommandTests.kt +++ b/game/plugin/cmd/test/AnimateCommandTests.kt @@ -4,6 +4,7 @@ import org.apollo.game.model.Animation import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.junit.jupiter.api.Test @@ -25,4 +26,15 @@ class AnimateCommandTests { verify { player.playAnimation(Animation(1)) } } + + @Test + fun `Help message sent on invalid syntax`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("animate", arrayOf(""))) + + verify { + player.sendMessage(contains("Invalid syntax")) + } + } + } \ No newline at end of file diff --git a/game/plugin/cmd/test/ItemCommandTests.kt b/game/plugin/cmd/test/ItemCommandTests.kt index 494b8e3d1..c9884105a 100644 --- a/game/plugin/cmd/test/ItemCommandTests.kt +++ b/game/plugin/cmd/test/ItemCommandTests.kt @@ -1,14 +1,18 @@ +import io.mockk.verify import org.apollo.cache.def.ItemDefinition import org.apollo.game.command.Command import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource @ExtendWith(ApolloTestingExtension::class) class ItemCommandTests { @@ -35,6 +39,17 @@ class ItemCommandTests { assertEquals(10, player.inventory.getAmount(1)) } + @ParameterizedTest(name = "::item {0}") + @ValueSource(strings = ["", "1 ", " 1"]) + fun `Help message sent on invalid syntax`(args: String) { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("item", args.split(" ").toTypedArray())) + + verify { + player.sendMessage(contains("Invalid syntax")) + } + } + companion object { @ItemDefinitions val items = listOf(ItemDefinition(1)) diff --git a/game/plugin/cmd/test/LookupCommandTests.kt b/game/plugin/cmd/test/LookupCommandTests.kt index 0372d9c3a..73208f8d6 100644 --- a/game/plugin/cmd/test/LookupCommandTests.kt +++ b/game/plugin/cmd/test/LookupCommandTests.kt @@ -6,6 +6,7 @@ import org.apollo.game.command.Command import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions @@ -13,6 +14,8 @@ import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource @ExtendWith(ApolloTestingExtension::class) class LookupCommandTests { @@ -56,6 +59,17 @@ class LookupCommandTests { } } + @ParameterizedTest(name = "::{0} ") + @ValueSource(strings = ["npcinfo", "iteminfo", "objectinfo"]) + fun `Help message sent on invalid syntax`(command: String) { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command(command, arrayOf(""))) + + verify { + player.sendMessage(contains("Invalid syntax")) + } + } + companion object { @ItemDefinitions val items = listOf(ItemDefinition(1).apply { diff --git a/game/plugin/cmd/test/SkillCommandTests.kt b/game/plugin/cmd/test/SkillCommandTests.kt new file mode 100644 index 000000000..3dd28af53 --- /dev/null +++ b/game/plugin/cmd/test/SkillCommandTests.kt @@ -0,0 +1,30 @@ +import org.apollo.game.command.Command +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class SkillCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @Test + fun `Max stats to 99`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("max", emptyArray())) + + for (stat in 0 until Skill.RUNECRAFT) { + assertEquals(99, player.skillSet.getCurrentLevel(99)) + } + } +} \ No newline at end of file diff --git a/game/plugin/cmd/test/TeleportCommandTests.kt b/game/plugin/cmd/test/TeleportCommandTests.kt new file mode 100644 index 000000000..16571fd1b --- /dev/null +++ b/game/plugin/cmd/test/TeleportCommandTests.kt @@ -0,0 +1,70 @@ +import io.mockk.verify +import org.apollo.game.command.Command +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.contains +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +@ExtendWith(ApolloTestingExtension::class) +class TeleportCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @Test + fun `Teleport to given coordinates`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("tele", arrayOf("1", "2", "0"))) + + assertEquals(Position(1, 2, 0), player.position) + } + + @Test + fun `Teleport to given coordinates on players plane when no plane given`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + player.position = Position(1, 1, 1) + world.commandDispatcher.dispatch(player, Command("tele", arrayOf("1", "2"))) + + assertEquals(Position(1, 2, 1), player.position) + } + + + @Test + fun `Shows current position information`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + player.position = Position(1, 2, 3) + world.commandDispatcher.dispatch(player, Command("pos", emptyArray())) + + verify { + player.sendMessage(contains("1, 2, 3")) + } + } + + @ParameterizedTest(name = "::tele {0}") + @ValueSource(strings = [ + "1 2 ", + "1 2", + "1", + "1 2 3 4" + ]) + fun `Help message sent on invalid syntax`(args: String) { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("tele", args.split(" ").toTypedArray())) + + verify { + player.sendMessage(contains("Invalid syntax")) + } + } + +} \ No newline at end of file diff --git a/game/plugin/cmd/test/TeleportToPlayerCommandTests.kt b/game/plugin/cmd/test/TeleportToPlayerCommandTests.kt new file mode 100644 index 000000000..6b4e28644 --- /dev/null +++ b/game/plugin/cmd/test/TeleportToPlayerCommandTests.kt @@ -0,0 +1,53 @@ +import io.mockk.verify +import org.apollo.game.command.Command +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.contains +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.Name +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +@ExtendWith(ApolloTestingExtension::class) +class TeleportToPlayerCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @TestMock + @Name("player_two") + lateinit var secondPlayer: Player + + @Test + fun `Teleport to given player`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + player.position = Position(300, 300) + secondPlayer.position = Position(1, 2) + world.commandDispatcher.dispatch(player, Command("teleto", arrayOf("player_two"))) + + assertEquals(secondPlayer.position, player.position) + } + + @ParameterizedTest(name = "::teleto {0}") + @ValueSource(strings = [ + "" + ]) + fun `Help message sent on invalid syntax`(args: String) { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("teleto", args.split(" ").toTypedArray())) + + verify { + player.sendMessage(contains("Invalid syntax")) + } + } + +} \ No newline at end of file diff --git a/gradle/config/checkstyle.xml b/gradle/config/checkstyle.xml new file mode 100644 index 000000000..e69de29bb From 20bb420916d5cc40a3ba4a5dd329b1b5969cf749 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 02:40:44 +0100 Subject: [PATCH 179/209] Fix typo in skill command tests --- game/plugin/cmd/test/SkillCommandTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/plugin/cmd/test/SkillCommandTests.kt b/game/plugin/cmd/test/SkillCommandTests.kt index 3dd28af53..53f7f3126 100644 --- a/game/plugin/cmd/test/SkillCommandTests.kt +++ b/game/plugin/cmd/test/SkillCommandTests.kt @@ -24,7 +24,7 @@ class SkillCommandTests { world.commandDispatcher.dispatch(player, Command("max", emptyArray())) for (stat in 0 until Skill.RUNECRAFT) { - assertEquals(99, player.skillSet.getCurrentLevel(99)) + assertEquals(99, player.skillSet.getCurrentLevel(stat)) } } } \ No newline at end of file From 5f49ec16a212938010e8e6230f801f5428fe438c Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 03:51:26 +0100 Subject: [PATCH 180/209] Add tests for remaining commands --- game/plugin/cmd/src/spawn-cmd.plugin.kts | 19 +++- game/plugin/cmd/test/PunishCommandTests.kt | 97 ++++++++++++++++++++ game/plugin/cmd/test/SkillCommandTests.kt | 47 +++++++++- game/plugin/cmd/test/SpawnCommandTests.kt | 75 +++++++++++++++ game/plugin/cmd/test/TeleportCommandTests.kt | 2 - 5 files changed, 233 insertions(+), 7 deletions(-) create mode 100644 game/plugin/cmd/test/PunishCommandTests.kt create mode 100644 game/plugin/cmd/test/SpawnCommandTests.kt diff --git a/game/plugin/cmd/src/spawn-cmd.plugin.kts b/game/plugin/cmd/src/spawn-cmd.plugin.kts index 70b80a2d5..4626503d2 100644 --- a/game/plugin/cmd/src/spawn-cmd.plugin.kts +++ b/game/plugin/cmd/src/spawn-cmd.plugin.kts @@ -35,16 +35,27 @@ on_command("spawn", PrivilegeLevel.ADMINISTRATOR) if (arguments.size == 1) { position = player.position } else { - var height = player.position.height - if (arguments.size == 4) { + val x = Ints.tryParse(arguments[1]) + val y = Ints.tryParse(arguments[2]) + + if (x == null || y == null) { + player.sendMessage(invalidSyntax) + return@then + } + + val height = if (arguments.size == 4) { val h = Ints.tryParse(arguments[3]) if (h == null) { player.sendMessage(invalidSyntax) return@then } - height = h + + h + } else { + player.position.height } - position = Position(arguments[1].toInt(), arguments[2].toInt(), height) + + position = Position(x, y, height) } player.world.register(Npc(player.world, id, position)) diff --git a/game/plugin/cmd/test/PunishCommandTests.kt b/game/plugin/cmd/test/PunishCommandTests.kt new file mode 100644 index 000000000..6f3c48801 --- /dev/null +++ b/game/plugin/cmd/test/PunishCommandTests.kt @@ -0,0 +1,97 @@ +import io.mockk.verify +import org.apollo.game.command.Command +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.Name +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class PunishCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var admin: Player + + @TestMock + @Name("player_two") + lateinit var player: Player + + @BeforeEach + fun setup() { + admin.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + } + + @Test + fun `Staff can mute players`() { + world.commandDispatcher.dispatch(admin, Command("mute", arrayOf("player_two"))) + + verify { + player.setMuted(true) + } + } + + @Test + fun `Staff can unmute players`() { + player.isMuted = true + world.commandDispatcher.dispatch(admin, Command("unmute", arrayOf("player_two"))) + + verify { + player.setMuted(false) + } + } + + @Test + fun `Staff cant mute admins`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(admin, Command("unmute", arrayOf("player_two"))) + + verify { + admin.sendMessage("You cannot perform this action on Administrators.") + } + } + + @Test + fun `Cant mute players that arent online`() { + world.commandDispatcher.dispatch(admin, Command("mute", arrayOf("player555"))) + + verify { + admin.sendMessage("That player does not exist.") + } + } + + @Test + fun `Staff can ban players`() { + world.commandDispatcher.dispatch(admin, Command("ban", arrayOf("player_two"))) + + verify { + player.ban() + player.logout() + } + } + + @Test + fun `Staff cant ban admins`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(admin, Command("ban", arrayOf("player_two"))) + + verify { + admin.sendMessage("You cannot perform this action on Administrators.") + } + } + + @Test + fun `Cant ban players that arent online`() { + world.commandDispatcher.dispatch(admin, Command("ban", arrayOf("player555"))) + + verify { + admin.sendMessage("That player does not exist.") + } + } +} \ No newline at end of file diff --git a/game/plugin/cmd/test/SkillCommandTests.kt b/game/plugin/cmd/test/SkillCommandTests.kt index 53f7f3126..4a243cb73 100644 --- a/game/plugin/cmd/test/SkillCommandTests.kt +++ b/game/plugin/cmd/test/SkillCommandTests.kt @@ -1,13 +1,18 @@ +import io.mockk.verify import org.apollo.game.command.Command import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource @ExtendWith(ApolloTestingExtension::class) class SkillCommandTests { @@ -18,13 +23,53 @@ class SkillCommandTests { @TestMock lateinit var player: Player + @BeforeEach + fun setup() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + } + @Test fun `Max stats to 99`() { - player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR world.commandDispatcher.dispatch(player, Command("max", emptyArray())) for (stat in 0 until Skill.RUNECRAFT) { assertEquals(99, player.skillSet.getCurrentLevel(stat)) } } + + @Test + fun `Set skill to given level`() { + world.commandDispatcher.dispatch(player, Command("level", arrayOf("1", "99"))) + + assertEquals(99, player.skillSet.getCurrentLevel(1)) + } + + @Test + fun `Set skill to given experience`() { + world.commandDispatcher.dispatch(player, Command("xp", arrayOf("1", "50"))) + + assertEquals(50.0, player.skillSet.getExperience(1)) + } + + @ParameterizedTest(name = "::{0}") + @ValueSource(strings = [ + "level 50 100", + "level 15 100", + "level 100", + "level 15 ", + "level", + "xp", + "xp 50 ", + "xp 50" + ]) + fun `Help message shown on invalid syntax`(command: String) { + val args = command.split(" ").toMutableList() + val cmd = args.removeAt(0) + + world.commandDispatcher.dispatch(player, Command(cmd, args.toTypedArray())) + + verify { + player.sendMessage(contains("Invalid syntax")) + } + } } \ No newline at end of file diff --git a/game/plugin/cmd/test/SpawnCommandTests.kt b/game/plugin/cmd/test/SpawnCommandTests.kt new file mode 100644 index 000000000..f7f0726d3 --- /dev/null +++ b/game/plugin/cmd/test/SpawnCommandTests.kt @@ -0,0 +1,75 @@ +import io.mockk.verify +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.command.Command +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Npc +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.testing.assertions.contains +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +@ExtendWith(ApolloTestingExtension::class) +class SpawnCommandTests { + + @TestMock + lateinit var world: World + + @TestMock + lateinit var player: Player + + @BeforeEach + fun setup() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + } + + @Test + fun `Spawns NPC at players position by default`() { + world.commandDispatcher.dispatch(player, Command("spawn", arrayOf("1"))) + + verify { + world.register(match { + it.id == 1 && it.position == player.position + }) + } + } + + @Test + fun `Spawn NPC at given position`() { + world.commandDispatcher.dispatch(player, Command("spawn", arrayOf("1", "5", "5"))) + + verify { + world.register(match { + it.id == 1 && it.position == Position(5, 5) + }) + } + } + + @ParameterizedTest(name = "::spawn {0}") + @ValueSource(strings = [ + "", + "1 2", + "1 2 ", + "1 2 3 " + ]) + fun `Help message on invalid syntax`(args: String) { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("spawn", args.split(" ").toTypedArray())) + + verify { + player.sendMessage(contains("Invalid syntax")) + } + } + + companion object { + @NpcDefinitions + val npcs = listOf(NpcDefinition(1)) + } +} \ No newline at end of file diff --git a/game/plugin/cmd/test/TeleportCommandTests.kt b/game/plugin/cmd/test/TeleportCommandTests.kt index 16571fd1b..32da197ab 100644 --- a/game/plugin/cmd/test/TeleportCommandTests.kt +++ b/game/plugin/cmd/test/TeleportCommandTests.kt @@ -39,7 +39,6 @@ class TeleportCommandTests { assertEquals(Position(1, 2, 1), player.position) } - @Test fun `Shows current position information`() { player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR @@ -66,5 +65,4 @@ class TeleportCommandTests { player.sendMessage(contains("Invalid syntax")) } } - } \ No newline at end of file From b6086d57b8e9a1b516ea8d7138ca228ff19a71e3 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 04:00:28 +0100 Subject: [PATCH 181/209] Fix mockk error in matcher --- game/plugin/cmd/test/SpawnCommandTests.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/game/plugin/cmd/test/SpawnCommandTests.kt b/game/plugin/cmd/test/SpawnCommandTests.kt index f7f0726d3..ef9a3d60b 100644 --- a/game/plugin/cmd/test/SpawnCommandTests.kt +++ b/game/plugin/cmd/test/SpawnCommandTests.kt @@ -32,11 +32,12 @@ class SpawnCommandTests { @Test fun `Spawns NPC at players position by default`() { + player.position = Position(3, 3, 0) world.commandDispatcher.dispatch(player, Command("spawn", arrayOf("1"))) verify { world.register(match { - it.id == 1 && it.position == player.position + it.id == 1 && it.position == Position(3, 3,0) }) } } From 475c7ac74136fc884ac746d2cbf35994972dafb9 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 04:43:34 +0100 Subject: [PATCH 182/209] Fix kotlin code style issues --- .../testing/assertions/actionAsserts.kt | 1 - .../plugin/testing/junit/ApolloTestState.kt | 2 +- ...Extension.kt => ApolloTestingExtension.kt} | 33 +-- .../plugin/testing/junit/api/ActionCapture.kt | 5 +- .../junit/api/annotations/testAnnotations.kt | 6 - .../testing/junit/api/interactions/world.kt | 1 - .../junit/params/DefinitionProviders.kt | 13 +- .../testing/junit/stubs/GameObjectStubInfo.kt | 1 - .../plugin/testing/junit/stubs/NpcStubInfo.kt | 1 - .../testing/junit/stubs/PlayerStubInfo.kt | 2 - .../org/apollo/game/plugin/api/Definitions.kt | 3 +- .../src/org/apollo/game/plugin/api/Player.kt | 1 - .../src/org/apollo/game/plugin/api/World.kt | 1 - .../game/plugin/api/DefinitionsTests.kt | 2 - .../org/apollo/game/plugin/api/PlayerTests.kt | 1 - .../apollo/game/plugin/api/PositionTests.kt | 1 - game/plugin/areas/src/Area.kt | 2 - game/plugin/areas/src/AreaActionBuilder.kt | 1 - game/plugin/areas/test/AreaActionTests.kt | 1 - game/plugin/bank/src/bank.plugin.kts | 3 - game/plugin/bank/test/OpenBankTest.kt | 1 - game/plugin/cmd/src/teleport-cmd.plugin.kts | 275 +++++++++--------- game/plugin/cmd/test/AnimateCommandTests.kt | 1 - game/plugin/cmd/test/LookupCommandTests.kt | 1 - game/plugin/cmd/test/SpawnCommandTests.kt | 2 +- .../cmd/test/TeleportToPlayerCommandTests.kt | 1 - game/plugin/consumables/src/consumables.kt | 14 +- .../consumables/src/consumables.plugin.kts | 1 - game/plugin/consumables/src/drinks.plugin.kts | 6 +- game/plugin/consumables/src/foods.plugin.kts | 26 +- .../consumables/test/FoodOrDrinkTests.kt | 8 +- game/plugin/dummy/src/dummy.plugin.kts | 6 - game/plugin/dummy/test/TrainingDummyTest.kt | 3 +- .../emote-tab/src/{emote.kt => Emote.kt} | 0 ...ote-tab.plugin.kts => EmoteTab.plugin.kts} | 0 .../entity/actions/src/PlayerActionEvent.kt | 6 + .../src/{PlayerAction.kt => playerAction.kt} | 5 +- .../entity/actions/test/PlayerActionTests.kt | 1 - .../{Following.kt => FollowAction.kt} | 1 - .../entity/following/Following.plugin.kts | 1 - .../game/plugin/entity/spawn/SpawnTests.kt | 1 - .../locations/edgeville/src/npcs.plugin.kts | 1 - .../locations/varrock/src/npcs.plugin.kts | 2 - game/plugin/logout/src/logout.plugin.kts | 4 +- game/plugin/logout/test/LogoutTests.kt | 16 +- game/plugin/navigation/door/src/door.kt | 7 +- game/plugin/run/src/run.plugin.kts | 8 +- game/plugin/shops/src/action.kt | 2 - game/plugin/shops/src/dsl.kt | 16 +- game/plugin/shops/src/shop.kt | 4 - .../apollo/game/plugin/skills/fishing/Fish.kt | 1 - .../plugin/skills/fishing/FishingAction.kt | 4 +- .../game/plugin/skills/fishing/FishingSpot.kt | 3 - .../plugin/skills/fishing/FishingTarget.kt | 1 - .../game/plugin/skills/fishing/FishingTool.kt | 1 - .../skills/fishing/FishingActionTests.kt | 1 - .../herblore/src/CrushIngredientAction.kt | 2 +- .../skills/herblore/src/IdentifyHerbAction.kt | 2 +- .../skills/herblore/src/MakePotionAction.kt | 2 +- .../mining/src/ExpiredProspectingAction.kt | 41 +++ .../skills/mining/src/{gem.kt => Gem.kt} | 0 .../{mining.plugin.kts => Mining.plugin.kts} | 0 .../mining/src/{mining.kt => MiningAction.kt} | 57 +--- game/plugin/skills/mining/src/MiningTarget.kt | 58 ++++ .../skills/mining/src/{ore.kt => Ore.kt} | 1 - .../mining/src/{pickaxe.kt => Pickaxe.kt} | 0 .../{prospecting.kt => ProspectingAction.kt} | 41 +-- .../skills/mining/test/MiningActionTests.kt | 1 - .../plugin/skills/mining/test/PickaxeTests.kt | 4 - .../skills/mining/test/ProspectingTests.kt | 1 - game/plugin/skills/mining/test/TestData.kt | 2 +- .../{BoneBuryAction.kt => BuryBoneAction.kt} | 1 - .../{prayer.plugin.kts => Prayer.plugin.kts} | 0 .../skills/prayer/test/BuryBoneTests.kt | 1 - game/plugin/skills/runecrafting/src/Rune.kt | 3 +- .../runecrafting/src/Runecrafting.plugin.kts | 3 +- .../runecrafting/src/RunecraftingAction.kt | 2 +- .../test/RunecraftingActionTests.kt | 1 - .../skills/woodcutting/src/{axe.kt => Axe.kt} | 0 .../woodcutting/src/{wood.kt => Tree.kt} | 0 ...ting.plugin.kts => Woodcutting.plugin.kts} | 4 +- .../skills/woodcutting/test/AxeTests.kt | 3 +- .../skills/woodcutting/test/TestData.kt | 2 +- .../woodcutting/test/WoodcuttingTests.kt | 2 +- .../org/apollo/game/action/ActionCoroutine.kt | 2 +- .../apollo/game/action/AsyncActionTrait.kt | 2 +- .../game/action/AsyncDistancedAction.kt | 1 - .../game/plugin/kotlin/KotlinPluginScript.kt | 13 +- gradle/config/detekt.yml | 9 +- 89 files changed, 338 insertions(+), 435 deletions(-) rename game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/{ApolloTestExtension.kt => ApolloTestingExtension.kt} (96%) delete mode 100644 game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt rename game/plugin/emote-tab/src/{emote.kt => Emote.kt} (100%) rename game/plugin/emote-tab/src/{emote-tab.plugin.kts => EmoteTab.plugin.kts} (100%) create mode 100644 game/plugin/entity/actions/src/PlayerActionEvent.kt rename game/plugin/entity/actions/src/{PlayerAction.kt => playerAction.kt} (84%) rename game/plugin/entity/following/src/org/apollo/plugin/entity/following/{Following.kt => FollowAction.kt} (99%) create mode 100644 game/plugin/skills/mining/src/ExpiredProspectingAction.kt rename game/plugin/skills/mining/src/{gem.kt => Gem.kt} (100%) rename game/plugin/skills/mining/src/{mining.plugin.kts => Mining.plugin.kts} (100%) rename game/plugin/skills/mining/src/{mining.kt => MiningAction.kt} (59%) create mode 100644 game/plugin/skills/mining/src/MiningTarget.kt rename game/plugin/skills/mining/src/{ore.kt => Ore.kt} (99%) rename game/plugin/skills/mining/src/{pickaxe.kt => Pickaxe.kt} (100%) rename game/plugin/skills/mining/src/{prospecting.kt => ProspectingAction.kt} (59%) rename game/plugin/skills/prayer/src/{BoneBuryAction.kt => BuryBoneAction.kt} (99%) rename game/plugin/skills/prayer/src/{prayer.plugin.kts => Prayer.plugin.kts} (100%) rename game/plugin/skills/woodcutting/src/{axe.kt => Axe.kt} (100%) rename game/plugin/skills/woodcutting/src/{wood.kt => Tree.kt} (100%) rename game/plugin/skills/woodcutting/src/{woodcutting.plugin.kts => Woodcutting.plugin.kts} (99%) diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt index 7433a0337..f514a0d5f 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/assertions/actionAsserts.kt @@ -4,7 +4,6 @@ import io.mockk.MockKVerificationScope import io.mockk.verify import org.apollo.game.plugin.testing.junit.api.ActionCaptureCallbackRegistration - /** * Verify some expectations on a [mock] after a delayed event (specified by [DelayMode]). */ diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt index a9e8c4f13..cae992930 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestState.kt @@ -3,6 +3,7 @@ package org.apollo.game.plugin.testing.junit import io.mockk.every import io.mockk.slot import io.mockk.spyk +import kotlin.reflect.KClass import org.apollo.game.action.Action import org.apollo.game.message.handler.MessageHandlerChainSet import org.apollo.game.model.World @@ -12,7 +13,6 @@ import org.apollo.game.plugin.testing.junit.mocking.StubPrototype import org.apollo.game.plugin.testing.junit.stubs.PlayerStubInfo import org.apollo.net.message.Message import org.apollo.util.security.PlayerCredentials -import kotlin.reflect.KClass data class ApolloTestState(val handlers: MessageHandlerChainSet, val world: World) { val players = mutableListOf() diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestingExtension.kt similarity index 96% rename from game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt rename to game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestingExtension.kt index d9fbfc512..1a6f5af2f 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestExtension.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/ApolloTestingExtension.kt @@ -4,6 +4,14 @@ import io.mockk.every import io.mockk.slot import io.mockk.spyk import io.mockk.staticMockk +import kotlin.reflect.KCallable +import kotlin.reflect.KMutableProperty +import kotlin.reflect.full.companionObject +import kotlin.reflect.full.createType +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.jvm.isAccessible +import kotlin.reflect.jvm.jvmErasure import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition @@ -20,22 +28,6 @@ import org.apollo.game.plugin.testing.junit.api.annotations.NpcDefinitions import org.apollo.game.plugin.testing.junit.api.annotations.ObjectDefinitions import org.apollo.game.plugin.testing.junit.mocking.StubPrototype import org.junit.jupiter.api.extension.* -import kotlin.reflect.KCallable -import kotlin.reflect.KMutableProperty -import kotlin.reflect.full.companionObject -import kotlin.reflect.full.createType -import kotlin.reflect.full.declaredMemberFunctions -import kotlin.reflect.full.declaredMemberProperties -import kotlin.reflect.jvm.isAccessible -import kotlin.reflect.jvm.jvmErasure - -internal val supportedTestDoubleTypes = setOf( - Player::class.createType(), - Npc::class.createType(), - GameObject::class.createType(), - World::class.createType(), - ActionCapture::class.createType() -) class ApolloTestingExtension : AfterTestExecutionCallback, @@ -168,6 +160,13 @@ class ApolloTestingExtension : } companion object { + internal val supportedTestDoubleTypes = setOf( + Player::class.createType(), + Npc::class.createType(), + GameObject::class.createType(), + World::class.createType(), + ActionCapture::class.createType() + ) inline fun findTestDefinitions( callables: Collection>, @@ -185,7 +184,5 @@ class ApolloTestingExtension : method.call(companionObjectInstance) } } - } - } \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt index 9d0a1478d..8ebf8fa35 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/ActionCapture.kt @@ -1,10 +1,10 @@ package org.apollo.game.plugin.testing.junit.api +import kotlin.reflect.KClass +import kotlin.reflect.full.isSuperclassOf import org.apollo.game.action.Action import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue -import kotlin.reflect.KClass -import kotlin.reflect.full.isSuperclassOf class ActionCapture(val type: KClass>) { private var action: Action<*>? = null @@ -62,7 +62,6 @@ class ActionCapture(val type: KClass>) { }) } - /** * Create a callback registration that triggers after exactly [count] ticks. */ diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt deleted file mode 100644 index 03aa36a17..000000000 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/annotations/testAnnotations.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.apollo.game.plugin.testing.junit.api.annotations - -import org.apollo.game.action.Action -import kotlin.reflect.KClass - -annotation class ActionTest(val value: KClass> = Action::class) \ No newline at end of file diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt index c94c6e10a..8dfd2cbcd 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/api/interactions/world.kt @@ -18,7 +18,6 @@ fun World.spawnObject(id: Int, position: Position): GameObject { return obj } - /** * Spawns a new NPC with the minimum set of dependencies required to function correctly in the world. */ diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt index 5edfd5eb6..1daced5d4 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/params/DefinitionProviders.kt @@ -1,5 +1,10 @@ package org.apollo.game.plugin.testing.junit.params +import java.util.stream.Stream +import kotlin.reflect.KCallable +import kotlin.reflect.full.companionObject +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.full.declaredMemberProperties import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition @@ -11,11 +16,6 @@ import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider import org.junit.jupiter.params.support.AnnotationConsumer -import java.util.stream.Stream -import kotlin.reflect.KCallable -import kotlin.reflect.full.companionObject -import kotlin.reflect.full.declaredMemberFunctions -import kotlin.reflect.full.declaredMemberProperties /** * An [ArgumentsProvider] for a definition of type `D`. @@ -64,7 +64,6 @@ object ItemDefinitionsProvider : DefinitionsProvider( override fun accept(source: ItemDefinitionSource) { sourceNames = source.sourceNames.toHashSet() } - } /** @@ -80,7 +79,6 @@ object NpcDefinitionsProvider : DefinitionsProvider( override fun accept(source: NpcDefinitionSource) { sourceNames = source.sourceNames.toHashSet() } - } /** @@ -96,5 +94,4 @@ object ObjectDefinitionsProvider : DefinitionsProvider( override fun accept(source: ObjectDefinitionSource) { sourceNames = source.sourceNames.toHashSet() } - } diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt index c5306f1f7..48c842f89 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/GameObjectStubInfo.kt @@ -1,2 +1 @@ package org.apollo.game.plugin.testing.junit.stubs - diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt index c5306f1f7..48c842f89 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/NpcStubInfo.kt @@ -1,2 +1 @@ package org.apollo.game.plugin.testing.junit.stubs - diff --git a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt index 3aae860cf..cd192c068 100644 --- a/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt +++ b/game/plugin-testing/src/main/kotlin/org/apollo/game/plugin/testing/junit/stubs/PlayerStubInfo.kt @@ -18,10 +18,8 @@ class PlayerStubInfo { return info } - } var position = Position(3222, 3222) var name = "test" } - diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt b/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt index d083dc9cb..f0873b998 100644 --- a/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/Definitions.kt @@ -1,9 +1,9 @@ package org.apollo.game.plugin.api +import java.lang.IllegalArgumentException import org.apollo.cache.def.ItemDefinition import org.apollo.cache.def.NpcDefinition import org.apollo.cache.def.ObjectDefinition -import java.lang.IllegalArgumentException /** * Provides plugins with access to item, npc, and object definitions @@ -101,5 +101,4 @@ object Definitions { val normalizedName = name.replace('_', ' ') return definitions.firstOrNull { it.nameSupplier().equals(normalizedName, ignoreCase = true) } } - } \ No newline at end of file diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/Player.kt b/game/plugin/api/src/org/apollo/game/plugin/api/Player.kt index 9205bc0b4..a98a54481 100644 --- a/game/plugin/api/src/org/apollo/game/plugin/api/Player.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/Player.kt @@ -86,5 +86,4 @@ class SkillProxy(private val skills: SkillSet, private val skill: Int) { val new = Math.min(current + amount, maximum) skills.setCurrentLevel(skill, new) } - } \ No newline at end of file diff --git a/game/plugin/api/src/org/apollo/game/plugin/api/World.kt b/game/plugin/api/src/org/apollo/game/plugin/api/World.kt index a44163c1b..6f981e487 100644 --- a/game/plugin/api/src/org/apollo/game/plugin/api/World.kt +++ b/game/plugin/api/src/org/apollo/game/plugin/api/World.kt @@ -100,5 +100,4 @@ private class ExpireObjectTask( stop() } } - } \ No newline at end of file diff --git a/game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt b/game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt index 43af94858..89c662aee 100644 --- a/game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt +++ b/game/plugin/api/test/org/apollo/game/plugin/api/DefinitionsTests.kt @@ -88,7 +88,5 @@ class DefinitionsTests { @ObjectDefinitions val objs = listOf("obj zero", "obj one", "obj two", "obj duplicate name", "obj duplicate name") .mapIndexed { id, name -> ObjectDefinition(id).also { it.name = name } } - } - } \ No newline at end of file diff --git a/game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt b/game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt index a1b1f3b78..753f16639 100644 --- a/game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt +++ b/game/plugin/api/test/org/apollo/game/plugin/api/PlayerTests.kt @@ -119,5 +119,4 @@ class PlayerTests { assertEquals(10, hitpoints.maximum) } } - } \ No newline at end of file diff --git a/game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt b/game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt index 452d2f00a..7d9644bf3 100644 --- a/game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt +++ b/game/plugin/api/test/org/apollo/game/plugin/api/PositionTests.kt @@ -22,5 +22,4 @@ class PositionTests { assertEquals(y, y2) { "y coordinate mismatch in Position destructuring." } assertEquals(z, z2) { "z coordinate mismatch in Position destructuring." } } - } \ No newline at end of file diff --git a/game/plugin/areas/src/Area.kt b/game/plugin/areas/src/Area.kt index 376ce33a8..e594a170d 100644 --- a/game/plugin/areas/src/Area.kt +++ b/game/plugin/areas/src/Area.kt @@ -14,7 +14,6 @@ interface Area { * Returns whether or not the specified [Position] is inside this [Area]. */ operator fun contains(position: Position): Boolean - } internal class RectangularArea(private val x: IntRange, private val y: IntRange, private val height: Int) : Area { @@ -23,5 +22,4 @@ internal class RectangularArea(private val x: IntRange, private val y: IntRange, val (x, y, z) = position return x in this.x && y in this.y && z == height } - } diff --git a/game/plugin/areas/src/AreaActionBuilder.kt b/game/plugin/areas/src/AreaActionBuilder.kt index 00ba8eb64..7da8aeada 100644 --- a/game/plugin/areas/src/AreaActionBuilder.kt +++ b/game/plugin/areas/src/AreaActionBuilder.kt @@ -38,5 +38,4 @@ class AreaActionBuilder internal constructor(val name: String, val area: Area) { fun exit(listener: AreaListener) { this.exit = listener } - } \ No newline at end of file diff --git a/game/plugin/areas/test/AreaActionTests.kt b/game/plugin/areas/test/AreaActionTests.kt index 0fbd5e1b6..7c577efd9 100644 --- a/game/plugin/areas/test/AreaActionTests.kt +++ b/game/plugin/areas/test/AreaActionTests.kt @@ -55,5 +55,4 @@ class AreaActionTests { assertTrue(triggered) { "exit_test_action was not triggered." } } - } \ No newline at end of file diff --git a/game/plugin/bank/src/bank.plugin.kts b/game/plugin/bank/src/bank.plugin.kts index 10d424e34..0aef5ac18 100644 --- a/game/plugin/bank/src/bank.plugin.kts +++ b/game/plugin/bank/src/bank.plugin.kts @@ -9,7 +9,6 @@ import org.apollo.net.message.Message val BANK_BOOTH_ID = 2213 - /** * Hook into the [ObjectActionMessage] and listen for when a bank booth's second action ("Open Bank") is selected. */ @@ -56,7 +55,6 @@ class BankAction(player: Player, position: Position) : DistancedAction(0 player.startAction(BankAction(player, position)) message.terminate() } - } override fun executeAction() { @@ -72,5 +70,4 @@ class BankAction(player: Player, position: Position) : DistancedAction(0 override fun hashCode(): Int { return position.hashCode() } - } diff --git a/game/plugin/bank/test/OpenBankTest.kt b/game/plugin/bank/test/OpenBankTest.kt index 58b7b5e49..578325e08 100644 --- a/game/plugin/bank/test/OpenBankTest.kt +++ b/game/plugin/bank/test/OpenBankTest.kt @@ -49,5 +49,4 @@ class OpenBankTest { verifyAfter(action.complete()) { player.openBank() } } - } \ No newline at end of file diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index 4cc6c8ad0..1aedd5b9a 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -1,139 +1,138 @@ - -import com.google.common.primitives.Ints -import org.apollo.game.model.Position -import org.apollo.game.model.entity.setting.PrivilegeLevel -import org.apollo.game.plugin.api.Position.component1 -import org.apollo.game.plugin.api.Position.component2 -import org.apollo.game.plugin.api.Position.component3 - -/** - * Sends the player's position. - */ -on_command("pos", PrivilegeLevel.MODERATOR) - .then { player -> - val (x, y, z) = player.position - val region = player.position.regionCoordinates - - player.sendMessage("You are at: ($x, $y, $z) in region (${region.x}, ${region.y}).") - } - -/** - * Teleports the player to the specified position. - */ -on_command("tele", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::tele [x] [y] [optional-z] or ::tele [place name]" - - if (arguments.size == 1) { - val query = arguments[0] - val results = TELEPORT_DESTINATIONS.filter { (name) -> name.startsWith(query) } - - if (results.isEmpty()) { - player.sendMessage("No destinations matching '$query'.") - player.sendMessage(invalidSyntax) - return@then - } else if (results.size > 1) { - player.sendMessage("Ambiguous query '$query' (could be $results). Please disambiguate.") - return@then - } - - val (name, dest) = results[0] - player.sendMessage("Teleporting to $name.") - player.teleport(dest) - - return@then - } - - if (arguments.size !in 2..3) { - player.sendMessage(invalidSyntax) - return@then - } - - val x = Ints.tryParse(arguments[0]) - if (x == null) { - player.sendMessage(invalidSyntax) - return@then - } - - val y = Ints.tryParse(arguments[1]) - if (y == null) { - player.sendMessage(invalidSyntax) - return@then - } - - var z = player.position.height - if (arguments.size == 3) { - val plane = Ints.tryParse(arguments[2]) - if (plane == null) { - player.sendMessage(invalidSyntax) - return@then - } - z = plane - } - - if (z in 0..4) { - player.teleport(Position(x, y, z)) - } - } - -/** - * Teleports the player to another player. - */ -on_command("teleto", PrivilegeLevel.ADMINISTRATOR) - .then { player -> - val invalidSyntax = "Invalid syntax - ::teleto [player name]" - - if (arguments.size == 1) { - val playerName = arguments[0] - try { - val foundPlayer = player.world.getPlayer(playerName) - - if (foundPlayer == null) { - player.sendMessage("Player $playerName is currently offline or does not exist.") - return@then - } - - player.teleport(foundPlayer.position) - player.sendMessage("You have teleported to player $playerName.") - } catch (_: Exception) { - // Invalid player name syntax - player.sendMessage(invalidSyntax) - } - } else { - player.sendMessage(invalidSyntax) - } - } - - -internal val TELEPORT_DESTINATIONS = listOf( - "alkharid" to Position(3292, 3171), - "ardougne" to Position(2662, 3304), - "barrows" to Position(3565, 3314), - "brimhaven" to Position(2802, 3179), - "burthorpe" to Position(2898, 3545), - "camelot" to Position(2757, 3478), - "canifis" to Position(3493, 3489), - "cw" to Position(2442, 3090), - "draynor" to Position(3082, 3249), - "duelarena" to Position(3370, 3267), - "edgeville" to Position(3087, 3504), - "entrana" to Position(2827, 3343), - "falador" to Position(2965, 3379), - "ge" to Position(3164, 3476), - "kbd" to Position(2273, 4680), - "keldagrim" to Position(2845, 10210), - "kq" to Position(3507, 9494), - "lumbridge" to Position(3222, 3219), - "lunar" to Position(2113, 3915), - "misc" to Position(2515, 3866), - "neit" to Position(2332, 3804), - "pc" to Position(2658, 2660), - "rellekka" to Position(2660, 3657), - "shilo" to Position(2852, 2955), - "taverley" to Position(2895, 3443), - "tutorial" to Position(3094, 3107), - "tzhaar" to Position(2480, 5175), - "varrock" to Position(3212, 3423), - "yanille" to Position(2605, 3096), - "zanaris" to Position(2452, 4473) + +import com.google.common.primitives.Ints +import org.apollo.game.model.Position +import org.apollo.game.model.entity.setting.PrivilegeLevel +import org.apollo.game.plugin.api.Position.component1 +import org.apollo.game.plugin.api.Position.component2 +import org.apollo.game.plugin.api.Position.component3 + +/** + * Sends the player's position. + */ +on_command("pos", PrivilegeLevel.MODERATOR) + .then { player -> + val (x, y, z) = player.position + val region = player.position.regionCoordinates + + player.sendMessage("You are at: ($x, $y, $z) in region (${region.x}, ${region.y}).") + } + +/** + * Teleports the player to the specified position. + */ +on_command("tele", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val invalidSyntax = "Invalid syntax - ::tele [x] [y] [optional-z] or ::tele [place name]" + + if (arguments.size == 1) { + val query = arguments[0] + val results = TELEPORT_DESTINATIONS.filter { (name) -> name.startsWith(query) } + + if (results.isEmpty()) { + player.sendMessage("No destinations matching '$query'.") + player.sendMessage(invalidSyntax) + return@then + } else if (results.size > 1) { + player.sendMessage("Ambiguous query '$query' (could be $results). Please disambiguate.") + return@then + } + + val (name, dest) = results[0] + player.sendMessage("Teleporting to $name.") + player.teleport(dest) + + return@then + } + + if (arguments.size !in 2..3) { + player.sendMessage(invalidSyntax) + return@then + } + + val x = Ints.tryParse(arguments[0]) + if (x == null) { + player.sendMessage(invalidSyntax) + return@then + } + + val y = Ints.tryParse(arguments[1]) + if (y == null) { + player.sendMessage(invalidSyntax) + return@then + } + + var z = player.position.height + if (arguments.size == 3) { + val plane = Ints.tryParse(arguments[2]) + if (plane == null) { + player.sendMessage(invalidSyntax) + return@then + } + z = plane + } + + if (z in 0..4) { + player.teleport(Position(x, y, z)) + } + } + +/** + * Teleports the player to another player. + */ +on_command("teleto", PrivilegeLevel.ADMINISTRATOR) + .then { player -> + val invalidSyntax = "Invalid syntax - ::teleto [player name]" + + if (arguments.size == 1) { + val playerName = arguments[0] + try { + val foundPlayer = player.world.getPlayer(playerName) + + if (foundPlayer == null) { + player.sendMessage("Player $playerName is currently offline or does not exist.") + return@then + } + + player.teleport(foundPlayer.position) + player.sendMessage("You have teleported to player $playerName.") + } catch (_: Exception) { + // Invalid player name syntax + player.sendMessage(invalidSyntax) + } + } else { + player.sendMessage(invalidSyntax) + } + } + +internal val TELEPORT_DESTINATIONS = listOf( + "alkharid" to Position(3292, 3171), + "ardougne" to Position(2662, 3304), + "barrows" to Position(3565, 3314), + "brimhaven" to Position(2802, 3179), + "burthorpe" to Position(2898, 3545), + "camelot" to Position(2757, 3478), + "canifis" to Position(3493, 3489), + "cw" to Position(2442, 3090), + "draynor" to Position(3082, 3249), + "duelarena" to Position(3370, 3267), + "edgeville" to Position(3087, 3504), + "entrana" to Position(2827, 3343), + "falador" to Position(2965, 3379), + "ge" to Position(3164, 3476), + "kbd" to Position(2273, 4680), + "keldagrim" to Position(2845, 10210), + "kq" to Position(3507, 9494), + "lumbridge" to Position(3222, 3219), + "lunar" to Position(2113, 3915), + "misc" to Position(2515, 3866), + "neit" to Position(2332, 3804), + "pc" to Position(2658, 2660), + "rellekka" to Position(2660, 3657), + "shilo" to Position(2852, 2955), + "taverley" to Position(2895, 3443), + "tutorial" to Position(3094, 3107), + "tzhaar" to Position(2480, 5175), + "varrock" to Position(3212, 3423), + "yanille" to Position(2605, 3096), + "zanaris" to Position(2452, 4473) ) \ No newline at end of file diff --git a/game/plugin/cmd/test/AnimateCommandTests.kt b/game/plugin/cmd/test/AnimateCommandTests.kt index c52e72bab..5a49dd6e1 100644 --- a/game/plugin/cmd/test/AnimateCommandTests.kt +++ b/game/plugin/cmd/test/AnimateCommandTests.kt @@ -36,5 +36,4 @@ class AnimateCommandTests { player.sendMessage(contains("Invalid syntax")) } } - } \ No newline at end of file diff --git a/game/plugin/cmd/test/LookupCommandTests.kt b/game/plugin/cmd/test/LookupCommandTests.kt index 73208f8d6..ada7ebeeb 100644 --- a/game/plugin/cmd/test/LookupCommandTests.kt +++ b/game/plugin/cmd/test/LookupCommandTests.kt @@ -93,5 +93,4 @@ class LookupCommandTests { length = 1 }) } - } \ No newline at end of file diff --git a/game/plugin/cmd/test/SpawnCommandTests.kt b/game/plugin/cmd/test/SpawnCommandTests.kt index ef9a3d60b..8dfde978e 100644 --- a/game/plugin/cmd/test/SpawnCommandTests.kt +++ b/game/plugin/cmd/test/SpawnCommandTests.kt @@ -37,7 +37,7 @@ class SpawnCommandTests { verify { world.register(match { - it.id == 1 && it.position == Position(3, 3,0) + it.id == 1 && it.position == Position(3, 3, 0) }) } } diff --git a/game/plugin/cmd/test/TeleportToPlayerCommandTests.kt b/game/plugin/cmd/test/TeleportToPlayerCommandTests.kt index 6b4e28644..d70c8e4d3 100644 --- a/game/plugin/cmd/test/TeleportToPlayerCommandTests.kt +++ b/game/plugin/cmd/test/TeleportToPlayerCommandTests.kt @@ -49,5 +49,4 @@ class TeleportToPlayerCommandTests { player.sendMessage(contains("Invalid syntax")) } } - } \ No newline at end of file diff --git a/game/plugin/consumables/src/consumables.kt b/game/plugin/consumables/src/consumables.kt index 3fec3eaf5..f8bc5ef0e 100644 --- a/game/plugin/consumables/src/consumables.kt +++ b/game/plugin/consumables/src/consumables.kt @@ -18,7 +18,6 @@ abstract class Consumable(val name: String, val id: Int, val sound: Int, val del player.inventory.add(replacement) } } - } private val consumables = mutableMapOf() @@ -41,12 +40,12 @@ class FoodOrDrink : Consumable { val type: FoodOrDrinkType constructor( - name: String, - id: Int, - delay: Int, - type: FoodOrDrinkType, - restoration: Int, - replacement: Int? = null + name: String, + id: Int, + delay: Int, + type: FoodOrDrinkType, + restoration: Int, + replacement: Int? = null ) : super(name, id, EAT_FOOD_SOUND, delay, replacement) { this.type = type this.restoration = restoration @@ -64,7 +63,6 @@ class FoodOrDrink : Consumable { player.skillSet.setCurrentLevel(Skill.HITPOINTS, newHitpointsLevel) } - } /** diff --git a/game/plugin/consumables/src/consumables.plugin.kts b/game/plugin/consumables/src/consumables.plugin.kts index c633e9002..1711d43eb 100644 --- a/game/plugin/consumables/src/consumables.plugin.kts +++ b/game/plugin/consumables/src/consumables.plugin.kts @@ -34,5 +34,4 @@ class ConsumeAction(val consumable: Consumable, player: Player, val slot: Int) : wait(consumable.delay) stop() } - } diff --git a/game/plugin/consumables/src/drinks.plugin.kts b/game/plugin/consumables/src/drinks.plugin.kts index f3c8075ae..a96a8a3f8 100644 --- a/game/plugin/consumables/src/drinks.plugin.kts +++ b/game/plugin/consumables/src/drinks.plugin.kts @@ -1,13 +1,13 @@ import org.apollo.plugin.consumables.drink -//# Wine +// # Wine drink(name = "jug_of_wine", id = 1993, restoration = 11) -//# Hot Drinks +// # Hot Drinks drink(name = "nettle_tea", id = 4239, restoration = 3) drink(name = "nettle_tea", id = 4240, restoration = 3) -//# Gnome Cocktails +// # Gnome Cocktails drink(name = "fruit_blast", id = 2034, restoration = 9) drink(name = "fruit_blast", id = 2084, restoration = 9) drink(name = "pineapple_punch", id = 2036, restoration = 9) diff --git a/game/plugin/consumables/src/foods.plugin.kts b/game/plugin/consumables/src/foods.plugin.kts index 7762969b9..029818900 100644 --- a/game/plugin/consumables/src/foods.plugin.kts +++ b/game/plugin/consumables/src/foods.plugin.kts @@ -32,12 +32,12 @@ food(name = "shark", id = 385, restoration = 20) food(name = "sea_turtle", id = 397, restoration = 21) food(name = "manta_ray", id = 391, restoration = 22) -//# Breads/Wraps +// # Breads/Wraps food(name = "bread", id = 2309, restoration = 5) food(name = "oomlie_wrap", id = 2343, restoration = 14) food(name = "ugthanki_kebab", id = 1883, restoration = 19) -//# Fruits +// # Fruits food(name = "banana", id = 1963, restoration = 2) food(name = "sliced_banana", id = 3162, restoration = 2) food(name = "lemon", id = 2102, restoration = 2) @@ -54,8 +54,8 @@ food(name = "orange", id = 2108, restoration = 2) food(name = "orange_rings", id = 2110, restoration = 2) food(name = "orange_slices", id = 2112, restoration = 2) -//# Pies -//# TODO: pie special effects (e.g. fish pie raises fishing level) +// # Pies +// # TODO: pie special effects (e.g. fish pie raises fishing level) food(name = "redberry_pie", id = 2325, restoration = 5, replacement = 2333, delay = 1) food(name = "redberry_pie", id = 2333, restoration = 5, delay = 1) @@ -77,12 +77,12 @@ food(name = "wild_pie", id = 7210, restoration = 11, delay = 1) food(name = "summer_pie", id = 7218, restoration = 11, replacement = 7220, delay = 1) food(name = "summer_pie", id = 7220, restoration = 11, delay = 1) -//# Stews +// # Stews food(name = "stew", id = 2003, restoration = 11) food(name = "banana_stew", id = 4016, restoration = 11) food(name = "curry", id = 2011, restoration = 19) -//# Pizzas +// # Pizzas food(name = "plain_pizza", id = 2289, restoration = 7, replacement = 2291) food(name = "plain_pizza", id = 2291, restoration = 7) @@ -95,7 +95,7 @@ food(name = "anchovy_pizza", id = 2299, restoration = 9) food(name = "pineapple_pizza", id = 2301, restoration = 11, replacement = 2303) food(name = "pineapple_pizza", id = 2303, restoration = 11) -//# Cakes +// # Cakes food(name = "fishcake", id = 7530, restoration = 11) food(name = "cake", id = 1891, restoration = 4, replacement = 1893) @@ -106,7 +106,7 @@ food(name = "chocolate_cake", id = 1897, restoration = 5, replacement = 1899) food(name = "chocolate_cake", id = 1899, restoration = 5, replacement = 1901) food(name = "chocolate_cake", id = 1901, restoration = 5) -//# Vegetables +// # Vegetables food(name = "potato", id = 1942, restoration = 1) food(name = "spinach_roll", id = 1969, restoration = 2) food(name = "baked_potato", id = 6701, restoration = 4) @@ -119,14 +119,14 @@ food(name = "egg_potato", id = 7056, restoration = 16) food(name = "mushroom_potato", id = 7058, restoration = 20) food(name = "tuna_potato", id = 7060, restoration = 22) -//# Dairy +// # Dairy food(name = "cheese", id = 1985, restoration = 2) food(name = "pot_of_cream", id = 2130, restoration = 1) -//# Gnome Food +// # Gnome Food food(name = "toads_legs", id = 2152, restoration = 3) -//# Gnome Bowls +// # Gnome Bowls food(name = "worm_hole", id = 2191, restoration = 12) food(name = "worm_hole", id = 2233, restoration = 12) food(name = "vegetable_ball", id = 2195, restoration = 12) @@ -136,7 +136,7 @@ food(name = "tangled_toads_legs", id = 2231, restoration = 15) food(name = "chocolate_bomb", id = 2185, restoration = 15) food(name = "chocolate_bomb", id = 2229, restoration = 15) -//# Gnome Crunchies +// # Gnome Crunchies food(name = "toad_crunchies", id = 2217, restoration = 7) food(name = "toad_crunchies", id = 2243, restoration = 7) food(name = "spicy_crunchies", id = 2213, restoration = 7) @@ -146,7 +146,7 @@ food(name = "worm_crunchies", id = 2237, restoration = 8) food(name = "chocchip_crunchies", id = 2209, restoration = 7) food(name = "chocchip_crunchies", id = 2239, restoration = 7) -//# Gnome Battas +// # Gnome Battas food(name = "fruit_batta", id = 2225, restoration = 11) food(name = "fruit_batta", id = 2277, restoration = 11) food(name = "toad_batta", id = 2221, restoration = 11) diff --git a/game/plugin/consumables/test/FoodOrDrinkTests.kt b/game/plugin/consumables/test/FoodOrDrinkTests.kt index 851f32900..59aad8da8 100644 --- a/game/plugin/consumables/test/FoodOrDrinkTests.kt +++ b/game/plugin/consumables/test/FoodOrDrinkTests.kt @@ -3,8 +3,8 @@ package org.apollo.plugin.consumables import io.mockk.verify import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill -import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.assertions.verifyAfter import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.ActionCapture @@ -81,15 +81,13 @@ class FoodOrDrinkTests { fun `A message should be sent saying the player has drank an item when consuming a drink`() { player.interactWithItem(TEST_DRINK_ID, option = 1, slot = 1) - verifyAfter(action.complete()) { player.sendMessage("You drink the ${TEST_DRINK_NAME}.") } - + verifyAfter(action.complete()) { player.sendMessage("You drink the $TEST_DRINK_NAME.") } } @Test fun `A message should be sent saying the player has eaten an item when consuming food`() { player.interactWithItem(TEST_FOOD_ID, option = 1, slot = 1) - verifyAfter(action.complete()) { player.sendMessage("You eat the ${TEST_FOOD_NAME}.") } + verifyAfter(action.complete()) { player.sendMessage("You eat the $TEST_FOOD_NAME.") } } - } \ No newline at end of file diff --git a/game/plugin/dummy/src/dummy.plugin.kts b/game/plugin/dummy/src/dummy.plugin.kts index f02507b12..a4501f95c 100644 --- a/game/plugin/dummy/src/dummy.plugin.kts +++ b/game/plugin/dummy/src/dummy.plugin.kts @@ -1,9 +1,6 @@ import kotlinx.coroutines.experimental.* -import kotlinx.coroutines.experimental.channels.Channel -import kotlinx.coroutines.experimental.selects.select import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction -import org.apollo.game.action.DistancedAction import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Animation import org.apollo.game.model.Position @@ -50,10 +47,8 @@ class DummyAction(val player: Player, position: Position) : AsyncDistancedAction player.startAction(DummyAction(player, position)) message.terminate() } - } - override fun action(): ActionBlock = { mob.sendMessage("You hit the dummy.") mob.turnTo(position) @@ -68,5 +63,4 @@ class DummyAction(val player: Player, position: Position) : AsyncDistancedAction skills.addExperience(Skill.ATTACK, EXP_PER_HIT) } } - } diff --git a/game/plugin/dummy/test/TrainingDummyTest.kt b/game/plugin/dummy/test/TrainingDummyTest.kt index 4a4284b52..ccc22be2b 100644 --- a/game/plugin/dummy/test/TrainingDummyTest.kt +++ b/game/plugin/dummy/test/TrainingDummyTest.kt @@ -5,12 +5,12 @@ import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill import org.apollo.game.plugin.testing.assertions.after +import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.junit.ApolloTestingExtension import org.apollo.game.plugin.testing.junit.api.ActionCapture import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.apollo.game.plugin.testing.junit.api.interactions.interactWith import org.apollo.game.plugin.testing.junit.api.interactions.spawnObject -import org.apollo.game.plugin.testing.assertions.contains import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test @@ -60,5 +60,4 @@ class TrainingDummyTest { assertEquals(beforeExp, skills.getExperience(Skill.ATTACK)) } } - } diff --git a/game/plugin/emote-tab/src/emote.kt b/game/plugin/emote-tab/src/Emote.kt similarity index 100% rename from game/plugin/emote-tab/src/emote.kt rename to game/plugin/emote-tab/src/Emote.kt diff --git a/game/plugin/emote-tab/src/emote-tab.plugin.kts b/game/plugin/emote-tab/src/EmoteTab.plugin.kts similarity index 100% rename from game/plugin/emote-tab/src/emote-tab.plugin.kts rename to game/plugin/emote-tab/src/EmoteTab.plugin.kts diff --git a/game/plugin/entity/actions/src/PlayerActionEvent.kt b/game/plugin/entity/actions/src/PlayerActionEvent.kt new file mode 100644 index 000000000..3cca682a5 --- /dev/null +++ b/game/plugin/entity/actions/src/PlayerActionEvent.kt @@ -0,0 +1,6 @@ +package org.apollo.game.plugin.entity.actions + +import org.apollo.game.model.entity.Player +import org.apollo.game.model.event.PlayerEvent + +class PlayerActionEvent(player: Player, val target: Player, val action: PlayerActionType) : PlayerEvent(player) \ No newline at end of file diff --git a/game/plugin/entity/actions/src/PlayerAction.kt b/game/plugin/entity/actions/src/playerAction.kt similarity index 84% rename from game/plugin/entity/actions/src/PlayerAction.kt rename to game/plugin/entity/actions/src/playerAction.kt index ff8fd6d2b..d08b77974 100644 --- a/game/plugin/entity/actions/src/PlayerAction.kt +++ b/game/plugin/entity/actions/src/playerAction.kt @@ -1,11 +1,8 @@ package org.apollo.game.plugin.entity.actions +import java.util.* import org.apollo.game.message.impl.SetPlayerActionMessage import org.apollo.game.model.entity.Player -import org.apollo.game.model.event.PlayerEvent -import java.util.* - -class PlayerActionEvent(player: Player, val target: Player, val action: PlayerActionType) : PlayerEvent(player) fun Player.enableAction(action: PlayerActionType) { send(SetPlayerActionMessage(action.displayName, action.slot, action.primary)) diff --git a/game/plugin/entity/actions/test/PlayerActionTests.kt b/game/plugin/entity/actions/test/PlayerActionTests.kt index 2a6546936..153345d0b 100644 --- a/game/plugin/entity/actions/test/PlayerActionTests.kt +++ b/game/plugin/entity/actions/test/PlayerActionTests.kt @@ -30,5 +30,4 @@ class PlayerActionTests { verify { player.send(eq(SetPlayerActionMessage("null", type.slot, type.primary))) } assertFalse(player.actionEnabled(type)) { "Action $type should not have been enabled, but was." } } - } \ No newline at end of file diff --git a/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.kt b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/FollowAction.kt similarity index 99% rename from game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.kt rename to game/plugin/entity/following/src/org/apollo/plugin/entity/following/FollowAction.kt index 2c678c283..517c0af96 100644 --- a/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.kt +++ b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/FollowAction.kt @@ -46,5 +46,4 @@ class FollowAction(player: Player, private val target: Player) : Action( lastPosition = target.position } } - } \ No newline at end of file diff --git a/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.plugin.kts b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.plugin.kts index 10d483ce4..98916343f 100644 --- a/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.plugin.kts +++ b/game/plugin/entity/following/src/org/apollo/plugin/entity/following/Following.plugin.kts @@ -2,7 +2,6 @@ package org.apollo.plugin.entity.following import org.apollo.game.plugin.entity.actions.PlayerActionEvent import org.apollo.game.plugin.entity.actions.PlayerActionType -import org.apollo.plugin.entity.following.FollowAction on_player_event { PlayerActionEvent::class } .where { action == PlayerActionType.FOLLOW } diff --git a/game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt b/game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt index 9e434b296..7290a7892 100644 --- a/game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt +++ b/game/plugin/entity/spawn/test/org/apollo/game/plugin/entity/spawn/SpawnTests.kt @@ -139,5 +139,4 @@ class SpawnTests { } } } - } diff --git a/game/plugin/locations/edgeville/src/npcs.plugin.kts b/game/plugin/locations/edgeville/src/npcs.plugin.kts index 7419b2b20..d89e84926 100644 --- a/game/plugin/locations/edgeville/src/npcs.plugin.kts +++ b/game/plugin/locations/edgeville/src/npcs.plugin.kts @@ -45,7 +45,6 @@ spawnNpc("oziach", x = 3067, y = 3518, facing = Direction.EAST) spawnNpc("shop_keeper", id = 528, x = 3079, y = 3509) spawnNpc("shop_assistant", id = 529, x = 3082, y = 3513) - spawnNpc("banker", x = 3096, y = 3489, facing = Direction.WEST) spawnNpc("banker", x = 3096, y = 3491, facing = Direction.WEST) spawnNpc("banker", x = 3096, y = 3492) diff --git a/game/plugin/locations/varrock/src/npcs.plugin.kts b/game/plugin/locations/varrock/src/npcs.plugin.kts index 1e5c9f0cc..83d5fb9ec 100644 --- a/game/plugin/locations/varrock/src/npcs.plugin.kts +++ b/game/plugin/locations/varrock/src/npcs.plugin.kts @@ -56,7 +56,6 @@ spawnNpc("woman", x = 3221, y = 3396) spawnNpc("woman", id = 5, x = 3279, y = 3497) spawnNpc("woman", id = 25, x = 3278, y = 3492) - spawnNpc("thief", x = 3285, y = 3500) spawnNpc("thief", x = 3234, y = 3389) spawnNpc("thief", x = 3188, y = 3383) @@ -130,7 +129,6 @@ spawnNpc("warrior_woman", x = 3205, y = 3493) spawnNpc("swan", x = 3261, y = 3354) spawnNpc("swan", x = 3260, y = 3356) - spawnNpc("ram", id = 3673, x = 3238, y = 3346) spawnNpc("ram", id = 3673, x = 3248, y = 3352) spawnNpc("ram", id = 3673, x = 3260, y = 3348) diff --git a/game/plugin/logout/src/logout.plugin.kts b/game/plugin/logout/src/logout.plugin.kts index e3bf59ef8..0243b091f 100644 --- a/game/plugin/logout/src/logout.plugin.kts +++ b/game/plugin/logout/src/logout.plugin.kts @@ -1,5 +1,5 @@ val LOGOUT_BUTTON_ID = 2458 on_button(LOGOUT_BUTTON_ID) - .where { widgetId == LOGOUT_BUTTON_ID } - .then { it.logout() } \ No newline at end of file + .where { widgetId == LOGOUT_BUTTON_ID } + .then { it.logout() } \ No newline at end of file diff --git a/game/plugin/logout/test/LogoutTests.kt b/game/plugin/logout/test/LogoutTests.kt index c536976f2..9a8cb9c66 100644 --- a/game/plugin/logout/test/LogoutTests.kt +++ b/game/plugin/logout/test/LogoutTests.kt @@ -1,4 +1,3 @@ - import io.mockk.verify import org.apollo.game.message.impl.ButtonMessage import org.apollo.game.model.entity.Player @@ -8,20 +7,19 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(ApolloTestingExtension::class) -class LogoutTests { +class LogoutTests { - companion object { - const val LOGOUT_BUTTON_ID = 2458 - } + companion object { + const val LOGOUT_BUTTON_ID = 2458 + } @TestMock lateinit var player: Player - @Test + @Test fun `The player should be logged out when they click the logout button`() { - player.send(ButtonMessage(LOGOUT_BUTTON_ID)) + player.send(ButtonMessage(LOGOUT_BUTTON_ID)) verify { player.logout() } - } - + } } \ No newline at end of file diff --git a/game/plugin/navigation/door/src/door.kt b/game/plugin/navigation/door/src/door.kt index d7255cb7c..59ee13256 100644 --- a/game/plugin/navigation/door/src/door.kt +++ b/game/plugin/navigation/door/src/door.kt @@ -1,5 +1,6 @@ package org.apollo.plugin.navigation.door +import java.util.* import org.apollo.game.action.DistancedAction import org.apollo.game.model.Direction import org.apollo.game.model.Position @@ -10,7 +11,6 @@ import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.api.findObject import org.apollo.net.message.Message -import java.util.* enum class DoorType { LEFT, RIGHT, NOT_SUPPORTED @@ -59,7 +59,6 @@ class Door(private val gameObject: GameObject) { return type() !== DoorType.NOT_SUPPORTED } - /** * Computes the given door type by which id exists in * the supported left and right hinged doors @@ -97,7 +96,6 @@ class Door(private val gameObject: GameObject) { toggledDoors.remove(gameObject) regionRepository.fromPosition(originalDoor.position).addEntity(originalDoor) } - } /** @@ -120,7 +118,6 @@ class Door(private val gameObject: GameObject) { DoorType.NOT_SUPPORTED -> null } } - } class OpenDoorAction(private val player: Player, private val door: Door, position: Position) : DistancedAction( @@ -140,7 +137,6 @@ class OpenDoorAction(private val player: Player, private val door: Door, positio player.startAction(OpenDoorAction(player, door, position)) message.terminate() } - } override fun executeAction() { @@ -156,7 +152,6 @@ class OpenDoorAction(private val player: Player, private val door: Door, positio } override fun hashCode(): Int = Objects.hash(position, player) - } class OpenDoorEvent(player: Player) : PlayerEvent(player) diff --git a/game/plugin/run/src/run.plugin.kts b/game/plugin/run/src/run.plugin.kts index 00c6a4705..fa65f0495 100644 --- a/game/plugin/run/src/run.plugin.kts +++ b/game/plugin/run/src/run.plugin.kts @@ -4,7 +4,7 @@ val WALK_BUTTON_ID = 152 val RUN_BUTTON_ID = 153 on { ButtonMessage::class } - .where { widgetId == WALK_BUTTON_ID || widgetId == RUN_BUTTON_ID } - .then { - it.toggleRunning() - } \ No newline at end of file + .where { widgetId == WALK_BUTTON_ID || widgetId == RUN_BUTTON_ID } + .then { + it.toggleRunning() + } \ No newline at end of file diff --git a/game/plugin/shops/src/action.kt b/game/plugin/shops/src/action.kt index 0449253cc..8f31158ff 100644 --- a/game/plugin/shops/src/action.kt +++ b/game/plugin/shops/src/action.kt @@ -50,7 +50,6 @@ class OpenShopAction( shop.removeListener(shopListener) } } - } /** @@ -64,5 +63,4 @@ class PlayerInventorySupplier : InventorySupplier { else -> null } } - } \ No newline at end of file diff --git a/game/plugin/shops/src/dsl.kt b/game/plugin/shops/src/dsl.kt index b5f5da39d..7974ff6d3 100644 --- a/game/plugin/shops/src/dsl.kt +++ b/game/plugin/shops/src/dsl.kt @@ -45,8 +45,12 @@ class ShopBuilder(val name: String) { * @param depluralise Whether or not the category name should have the "s". * @param builder The builder used to add items to the category. */ - fun category(name: String, affix: Affix = Affix.Suffix, depluralise: Boolean = true, - builder: CategoryWrapper.() -> Unit) { + fun category( + name: String, + affix: Affix = Affix.Suffix, + depluralise: Boolean = true, + builder: CategoryWrapper.() -> Unit + ) { val items = mutableListOf>() builder.invoke(CategoryWrapper(items)) @@ -118,7 +122,6 @@ class ShopBuilder(val name: String) { * Gets the [List] of shop operator ids. */ internal fun operators(): MutableList = operated.operators - } @ShopDslMarker @@ -148,14 +151,12 @@ class CategoryWrapper(private val items: MutableList>) { * Joins the item and category name in the expected manner. */ fun join(item: String, category: String): String = joiner(item, category) - } /** * Creates a [SellBuilder] with the specified [amount]. */ fun sell(amount: Int): SellBuilder = SellBuilder(amount, items) - } /** @@ -210,7 +211,6 @@ class OperatorBuilder internal constructor() { * `"Shopkeeper"(500) vs `"Shopkeeper"(501)`). Use [by(String][by] if the npc name is unambiguous. */ operator fun plus(pair: Pair): OperatorBuilder = by(pair) - } /** @@ -270,7 +270,6 @@ class ActionBuilder { */ override fun hashCode(): Int = throw UnsupportedOperationException("ActionBuilder is a utility class for a DSL " + "and improperly implements equals() - it should not be used anywhere outside of the DSL.") - } /** @@ -288,7 +287,6 @@ class CurrencyBuilder { builder.currency = this return true } - } /** @@ -312,7 +310,6 @@ class PurchasesBuilder { infix fun any(@Suppress("UNUSED_PARAMETER") items: Unit) { policy = Shop.PurchasePolicy.ANY } - } /** @@ -348,5 +345,4 @@ class SellBuilder(val amount: Int, val items: MutableList>) { * Overloads function invokation on Strings to map `"ambiguous_npc_name"(id)` to a [Pair]. */ operator fun String.invoke(id: Int): Pair = Pair(this, id) - } diff --git a/game/plugin/shops/src/shop.kt b/game/plugin/shops/src/shop.kt index 208632257..f5490906b 100644 --- a/game/plugin/shops/src/shop.kt +++ b/game/plugin/shops/src/shop.kt @@ -40,7 +40,6 @@ object Interfaces { * The id of the text widget that displays a shop's name. */ const val SHOP_NAME = 3901 - } /** @@ -69,7 +68,6 @@ data class Currency(val id: Int, val plural: Boolean = false) { else -> name } } - } /** @@ -124,7 +122,6 @@ class Shop( else -> throw IllegalArgumentException("Option must be 1-4") } } - } /** @@ -331,5 +328,4 @@ class Shop( * @param id The id of the [Item] to sell. */ private fun sells(id: Int): Boolean = sells.containsKey(id) - } \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt index 1a281943f..45f76b826 100644 --- a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/Fish.kt @@ -27,5 +27,4 @@ enum class Fish(val id: Int, val level: Int, val experience: Double, catchSuffix val catchMessage by lazy { "You catch ${catchSuffix ?: "a $catchName."}" } private val catchName by lazy { Definitions.item(id).name.toLowerCase().removePrefix("raw ") } - } diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt index a02412e7a..9eacf024e 100644 --- a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingAction.kt @@ -1,10 +1,10 @@ package org.apollo.game.plugin.skills.fishing +import java.util.Objects import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.model.entity.Player import org.apollo.game.plugin.api.fishing -import java.util.Objects class FishingAction( player: Player, @@ -82,7 +82,5 @@ class FishingAction( internal fun hasTool(player: Player, tool: FishingTool): Boolean { return tool.id in player.equipment || tool.id in player.inventory } - } - } \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingSpot.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingSpot.kt index 54a542985..380dd1a07 100644 --- a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingSpot.kt +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingSpot.kt @@ -106,9 +106,7 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco else -> Pair(tool, secondary, primary) } } - } - } companion object { @@ -119,5 +117,4 @@ enum class FishingSpot(val npc: Int, private val first: Option, private val seco */ fun lookup(id: Int): FishingSpot? = FISHING_SPOTS[id] } - } \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt index 7275ee638..bdcb5713a 100644 --- a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTarget.kt @@ -35,5 +35,4 @@ data class FishingTarget(val position: Position, val option: FishingSpot.Option) return false } - } \ No newline at end of file diff --git a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt index 41f639d0b..e49122142 100644 --- a/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt +++ b/game/plugin/skills/fishing/src/org/apollo/game/plugin/skills/fishing/FishingTool.kt @@ -29,5 +29,4 @@ enum class FishingTool( * The name of this tool, formatted so it can be inserted into a message. */ val formattedName by lazy { Definitions.item(id).name.toLowerCase() } - } \ No newline at end of file diff --git a/game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt b/game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt index 10f90abb9..42fd6cbb6 100644 --- a/game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt +++ b/game/plugin/skills/fishing/test/org/apollo/game/plugin/skills/fishing/FishingActionTests.kt @@ -89,5 +89,4 @@ class FishingActionTests { private val spots = FishingSpot.values() .map { NpcDefinition(it.npc).apply { name = "" } } } - } \ No newline at end of file diff --git a/game/plugin/skills/herblore/src/CrushIngredientAction.kt b/game/plugin/skills/herblore/src/CrushIngredientAction.kt index bf9cb2834..6c519431b 100644 --- a/game/plugin/skills/herblore/src/CrushIngredientAction.kt +++ b/game/plugin/skills/herblore/src/CrushIngredientAction.kt @@ -1,8 +1,8 @@ +import java.util.Objects import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncAction import org.apollo.game.model.Animation import org.apollo.game.model.entity.Player -import java.util.Objects class CrushIngredientAction( player: Player, diff --git a/game/plugin/skills/herblore/src/IdentifyHerbAction.kt b/game/plugin/skills/herblore/src/IdentifyHerbAction.kt index a3b11ac90..bd9bd4b75 100644 --- a/game/plugin/skills/herblore/src/IdentifyHerbAction.kt +++ b/game/plugin/skills/herblore/src/IdentifyHerbAction.kt @@ -1,10 +1,10 @@ +import java.util.Objects import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncAction import org.apollo.game.model.entity.Player import org.apollo.game.plugin.api.herblore import org.apollo.util.LanguageUtil -import java.util.Objects class IdentifyHerbAction( player: Player, diff --git a/game/plugin/skills/herblore/src/MakePotionAction.kt b/game/plugin/skills/herblore/src/MakePotionAction.kt index 46759d795..19f5ef94c 100644 --- a/game/plugin/skills/herblore/src/MakePotionAction.kt +++ b/game/plugin/skills/herblore/src/MakePotionAction.kt @@ -1,10 +1,10 @@ +import java.util.* import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncAction import org.apollo.game.model.Animation import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill import org.apollo.game.plugin.api.herblore -import java.util.* abstract class MakePotionAction( player: Player, diff --git a/game/plugin/skills/mining/src/ExpiredProspectingAction.kt b/game/plugin/skills/mining/src/ExpiredProspectingAction.kt new file mode 100644 index 000000000..41f3229e6 --- /dev/null +++ b/game/plugin/skills/mining/src/ExpiredProspectingAction.kt @@ -0,0 +1,41 @@ +import java.util.* +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player + +class ExpiredProspectingAction( + mob: Player, + position: Position +) : DistancedAction(DELAY, true, mob, position, ORE_SIZE) { + + companion object { + private const val DELAY = 0 + private const val ORE_SIZE = 1 + + /** + * Starts a [ExpiredProspectingAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player) { + val action = ExpiredProspectingAction(player, message.position) + player.startAction(action) + + message.terminate() + } + } + + override fun executeAction() { + mob.sendMessage("There is currently no ore available in this rock.") + stop() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ExpiredProspectingAction + return mob == other.mob && position == other.position + } + + override fun hashCode(): Int = Objects.hash(mob, position) +} \ No newline at end of file diff --git a/game/plugin/skills/mining/src/gem.kt b/game/plugin/skills/mining/src/Gem.kt similarity index 100% rename from game/plugin/skills/mining/src/gem.kt rename to game/plugin/skills/mining/src/Gem.kt diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/Mining.plugin.kts similarity index 100% rename from game/plugin/skills/mining/src/mining.plugin.kts rename to game/plugin/skills/mining/src/Mining.plugin.kts diff --git a/game/plugin/skills/mining/src/mining.kt b/game/plugin/skills/mining/src/MiningAction.kt similarity index 59% rename from game/plugin/skills/mining/src/mining.kt rename to game/plugin/skills/mining/src/MiningAction.kt index c3b773f23..0f159b388 100644 --- a/game/plugin/skills/mining/src/mining.kt +++ b/game/plugin/skills/mining/src/MiningAction.kt @@ -1,14 +1,12 @@ +import java.util.* import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.message.impl.ObjectActionMessage -import org.apollo.game.model.Position -import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.plugin.api.* import org.apollo.game.plugin.skills.mining.Ore import org.apollo.game.plugin.skills.mining.Pickaxe import org.apollo.net.message.Message -import java.util.* class MiningAction( player: Player, @@ -82,57 +80,4 @@ class MiningAction( } override fun hashCode(): Int = Objects.hash(mob, target) - -} - -data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { - - /** - * Deplete this mining resource from the [World], and schedule it to be respawned - * in a number of ticks specified by the [Ore]. - */ - fun deplete(world: World) { - val obj = world.findObject(position, objectId)!! - - world.replaceObject(obj, ore.objects[objectId]!!, ore.respawn) - } - - /** - * Check if the [Player] was successful in mining this ore with a random success [chance] value between 0 and 100. - */ - fun isSuccessful(mob: Player, chance: Int): Boolean { - val percent = (ore.chance * mob.mining.current + ore.chanceOffset) * 100 - return chance < percent - } - - /** - * Check if this target is still valid in the [World] (i.e. has not been [deplete]d). - */ - fun isValid(world: World) = world.findObject(position, objectId) != null - - /** - * Get the normalized name of the [Ore] represented by this target. - */ - fun oreName() = Definitions.item(ore.id).name.toLowerCase() - - /** - * Reward a [player] with experience and ore if they have the inventory capacity to take a new ore. - */ - fun reward(player: Player): Boolean { - val hasInventorySpace = player.inventory.add(ore.id) - - if (hasInventorySpace) { - player.mining.experience += ore.exp - } - - return hasInventorySpace - } - - /** - * Check if the [mob] has met the skill requirements to mine te [Ore] represented by - * this [MiningTarget]. - */ - fun skillRequirementsMet(mob: Player) = mob.mining.current < ore.level - } - diff --git a/game/plugin/skills/mining/src/MiningTarget.kt b/game/plugin/skills/mining/src/MiningTarget.kt new file mode 100644 index 000000000..5bbe1b4a1 --- /dev/null +++ b/game/plugin/skills/mining/src/MiningTarget.kt @@ -0,0 +1,58 @@ +import org.apollo.game.model.Position +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.api.findObject +import org.apollo.game.plugin.api.mining +import org.apollo.game.plugin.api.replaceObject +import org.apollo.game.plugin.skills.mining.Ore + +data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { + + /** + * Deplete this mining resource from the [World], and schedule it to be respawned + * in a number of ticks specified by the [Ore]. + */ + fun deplete(world: World) { + val obj = world.findObject(position, objectId)!! + + world.replaceObject(obj, ore.objects[objectId]!!, ore.respawn) + } + + /** + * Check if the [Player] was successful in mining this ore with a random success [chance] value between 0 and 100. + */ + fun isSuccessful(mob: Player, chance: Int): Boolean { + val percent = (ore.chance * mob.mining.current + ore.chanceOffset) * 100 + return chance < percent + } + + /** + * Check if this target is still valid in the [World] (i.e. has not been [deplete]d). + */ + fun isValid(world: World) = world.findObject(position, objectId) != null + + /** + * Get the normalized name of the [Ore] represented by this target. + */ + fun oreName() = Definitions.item(ore.id).name.toLowerCase() + + /** + * Reward a [player] with experience and ore if they have the inventory capacity to take a new ore. + */ + fun reward(player: Player): Boolean { + val hasInventorySpace = player.inventory.add(ore.id) + + if (hasInventorySpace) { + player.mining.experience += ore.exp + } + + return hasInventorySpace + } + + /** + * Check if the [mob] has met the skill requirements to mine te [Ore] represented by + * this [MiningTarget]. + */ + fun skillRequirementsMet(mob: Player) = mob.mining.current < ore.level +} \ No newline at end of file diff --git a/game/plugin/skills/mining/src/ore.kt b/game/plugin/skills/mining/src/Ore.kt similarity index 99% rename from game/plugin/skills/mining/src/ore.kt rename to game/plugin/skills/mining/src/Ore.kt index 7e76cf81c..1f4a94ff9 100644 --- a/game/plugin/skills/mining/src/ore.kt +++ b/game/plugin/skills/mining/src/Ore.kt @@ -36,7 +36,6 @@ enum class Ore( fun fromRock(id: Int): Ore? = ORE_ROCKS[id] fun fromExpiredRock(id: Int): Ore? = EXPIRED_ORE[id] - } } diff --git a/game/plugin/skills/mining/src/pickaxe.kt b/game/plugin/skills/mining/src/Pickaxe.kt similarity index 100% rename from game/plugin/skills/mining/src/pickaxe.kt rename to game/plugin/skills/mining/src/Pickaxe.kt diff --git a/game/plugin/skills/mining/src/prospecting.kt b/game/plugin/skills/mining/src/ProspectingAction.kt similarity index 59% rename from game/plugin/skills/mining/src/prospecting.kt rename to game/plugin/skills/mining/src/ProspectingAction.kt index 9b0f3d1cc..10bf83a11 100644 --- a/game/plugin/skills/mining/src/prospecting.kt +++ b/game/plugin/skills/mining/src/ProspectingAction.kt @@ -1,13 +1,12 @@ +import java.util.Objects import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction -import org.apollo.game.action.DistancedAction import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.Position import org.apollo.game.model.entity.Player import org.apollo.game.plugin.api.Definitions import org.apollo.game.plugin.skills.mining.Ore import org.apollo.net.message.Message -import java.util.Objects class ProspectingAction( player: Player, @@ -51,42 +50,4 @@ class ProspectingAction( } override fun hashCode(): Int = Objects.hash(mob, position, ore) - } - -class ExpiredProspectingAction( - mob: Player, - position: Position -) : DistancedAction(DELAY, true, mob, position, ORE_SIZE) { - - companion object { - private const val DELAY = 0 - private const val ORE_SIZE = 1 - - /** - * Starts a [ExpiredProspectingAction] for the specified [Player], terminating the [Message] that triggered it. - */ - fun start(message: ObjectActionMessage, player: Player) { - val action = ExpiredProspectingAction(player, message.position) - player.startAction(action) - - message.terminate() - } - } - - override fun executeAction() { - mob.sendMessage("There is currently no ore available in this rock.") - stop() - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as ExpiredProspectingAction - return mob == other.mob && position == other.position - } - - override fun hashCode(): Int = Objects.hash(mob, position) - -} \ No newline at end of file diff --git a/game/plugin/skills/mining/test/MiningActionTests.kt b/game/plugin/skills/mining/test/MiningActionTests.kt index 2bd964f5b..59e9a6bec 100644 --- a/game/plugin/skills/mining/test/MiningActionTests.kt +++ b/game/plugin/skills/mining/test/MiningActionTests.kt @@ -87,5 +87,4 @@ class MiningActionTests { @ItemDefinitions fun pickaxes() = listOf(ItemDefinition(Pickaxe.BRONZE.id)) } - } \ No newline at end of file diff --git a/game/plugin/skills/mining/test/PickaxeTests.kt b/game/plugin/skills/mining/test/PickaxeTests.kt index 69e375395..70112ec14 100644 --- a/game/plugin/skills/mining/test/PickaxeTests.kt +++ b/game/plugin/skills/mining/test/PickaxeTests.kt @@ -24,7 +24,6 @@ class PickaxeTests { assertEquals(null, Pickaxe.bestFor(player)) } - @ParameterizedTest @EnumSource(Pickaxe::class) fun `The highest level pickaxe is chosen when available`(pickaxe: Pickaxe) { @@ -43,7 +42,6 @@ class PickaxeTests { assertEquals(Pickaxe.BRONZE, Pickaxe.bestFor(player)) } - @ParameterizedTest @EnumSource(value = Pickaxe::class) fun `Pickaxes can be chosen from equipment as well as inventory`(pickaxe: Pickaxe) { @@ -53,7 +51,6 @@ class PickaxeTests { assertEquals(pickaxe, Pickaxe.bestFor(player)) } - @ParameterizedTest @EnumSource(value = Pickaxe::class) fun `Pickaxes with a level requirement higher than the player's are ignored`(pickaxe: Pickaxe) { @@ -73,5 +70,4 @@ class PickaxeTests { ItemDefinition(it.id).apply { isStackable = false } } } - } \ No newline at end of file diff --git a/game/plugin/skills/mining/test/ProspectingTests.kt b/game/plugin/skills/mining/test/ProspectingTests.kt index 2bbc07665..27d11c712 100644 --- a/game/plugin/skills/mining/test/ProspectingTests.kt +++ b/game/plugin/skills/mining/test/ProspectingTests.kt @@ -45,5 +45,4 @@ class ProspectingTests { ItemDefinition(it.id).also { it.name = "" } } } - } \ No newline at end of file diff --git a/game/plugin/skills/mining/test/TestData.kt b/game/plugin/skills/mining/test/TestData.kt index e6583035b..aa798d24a 100644 --- a/game/plugin/skills/mining/test/TestData.kt +++ b/game/plugin/skills/mining/test/TestData.kt @@ -1,8 +1,8 @@ +import java.util.stream.Stream import org.apollo.game.plugin.skills.mining.Ore import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider -import java.util.stream.Stream data class MiningTestData(val rockId: Int, val expiredRockId: Int, val ore: Ore) diff --git a/game/plugin/skills/prayer/src/BoneBuryAction.kt b/game/plugin/skills/prayer/src/BuryBoneAction.kt similarity index 99% rename from game/plugin/skills/prayer/src/BoneBuryAction.kt rename to game/plugin/skills/prayer/src/BuryBoneAction.kt index c5fe00897..3b6720caf 100644 --- a/game/plugin/skills/prayer/src/BoneBuryAction.kt +++ b/game/plugin/skills/prayer/src/BuryBoneAction.kt @@ -28,5 +28,4 @@ class BuryBoneAction( public val BURY_BONE_ANIMATION = Animation(827) internal const val BURY_OPTION = 1 } - } \ No newline at end of file diff --git a/game/plugin/skills/prayer/src/prayer.plugin.kts b/game/plugin/skills/prayer/src/Prayer.plugin.kts similarity index 100% rename from game/plugin/skills/prayer/src/prayer.plugin.kts rename to game/plugin/skills/prayer/src/Prayer.plugin.kts diff --git a/game/plugin/skills/prayer/test/BuryBoneTests.kt b/game/plugin/skills/prayer/test/BuryBoneTests.kt index 6d485334b..23d57f684 100644 --- a/game/plugin/skills/prayer/test/BuryBoneTests.kt +++ b/game/plugin/skills/prayer/test/BuryBoneTests.kt @@ -70,5 +70,4 @@ class BuryBoneTests { return Bone.values().map { ItemDefinition(it.id) } } } - } \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/Rune.kt b/game/plugin/skills/runecrafting/src/Rune.kt index 9d2c3991e..5717442b5 100644 --- a/game/plugin/skills/runecrafting/src/Rune.kt +++ b/game/plugin/skills/runecrafting/src/Rune.kt @@ -2,7 +2,6 @@ package org.apollo.game.plugin.skill.runecrafting import org.apollo.game.plugin.skill.runecrafting.Altar.* - interface Rune { /** * The item id of the rune. @@ -29,7 +28,7 @@ interface Rune { * * [playerLevel] - The players current runecrafting level. */ - fun getBonusMultiplier(playerLevel: Int) : Double + fun getBonusMultiplier(playerLevel: Int): Double } enum class DefaultRune( diff --git a/game/plugin/skills/runecrafting/src/Runecrafting.plugin.kts b/game/plugin/skills/runecrafting/src/Runecrafting.plugin.kts index b31dbc5bf..88f983f77 100644 --- a/game/plugin/skills/runecrafting/src/Runecrafting.plugin.kts +++ b/game/plugin/skills/runecrafting/src/Runecrafting.plugin.kts @@ -8,11 +8,10 @@ private val changeAltarObjectConfigId = 491 internal val RUNES = mutableListOf() -fun List.findById(id: Int) : Rune? { +fun List.findById(id: Int): Rune? { return find { rune -> rune.id == id } } - start { RUNES.addAll(DefaultRune.values()) } diff --git a/game/plugin/skills/runecrafting/src/RunecraftingAction.kt b/game/plugin/skills/runecrafting/src/RunecraftingAction.kt index 371a35543..ec8c04381 100644 --- a/game/plugin/skills/runecrafting/src/RunecraftingAction.kt +++ b/game/plugin/skills/runecrafting/src/RunecraftingAction.kt @@ -25,7 +25,7 @@ class RunecraftingAction(val player: Player, val rune: Rune, altar: Altar) : Asy wait(1) - val name = Definitions.item(rune.id).name; + val name = Definitions.item(rune.id).name val nameArticle = LanguageUtil.getIndefiniteArticle(name) val essenceAmount = player.inventory.removeAll(runeEssenceId) val runeAmount = essenceAmount * rune.getBonusMultiplier(player.runecraft.current) diff --git a/game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt b/game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt index 4e01a44bc..9751696bc 100644 --- a/game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt +++ b/game/plugin/skills/runecrafting/test/RunecraftingActionTests.kt @@ -27,7 +27,6 @@ class RunecraftingActionTests { fun setupPlayer() { player.position = TEST_ALTAR.center player.inventory.add(runeEssenceId, 25) - } @Test diff --git a/game/plugin/skills/woodcutting/src/axe.kt b/game/plugin/skills/woodcutting/src/Axe.kt similarity index 100% rename from game/plugin/skills/woodcutting/src/axe.kt rename to game/plugin/skills/woodcutting/src/Axe.kt diff --git a/game/plugin/skills/woodcutting/src/wood.kt b/game/plugin/skills/woodcutting/src/Tree.kt similarity index 100% rename from game/plugin/skills/woodcutting/src/wood.kt rename to game/plugin/skills/woodcutting/src/Tree.kt diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/Woodcutting.plugin.kts similarity index 99% rename from game/plugin/skills/woodcutting/src/woodcutting.plugin.kts rename to game/plugin/skills/woodcutting/src/Woodcutting.plugin.kts index 2966914ed..f0d962395 100644 --- a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts +++ b/game/plugin/skills/woodcutting/src/Woodcutting.plugin.kts @@ -1,4 +1,5 @@ +import java.util.concurrent.TimeUnit import org.apollo.game.GameConstants import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction @@ -10,7 +11,6 @@ import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.plugin.api.* import org.apollo.game.plugin.skills.woodcutting.Axe import org.apollo.game.plugin.skills.woodcutting.Tree -import java.util.concurrent.TimeUnit // TODO Accurate chopping rates, e.g. https://twitter.com/JagexKieren/status/713403124464107520 @@ -33,7 +33,6 @@ class WoodcuttingTarget(private val objectId: Int, val position: Position, val t * Returns whether or not the tree was cut down. */ fun isCutDown(): Boolean = rand(100) <= tree.chance * 100 - } class WoodcuttingAction( @@ -102,5 +101,4 @@ class WoodcuttingAction( } } } - } \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/test/AxeTests.kt b/game/plugin/skills/woodcutting/test/AxeTests.kt index cbbedb551..4f271f489 100644 --- a/game/plugin/skills/woodcutting/test/AxeTests.kt +++ b/game/plugin/skills/woodcutting/test/AxeTests.kt @@ -11,7 +11,7 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource @ExtendWith(ApolloTestingExtension::class) -class AxeTests { +class AxeTests { @TestMock lateinit var player: Player @@ -70,5 +70,4 @@ class AxeTests { ItemDefinition(it.id).apply { isStackable = false } } } - } \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/test/TestData.kt b/game/plugin/skills/woodcutting/test/TestData.kt index 073b81ef1..80c82e76f 100644 --- a/game/plugin/skills/woodcutting/test/TestData.kt +++ b/game/plugin/skills/woodcutting/test/TestData.kt @@ -1,8 +1,8 @@ +import java.util.stream.Stream import org.apollo.game.plugin.skills.woodcutting.Tree import org.junit.jupiter.api.extension.ExtensionContext import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider -import java.util.stream.Stream data class WoodcuttingTestData(val treeId: Int, val stumpId: Int, val tree: Tree) diff --git a/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt b/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt index c1a6e1ad3..f98ab24f4 100644 --- a/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt +++ b/game/plugin/skills/woodcutting/test/WoodcuttingTests.kt @@ -2,6 +2,7 @@ import io.mockk.every import io.mockk.mockk import io.mockk.verify +import java.util.Random import org.apollo.cache.def.ItemDefinition import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill @@ -20,7 +21,6 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ArgumentsSource -import java.util.Random @ExtendWith(ApolloTestingExtension::class) class WoodcuttingTests { diff --git a/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt index 5c49c794e..28ca3338f 100644 --- a/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt +++ b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt @@ -1,6 +1,5 @@ package org.apollo.game.action -import kotlinx.coroutines.experimental.suspendCancellableCoroutine import java.util.concurrent.CancellationException import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference @@ -11,6 +10,7 @@ import kotlin.coroutines.experimental.RestrictsSuspension import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED import kotlin.coroutines.experimental.intrinsics.createCoroutineUnchecked import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn +import kotlinx.coroutines.experimental.suspendCancellableCoroutine typealias ActionPredicate = () -> Boolean typealias ActionBlock = suspend ActionCoroutine.() -> Unit diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt index 55a02aefd..2f0e20d0c 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncActionTrait.kt @@ -25,5 +25,5 @@ interface AsyncActionTrait { /** * Create a new `ActionBlock` to execute. */ - fun action() : ActionBlock + fun action(): ActionBlock } \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt index 761714d00..ce550eb34 100644 --- a/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt +++ b/game/src/main/kotlin/org/apollo/game/action/AsyncDistancedAction.kt @@ -19,4 +19,3 @@ abstract class AsyncDistancedAction : DistancedAction, AsyncActionTr } } } - diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index fca5698d9..a1a0ba4f3 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -1,5 +1,8 @@ package org.apollo.game.plugin.kotlin +import kotlin.reflect.KClass +import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.annotations.KotlinScriptFileExtension import org.apollo.game.command.Command import org.apollo.game.command.CommandListener import org.apollo.game.message.handler.MessageHandler @@ -12,9 +15,6 @@ import org.apollo.game.model.event.EventListener import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message -import kotlin.reflect.KClass -import kotlin.script.experimental.annotations.KotlinScript -import kotlin.script.experimental.annotations.KotlinScriptFileExtension @KotlinScript("Apollo Plugin Script") @KotlinScriptFileExtension("plugin.kts") @@ -63,7 +63,6 @@ abstract class KotlinPluginScript(private var world: World, val context: PluginC fun doStop(world: World) { this.stopListener.invoke(world) } - } /** @@ -86,13 +85,11 @@ interface KotlinPlayerHandlerProxyTrait { this.register() } - fun handleProxy(player: Player, subject: S) { if (subject.predicate()) { subject.callback(player) } } - } /** @@ -106,7 +103,6 @@ class KotlinPlayerEventHandler(val world: World, val type: KCla override fun handle(event: T) = handleProxy(event.player, event) override fun register() = world.listenFor(type.java, this) - } /** @@ -134,7 +130,6 @@ class KotlinEventHandler(val world: World, val type: KClass) : Eve } fun register() = world.listenFor(type.java, this) - } /** @@ -148,7 +143,6 @@ class KotlinMessageHandler(val world: World, val context: PluginCon override fun handle(player: Player, message: T) = handleProxy(player, message) override fun register() = context.addMessageHandler(type.java, this) - } /** @@ -162,5 +156,4 @@ class KotlinCommandHandler(val world: World, val command: String, privileges: Pr override fun execute(player: Player, command: Command) = handleProxy(player, command) override fun register() = world.commandDispatcher.register(command, this) - } diff --git a/gradle/config/detekt.yml b/gradle/config/detekt.yml index 774cafc7b..493cd78ba 100644 --- a/gradle/config/detekt.yml +++ b/gradle/config/detekt.yml @@ -257,7 +257,7 @@ formatting: active: true autoCorrect: true NoWildcardImports: - active: true + active: false autoCorrect: true ParameterListWrapping: active: true @@ -304,10 +304,11 @@ naming: minimumFunctionNameLength: 3 FunctionNaming: active: true - functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' + functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)|(on_[a-zA-Z_$0-9]*)$' excludeClassPattern: '$^' MatchingDeclarationName: active: true + autoCorrect: true MemberNameEqualsClassName: active: false ignoreOverriddenFunction: true @@ -317,7 +318,7 @@ naming: constantPattern: '[A-Za-z][_A-Za-z0-9]*' PackageNaming: active: true - packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$' + packagePattern: '^[a-z]+(\.[a-z][a-zA-Z0-9]*)*$' TopLevelPropertyNaming: active: false constantPattern: '[A-Z][_A-Z0-9]*' @@ -470,5 +471,5 @@ style: VarCouldBeVal: active: false WildcardImport: - active: true + active: false excludeImports: 'java.util.*,kotlinx.android.synthetic.*' From a0c78ced90eebf90ed9b0a4e51cece6ddf10932e Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 4 Sep 2018 05:53:06 +0100 Subject: [PATCH 183/209] Add library containing detekt rules for apollo plugins --- game/plugin-detekt-rules/build.gradle | 15 +++++++++ .../detekt/ApolloPluginRuleSetProvider.kt | 16 ++++++++++ .../detekt/rules/DeclarationInScriptRule.kt | 31 +++++++++++++++++++ ...tlab.arturbosch.detekt.api.RuleSetProvider | 1 + .../rules/DeclarationInScriptRuleTest.kt | 19 ++++++++++++ .../src/test/resources/testData/example.kts | 3 ++ gradle/code-quality.gradle | 1 + gradle/config/detekt.yml | 4 +++ settings.gradle | 1 + 9 files changed, 91 insertions(+) create mode 100644 game/plugin-detekt-rules/build.gradle create mode 100644 game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/ApolloPluginRuleSetProvider.kt create mode 100644 game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRule.kt create mode 100644 game/plugin-detekt-rules/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider create mode 100644 game/plugin-detekt-rules/src/test/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRuleTest.kt create mode 100644 game/plugin-detekt-rules/src/test/resources/testData/example.kts diff --git a/game/plugin-detekt-rules/build.gradle b/game/plugin-detekt-rules/build.gradle new file mode 100644 index 000000000..a57e036c7 --- /dev/null +++ b/game/plugin-detekt-rules/build.gradle @@ -0,0 +1,15 @@ +apply plugin: 'java-library' +apply plugin: 'org.jetbrains.kotlin.jvm' +apply from: "$rootDir/gradle/kotlin.gradle" + +dependencies { + api group: 'io.gitlab.arturbosch.detekt', name: 'detekt-api', version: detektVersion + + test.useJUnitPlatform() + testImplementation("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}") + testImplementation("org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}") + testImplementation("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}") + testImplementation("org.junit.platform:junit-platform-launcher:${junitPlatformVersion}") + + testImplementation group: 'io.gitlab.arturbosch.detekt', name: 'detekt-test', version: detektVersion +} diff --git a/game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/ApolloPluginRuleSetProvider.kt b/game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/ApolloPluginRuleSetProvider.kt new file mode 100644 index 000000000..c084d54b9 --- /dev/null +++ b/game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/ApolloPluginRuleSetProvider.kt @@ -0,0 +1,16 @@ +package org.apollo.game.plugin.detekt + +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.RuleSet +import io.gitlab.arturbosch.detekt.api.RuleSetProvider +import org.apollo.game.plugin.detekt.rules.DeclarationInScriptRule + +class ApolloPluginRuleSetProvider : RuleSetProvider { + override val ruleSetId = "apollo-plugin" + + override fun instance(config: Config): RuleSet { + return RuleSet(ruleSetId, listOf( + DeclarationInScriptRule() + )) + } +} \ No newline at end of file diff --git a/game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRule.kt b/game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRule.kt new file mode 100644 index 000000000..055b5fd1d --- /dev/null +++ b/game/plugin-detekt-rules/src/main/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRule.kt @@ -0,0 +1,31 @@ +package org.apollo.game.plugin.detekt.rules + +import io.gitlab.arturbosch.detekt.api.* +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtObjectDeclaration + +class DeclarationInScriptRule : Rule() { + override val issue = Issue( + "DeclarationInScript", + Severity.CodeSmell, + "This rule reports a plugin file containing class or object declarations.", + Debt.FIVE_MINS + ) + + override fun visit(root: KtFile) { + super.visit(root) + + val script = root.script ?: return + val declarations = script.declarations.filter { it is KtClass || it is KtObjectDeclaration } + + declarations + .forEach { + report(CodeSmell( + issue, + Entity.from(it), + message = "Declaration of ${it.name} should live in a top-level file, not a script" + )) + } + } +} \ No newline at end of file diff --git a/game/plugin-detekt-rules/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider b/game/plugin-detekt-rules/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider new file mode 100644 index 000000000..3eb44c259 --- /dev/null +++ b/game/plugin-detekt-rules/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider @@ -0,0 +1 @@ +org.apollo.game.plugin.detekt.ApolloPluginRuleSetProvider \ No newline at end of file diff --git a/game/plugin-detekt-rules/src/test/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRuleTest.kt b/game/plugin-detekt-rules/src/test/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRuleTest.kt new file mode 100644 index 000000000..f6ca6daeb --- /dev/null +++ b/game/plugin-detekt-rules/src/test/kotlin/org/apollo/game/plugin/detekt/rules/DeclarationInScriptRuleTest.kt @@ -0,0 +1,19 @@ +package org.apollo.game.plugin.detekt.rules + +import io.gitlab.arturbosch.detekt.test.lint +import java.nio.file.Paths +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test + +internal class DeclarationInScriptRuleTest { + val rule = DeclarationInScriptRule() + + @Test + fun `Finds warning in script file`() { + val srcPath = Paths.get(this.javaClass.getResource("/testData/example.kts").toURI()) + val findings = rule.lint(srcPath) + + assertEquals(1, findings.size) + assertEquals("Declaration of ExampleDeclaration should live in a top-level file, not a script", findings[0].message) + } +} \ No newline at end of file diff --git a/game/plugin-detekt-rules/src/test/resources/testData/example.kts b/game/plugin-detekt-rules/src/test/resources/testData/example.kts new file mode 100644 index 000000000..0fb1729b7 --- /dev/null +++ b/game/plugin-detekt-rules/src/test/resources/testData/example.kts @@ -0,0 +1,3 @@ +class ExampleDeclaration { + +} \ No newline at end of file diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle index 7a269657a..2dfdb9113 100644 --- a/gradle/code-quality.gradle +++ b/gradle/code-quality.gradle @@ -15,6 +15,7 @@ detekt { dependencies { detekt group: 'io.gitlab.arturbosch.detekt', name: 'detekt-formatting', version: detektVersion + detekt project(':game:plugin-detekt-rules') } sonarqube { diff --git a/gradle/config/detekt.yml b/gradle/config/detekt.yml index 493cd78ba..5ff588626 100644 --- a/gradle/config/detekt.yml +++ b/gradle/config/detekt.yml @@ -473,3 +473,7 @@ style: WildcardImport: active: false excludeImports: 'java.util.*,kotlinx.android.synthetic.*' + +apollo-plugin: + DeclarationInScript: + active: true \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 6cd4ff993..b9ba28b0f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,6 +5,7 @@ rootProject.name = 'org.apollo' include ':cache' include ':game' include ':game:plugin' +include ':game:plugin-detekt-rules' include ':game:plugin-testing' include ':net' include ':util' From 3326dba3cd5c8fb8befbfa6e340c54426f818eeb Mon Sep 17 00:00:00 2001 From: atomicint Date: Sun, 11 Nov 2018 10:48:41 -0500 Subject: [PATCH 184/209] Allow Netty to automatically maintain our internal usages of ByteBuf --- .../GroupedRegionUpdateMessageEncoder.java | 2 +- .../r317/SpamPacketMessageDecoder.java | 2 +- .../GroupedRegionUpdateMessageEncoder.java | 2 +- .../r377/SpamPacketMessageDecoder.java | 2 +- .../apollo/game/session/ApolloHandler.java | 45 +++++++++---------- .../org/apollo/net/codec/game/GamePacket.java | 19 ++------ .../net/codec/game/GamePacketEncoder.java | 2 +- .../net/codec/game/GamePacketReader.java | 2 +- 8 files changed, 29 insertions(+), 47 deletions(-) diff --git a/game/src/main/java/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java b/game/src/main/java/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java index 80fa508fd..cd6703b77 100644 --- a/game/src/main/java/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java +++ b/game/src/main/java/org/apollo/game/release/r317/GroupedRegionUpdateMessageEncoder.java @@ -47,7 +47,7 @@ public GamePacket encode(GroupedRegionUpdateMessage message) { GamePacket packet = encoder.encode(update); builder.put(DataType.BYTE, packet.getOpcode()); - builder.putBytes(packet.getPayload()); + builder.putBytes(packet.content()); } return builder.toGamePacket(); diff --git a/game/src/main/java/org/apollo/game/release/r317/SpamPacketMessageDecoder.java b/game/src/main/java/org/apollo/game/release/r317/SpamPacketMessageDecoder.java index 9b908c5ed..4a1a85834 100644 --- a/game/src/main/java/org/apollo/game/release/r317/SpamPacketMessageDecoder.java +++ b/game/src/main/java/org/apollo/game/release/r317/SpamPacketMessageDecoder.java @@ -13,7 +13,7 @@ public final class SpamPacketMessageDecoder extends MessageDecoder attribute = channel.attr(ApolloHandler.SESSION_KEY); - Session session = attribute.get(); + Channel channel = ctx.channel(); + Attribute attribute = channel.attr(ApolloHandler.SESSION_KEY); + Session session = attribute.get(); - if (message instanceof HttpRequest || message instanceof JagGrabRequest) { - session = new UpdateSession(channel, serverContext); - } + if (message instanceof HttpRequest || message instanceof JagGrabRequest) { + session = new UpdateSession(channel, serverContext); + } - if (session != null) { - session.messageReceived(message); - return; - } + if (session != null) { + session.messageReceived(message); + return; + } - // TODO: Perhaps let HandshakeMessage implement Message to remove this explicit check - if (message instanceof HandshakeMessage) { - HandshakeMessage handshakeMessage = (HandshakeMessage) message; + // TODO: Perhaps let HandshakeMessage implement Message to remove this explicit check + if (message instanceof HandshakeMessage) { + HandshakeMessage handshakeMessage = (HandshakeMessage) message; - switch (handshakeMessage.getServiceId()) { - case HandshakeConstants.SERVICE_GAME: - attribute.set(new LoginSession(channel, serverContext)); - break; + switch (handshakeMessage.getServiceId()) { + case HandshakeConstants.SERVICE_GAME: + attribute.set(new LoginSession(channel, serverContext)); + break; - case HandshakeConstants.SERVICE_UPDATE: - attribute.set(new UpdateSession(channel, serverContext)); - break; - } + case HandshakeConstants.SERVICE_UPDATE: + attribute.set(new UpdateSession(channel, serverContext)); + break; } - - } finally { - ReferenceCountUtil.release(message); } } diff --git a/net/src/main/java/org/apollo/net/codec/game/GamePacket.java b/net/src/main/java/org/apollo/net/codec/game/GamePacket.java index 0f51e9cbf..5c082f82e 100644 --- a/net/src/main/java/org/apollo/net/codec/game/GamePacket.java +++ b/net/src/main/java/org/apollo/net/codec/game/GamePacket.java @@ -2,6 +2,7 @@ import io.netty.buffer.ByteBuf; +import io.netty.buffer.DefaultByteBufHolder; import org.apollo.net.meta.PacketType; /** @@ -9,7 +10,7 @@ * * @author Graham */ -public final class GamePacket { +public final class GamePacket extends DefaultByteBufHolder { /** * The length. @@ -21,11 +22,6 @@ public final class GamePacket { */ private final int opcode; - /** - * The payload. - */ - private final ByteBuf payload; - /** * The packet type. */ @@ -39,10 +35,10 @@ public final class GamePacket { * @param payload The payload. */ public GamePacket(int opcode, PacketType type, ByteBuf payload) { + super(payload); this.opcode = opcode; this.type = type; length = payload.readableBytes(); - this.payload = payload; } /** @@ -63,15 +59,6 @@ public int getOpcode() { return opcode; } - /** - * Gets the payload. - * - * @return The payload. - */ - public ByteBuf getPayload() { - return payload; - } - /** * Gets the packet type. * diff --git a/net/src/main/java/org/apollo/net/codec/game/GamePacketEncoder.java b/net/src/main/java/org/apollo/net/codec/game/GamePacketEncoder.java index 0a9bfa1e6..a5fda4faf 100644 --- a/net/src/main/java/org/apollo/net/codec/game/GamePacketEncoder.java +++ b/net/src/main/java/org/apollo/net/codec/game/GamePacketEncoder.java @@ -44,7 +44,7 @@ protected void encode(ChannelHandlerContext ctx, GamePacket packet, ByteBuf out) } else if (type == PacketType.VARIABLE_SHORT) { out.writeShort(payloadLength); } - out.writeBytes(packet.getPayload()); + out.writeBytes(packet.content()); } } \ No newline at end of file diff --git a/net/src/main/java/org/apollo/net/codec/game/GamePacketReader.java b/net/src/main/java/org/apollo/net/codec/game/GamePacketReader.java index 00e4ca9e1..0f8bae99b 100644 --- a/net/src/main/java/org/apollo/net/codec/game/GamePacketReader.java +++ b/net/src/main/java/org/apollo/net/codec/game/GamePacketReader.java @@ -34,7 +34,7 @@ public final class GamePacketReader { * @param packet The packet. */ public GamePacketReader(GamePacket packet) { - buffer = packet.getPayload(); + buffer = packet.content(); } /** From 739c33186068de1d9a6a1d9a1933d4536e102178 Mon Sep 17 00:00:00 2001 From: KeepBotting Date: Tue, 26 Mar 2019 14:05:40 -0400 Subject: [PATCH 185/209] Housekeeping --- .gitignore | 4 ++-- game/build.gradle | 4 ++-- {data => game/data}/equipment-317.dat | Bin {data => game/data}/equipment-377.dat | Bin {data => game/data}/fs/.gitignore | 0 {data => game/data}/login.xml | 0 {data => game/data}/messages.xml | 0 {data => game/data}/net.xml | 0 {data => game/data}/plugins/.rubocop.yml | 0 {data => game/data}/plugins/areas/actions.rb | 0 {data => game/data}/plugins/areas/areas.rb | 0 {data => game/data}/plugins/areas/plugin.xml | 0 {data => game/data}/plugins/bank/bank.rb | 0 {data => game/data}/plugins/bank/plugin.xml | 0 {data => game/data}/plugins/bootstrap.rb | 0 {data => game/data}/plugins/chat/privacy/plugin.xml | 0 {data => game/data}/plugins/chat/privacy/privacy.rb | 0 .../data}/plugins/chat/private-messaging/friend.rb | 0 .../data}/plugins/chat/private-messaging/ignore.rb | 0 .../plugins/chat/private-messaging/messaging.rb | 0 .../data}/plugins/chat/private-messaging/plugin.xml | 0 {data => game/data}/plugins/cmd/animate/animate.rb | 0 {data => game/data}/plugins/cmd/animate/plugin.xml | 0 {data => game/data}/plugins/cmd/bank/bank.rb | 0 {data => game/data}/plugins/cmd/bank/plugin.xml | 0 {data => game/data}/plugins/cmd/item/item.rb | 0 {data => game/data}/plugins/cmd/item/plugin.xml | 0 {data => game/data}/plugins/cmd/lookup/lookup.rb | 0 {data => game/data}/plugins/cmd/lookup/plugin.xml | 0 .../data}/plugins/cmd/messaging/broadcast.rb | 0 .../data}/plugins/cmd/messaging/plugin.xml | 0 {data => game/data}/plugins/cmd/npc/plugin.xml | 0 {data => game/data}/plugins/cmd/npc/spawn.rb | 0 .../data}/plugins/cmd/punishment/plugin.xml | 0 .../data}/plugins/cmd/punishment/punish.rb | 0 {data => game/data}/plugins/cmd/skill/plugin.xml | 0 {data => game/data}/plugins/cmd/skill/skill.rb | 0 {data => game/data}/plugins/cmd/teleport/plugin.xml | 0 .../data}/plugins/cmd/teleport/teleport.rb | 0 {data => game/data}/plugins/combat/plugin.xml | 0 {data => game/data}/plugins/combat/wilderness.rb | 0 .../data}/plugins/consumables/consumable.rb | 0 {data => game/data}/plugins/consumables/drink.rb | 0 {data => game/data}/plugins/consumables/food.rb | 0 {data => game/data}/plugins/consumables/plugin.xml | 0 {data => game/data}/plugins/consumables/potions.rb | 0 {data => game/data}/plugins/dialogue/dialogue.rb | 0 {data => game/data}/plugins/dialogue/emotes.rb | 0 {data => game/data}/plugins/dialogue/plugin.xml | 0 {data => game/data}/plugins/dummy/dummy.rb | 0 {data => game/data}/plugins/dummy/plugin.xml | 0 {data => game/data}/plugins/emote-tab/emote_tab.rb | 0 {data => game/data}/plugins/emote-tab/plugin.xml | 0 .../data}/plugins/entity/attributes/attributes.rb | 0 .../data}/plugins/entity/attributes/plugin.xml | 0 .../data}/plugins/entity/mob/extension/extension.rb | 0 .../data}/plugins/entity/mob/extension/plugin.xml | 0 .../data}/plugins/entity/mob/following/following.rb | 0 .../data}/plugins/entity/mob/following/plugin.xml | 0 .../data}/plugins/entity/mob/walk-to/plugin.xml | 0 .../data}/plugins/entity/mob/walk-to/walk_to.rb | 0 .../data}/plugins/entity/spawning/npc-spawn.rb | 0 .../data}/plugins/entity/spawning/plugin.xml | 0 .../data}/plugins/location/al-kharid/npcs.rb | 0 .../data}/plugins/location/al-kharid/plugin.xml | 0 .../data}/plugins/location/edgeville/npcs.rb | 0 .../data}/plugins/location/edgeville/plugin.xml | 0 .../data}/plugins/location/falador/npcs.rb | 0 .../data}/plugins/location/falador/plugin.xml | 0 .../data}/plugins/location/lumbridge/npcs.rb | 0 .../data}/plugins/location/lumbridge/plugin.xml | 0 .../data}/plugins/location/tutorial-island/guide.rb | 0 .../location/tutorial-island/instructions.rb | 0 .../data}/plugins/location/tutorial-island/npcs.rb | 0 .../plugins/location/tutorial-island/plugin.xml | 0 .../plugins/location/tutorial-island/stages.rb | 0 .../plugins/location/tutorial-island/survival.rb | 0 .../data}/plugins/location/tutorial-island/utils.rb | 0 .../data}/plugins/location/varrock/npcs.rb | 0 .../data}/plugins/location/varrock/plugin.xml | 0 .../data}/plugins/location/varrock/shops.rb | 0 {data => game/data}/plugins/logout/logout.rb | 0 {data => game/data}/plugins/logout/plugin.xml | 0 .../data}/plugins/navigation/door/constants.rb | 0 {data => game/data}/plugins/navigation/door/door.rb | 0 .../data}/plugins/navigation/door/plugin.xml | 0 {data => game/data}/plugins/navigation/door/util.rb | 0 {data => game/data}/plugins/player-action/action.rb | 0 {data => game/data}/plugins/player-action/login.rb | 0 .../data}/plugins/player-action/plugin.xml | 0 {data => game/data}/plugins/quest/plugin.xml | 0 {data => game/data}/plugins/quest/repository.rb | 0 {data => game/data}/plugins/run/plugin.xml | 0 {data => game/data}/plugins/run/run.rb | 0 {data => game/data}/plugins/shops/currency.rb | 0 {data => game/data}/plugins/shops/plugin.xml | 0 {data => game/data}/plugins/shops/shop.rb | 0 {data => game/data}/plugins/shops/shop_item.rb | 0 {data => game/data}/plugins/shops/shops.rb | 0 {data => game/data}/plugins/skill/fishing/fish.rb | 0 .../data}/plugins/skill/fishing/fishing.rb | 0 .../data}/plugins/skill/fishing/plugin.xml | 0 {data => game/data}/plugins/skill/fishing/spot.rb | 0 {data => game/data}/plugins/skill/fishing/tool.rb | 0 {data => game/data}/plugins/skill/herblore/herb.rb | 0 .../data}/plugins/skill/herblore/herblore.rb | 0 .../data}/plugins/skill/herblore/ingredient.rb | 0 .../data}/plugins/skill/herblore/plugin.xml | 0 .../data}/plugins/skill/herblore/potion.rb | 0 {data => game/data}/plugins/skill/magic/alchemy.rb | 0 {data => game/data}/plugins/skill/magic/convert.rb | 0 {data => game/data}/plugins/skill/magic/element.rb | 0 {data => game/data}/plugins/skill/magic/enchant.rb | 0 {data => game/data}/plugins/skill/magic/magic.rb | 0 {data => game/data}/plugins/skill/magic/plugin.xml | 0 {data => game/data}/plugins/skill/magic/teleport.rb | 0 {data => game/data}/plugins/skill/mining/gem.rb | 0 {data => game/data}/plugins/skill/mining/mining.rb | 0 {data => game/data}/plugins/skill/mining/ore.rb | 0 {data => game/data}/plugins/skill/mining/pickaxe.rb | 0 {data => game/data}/plugins/skill/mining/plugin.xml | 0 {data => game/data}/plugins/skill/mining/respawn.rb | 0 {data => game/data}/plugins/skill/prayer/bury.rb | 0 {data => game/data}/plugins/skill/prayer/plugin.xml | 0 {data => game/data}/plugins/skill/prayer/prayers.rb | 0 .../data}/plugins/skill/runecraft/altar.rb | 0 .../data}/plugins/skill/runecraft/plugin.xml | 0 {data => game/data}/plugins/skill/runecraft/rune.rb | 0 .../data}/plugins/skill/runecraft/runecraft.rb | 0 .../data}/plugins/skill/runecraft/talisman.rb | 0 .../data}/plugins/skill/runecraft/tiara.rb | 0 {data => game/data}/plugins/util/command.rb | 0 {data => game/data}/plugins/util/name_lookup.rb | 0 {data => game/data}/plugins/util/plugin.xml | 0 {data => game/data}/synchronizer.xml | 0 135 files changed, 4 insertions(+), 4 deletions(-) rename {data => game/data}/equipment-317.dat (100%) rename {data => game/data}/equipment-377.dat (100%) rename {data => game/data}/fs/.gitignore (100%) rename {data => game/data}/login.xml (100%) rename {data => game/data}/messages.xml (100%) rename {data => game/data}/net.xml (100%) rename {data => game/data}/plugins/.rubocop.yml (100%) rename {data => game/data}/plugins/areas/actions.rb (100%) rename {data => game/data}/plugins/areas/areas.rb (100%) rename {data => game/data}/plugins/areas/plugin.xml (100%) rename {data => game/data}/plugins/bank/bank.rb (100%) rename {data => game/data}/plugins/bank/plugin.xml (100%) rename {data => game/data}/plugins/bootstrap.rb (100%) rename {data => game/data}/plugins/chat/privacy/plugin.xml (100%) rename {data => game/data}/plugins/chat/privacy/privacy.rb (100%) rename {data => game/data}/plugins/chat/private-messaging/friend.rb (100%) rename {data => game/data}/plugins/chat/private-messaging/ignore.rb (100%) rename {data => game/data}/plugins/chat/private-messaging/messaging.rb (100%) rename {data => game/data}/plugins/chat/private-messaging/plugin.xml (100%) rename {data => game/data}/plugins/cmd/animate/animate.rb (100%) rename {data => game/data}/plugins/cmd/animate/plugin.xml (100%) rename {data => game/data}/plugins/cmd/bank/bank.rb (100%) rename {data => game/data}/plugins/cmd/bank/plugin.xml (100%) rename {data => game/data}/plugins/cmd/item/item.rb (100%) rename {data => game/data}/plugins/cmd/item/plugin.xml (100%) rename {data => game/data}/plugins/cmd/lookup/lookup.rb (100%) rename {data => game/data}/plugins/cmd/lookup/plugin.xml (100%) rename {data => game/data}/plugins/cmd/messaging/broadcast.rb (100%) rename {data => game/data}/plugins/cmd/messaging/plugin.xml (100%) rename {data => game/data}/plugins/cmd/npc/plugin.xml (100%) rename {data => game/data}/plugins/cmd/npc/spawn.rb (100%) rename {data => game/data}/plugins/cmd/punishment/plugin.xml (100%) rename {data => game/data}/plugins/cmd/punishment/punish.rb (100%) rename {data => game/data}/plugins/cmd/skill/plugin.xml (100%) rename {data => game/data}/plugins/cmd/skill/skill.rb (100%) rename {data => game/data}/plugins/cmd/teleport/plugin.xml (100%) rename {data => game/data}/plugins/cmd/teleport/teleport.rb (100%) rename {data => game/data}/plugins/combat/plugin.xml (100%) rename {data => game/data}/plugins/combat/wilderness.rb (100%) rename {data => game/data}/plugins/consumables/consumable.rb (100%) rename {data => game/data}/plugins/consumables/drink.rb (100%) rename {data => game/data}/plugins/consumables/food.rb (100%) rename {data => game/data}/plugins/consumables/plugin.xml (100%) rename {data => game/data}/plugins/consumables/potions.rb (100%) rename {data => game/data}/plugins/dialogue/dialogue.rb (100%) rename {data => game/data}/plugins/dialogue/emotes.rb (100%) rename {data => game/data}/plugins/dialogue/plugin.xml (100%) rename {data => game/data}/plugins/dummy/dummy.rb (100%) rename {data => game/data}/plugins/dummy/plugin.xml (100%) rename {data => game/data}/plugins/emote-tab/emote_tab.rb (100%) rename {data => game/data}/plugins/emote-tab/plugin.xml (100%) rename {data => game/data}/plugins/entity/attributes/attributes.rb (100%) rename {data => game/data}/plugins/entity/attributes/plugin.xml (100%) rename {data => game/data}/plugins/entity/mob/extension/extension.rb (100%) rename {data => game/data}/plugins/entity/mob/extension/plugin.xml (100%) rename {data => game/data}/plugins/entity/mob/following/following.rb (100%) rename {data => game/data}/plugins/entity/mob/following/plugin.xml (100%) rename {data => game/data}/plugins/entity/mob/walk-to/plugin.xml (100%) rename {data => game/data}/plugins/entity/mob/walk-to/walk_to.rb (100%) rename {data => game/data}/plugins/entity/spawning/npc-spawn.rb (100%) rename {data => game/data}/plugins/entity/spawning/plugin.xml (100%) rename {data => game/data}/plugins/location/al-kharid/npcs.rb (100%) rename {data => game/data}/plugins/location/al-kharid/plugin.xml (100%) rename {data => game/data}/plugins/location/edgeville/npcs.rb (100%) rename {data => game/data}/plugins/location/edgeville/plugin.xml (100%) rename {data => game/data}/plugins/location/falador/npcs.rb (100%) rename {data => game/data}/plugins/location/falador/plugin.xml (100%) rename {data => game/data}/plugins/location/lumbridge/npcs.rb (100%) rename {data => game/data}/plugins/location/lumbridge/plugin.xml (100%) rename {data => game/data}/plugins/location/tutorial-island/guide.rb (100%) rename {data => game/data}/plugins/location/tutorial-island/instructions.rb (100%) rename {data => game/data}/plugins/location/tutorial-island/npcs.rb (100%) rename {data => game/data}/plugins/location/tutorial-island/plugin.xml (100%) rename {data => game/data}/plugins/location/tutorial-island/stages.rb (100%) rename {data => game/data}/plugins/location/tutorial-island/survival.rb (100%) rename {data => game/data}/plugins/location/tutorial-island/utils.rb (100%) rename {data => game/data}/plugins/location/varrock/npcs.rb (100%) rename {data => game/data}/plugins/location/varrock/plugin.xml (100%) rename {data => game/data}/plugins/location/varrock/shops.rb (100%) rename {data => game/data}/plugins/logout/logout.rb (100%) rename {data => game/data}/plugins/logout/plugin.xml (100%) rename {data => game/data}/plugins/navigation/door/constants.rb (100%) rename {data => game/data}/plugins/navigation/door/door.rb (100%) rename {data => game/data}/plugins/navigation/door/plugin.xml (100%) rename {data => game/data}/plugins/navigation/door/util.rb (100%) rename {data => game/data}/plugins/player-action/action.rb (100%) rename {data => game/data}/plugins/player-action/login.rb (100%) rename {data => game/data}/plugins/player-action/plugin.xml (100%) rename {data => game/data}/plugins/quest/plugin.xml (100%) rename {data => game/data}/plugins/quest/repository.rb (100%) rename {data => game/data}/plugins/run/plugin.xml (100%) rename {data => game/data}/plugins/run/run.rb (100%) rename {data => game/data}/plugins/shops/currency.rb (100%) rename {data => game/data}/plugins/shops/plugin.xml (100%) rename {data => game/data}/plugins/shops/shop.rb (100%) rename {data => game/data}/plugins/shops/shop_item.rb (100%) rename {data => game/data}/plugins/shops/shops.rb (100%) rename {data => game/data}/plugins/skill/fishing/fish.rb (100%) rename {data => game/data}/plugins/skill/fishing/fishing.rb (100%) rename {data => game/data}/plugins/skill/fishing/plugin.xml (100%) rename {data => game/data}/plugins/skill/fishing/spot.rb (100%) rename {data => game/data}/plugins/skill/fishing/tool.rb (100%) rename {data => game/data}/plugins/skill/herblore/herb.rb (100%) rename {data => game/data}/plugins/skill/herblore/herblore.rb (100%) rename {data => game/data}/plugins/skill/herblore/ingredient.rb (100%) rename {data => game/data}/plugins/skill/herblore/plugin.xml (100%) rename {data => game/data}/plugins/skill/herblore/potion.rb (100%) rename {data => game/data}/plugins/skill/magic/alchemy.rb (100%) rename {data => game/data}/plugins/skill/magic/convert.rb (100%) rename {data => game/data}/plugins/skill/magic/element.rb (100%) rename {data => game/data}/plugins/skill/magic/enchant.rb (100%) rename {data => game/data}/plugins/skill/magic/magic.rb (100%) rename {data => game/data}/plugins/skill/magic/plugin.xml (100%) rename {data => game/data}/plugins/skill/magic/teleport.rb (100%) rename {data => game/data}/plugins/skill/mining/gem.rb (100%) rename {data => game/data}/plugins/skill/mining/mining.rb (100%) rename {data => game/data}/plugins/skill/mining/ore.rb (100%) rename {data => game/data}/plugins/skill/mining/pickaxe.rb (100%) rename {data => game/data}/plugins/skill/mining/plugin.xml (100%) rename {data => game/data}/plugins/skill/mining/respawn.rb (100%) rename {data => game/data}/plugins/skill/prayer/bury.rb (100%) rename {data => game/data}/plugins/skill/prayer/plugin.xml (100%) rename {data => game/data}/plugins/skill/prayer/prayers.rb (100%) rename {data => game/data}/plugins/skill/runecraft/altar.rb (100%) rename {data => game/data}/plugins/skill/runecraft/plugin.xml (100%) rename {data => game/data}/plugins/skill/runecraft/rune.rb (100%) rename {data => game/data}/plugins/skill/runecraft/runecraft.rb (100%) rename {data => game/data}/plugins/skill/runecraft/talisman.rb (100%) rename {data => game/data}/plugins/skill/runecraft/tiara.rb (100%) rename {data => game/data}/plugins/util/command.rb (100%) rename {data => game/data}/plugins/util/name_lookup.rb (100%) rename {data => game/data}/plugins/util/plugin.xml (100%) rename {data => game/data}/synchronizer.xml (100%) diff --git a/.gitignore b/.gitignore index c852a9f9b..4f11942ef 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,8 @@ *.class *.iml -/data/rsa.pem -/data/savedGames +/game/data/rsa.pem +/game/data/savedGames /lib/ */target/ */build/ diff --git a/game/build.gradle b/game/build.gradle index a5eb72e8e..491eceb40 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -31,7 +31,7 @@ dependencies { testImplementation group: 'org.assertj', name: 'assertj-core', version: assertjVersion project(":game:plugin").subprojects { pluginProject -> - plugins.withId('apollo-plugin') { + if (pluginProject.buildFile.exists()) { runtimeClasspath pluginProject } } @@ -41,4 +41,4 @@ applicationDistribution.from("$rootDir/data") { include '*.dat' include '*.xml' into "data/" -} \ No newline at end of file +} diff --git a/data/equipment-317.dat b/game/data/equipment-317.dat similarity index 100% rename from data/equipment-317.dat rename to game/data/equipment-317.dat diff --git a/data/equipment-377.dat b/game/data/equipment-377.dat similarity index 100% rename from data/equipment-377.dat rename to game/data/equipment-377.dat diff --git a/data/fs/.gitignore b/game/data/fs/.gitignore similarity index 100% rename from data/fs/.gitignore rename to game/data/fs/.gitignore diff --git a/data/login.xml b/game/data/login.xml similarity index 100% rename from data/login.xml rename to game/data/login.xml diff --git a/data/messages.xml b/game/data/messages.xml similarity index 100% rename from data/messages.xml rename to game/data/messages.xml diff --git a/data/net.xml b/game/data/net.xml similarity index 100% rename from data/net.xml rename to game/data/net.xml diff --git a/data/plugins/.rubocop.yml b/game/data/plugins/.rubocop.yml similarity index 100% rename from data/plugins/.rubocop.yml rename to game/data/plugins/.rubocop.yml diff --git a/data/plugins/areas/actions.rb b/game/data/plugins/areas/actions.rb similarity index 100% rename from data/plugins/areas/actions.rb rename to game/data/plugins/areas/actions.rb diff --git a/data/plugins/areas/areas.rb b/game/data/plugins/areas/areas.rb similarity index 100% rename from data/plugins/areas/areas.rb rename to game/data/plugins/areas/areas.rb diff --git a/data/plugins/areas/plugin.xml b/game/data/plugins/areas/plugin.xml similarity index 100% rename from data/plugins/areas/plugin.xml rename to game/data/plugins/areas/plugin.xml diff --git a/data/plugins/bank/bank.rb b/game/data/plugins/bank/bank.rb similarity index 100% rename from data/plugins/bank/bank.rb rename to game/data/plugins/bank/bank.rb diff --git a/data/plugins/bank/plugin.xml b/game/data/plugins/bank/plugin.xml similarity index 100% rename from data/plugins/bank/plugin.xml rename to game/data/plugins/bank/plugin.xml diff --git a/data/plugins/bootstrap.rb b/game/data/plugins/bootstrap.rb similarity index 100% rename from data/plugins/bootstrap.rb rename to game/data/plugins/bootstrap.rb diff --git a/data/plugins/chat/privacy/plugin.xml b/game/data/plugins/chat/privacy/plugin.xml similarity index 100% rename from data/plugins/chat/privacy/plugin.xml rename to game/data/plugins/chat/privacy/plugin.xml diff --git a/data/plugins/chat/privacy/privacy.rb b/game/data/plugins/chat/privacy/privacy.rb similarity index 100% rename from data/plugins/chat/privacy/privacy.rb rename to game/data/plugins/chat/privacy/privacy.rb diff --git a/data/plugins/chat/private-messaging/friend.rb b/game/data/plugins/chat/private-messaging/friend.rb similarity index 100% rename from data/plugins/chat/private-messaging/friend.rb rename to game/data/plugins/chat/private-messaging/friend.rb diff --git a/data/plugins/chat/private-messaging/ignore.rb b/game/data/plugins/chat/private-messaging/ignore.rb similarity index 100% rename from data/plugins/chat/private-messaging/ignore.rb rename to game/data/plugins/chat/private-messaging/ignore.rb diff --git a/data/plugins/chat/private-messaging/messaging.rb b/game/data/plugins/chat/private-messaging/messaging.rb similarity index 100% rename from data/plugins/chat/private-messaging/messaging.rb rename to game/data/plugins/chat/private-messaging/messaging.rb diff --git a/data/plugins/chat/private-messaging/plugin.xml b/game/data/plugins/chat/private-messaging/plugin.xml similarity index 100% rename from data/plugins/chat/private-messaging/plugin.xml rename to game/data/plugins/chat/private-messaging/plugin.xml diff --git a/data/plugins/cmd/animate/animate.rb b/game/data/plugins/cmd/animate/animate.rb similarity index 100% rename from data/plugins/cmd/animate/animate.rb rename to game/data/plugins/cmd/animate/animate.rb diff --git a/data/plugins/cmd/animate/plugin.xml b/game/data/plugins/cmd/animate/plugin.xml similarity index 100% rename from data/plugins/cmd/animate/plugin.xml rename to game/data/plugins/cmd/animate/plugin.xml diff --git a/data/plugins/cmd/bank/bank.rb b/game/data/plugins/cmd/bank/bank.rb similarity index 100% rename from data/plugins/cmd/bank/bank.rb rename to game/data/plugins/cmd/bank/bank.rb diff --git a/data/plugins/cmd/bank/plugin.xml b/game/data/plugins/cmd/bank/plugin.xml similarity index 100% rename from data/plugins/cmd/bank/plugin.xml rename to game/data/plugins/cmd/bank/plugin.xml diff --git a/data/plugins/cmd/item/item.rb b/game/data/plugins/cmd/item/item.rb similarity index 100% rename from data/plugins/cmd/item/item.rb rename to game/data/plugins/cmd/item/item.rb diff --git a/data/plugins/cmd/item/plugin.xml b/game/data/plugins/cmd/item/plugin.xml similarity index 100% rename from data/plugins/cmd/item/plugin.xml rename to game/data/plugins/cmd/item/plugin.xml diff --git a/data/plugins/cmd/lookup/lookup.rb b/game/data/plugins/cmd/lookup/lookup.rb similarity index 100% rename from data/plugins/cmd/lookup/lookup.rb rename to game/data/plugins/cmd/lookup/lookup.rb diff --git a/data/plugins/cmd/lookup/plugin.xml b/game/data/plugins/cmd/lookup/plugin.xml similarity index 100% rename from data/plugins/cmd/lookup/plugin.xml rename to game/data/plugins/cmd/lookup/plugin.xml diff --git a/data/plugins/cmd/messaging/broadcast.rb b/game/data/plugins/cmd/messaging/broadcast.rb similarity index 100% rename from data/plugins/cmd/messaging/broadcast.rb rename to game/data/plugins/cmd/messaging/broadcast.rb diff --git a/data/plugins/cmd/messaging/plugin.xml b/game/data/plugins/cmd/messaging/plugin.xml similarity index 100% rename from data/plugins/cmd/messaging/plugin.xml rename to game/data/plugins/cmd/messaging/plugin.xml diff --git a/data/plugins/cmd/npc/plugin.xml b/game/data/plugins/cmd/npc/plugin.xml similarity index 100% rename from data/plugins/cmd/npc/plugin.xml rename to game/data/plugins/cmd/npc/plugin.xml diff --git a/data/plugins/cmd/npc/spawn.rb b/game/data/plugins/cmd/npc/spawn.rb similarity index 100% rename from data/plugins/cmd/npc/spawn.rb rename to game/data/plugins/cmd/npc/spawn.rb diff --git a/data/plugins/cmd/punishment/plugin.xml b/game/data/plugins/cmd/punishment/plugin.xml similarity index 100% rename from data/plugins/cmd/punishment/plugin.xml rename to game/data/plugins/cmd/punishment/plugin.xml diff --git a/data/plugins/cmd/punishment/punish.rb b/game/data/plugins/cmd/punishment/punish.rb similarity index 100% rename from data/plugins/cmd/punishment/punish.rb rename to game/data/plugins/cmd/punishment/punish.rb diff --git a/data/plugins/cmd/skill/plugin.xml b/game/data/plugins/cmd/skill/plugin.xml similarity index 100% rename from data/plugins/cmd/skill/plugin.xml rename to game/data/plugins/cmd/skill/plugin.xml diff --git a/data/plugins/cmd/skill/skill.rb b/game/data/plugins/cmd/skill/skill.rb similarity index 100% rename from data/plugins/cmd/skill/skill.rb rename to game/data/plugins/cmd/skill/skill.rb diff --git a/data/plugins/cmd/teleport/plugin.xml b/game/data/plugins/cmd/teleport/plugin.xml similarity index 100% rename from data/plugins/cmd/teleport/plugin.xml rename to game/data/plugins/cmd/teleport/plugin.xml diff --git a/data/plugins/cmd/teleport/teleport.rb b/game/data/plugins/cmd/teleport/teleport.rb similarity index 100% rename from data/plugins/cmd/teleport/teleport.rb rename to game/data/plugins/cmd/teleport/teleport.rb diff --git a/data/plugins/combat/plugin.xml b/game/data/plugins/combat/plugin.xml similarity index 100% rename from data/plugins/combat/plugin.xml rename to game/data/plugins/combat/plugin.xml diff --git a/data/plugins/combat/wilderness.rb b/game/data/plugins/combat/wilderness.rb similarity index 100% rename from data/plugins/combat/wilderness.rb rename to game/data/plugins/combat/wilderness.rb diff --git a/data/plugins/consumables/consumable.rb b/game/data/plugins/consumables/consumable.rb similarity index 100% rename from data/plugins/consumables/consumable.rb rename to game/data/plugins/consumables/consumable.rb diff --git a/data/plugins/consumables/drink.rb b/game/data/plugins/consumables/drink.rb similarity index 100% rename from data/plugins/consumables/drink.rb rename to game/data/plugins/consumables/drink.rb diff --git a/data/plugins/consumables/food.rb b/game/data/plugins/consumables/food.rb similarity index 100% rename from data/plugins/consumables/food.rb rename to game/data/plugins/consumables/food.rb diff --git a/data/plugins/consumables/plugin.xml b/game/data/plugins/consumables/plugin.xml similarity index 100% rename from data/plugins/consumables/plugin.xml rename to game/data/plugins/consumables/plugin.xml diff --git a/data/plugins/consumables/potions.rb b/game/data/plugins/consumables/potions.rb similarity index 100% rename from data/plugins/consumables/potions.rb rename to game/data/plugins/consumables/potions.rb diff --git a/data/plugins/dialogue/dialogue.rb b/game/data/plugins/dialogue/dialogue.rb similarity index 100% rename from data/plugins/dialogue/dialogue.rb rename to game/data/plugins/dialogue/dialogue.rb diff --git a/data/plugins/dialogue/emotes.rb b/game/data/plugins/dialogue/emotes.rb similarity index 100% rename from data/plugins/dialogue/emotes.rb rename to game/data/plugins/dialogue/emotes.rb diff --git a/data/plugins/dialogue/plugin.xml b/game/data/plugins/dialogue/plugin.xml similarity index 100% rename from data/plugins/dialogue/plugin.xml rename to game/data/plugins/dialogue/plugin.xml diff --git a/data/plugins/dummy/dummy.rb b/game/data/plugins/dummy/dummy.rb similarity index 100% rename from data/plugins/dummy/dummy.rb rename to game/data/plugins/dummy/dummy.rb diff --git a/data/plugins/dummy/plugin.xml b/game/data/plugins/dummy/plugin.xml similarity index 100% rename from data/plugins/dummy/plugin.xml rename to game/data/plugins/dummy/plugin.xml diff --git a/data/plugins/emote-tab/emote_tab.rb b/game/data/plugins/emote-tab/emote_tab.rb similarity index 100% rename from data/plugins/emote-tab/emote_tab.rb rename to game/data/plugins/emote-tab/emote_tab.rb diff --git a/data/plugins/emote-tab/plugin.xml b/game/data/plugins/emote-tab/plugin.xml similarity index 100% rename from data/plugins/emote-tab/plugin.xml rename to game/data/plugins/emote-tab/plugin.xml diff --git a/data/plugins/entity/attributes/attributes.rb b/game/data/plugins/entity/attributes/attributes.rb similarity index 100% rename from data/plugins/entity/attributes/attributes.rb rename to game/data/plugins/entity/attributes/attributes.rb diff --git a/data/plugins/entity/attributes/plugin.xml b/game/data/plugins/entity/attributes/plugin.xml similarity index 100% rename from data/plugins/entity/attributes/plugin.xml rename to game/data/plugins/entity/attributes/plugin.xml diff --git a/data/plugins/entity/mob/extension/extension.rb b/game/data/plugins/entity/mob/extension/extension.rb similarity index 100% rename from data/plugins/entity/mob/extension/extension.rb rename to game/data/plugins/entity/mob/extension/extension.rb diff --git a/data/plugins/entity/mob/extension/plugin.xml b/game/data/plugins/entity/mob/extension/plugin.xml similarity index 100% rename from data/plugins/entity/mob/extension/plugin.xml rename to game/data/plugins/entity/mob/extension/plugin.xml diff --git a/data/plugins/entity/mob/following/following.rb b/game/data/plugins/entity/mob/following/following.rb similarity index 100% rename from data/plugins/entity/mob/following/following.rb rename to game/data/plugins/entity/mob/following/following.rb diff --git a/data/plugins/entity/mob/following/plugin.xml b/game/data/plugins/entity/mob/following/plugin.xml similarity index 100% rename from data/plugins/entity/mob/following/plugin.xml rename to game/data/plugins/entity/mob/following/plugin.xml diff --git a/data/plugins/entity/mob/walk-to/plugin.xml b/game/data/plugins/entity/mob/walk-to/plugin.xml similarity index 100% rename from data/plugins/entity/mob/walk-to/plugin.xml rename to game/data/plugins/entity/mob/walk-to/plugin.xml diff --git a/data/plugins/entity/mob/walk-to/walk_to.rb b/game/data/plugins/entity/mob/walk-to/walk_to.rb similarity index 100% rename from data/plugins/entity/mob/walk-to/walk_to.rb rename to game/data/plugins/entity/mob/walk-to/walk_to.rb diff --git a/data/plugins/entity/spawning/npc-spawn.rb b/game/data/plugins/entity/spawning/npc-spawn.rb similarity index 100% rename from data/plugins/entity/spawning/npc-spawn.rb rename to game/data/plugins/entity/spawning/npc-spawn.rb diff --git a/data/plugins/entity/spawning/plugin.xml b/game/data/plugins/entity/spawning/plugin.xml similarity index 100% rename from data/plugins/entity/spawning/plugin.xml rename to game/data/plugins/entity/spawning/plugin.xml diff --git a/data/plugins/location/al-kharid/npcs.rb b/game/data/plugins/location/al-kharid/npcs.rb similarity index 100% rename from data/plugins/location/al-kharid/npcs.rb rename to game/data/plugins/location/al-kharid/npcs.rb diff --git a/data/plugins/location/al-kharid/plugin.xml b/game/data/plugins/location/al-kharid/plugin.xml similarity index 100% rename from data/plugins/location/al-kharid/plugin.xml rename to game/data/plugins/location/al-kharid/plugin.xml diff --git a/data/plugins/location/edgeville/npcs.rb b/game/data/plugins/location/edgeville/npcs.rb similarity index 100% rename from data/plugins/location/edgeville/npcs.rb rename to game/data/plugins/location/edgeville/npcs.rb diff --git a/data/plugins/location/edgeville/plugin.xml b/game/data/plugins/location/edgeville/plugin.xml similarity index 100% rename from data/plugins/location/edgeville/plugin.xml rename to game/data/plugins/location/edgeville/plugin.xml diff --git a/data/plugins/location/falador/npcs.rb b/game/data/plugins/location/falador/npcs.rb similarity index 100% rename from data/plugins/location/falador/npcs.rb rename to game/data/plugins/location/falador/npcs.rb diff --git a/data/plugins/location/falador/plugin.xml b/game/data/plugins/location/falador/plugin.xml similarity index 100% rename from data/plugins/location/falador/plugin.xml rename to game/data/plugins/location/falador/plugin.xml diff --git a/data/plugins/location/lumbridge/npcs.rb b/game/data/plugins/location/lumbridge/npcs.rb similarity index 100% rename from data/plugins/location/lumbridge/npcs.rb rename to game/data/plugins/location/lumbridge/npcs.rb diff --git a/data/plugins/location/lumbridge/plugin.xml b/game/data/plugins/location/lumbridge/plugin.xml similarity index 100% rename from data/plugins/location/lumbridge/plugin.xml rename to game/data/plugins/location/lumbridge/plugin.xml diff --git a/data/plugins/location/tutorial-island/guide.rb b/game/data/plugins/location/tutorial-island/guide.rb similarity index 100% rename from data/plugins/location/tutorial-island/guide.rb rename to game/data/plugins/location/tutorial-island/guide.rb diff --git a/data/plugins/location/tutorial-island/instructions.rb b/game/data/plugins/location/tutorial-island/instructions.rb similarity index 100% rename from data/plugins/location/tutorial-island/instructions.rb rename to game/data/plugins/location/tutorial-island/instructions.rb diff --git a/data/plugins/location/tutorial-island/npcs.rb b/game/data/plugins/location/tutorial-island/npcs.rb similarity index 100% rename from data/plugins/location/tutorial-island/npcs.rb rename to game/data/plugins/location/tutorial-island/npcs.rb diff --git a/data/plugins/location/tutorial-island/plugin.xml b/game/data/plugins/location/tutorial-island/plugin.xml similarity index 100% rename from data/plugins/location/tutorial-island/plugin.xml rename to game/data/plugins/location/tutorial-island/plugin.xml diff --git a/data/plugins/location/tutorial-island/stages.rb b/game/data/plugins/location/tutorial-island/stages.rb similarity index 100% rename from data/plugins/location/tutorial-island/stages.rb rename to game/data/plugins/location/tutorial-island/stages.rb diff --git a/data/plugins/location/tutorial-island/survival.rb b/game/data/plugins/location/tutorial-island/survival.rb similarity index 100% rename from data/plugins/location/tutorial-island/survival.rb rename to game/data/plugins/location/tutorial-island/survival.rb diff --git a/data/plugins/location/tutorial-island/utils.rb b/game/data/plugins/location/tutorial-island/utils.rb similarity index 100% rename from data/plugins/location/tutorial-island/utils.rb rename to game/data/plugins/location/tutorial-island/utils.rb diff --git a/data/plugins/location/varrock/npcs.rb b/game/data/plugins/location/varrock/npcs.rb similarity index 100% rename from data/plugins/location/varrock/npcs.rb rename to game/data/plugins/location/varrock/npcs.rb diff --git a/data/plugins/location/varrock/plugin.xml b/game/data/plugins/location/varrock/plugin.xml similarity index 100% rename from data/plugins/location/varrock/plugin.xml rename to game/data/plugins/location/varrock/plugin.xml diff --git a/data/plugins/location/varrock/shops.rb b/game/data/plugins/location/varrock/shops.rb similarity index 100% rename from data/plugins/location/varrock/shops.rb rename to game/data/plugins/location/varrock/shops.rb diff --git a/data/plugins/logout/logout.rb b/game/data/plugins/logout/logout.rb similarity index 100% rename from data/plugins/logout/logout.rb rename to game/data/plugins/logout/logout.rb diff --git a/data/plugins/logout/plugin.xml b/game/data/plugins/logout/plugin.xml similarity index 100% rename from data/plugins/logout/plugin.xml rename to game/data/plugins/logout/plugin.xml diff --git a/data/plugins/navigation/door/constants.rb b/game/data/plugins/navigation/door/constants.rb similarity index 100% rename from data/plugins/navigation/door/constants.rb rename to game/data/plugins/navigation/door/constants.rb diff --git a/data/plugins/navigation/door/door.rb b/game/data/plugins/navigation/door/door.rb similarity index 100% rename from data/plugins/navigation/door/door.rb rename to game/data/plugins/navigation/door/door.rb diff --git a/data/plugins/navigation/door/plugin.xml b/game/data/plugins/navigation/door/plugin.xml similarity index 100% rename from data/plugins/navigation/door/plugin.xml rename to game/data/plugins/navigation/door/plugin.xml diff --git a/data/plugins/navigation/door/util.rb b/game/data/plugins/navigation/door/util.rb similarity index 100% rename from data/plugins/navigation/door/util.rb rename to game/data/plugins/navigation/door/util.rb diff --git a/data/plugins/player-action/action.rb b/game/data/plugins/player-action/action.rb similarity index 100% rename from data/plugins/player-action/action.rb rename to game/data/plugins/player-action/action.rb diff --git a/data/plugins/player-action/login.rb b/game/data/plugins/player-action/login.rb similarity index 100% rename from data/plugins/player-action/login.rb rename to game/data/plugins/player-action/login.rb diff --git a/data/plugins/player-action/plugin.xml b/game/data/plugins/player-action/plugin.xml similarity index 100% rename from data/plugins/player-action/plugin.xml rename to game/data/plugins/player-action/plugin.xml diff --git a/data/plugins/quest/plugin.xml b/game/data/plugins/quest/plugin.xml similarity index 100% rename from data/plugins/quest/plugin.xml rename to game/data/plugins/quest/plugin.xml diff --git a/data/plugins/quest/repository.rb b/game/data/plugins/quest/repository.rb similarity index 100% rename from data/plugins/quest/repository.rb rename to game/data/plugins/quest/repository.rb diff --git a/data/plugins/run/plugin.xml b/game/data/plugins/run/plugin.xml similarity index 100% rename from data/plugins/run/plugin.xml rename to game/data/plugins/run/plugin.xml diff --git a/data/plugins/run/run.rb b/game/data/plugins/run/run.rb similarity index 100% rename from data/plugins/run/run.rb rename to game/data/plugins/run/run.rb diff --git a/data/plugins/shops/currency.rb b/game/data/plugins/shops/currency.rb similarity index 100% rename from data/plugins/shops/currency.rb rename to game/data/plugins/shops/currency.rb diff --git a/data/plugins/shops/plugin.xml b/game/data/plugins/shops/plugin.xml similarity index 100% rename from data/plugins/shops/plugin.xml rename to game/data/plugins/shops/plugin.xml diff --git a/data/plugins/shops/shop.rb b/game/data/plugins/shops/shop.rb similarity index 100% rename from data/plugins/shops/shop.rb rename to game/data/plugins/shops/shop.rb diff --git a/data/plugins/shops/shop_item.rb b/game/data/plugins/shops/shop_item.rb similarity index 100% rename from data/plugins/shops/shop_item.rb rename to game/data/plugins/shops/shop_item.rb diff --git a/data/plugins/shops/shops.rb b/game/data/plugins/shops/shops.rb similarity index 100% rename from data/plugins/shops/shops.rb rename to game/data/plugins/shops/shops.rb diff --git a/data/plugins/skill/fishing/fish.rb b/game/data/plugins/skill/fishing/fish.rb similarity index 100% rename from data/plugins/skill/fishing/fish.rb rename to game/data/plugins/skill/fishing/fish.rb diff --git a/data/plugins/skill/fishing/fishing.rb b/game/data/plugins/skill/fishing/fishing.rb similarity index 100% rename from data/plugins/skill/fishing/fishing.rb rename to game/data/plugins/skill/fishing/fishing.rb diff --git a/data/plugins/skill/fishing/plugin.xml b/game/data/plugins/skill/fishing/plugin.xml similarity index 100% rename from data/plugins/skill/fishing/plugin.xml rename to game/data/plugins/skill/fishing/plugin.xml diff --git a/data/plugins/skill/fishing/spot.rb b/game/data/plugins/skill/fishing/spot.rb similarity index 100% rename from data/plugins/skill/fishing/spot.rb rename to game/data/plugins/skill/fishing/spot.rb diff --git a/data/plugins/skill/fishing/tool.rb b/game/data/plugins/skill/fishing/tool.rb similarity index 100% rename from data/plugins/skill/fishing/tool.rb rename to game/data/plugins/skill/fishing/tool.rb diff --git a/data/plugins/skill/herblore/herb.rb b/game/data/plugins/skill/herblore/herb.rb similarity index 100% rename from data/plugins/skill/herblore/herb.rb rename to game/data/plugins/skill/herblore/herb.rb diff --git a/data/plugins/skill/herblore/herblore.rb b/game/data/plugins/skill/herblore/herblore.rb similarity index 100% rename from data/plugins/skill/herblore/herblore.rb rename to game/data/plugins/skill/herblore/herblore.rb diff --git a/data/plugins/skill/herblore/ingredient.rb b/game/data/plugins/skill/herblore/ingredient.rb similarity index 100% rename from data/plugins/skill/herblore/ingredient.rb rename to game/data/plugins/skill/herblore/ingredient.rb diff --git a/data/plugins/skill/herblore/plugin.xml b/game/data/plugins/skill/herblore/plugin.xml similarity index 100% rename from data/plugins/skill/herblore/plugin.xml rename to game/data/plugins/skill/herblore/plugin.xml diff --git a/data/plugins/skill/herblore/potion.rb b/game/data/plugins/skill/herblore/potion.rb similarity index 100% rename from data/plugins/skill/herblore/potion.rb rename to game/data/plugins/skill/herblore/potion.rb diff --git a/data/plugins/skill/magic/alchemy.rb b/game/data/plugins/skill/magic/alchemy.rb similarity index 100% rename from data/plugins/skill/magic/alchemy.rb rename to game/data/plugins/skill/magic/alchemy.rb diff --git a/data/plugins/skill/magic/convert.rb b/game/data/plugins/skill/magic/convert.rb similarity index 100% rename from data/plugins/skill/magic/convert.rb rename to game/data/plugins/skill/magic/convert.rb diff --git a/data/plugins/skill/magic/element.rb b/game/data/plugins/skill/magic/element.rb similarity index 100% rename from data/plugins/skill/magic/element.rb rename to game/data/plugins/skill/magic/element.rb diff --git a/data/plugins/skill/magic/enchant.rb b/game/data/plugins/skill/magic/enchant.rb similarity index 100% rename from data/plugins/skill/magic/enchant.rb rename to game/data/plugins/skill/magic/enchant.rb diff --git a/data/plugins/skill/magic/magic.rb b/game/data/plugins/skill/magic/magic.rb similarity index 100% rename from data/plugins/skill/magic/magic.rb rename to game/data/plugins/skill/magic/magic.rb diff --git a/data/plugins/skill/magic/plugin.xml b/game/data/plugins/skill/magic/plugin.xml similarity index 100% rename from data/plugins/skill/magic/plugin.xml rename to game/data/plugins/skill/magic/plugin.xml diff --git a/data/plugins/skill/magic/teleport.rb b/game/data/plugins/skill/magic/teleport.rb similarity index 100% rename from data/plugins/skill/magic/teleport.rb rename to game/data/plugins/skill/magic/teleport.rb diff --git a/data/plugins/skill/mining/gem.rb b/game/data/plugins/skill/mining/gem.rb similarity index 100% rename from data/plugins/skill/mining/gem.rb rename to game/data/plugins/skill/mining/gem.rb diff --git a/data/plugins/skill/mining/mining.rb b/game/data/plugins/skill/mining/mining.rb similarity index 100% rename from data/plugins/skill/mining/mining.rb rename to game/data/plugins/skill/mining/mining.rb diff --git a/data/plugins/skill/mining/ore.rb b/game/data/plugins/skill/mining/ore.rb similarity index 100% rename from data/plugins/skill/mining/ore.rb rename to game/data/plugins/skill/mining/ore.rb diff --git a/data/plugins/skill/mining/pickaxe.rb b/game/data/plugins/skill/mining/pickaxe.rb similarity index 100% rename from data/plugins/skill/mining/pickaxe.rb rename to game/data/plugins/skill/mining/pickaxe.rb diff --git a/data/plugins/skill/mining/plugin.xml b/game/data/plugins/skill/mining/plugin.xml similarity index 100% rename from data/plugins/skill/mining/plugin.xml rename to game/data/plugins/skill/mining/plugin.xml diff --git a/data/plugins/skill/mining/respawn.rb b/game/data/plugins/skill/mining/respawn.rb similarity index 100% rename from data/plugins/skill/mining/respawn.rb rename to game/data/plugins/skill/mining/respawn.rb diff --git a/data/plugins/skill/prayer/bury.rb b/game/data/plugins/skill/prayer/bury.rb similarity index 100% rename from data/plugins/skill/prayer/bury.rb rename to game/data/plugins/skill/prayer/bury.rb diff --git a/data/plugins/skill/prayer/plugin.xml b/game/data/plugins/skill/prayer/plugin.xml similarity index 100% rename from data/plugins/skill/prayer/plugin.xml rename to game/data/plugins/skill/prayer/plugin.xml diff --git a/data/plugins/skill/prayer/prayers.rb b/game/data/plugins/skill/prayer/prayers.rb similarity index 100% rename from data/plugins/skill/prayer/prayers.rb rename to game/data/plugins/skill/prayer/prayers.rb diff --git a/data/plugins/skill/runecraft/altar.rb b/game/data/plugins/skill/runecraft/altar.rb similarity index 100% rename from data/plugins/skill/runecraft/altar.rb rename to game/data/plugins/skill/runecraft/altar.rb diff --git a/data/plugins/skill/runecraft/plugin.xml b/game/data/plugins/skill/runecraft/plugin.xml similarity index 100% rename from data/plugins/skill/runecraft/plugin.xml rename to game/data/plugins/skill/runecraft/plugin.xml diff --git a/data/plugins/skill/runecraft/rune.rb b/game/data/plugins/skill/runecraft/rune.rb similarity index 100% rename from data/plugins/skill/runecraft/rune.rb rename to game/data/plugins/skill/runecraft/rune.rb diff --git a/data/plugins/skill/runecraft/runecraft.rb b/game/data/plugins/skill/runecraft/runecraft.rb similarity index 100% rename from data/plugins/skill/runecraft/runecraft.rb rename to game/data/plugins/skill/runecraft/runecraft.rb diff --git a/data/plugins/skill/runecraft/talisman.rb b/game/data/plugins/skill/runecraft/talisman.rb similarity index 100% rename from data/plugins/skill/runecraft/talisman.rb rename to game/data/plugins/skill/runecraft/talisman.rb diff --git a/data/plugins/skill/runecraft/tiara.rb b/game/data/plugins/skill/runecraft/tiara.rb similarity index 100% rename from data/plugins/skill/runecraft/tiara.rb rename to game/data/plugins/skill/runecraft/tiara.rb diff --git a/data/plugins/util/command.rb b/game/data/plugins/util/command.rb similarity index 100% rename from data/plugins/util/command.rb rename to game/data/plugins/util/command.rb diff --git a/data/plugins/util/name_lookup.rb b/game/data/plugins/util/name_lookup.rb similarity index 100% rename from data/plugins/util/name_lookup.rb rename to game/data/plugins/util/name_lookup.rb diff --git a/data/plugins/util/plugin.xml b/game/data/plugins/util/plugin.xml similarity index 100% rename from data/plugins/util/plugin.xml rename to game/data/plugins/util/plugin.xml diff --git a/data/synchronizer.xml b/game/data/synchronizer.xml similarity index 100% rename from data/synchronizer.xml rename to game/data/synchronizer.xml From 9c1944c969886d375f10a85ffa954e8b3c4b19ba Mon Sep 17 00:00:00 2001 From: KeepBotting Date: Fri, 29 Mar 2019 18:36:07 -0400 Subject: [PATCH 186/209] Let ::pos return other players positions (#422) Rework ::pos to allow a user to return another player's position --- game/plugin/cmd/src/teleport-cmd.plugin.kts | 24 +++++++++++++++--- game/plugin/cmd/test/TeleportCommandTests.kt | 26 ++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/game/plugin/cmd/src/teleport-cmd.plugin.kts b/game/plugin/cmd/src/teleport-cmd.plugin.kts index 1aedd5b9a..2ff9ad5db 100644 --- a/game/plugin/cmd/src/teleport-cmd.plugin.kts +++ b/game/plugin/cmd/src/teleport-cmd.plugin.kts @@ -1,20 +1,36 @@ import com.google.common.primitives.Ints import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel import org.apollo.game.plugin.api.Position.component1 import org.apollo.game.plugin.api.Position.component2 import org.apollo.game.plugin.api.Position.component3 /** - * Sends the player's position. + * Sends a player's position. */ on_command("pos", PrivilegeLevel.MODERATOR) .then { player -> - val (x, y, z) = player.position - val region = player.position.regionCoordinates + val target: Player + val name: String + + if (arguments.size >= 1) { + name = arguments.joinToString(" ") + if (player.world.isPlayerOnline(name)) { + target = player.world.getPlayer(name) + } else { + player.sendMessage("$name is offline.") + return@then + } + } else { + target = player + } + + val (x, y, z) = target.position + val region = target.position.regionCoordinates - player.sendMessage("You are at: ($x, $y, $z) in region (${region.x}, ${region.y}).") + player.sendMessage("${target.username} is located at ($x, $y, $z) in region (${region.x}, ${region.y}).") } /** diff --git a/game/plugin/cmd/test/TeleportCommandTests.kt b/game/plugin/cmd/test/TeleportCommandTests.kt index 32da197ab..2fffdf342 100644 --- a/game/plugin/cmd/test/TeleportCommandTests.kt +++ b/game/plugin/cmd/test/TeleportCommandTests.kt @@ -6,6 +6,7 @@ import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel import org.apollo.game.plugin.testing.assertions.contains import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.Name import org.apollo.game.plugin.testing.junit.api.annotations.TestMock import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -22,6 +23,10 @@ class TeleportCommandTests { @TestMock lateinit var player: Player + @TestMock + @Name("player_two") + lateinit var player_two: Player + @Test fun `Teleport to given coordinates`() { player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR @@ -50,6 +55,27 @@ class TeleportCommandTests { } } + @Test + fun `Shows another players current position information`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + player_two.position = Position(1, 2, 3) + world.commandDispatcher.dispatch(player, Command("pos", arrayOf("player_two"))) + + verify { + player.sendMessage(contains("1, 2, 3")) + } + } + + @Test + fun `Shows no position information for a nonexistent player`() { + player.privilegeLevel = PrivilegeLevel.ADMINISTRATOR + world.commandDispatcher.dispatch(player, Command("pos", arrayOf("player999"))) + + verify { + player.sendMessage(contains("offline")) + } + } + @ParameterizedTest(name = "::tele {0}") @ValueSource(strings = [ "1 2 ", From 8753bedf7ed4fde4e2505f93a49a1bbd588da1e9 Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 13 Jul 2019 15:14:35 +0100 Subject: [PATCH 187/209] Update kotlin and coroutines dependencies --- build.gradle | 4 +-- game/build.gradle | 1 + game/plugin/dummy/src/dummy.plugin.kts | 5 ++-- .../org/apollo/game/action/ActionCoroutine.kt | 25 +++++++++---------- .../game/plugin/kotlin/KotlinPluginScript.kt | 4 +-- gradle/kotlin.gradle | 4 ++- gradle/properties.gradle | 6 ++--- 7 files changed, 24 insertions(+), 25 deletions(-) diff --git a/build.gradle b/build.gradle index a5ebeebbc..8e578d7d3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version '1.2.60' apply(false) - id 'org.jetbrains.intellij' version '0.3.6' apply(false) + id 'org.jetbrains.kotlin.jvm' version '1.3.40' apply(false) + id 'org.jetbrains.intellij' version '0.4.9' apply(false) id 'org.jmailen.kotlinter' version '1.16.0' apply(false) id 'org.sonarqube' version '2.6.2' id "io.gitlab.arturbosch.detekt" version "1.0.0.RC8" diff --git a/game/build.gradle b/game/build.gradle index 491eceb40..ac4d3f1c9 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -12,6 +12,7 @@ dependencies { compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8' compile group: 'org.jetbrains.kotlin', name: 'kotlin-scripting-common' + compile group: 'org.jetbrains.kotlin', name: 'kotlin-script-runtime' compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-jdk8', version: kotlinxCoroutinesVersion compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: kotlinxCoroutinesVersion diff --git a/game/plugin/dummy/src/dummy.plugin.kts b/game/plugin/dummy/src/dummy.plugin.kts index a4501f95c..75dee6f19 100644 --- a/game/plugin/dummy/src/dummy.plugin.kts +++ b/game/plugin/dummy/src/dummy.plugin.kts @@ -1,4 +1,3 @@ -import kotlinx.coroutines.experimental.* import org.apollo.game.action.ActionBlock import org.apollo.game.action.AsyncDistancedAction import org.apollo.game.message.impl.ObjectActionMessage @@ -13,8 +12,8 @@ import org.apollo.net.message.Message val DUMMY_IDS = setOf(823) on { ObjectActionMessage::class } - .where { option == 2 && id in DUMMY_IDS } - .then { DummyAction.start(this, it, position) } + .where { option == 2 && id in DUMMY_IDS } + .then { DummyAction.start(this, it, position) } class DummyAction(val player: Player, position: Position) : AsyncDistancedAction(0, true, player, position, DISTANCE) { diff --git a/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt index 28ca3338f..9f1bd9fd9 100644 --- a/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt +++ b/game/src/main/kotlin/org/apollo/game/action/ActionCoroutine.kt @@ -3,14 +3,10 @@ package org.apollo.game.action import java.util.concurrent.CancellationException import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference -import kotlin.coroutines.experimental.Continuation -import kotlin.coroutines.experimental.CoroutineContext -import kotlin.coroutines.experimental.EmptyCoroutineContext -import kotlin.coroutines.experimental.RestrictsSuspension -import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED -import kotlin.coroutines.experimental.intrinsics.createCoroutineUnchecked -import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn -import kotlinx.coroutines.experimental.suspendCancellableCoroutine +import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED +import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.* typealias ActionPredicate = () -> Boolean typealias ActionBlock = suspend ActionCoroutine.() -> Unit @@ -57,7 +53,7 @@ class ActionCoroutine : Continuation { */ fun start(block: ActionBlock): ActionCoroutine { val coroutine = ActionCoroutine() - val continuation = block.createCoroutineUnchecked(coroutine, coroutine) + val continuation = block.createCoroutine(coroutine, coroutine) coroutine.resumeContinuation(continuation) @@ -66,8 +62,11 @@ class ActionCoroutine : Continuation { } override val context: CoroutineContext = EmptyCoroutineContext - override fun resume(value: Unit) {} - override fun resumeWithException(exception: Throwable) = throw exception + override fun resumeWith(result: Result) { + if (result.isFailure) { + throw result.exceptionOrNull()!! + } + } private fun resumeContinuation(continuation: Continuation, allowCancellation: Boolean = true) { try { @@ -108,7 +107,7 @@ class ActionCoroutine : Continuation { } private suspend fun awaitCondition(condition: ActionCoroutineCondition) { - return suspendCoroutineOrReturn { cont -> + return suspendCoroutineUninterceptedOrReturn { cont -> next.compareAndSet(null, ActionCoroutineStep(condition, cont)) COROUTINE_SUSPENDED } @@ -118,7 +117,7 @@ class ActionCoroutine : Continuation { * Stop execution of this continuation. */ suspend fun stop(): Nothing { - suspendCancellableCoroutine(true) { cont -> + suspendCancellableCoroutine { cont -> next.set(null) cont.cancel() } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index a1a0ba4f3..b3e8eb346 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -2,7 +2,6 @@ package org.apollo.game.plugin.kotlin import kotlin.reflect.KClass import kotlin.script.experimental.annotations.KotlinScript -import kotlin.script.experimental.annotations.KotlinScriptFileExtension import org.apollo.game.command.Command import org.apollo.game.command.CommandListener import org.apollo.game.message.handler.MessageHandler @@ -16,8 +15,7 @@ import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message -@KotlinScript("Apollo Plugin Script") -@KotlinScriptFileExtension("plugin.kts") +@KotlinScript("Apollo Plugin Script", fileExtension = "plugin.kts") abstract class KotlinPluginScript(private var world: World, val context: PluginContext) { var startListener: (World) -> Unit = { _ -> } var stopListener: (World) -> Unit = { _ -> } diff --git a/gradle/kotlin.gradle b/gradle/kotlin.gradle index ab84ae131..04894ed9f 100644 --- a/gradle/kotlin.gradle +++ b/gradle/kotlin.gradle @@ -1 +1,3 @@ -kotlin { experimental { coroutines 'enable' } } +kotlin { + +} diff --git a/gradle/properties.gradle b/gradle/properties.gradle index 03663a88f..76f3789de 100644 --- a/gradle/properties.gradle +++ b/gradle/properties.gradle @@ -1,6 +1,6 @@ ext { - kotlinVersion = '1.2.60' - kotlinxCoroutinesVersion = '0.24.0' + kotlinVersion = '1.3.40' + kotlinxCoroutinesVersion = '1.3.0-M2' junitVersion = '4.12' powermockVersion = '1.6.4' bouncycastleVersion = '1.54' @@ -16,5 +16,5 @@ ext { junitJupiterVersion = '5.1.0' mockkVersion = '1.7.15' assertkVersion = '0.9' - detektVersion = '1.0.0.RC8' + detektVersion = '1.0.0-RC16' } \ No newline at end of file From a8d9db500925636e8fe20fcbc3479fe9bf40bfda Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 13 Jul 2019 19:00:22 +0100 Subject: [PATCH 188/209] Update detekt This temporarily disables the custom detekt rules, as they break the build in hard-to-debug ways. --- build.gradle | 4 ++-- gradle/code-quality.gradle | 22 ++++++++-------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index 8e578d7d3..e0e1be55e 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { id 'org.jetbrains.intellij' version '0.4.9' apply(false) id 'org.jmailen.kotlinter' version '1.16.0' apply(false) id 'org.sonarqube' version '2.6.2' - id "io.gitlab.arturbosch.detekt" version "1.0.0.RC8" + id "io.gitlab.arturbosch.detekt" version '1.0.0-RC16' } allprojects { @@ -26,7 +26,7 @@ gradle.projectsEvaluated { task check { def deps = [] deps += getTasksByName("check", true).findAll { it.project != rootProject } - deps += detektCheck + deps += "detekt" deps += jacocoReport dependsOn(deps) diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle index 2dfdb9113..0587c58af 100644 --- a/gradle/code-quality.gradle +++ b/gradle/code-quality.gradle @@ -1,21 +1,15 @@ def detektAggregateReport = "$buildDir/reports/detekt-report.xml" -detekt { - version = detektVersion - - profile("main") { - input = rootProject.projectDir.absolutePath - filters = ".*/resources/.*, .*/build/.*" - output = file("$buildDir/reports") - outputName = "detekt-report" - config = file("$rootDir/gradle/config/detekt.yml") - parallel = true - } +repositories { + maven { url "https://repo.spring.io/plugins-release/" } } -dependencies { - detekt group: 'io.gitlab.arturbosch.detekt', name: 'detekt-formatting', version: detektVersion - detekt project(':game:plugin-detekt-rules') +detekt { + toolVersion = detektVersion + input = files(rootProject.projectDir.absolutePath) + filters = ".*/resources/.*, .*/build/.*" + config = files("$rootDir/gradle/config/detekt.yml") + parallel = true } sonarqube { From 16599dd2315221782bd7c2a9b6616031c00899ac Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 13 Jul 2019 19:00:08 +0100 Subject: [PATCH 189/209] Refactor shops plugin --- .../locations/al-kharid/src/shops.plugin.kts | 2 +- .../locations/edgeville/src/shops.plugin.kts | 2 +- .../locations/falador/src/shops.plugin.kts | 2 +- .../locations/lumbridge/src/shops.plugin.kts | 2 +- .../locations/varrock/src/shops.plugin.kts | 2 +- game/plugin/shops/src/dsl.kt | 348 ------------------ .../org/apollo/game/plugin/shops/Currency.kt | 26 ++ .../game/plugin/shops/OpenShopAction.kt} | 27 +- .../apollo/game/plugin/shops/Shop.kt} | 145 ++++---- .../game/plugin/shops/ShopInterfaces.kt | 33 ++ .../apollo/game/plugin/shops/Shops.plugin.kts | 47 +++ .../plugin/shops/builder/ActionBuilder.kt | 62 ++++ .../plugin/shops/builder/CategoryBuilder.kt | 59 +++ .../plugin/shops/builder/CurrencyBuilder.kt | 25 ++ .../plugin/shops/builder/OperatorBuilder.kt | 82 +++++ .../plugin/shops/builder/PurchasesBuilder.kt | 29 ++ .../game/plugin/shops/builder/SellBuilder.kt | 43 +++ .../game/plugin/shops/builder/ShopBuilder.kt | 117 ++++++ .../plugin/shops/builder/ShopDslMarker.kt | 7 + game/plugin/shops/src/shop.plugin.kts | 50 --- .../apollo/game/plugin/shops/CurrencyTests.kt | 27 ++ .../game/plugin/shops/ShopActionTests.kt | 21 ++ 22 files changed, 661 insertions(+), 497 deletions(-) delete mode 100644 game/plugin/shops/src/dsl.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/Currency.kt rename game/plugin/shops/src/{action.kt => org/apollo/game/plugin/shops/OpenShopAction.kt} (68%) rename game/plugin/shops/src/{shop.kt => org/apollo/game/plugin/shops/Shop.kt} (93%) create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/ShopInterfaces.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/Shops.plugin.kts create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ActionBuilder.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CategoryBuilder.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CurrencyBuilder.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/OperatorBuilder.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/PurchasesBuilder.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/SellBuilder.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopBuilder.kt create mode 100644 game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopDslMarker.kt delete mode 100644 game/plugin/shops/src/shop.plugin.kts create mode 100644 game/plugin/shops/test/org/apollo/game/plugin/shops/CurrencyTests.kt create mode 100644 game/plugin/shops/test/org/apollo/game/plugin/shops/ShopActionTests.kt diff --git a/game/plugin/locations/al-kharid/src/shops.plugin.kts b/game/plugin/locations/al-kharid/src/shops.plugin.kts index ec55c37a5..2d51292bc 100644 --- a/game/plugin/locations/al-kharid/src/shops.plugin.kts +++ b/game/plugin/locations/al-kharid/src/shops.plugin.kts @@ -1,6 +1,6 @@ package org.apollo.plugin.locations.alKharid -import org.apollo.game.plugin.shops.shop +import org.apollo.game.plugin.shops.builder.shop shop("Al-Kharid General Store") { operated by "Shop keeper"(524) and "Shop assistant"(525) diff --git a/game/plugin/locations/edgeville/src/shops.plugin.kts b/game/plugin/locations/edgeville/src/shops.plugin.kts index cb43fa596..0a5facec5 100644 --- a/game/plugin/locations/edgeville/src/shops.plugin.kts +++ b/game/plugin/locations/edgeville/src/shops.plugin.kts @@ -1,6 +1,6 @@ package org.apollo.plugin.locations.edgeville -import org.apollo.game.plugin.shops.shop +import org.apollo.game.plugin.shops.builder.shop shop("Edgeville General Store") { operated by "Shop keeper"(528) and "Shop assistant"(529) diff --git a/game/plugin/locations/falador/src/shops.plugin.kts b/game/plugin/locations/falador/src/shops.plugin.kts index c79007e6b..5b7446fa9 100644 --- a/game/plugin/locations/falador/src/shops.plugin.kts +++ b/game/plugin/locations/falador/src/shops.plugin.kts @@ -1,6 +1,6 @@ package org.apollo.plugin.locations.falador -import org.apollo.game.plugin.shops.shop +import org.apollo.game.plugin.shops.builder.shop shop("Falador General Store") { operated by "Shop keeper"(524) and "Shop assistant"( 525) diff --git a/game/plugin/locations/lumbridge/src/shops.plugin.kts b/game/plugin/locations/lumbridge/src/shops.plugin.kts index e67a4c8a3..942bb62d3 100644 --- a/game/plugin/locations/lumbridge/src/shops.plugin.kts +++ b/game/plugin/locations/lumbridge/src/shops.plugin.kts @@ -1,6 +1,6 @@ package org.apollo.plugin.locations.lumbridge -import org.apollo.game.plugin.shops.shop +import org.apollo.game.plugin.shops.builder.shop shop("Lumbridge General Store") { operated by "Shop keeper" and "Shop assistant" diff --git a/game/plugin/locations/varrock/src/shops.plugin.kts b/game/plugin/locations/varrock/src/shops.plugin.kts index 4ee6c7e63..cc3d14881 100644 --- a/game/plugin/locations/varrock/src/shops.plugin.kts +++ b/game/plugin/locations/varrock/src/shops.plugin.kts @@ -1,6 +1,6 @@ package org.apollo.plugin.locations.varrock -import org.apollo.game.plugin.shops.shop +import org.apollo.game.plugin.shops.builder.shop shop("Aubury's Rune Shop.") { operated by "Aubury" diff --git a/game/plugin/shops/src/dsl.kt b/game/plugin/shops/src/dsl.kt deleted file mode 100644 index 7974ff6d3..000000000 --- a/game/plugin/shops/src/dsl.kt +++ /dev/null @@ -1,348 +0,0 @@ -package org.apollo.game.plugin.shops - -import org.apollo.cache.def.NpcDefinition -import org.apollo.game.plugin.api.Definitions -import org.apollo.game.plugin.shops.CategoryWrapper.Affix - -/** - * Creates a [Shop]. - * - * @param name The name of the shop. - */ -fun shop(name: String, builder: ShopBuilder.() -> Unit) { - val shop = ShopBuilder(name) - builder(shop) - - val built = shop.build() - val operators = shop.operators().map { it to built }.toMap() - - SHOPS.putAll(operators) -} - -/** - * A [DslMarker] for the shop DSL. - */ -@DslMarker -annotation class ShopDslMarker - -/** - * A builder for a [Shop]. - */ -@ShopDslMarker -class ShopBuilder(val name: String) { - - /** - * Overloads function invokation on strings to map `"ambiguous_npc_name"(id)` to a [Pair]. - */ - operator fun String.invoke(id: Int): Pair = Pair(this, id) - - /** - * Adds a sequence of items to this Shop, grouped together (in the DSL) for convenience. Items will be displayed - * in the same order they are provided. - * - * @param name The name of the category. - * @param affix The method of affixation between the item and category name (see [Affix]). - * @param depluralise Whether or not the category name should have the "s". - * @param builder The builder used to add items to the category. - */ - fun category( - name: String, - affix: Affix = Affix.Suffix, - depluralise: Boolean = true, - builder: CategoryWrapper.() -> Unit - ) { - val items = mutableListOf>() - builder.invoke(CategoryWrapper(items)) - - val category = when { - depluralise -> name.removeSuffix("s") - else -> name - } - - val affixed = items.map { (name, amount) -> Pair(affix.join(name, category), amount) } - sold.addAll(affixed) - } - - /** - * Creates a [SellBuilder] with the specified [amount]. - */ - fun sell(amount: Int): SellBuilder = SellBuilder(amount, sold) - - /** - * The id on the operator npc's action menu used to open the shop. - */ - val action = ActionBuilder() - - /** - * The type of [Currency] the [Shop] makes exchanges with. - */ - var trades = CurrencyBuilder() - - /** - * The [Shop]'s policy towards purchasing items from players. - */ - var buys = PurchasesBuilder() - - /** - * Redundant variable used only to complete the [PurchasesBuilder] (e.g. `buys no items`). - */ - val items = Unit - - /** - * Places the category name before the item name (inserting a space between the names). - */ - val prefix = Affix.Prefix - - /** - * Prevents the category name from being joined to the item name in any way. - */ - val nothing = Affix.None - - /** - * The [OperatorBuilder] used to collate the [Shop]'s operators. - */ - val operated = OperatorBuilder() - - /** - * The [List] of items sold by the shop, as (name, amount) [Pair]s. - */ - private val sold = mutableListOf>() - - /** - * Converts this builder into a [Shop]. - */ - internal fun build(): Shop { - val items = sold.associateBy({ (first) -> Definitions.item(first)!!.id }, Pair::second) - val npc = NpcDefinition.lookup(operators().first()) - - return Shop(name, action.action(npc), items, trades.currency, buys.policy) - } - - /** - * Gets the [List] of shop operator ids. - */ - internal fun operators(): MutableList = operated.operators -} - -@ShopDslMarker -class CategoryWrapper(private val items: MutableList>) { - - /** - * The method of joining the item and category name. - */ - sealed class Affix(private val joiner: (item: String, category: String) -> String) { - - /** - * Appends the category after the item name (with a space between). - */ - object Suffix : Affix({ item, affix -> "$item $affix" }) - - /** - * Prepends the category before the item name (with a space between). - */ - object Prefix : Affix({ item, affix -> "$affix $item" }) - - /** - * Does not join the category at all (i.e. only returns the item name). - */ - object None : Affix({ item, _ -> item }) - - /** - * Joins the item and category name in the expected manner. - */ - fun join(item: String, category: String): String = joiner(item, category) - } - - /** - * Creates a [SellBuilder] with the specified [amount]. - */ - fun sell(amount: Int): SellBuilder = SellBuilder(amount, items) -} - -/** - * A builder to provide the list of shop operators - the npcs that can be interacted with to access the shop. - */ -@ShopDslMarker -class OperatorBuilder internal constructor() { - - /** - * The [List] of shop operators. - */ - val operators: MutableList = mutableListOf() - - /** - * Adds a shop operator, using the specified [name] to resolve the npc id. - */ - infix fun by(name: String): OperatorBuilder { - operators.add(Definitions.npc(name)!!.id) - return this - } - - /** - * Adds a shop operator, using the specified [name] to resolve the npc id. - */ - infix fun and(name: String): OperatorBuilder = by(name) - - /** - * Adds a shop operator, using the specified [name] to resolve the npc id. - */ - operator fun plus(name: String): OperatorBuilder = and(name) - - /** - * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation - * operator, solely to disambiguate between npcs with the same name (e.g. - * `"Shopkeeper"(500) vs `"Shopkeeper"(501)`). Use [by(String][by] if the npc name is unambiguous. - */ - infix fun by(pair: Pair): OperatorBuilder { - operators.add(pair.second) - return this - } - - /** - * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation - * operator, solely to disambiguate between npcs with the same name (e.g. - * `"Shopkeeper"(500) vs `"Shopkeeper"(501)`). Use [by(String][by] if the npc name is unambiguous. - */ - infix fun and(pair: Pair): OperatorBuilder = by(pair) - - /** - * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation - * operator, solely to disambiguate between npcs with the same name (e.g. - * `"Shopkeeper"(500) vs `"Shopkeeper"(501)`). Use [by(String][by] if the npc name is unambiguous. - */ - operator fun plus(pair: Pair): OperatorBuilder = by(pair) -} - -/** - * A builder to provide the action id used to open the shop. - */ -@ShopDslMarker -class ActionBuilder { - - private var action: String = "Trade" - - private var actionId: Int? = null - - /** - * Sets the name or id of the action used to open the shop interface with an npc. Defaults to "Trade". - * - * If specifying an id it must account for hidden npc menu actions (if any exist) - if "Open Shop" is the first - * action displayed when the npc is right-clicked, it does not necessarily mean that the action id is `1`. - * - * @param action The `name` (as a [String]) or `id` (as an `Int`) of the npc's action menu, to open the shop. - * @throws IllegalArgumentException If `action` is not a [String] or [Int]. - */ - override fun equals(@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") action: Any?): Boolean { - if (action is String) { - this.action = action - return true - } else if (action is Int) { - actionId = action - return true - } - - throw IllegalArgumentException("The Npc option must be provided as a String (the option name) or the ") - } - - /** - * Returns the open shop action slot. - * - * @throws IllegalArgumentException If the action id or name is invalid. - */ - internal fun action(npc: NpcDefinition): Int { - actionId?.let { action -> - if (npc.hasInteraction(action - 1)) { // ActionMessages are 1-based - return action - } - - throw IllegalArgumentException("Npc ${npc.name} does not have an an action $action.") - } - - val index = npc.interactions.indexOf(action) - when (index) { - -1 -> throw IllegalArgumentException("Npc ${npc.name} does not have an an action $action.") - else -> return index + 1 // ActionMessages are 1-based - } - } - - /** - * Throws [UnsupportedOperationException]. - */ - override fun hashCode(): Int = throw UnsupportedOperationException("ActionBuilder is a utility class for a DSL " + - "and improperly implements equals() - it should not be used anywhere outside of the DSL.") -} - -/** - * A builder to provide the currency used by the [Shop]. - */ -@ShopDslMarker -class CurrencyBuilder { - - internal var currency = Currency.COINS - - /** - * Overloads the `in` operator on [Currency] to achieve e.g. `trades in tokkul`. - */ - operator fun Currency.contains(builder: CurrencyBuilder): Boolean { - builder.currency = this - return true - } -} - -/** - * A builder to provide the [Shop.PurchasePolicy]. - */ -@ShopDslMarker -class PurchasesBuilder { - - internal var policy = Shop.PurchasePolicy.OWNED - - /** - * Instructs the shop to purchase no items, regardless of whether or not it sells it. - */ - infix fun no(@Suppress("UNUSED_PARAMETER") items: Unit) { - policy = Shop.PurchasePolicy.NOTHING - } - - /** - * Instructs the shop to purchase any tradeable item. - */ - infix fun any(@Suppress("UNUSED_PARAMETER") items: Unit) { - policy = Shop.PurchasePolicy.ANY - } -} - -/** - * A builder to provide the items to sell. - * - * @param amount The amount to sell (of each item). - * @param items The [MutableList] to insert the given items into. - */ -@ShopDslMarker -class SellBuilder(val amount: Int, val items: MutableList>) { - - infix fun of(lambda: SellBuilder.() -> Unit) = lambda.invoke(this) - - /** - * Provides an item with the specified name. - * - * @name The item name. Must be unambiguous. - */ - infix fun of(name: String) = items.add(Pair(name, amount)) - - /** - * Overloads unary minus on Strings so that item names can be listed. - */ - operator fun String.unaryMinus() = items.add(Pair(this, amount)) - - /** - * Overloads the unary minus on Pairs so that name+id pairs can be listed. Only intended to be used with the - * overloaded String invokation operator. - */ // ShopBuilder uses the lookup plugin, which can operate on _ids tacked on the end - operator fun Pair.unaryMinus() = items.add(Pair("${this.first}_${this.second}", amount)) - - /** - * Overloads function invokation on Strings to map `"ambiguous_npc_name"(id)` to a [Pair]. - */ - operator fun String.invoke(id: Int): Pair = Pair(this, id) -} diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/Currency.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/Currency.kt new file mode 100644 index 000000000..6548f4d30 --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/Currency.kt @@ -0,0 +1,26 @@ +package org.apollo.game.plugin.shops + +import org.apollo.game.plugin.api.Definitions + +/** + * A [Shop]'s method of payment. + * + * @param id The item id of the currency. + * @param plural Whether or not the name of this currency is plural. + */ +data class Currency(val id: Int, val plural: Boolean = false) { + + val name = requireNotNull(Definitions.item(id).name?.toLowerCase()) { "Currencies must have a name." } + + fun name(amount: Int): String { + return when { + amount == 1 && plural -> name.removeSuffix("s") + else -> name + } + } + + companion object { + val COINS = Currency(995, plural = true) + } + +} \ No newline at end of file diff --git a/game/plugin/shops/src/action.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/OpenShopAction.kt similarity index 68% rename from game/plugin/shops/src/action.kt rename to game/plugin/shops/src/org/apollo/game/plugin/shops/OpenShopAction.kt index 8f31158ff..a87a31256 100644 --- a/game/plugin/shops/src/action.kt +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/OpenShopAction.kt @@ -1,7 +1,7 @@ package org.apollo.game.plugin.shops import org.apollo.game.action.DistancedAction -import org.apollo.game.message.handler.ItemVerificationHandler.InventorySupplier +import org.apollo.game.message.handler.ItemVerificationHandler import org.apollo.game.message.impl.SetWidgetTextMessage import org.apollo.game.model.entity.Mob import org.apollo.game.model.entity.Player @@ -15,16 +15,17 @@ import org.apollo.game.model.inv.SynchronizationInventoryListener class OpenShopAction( player: Player, private val shop: Shop, - val npc: Mob -) : DistancedAction(0, true, player, npc.position, 1) { // TODO this needs to follow the NPC if they move + private val operator: Mob +) : DistancedAction(0, true, player, operator.position, 1) { // TODO this needs to follow the NPC if they move override fun executeAction() { - mob.interactingMob = npc + mob.interactingMob = operator val closeListener = addInventoryListeners(mob, shop.inventory) - mob.send(SetWidgetTextMessage(Interfaces.SHOP_NAME, shop.name)) + mob.send(SetWidgetTextMessage(ShopInterfaces.SHOP_NAME, shop.name)) - mob.interfaceSet.openWindowWithSidebar(closeListener, Interfaces.SHOP_WINDOW, Interfaces.INVENTORY_SIDEBAR) + mob.interfaceSet.openWindowWithSidebar(closeListener, ShopInterfaces.SHOP_WINDOW, + ShopInterfaces.INVENTORY_SIDEBAR) stop() } @@ -33,8 +34,8 @@ class OpenShopAction( * [InterfaceListener] that removes them when the interface is closed. */ private fun addInventoryListeners(player: Player, shop: Inventory): InterfaceListener { - val invListener = SynchronizationInventoryListener(player, Interfaces.INVENTORY_CONTAINER) - val shopListener = SynchronizationInventoryListener(player, Interfaces.SHOP_CONTAINER) + val invListener = SynchronizationInventoryListener(player, ShopInterfaces.INVENTORY_CONTAINER) + val shopListener = SynchronizationInventoryListener(player, ShopInterfaces.SHOP_CONTAINER) player.inventory.addListener(invListener) player.inventory.forceRefresh() @@ -55,12 +56,14 @@ class OpenShopAction( /** * An [InventorySupplier] that returns a [Player]'s [Inventory] if they are browsing a shop. */ -class PlayerInventorySupplier : InventorySupplier { +object PlayerInventorySupplier : ItemVerificationHandler.InventorySupplier { override fun getInventory(player: Player): Inventory? { - return when { - player.interfaceSet.contains(Interfaces.SHOP_WINDOW) -> player.inventory - else -> null + return if (Interfaces.SHOP_WINDOW in player.interfaceSet) { + player.inventory + } else { + null } } + } \ No newline at end of file diff --git a/game/plugin/shops/src/shop.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/Shop.kt similarity index 93% rename from game/plugin/shops/src/shop.kt rename to game/plugin/shops/src/org/apollo/game/plugin/shops/Shop.kt index f5490906b..08f9014c3 100644 --- a/game/plugin/shops/src/shop.kt +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/Shop.kt @@ -47,35 +47,13 @@ object Interfaces { */ val SHOPS = mutableMapOf() -/** - * A [Shop]'s method of payment. - * - * @param id The item id of the currency. - * @param plural Whether or not the name of this currency is plural. - */ -data class Currency(val id: Int, val plural: Boolean = false) { - - companion object { - val COINS = Currency(995, plural = true) - } - - val name: String = ItemDefinition.lookup(id).name?.toLowerCase() - ?: throw IllegalArgumentException("Currencies must have a name.") - - fun name(amount: Int): String { - return when { - amount == 1 && plural -> name.removeSuffix("s") - else -> name - } - } -} - /** * An in-game shop, operated by one or more npcs. * * @param name The name of the shop. * @param action The id of the NpcActionMessage sent (by the client) when a player opens this shop. * @param sells The [Map] from item id to amount sold. + * @param operators The [List] of Npc ids that can open this shop. * @param currency The [Currency] used when making exchanges with this [Shop]. * @param purchases This [Shop]'s attitude towards purchasing items from players. */ @@ -83,68 +61,11 @@ class Shop( val name: String, val action: Int, private val sells: Map, + val operators: List, private val currency: Currency = Currency.COINS, private val purchases: PurchasePolicy = OWNED ) { - companion object { - - /** - * The amount of pulses between shop inventory restocking. - */ - const val RESTOCK_INTERVAL = 100 - - /** - * The capacity of a [Shop]. - */ - private const val CAPACITY = 30 - - /** - * The type of exchange occurring between the [Player] and [Shop]. - */ - private enum class ExchangeType { BUYING, SELLING } - - /** - * The option id for item valuation. - */ - private const val VALUATION_OPTION = 1 - - /** - * Returns the amount that a player tried to buy or sell. - * - * @param option The id of the option the player selected. - */ - private fun amount(option: Int): Int { - return when (option) { - 2 -> 1 - 3 -> 5 - 4 -> 10 - else -> throw IllegalArgumentException("Option must be 1-4") - } - } - } - - /** - * The [Shop]s policy regarding purchasing items from players. - */ - enum class PurchasePolicy { - - /** - * Never purchase anything from players. - */ - NOTHING, - - /** - * Only purchase items that this Shop sells by default. - */ - OWNED, - - /** - * Purchase any tradeable items. - */ - ANY - } - /** * The [Inventory] containing this [Shop]'s current items. */ @@ -183,7 +104,7 @@ class Shop( return } - var buying: Int = amount(option) + var buying = amount(option) var unavailable = false val amount = item.amount @@ -328,4 +249,64 @@ class Shop( * @param id The id of the [Item] to sell. */ private fun sells(id: Int): Boolean = sells.containsKey(id) + + /** + * The [Shop]s policy regarding purchasing items from players. + */ + enum class PurchasePolicy { + + /** + * Never purchase anything from players. + */ + NOTHING, + + /** + * Only purchase items that this Shop sells by default. + */ + OWNED, + + /** + * Purchase any tradeable items. + */ + ANY + } + + companion object { + + /** + * The amount of pulses between shop inventory restocking. + */ + const val RESTOCK_INTERVAL = 100 + + /** + * The capacity of a [Shop]. + */ + private const val CAPACITY = 30 + + /** + * The type of exchange occurring between the [Player] and [Shop]. + */ + private enum class ExchangeType { BUYING, SELLING } + + /** + * The option id for item valuation. + */ + private const val VALUATION_OPTION = 1 + + /** + * Returns the amount that a player tried to buy or sell. + * + * @param option The id of the option the player selected. + */ + private fun amount(option: Int): Int { + return when (option) { + 2 -> 1 + 3 -> 5 + 4 -> 10 + else -> throw IllegalArgumentException("Option must be 1-4") + } + } + + } + } \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/ShopInterfaces.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/ShopInterfaces.kt new file mode 100644 index 000000000..4a678bd8f --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/ShopInterfaces.kt @@ -0,0 +1,33 @@ +package org.apollo.game.plugin.shops + +/** + * Contains shop-related interface ids. + */ +internal object ShopInterfaces { + + /** + * The container interface id for the player's inventory. + */ + const val INVENTORY_CONTAINER = 3823 + + /** + * The sidebar id for the inventory, when a Shop window is open. + */ + const val INVENTORY_SIDEBAR = 3822 + + /** + * The shop window interface id. + */ + const val SHOP_WINDOW = 3824 + + /** + * The container interface id for the shop's inventory. + */ + const val SHOP_CONTAINER = 3900 + + /** + * The id of the text widget that displays a shop's name. + */ + const val SHOP_NAME = 3901 + +} \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/Shops.plugin.kts b/game/plugin/shops/src/org/apollo/game/plugin/shops/Shops.plugin.kts new file mode 100644 index 000000000..4d3be298d --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/Shops.plugin.kts @@ -0,0 +1,47 @@ +package org.apollo.game.plugin.shops + +import org.apollo.game.message.handler.ItemVerificationHandler +import org.apollo.game.message.impl.ItemActionMessage +import org.apollo.game.message.impl.NpcActionMessage +import org.apollo.game.model.entity.Mob +import org.apollo.game.scheduling.ScheduledTask + +fun Mob.shop(): Shop? = SHOPS[definition.id] + +start { world -> + ItemVerificationHandler.addInventory(ShopInterfaces.SHOP_CONTAINER) { it.interactingMob?.shop()?.inventory } + ItemVerificationHandler.addInventory(ShopInterfaces.INVENTORY_CONTAINER, PlayerInventorySupplier) + + world.schedule(object : ScheduledTask(Shop.RESTOCK_INTERVAL, false) { + override fun execute() = SHOPS.values.distinct().forEach(Shop::restock) + }) +} + +on { NpcActionMessage::class } + .then { player -> + val npc = player.world.npcRepository.get(index) + val shop = npc.shop() ?: return@then + + if (shop.action == option) { + player.startAction(OpenShopAction(player, shop, npc)) + terminate() + } + } + + +on { ItemActionMessage::class } + .where { interfaceId == ShopInterfaces.SHOP_CONTAINER || interfaceId == ShopInterfaces.INVENTORY_CONTAINER } + .then { player -> + if (ShopInterfaces.SHOP_WINDOW !in player.interfaceSet) { + return@then + } + + val shop = player.interactingMob?.shop() ?: return@then + when (interfaceId) { + ShopInterfaces.INVENTORY_CONTAINER -> shop.buy(player, slot, option) + ShopInterfaces.SHOP_CONTAINER -> shop.sell(player, slot, option) + else -> error("Supposedly unreacheable case.") + } + + terminate() + } diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ActionBuilder.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ActionBuilder.kt new file mode 100644 index 000000000..bfd251a11 --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ActionBuilder.kt @@ -0,0 +1,62 @@ +package org.apollo.game.plugin.shops.builder + +import org.apollo.cache.def.NpcDefinition + +/** + * A builder to provide the action id used to open the shop. + */ +@ShopDslMarker +class ActionBuilder { + + private var action: String = "Trade" + + private var actionId: Int? = null + + /** + * Sets the name or id of the action used to open the shop interface with an npc. Defaults to "Trade". + * + * If specifying an id it must account for hidden npc menu actions (if any exist) - if "Open Shop" is the first + * action displayed when the npc is right-clicked, it does not necessarily mean that the action id is `1`. + * + * @param action The `name` (as a [String]) or `id` (as an `Int`) of the npc's action menu, to open the shop. + * @throws IllegalArgumentException If `action` is not a [String] or [Int]. + */ // TODO this is dumb, replace it + override fun equals(@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") action: Any?): Boolean { + if (action is String) { + this.action = action + return true + } else if (action is Int) { + actionId = action + return true + } + + throw IllegalArgumentException("The Npc option must be provided as a String (the option name) or an Int (the option index)\"") + } + + /** + * Returns the open shop action slot. + * + * @throws IllegalArgumentException If the action id or name is invalid. + */ + internal fun slot(npc: NpcDefinition): Int { + actionId?.let { action -> + require(npc.hasInteraction(action - 1)) { + "Npc ${npc.name} does not have an an action $action." // action - 1 because ActionMessages are 1-based + } + + return action + } + + val index = npc.interactions.indexOf(action) + require(index != -1) { "Npc ${npc.name} does not have an an action $action." } + + return index + 1 // ActionMessages are 1-based + } + + /** + * Throws [UnsupportedOperationException]. + */ + override fun hashCode(): Int = throw UnsupportedOperationException("ActionBuilder is a utility class for a DSL " + + "and improperly implements equals() - it should not be used anywhere outside of the DSL.") + +} \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CategoryBuilder.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CategoryBuilder.kt new file mode 100644 index 000000000..5f10c470c --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CategoryBuilder.kt @@ -0,0 +1,59 @@ +package org.apollo.game.plugin.shops.builder + +/** + * A builder for a category - a collection of sold items that share a common prefix or suffix. + * + * ``` + * category("mould") { + * sell(10) of "Ring" + * sell(2) of "Necklace" + * sell(10) of "Amulet" + * } + * ``` + */ +@ShopDslMarker +class CategoryBuilder { + + /** + * The items that this shop sells, as a pair of item name to amount sold. + */ + private val items = mutableListOf>() + + /** + * Creates a [SellBuilder] with the specified [amount]. + */ + fun sell(amount: Int): SellBuilder = SellBuilder(amount, items) + + /** + * Builds this category into a list of sold items, represented as a pair of item name to amount sold. + */ + fun build(): List> = items + + /** + * The method of joining the item and category name. + */ + sealed class Affix(private val joiner: (item: String, category: String) -> String) { + + /** + * Appends the category after the item name (with a space between). + */ + object Suffix : Affix({ item, affix -> "$item $affix" }) + + /** + * Prepends the category before the item name (with a space between). + */ + object Prefix : Affix({ item, affix -> "$affix $item" }) + + /** + * Does not join the category at all (i.e. only returns the item name). + */ + object None : Affix({ item, _ -> item }) + + /** + * Joins the item and category name in the expected manner. + */ + fun join(item: String, category: String): String = joiner(item, category) + + } + +} \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CurrencyBuilder.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CurrencyBuilder.kt new file mode 100644 index 000000000..f4d812245 --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/CurrencyBuilder.kt @@ -0,0 +1,25 @@ +package org.apollo.game.plugin.shops.builder + +import org.apollo.game.plugin.shops.Currency + +/** + * A builder to provide the currency used by the [Shop]. + */ +@ShopDslMarker +class CurrencyBuilder { + + private var currency = Currency.COINS + + /** + * Overloads the `in` operator on [Currency] to achieve e.g. `trades in tokkul`. + * + * This function violates the contract for the `in` operator and is only to be used inside the Shops DSL. + */ + operator fun Currency.contains(builder: CurrencyBuilder): Boolean { + builder.currency = this + return true + } + + fun build(): Currency = currency + +} \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/OperatorBuilder.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/OperatorBuilder.kt new file mode 100644 index 000000000..7585cbbba --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/OperatorBuilder.kt @@ -0,0 +1,82 @@ +package org.apollo.game.plugin.shops.builder + +import org.apollo.game.plugin.api.Definitions + +/** + * A builder to provide the list of shop operators - the npcs that can be interacted with to access the shop. + * + * ``` + * shop("General Store.") { + * operated by "Shopkeeper"(522) and "Shop assistant"(523) and "Shop assistant"(524) + * ... + * } + * ``` + */ +@ShopDslMarker +class OperatorBuilder internal constructor(private val shopName: String) { + + /** + * The [List] of shop operator ids. + */ + private val operators = mutableListOf() + + /** + * Adds a shop operator, using the specified [name] to resolve the npc id. + */ + infix fun by(name: String): OperatorBuilder { + val npc = requireNotNull(Definitions.npc(name)) { + "Failed to resolve npc named `$name` when building shop $shopName." + } + + operators += npc.id + return this + } + + /** + * Adds a shop operator, using the specified [name] to resolve the npc id. + * + * An alias for [by]. + */ + infix fun and(name: String): OperatorBuilder = by(name) + + /** + * Adds a shop operator, using the specified [name] to resolve the npc id. + * + * An alias for [by]. + */ + operator fun plus(name: String): OperatorBuilder = and(name) + + /** + * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation + * operator, solely to disambiguate between npcs with the same name (e.g. `"Shopkeeper"(500) vs + * `"Shopkeeper"(501)`). Use [by(String)][by] if the npc name is unambiguous. + */ + infix fun by(pair: Pair): OperatorBuilder { + operators += pair.second + return this + } + + /** + * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation + * operator, solely to disambiguate between npcs with the same name (e.g. `"Shopkeeper"(500) vs + * `"Shopkeeper"(501)`). Use [by(String)][by] if the npc name is unambiguous. + * + * An alias for [by(Pair)][by]. + */ + infix fun and(pair: Pair): OperatorBuilder = by(pair) + + /** + * Adds a shop operator with the specified npc id. Intended to be used with the overloaded String invokation + * operator, solely to disambiguate between npcs with the same name (e.g. `"Shopkeeper"(500) vs + * `"Shopkeeper"(501)`). Use [by(String)][by] if the npc name is unambiguous. + * + * An alias for [by(Pair)][by]. + */ + operator fun plus(pair: Pair): OperatorBuilder = by(pair) + + /** + * Builds this [OperatorBuilder] into a [List] of operator npc ids. + */ + fun build(): List = operators + +} \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/PurchasesBuilder.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/PurchasesBuilder.kt new file mode 100644 index 000000000..9adfa8deb --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/PurchasesBuilder.kt @@ -0,0 +1,29 @@ +package org.apollo.game.plugin.shops.builder + +import org.apollo.game.plugin.shops.Shop + +/** + * A builder to provide the [Shop.PurchasePolicy]. + */ +@ShopDslMarker +class PurchasesBuilder { + + private var policy = Shop.PurchasePolicy.OWNED + + /** + * Instructs the shop to purchase no items, regardless of whether or not it sells it. + */ + infix fun no(@Suppress("UNUSED_PARAMETER") items: Unit) { + policy = Shop.PurchasePolicy.NOTHING + } + + /** + * Instructs the shop to purchase any tradeable item. + */ + infix fun any(@Suppress("UNUSED_PARAMETER") items: Unit) { + policy = Shop.PurchasePolicy.ANY + } + + fun build(): Shop.PurchasePolicy = policy + +} \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/SellBuilder.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/SellBuilder.kt new file mode 100644 index 000000000..fe9550564 --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/SellBuilder.kt @@ -0,0 +1,43 @@ +package org.apollo.game.plugin.shops.builder + +/** + * A builder to provide the items to sell. + * + * @param amount The amount to sell (of each item). + * @param items The [MutableList] to insert the given items into. + */ +@ShopDslMarker +class SellBuilder(val amount: Int, val items: MutableList>) { + + infix fun of(lambda: SellBuilder.() -> Unit) = lambda(this) + + /** + * Provides an item with the specified name. + * + * @name The item name. Must be unambiguous. + */ + infix fun of(name: String) { + items += Pair(name, amount) + } + + /** + * Overloads unary minus on Strings so that item names can be listed. + */ + operator fun String.unaryMinus() { + of(this) + } + + /** + * Overloads the unary minus on Pairs so that name+id pairs can be listed. Only intended to be used with the + * overloaded String invokation operator. + */ // ShopBuilder uses the lookup plugin, which can operate on _ids tacked on the end + operator fun Pair.unaryMinus() { + items += Pair("${first}_$second", amount) + } + + /** + * Overloads function invokation on Strings to map `"ambiguous_npc_name"(id)` to a [Pair]. + */ + operator fun String.invoke(id: Int): Pair = Pair(this, id) + +} \ No newline at end of file diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopBuilder.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopBuilder.kt new file mode 100644 index 000000000..00b6b3b94 --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopBuilder.kt @@ -0,0 +1,117 @@ +package org.apollo.game.plugin.shops.builder + +import org.apollo.cache.def.NpcDefinition +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.shops.Currency +import org.apollo.game.plugin.shops.SHOPS +import org.apollo.game.plugin.shops.Shop +import org.apollo.game.plugin.shops.builder.CategoryBuilder.Affix + +/** + * Creates a [Shop]. + * + * @param name The name of the shop. + */ +fun shop(name: String, builder: ShopBuilder.() -> Unit) { + val shop = ShopBuilder(name).apply(builder).build() + + shop.operators.associateByTo(SHOPS, { it }, { shop }) +} + +/** + * A builder for a [Shop]. + */ +@ShopDslMarker +class ShopBuilder(val name: String) { + + /** + * The id on the operator npc's action menu used to open the shop. + */ + val action = ActionBuilder() + + /** + * The type of [Currency] the [Shop] makes exchanges with. + */ + var trades = CurrencyBuilder() + + /** + * The [OperatorBuilder] used to collate the [Shop]'s operators. + */ + val operated = OperatorBuilder(name) + + /** + * The [Shop]'s policy towards purchasing items from players. + */ + var buys = PurchasesBuilder() + + /** + * Redundant variable used in the purchases dsl, to complete the [PurchasesBuilder] (e.g. `buys no items`). + */ + val items = Unit + + /** + * Used in the category dsl. Places the category name before the item name (inserting a space between the names). + */ + val prefix = Affix.Prefix + + /** + * Used in the category dsl. Prevents the category name from being joined to the item name in any way. + */ + val nothing = Affix.None + + /** + * The [List] of items sold by the shop, as (name, amount) [Pair]s. + */ + private val sold = mutableListOf>() + + /** + * Overloads function invokation on strings to map `"ambiguous_npc_name"(id)` to a [Pair]. + */ + operator fun String.invoke(id: Int): Pair = Pair(this, id) + + /** + * Adds a sequence of items to this Shop, grouped together (in the DSL) for convenience. Items will be displayed + * in the same order they are provided. + * + * @param name The name of the category. + * @param affix The method of affixation between the item and category name (see [Affix]). + * @param depluralise Whether or not the category name should have the "s". + * @param builder The builder that adds items to the category. + */ + fun category( + name: String, + affix: Affix = Affix.Suffix, + depluralise: Boolean = true, // TODO search for both with and without plural + builder: CategoryBuilder.() -> Unit + ) { + val items = CategoryBuilder().apply(builder).build() + + val category = when { + depluralise -> name.removeSuffix("s") + else -> name + } + + sold += items.map { (name, amount) -> Pair(affix.join(name, category), amount) } + } + + /** + * Creates a [SellBuilder] with the specified [amount]. + */ + fun sell(amount: Int): SellBuilder = SellBuilder(amount, sold) + + /** + * Converts this builder into a [Shop]. + */ + internal fun build(): Shop { + val operators = operated.build() + val npc = NpcDefinition.lookup(operators.first()) + + val items = sold.associateBy( + { requireNotNull(Definitions.item(it.first)?.id) { "Failed to find item ${it.first} in shop $name." } }, + { it.second } + ) + + return Shop(name, action.slot(npc), items, operators, trades.build(), buys.build()) + } + +} diff --git a/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopDslMarker.kt b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopDslMarker.kt new file mode 100644 index 000000000..3187a23bb --- /dev/null +++ b/game/plugin/shops/src/org/apollo/game/plugin/shops/builder/ShopDslMarker.kt @@ -0,0 +1,7 @@ +package org.apollo.game.plugin.shops.builder + +/** + * A [DslMarker] for the shop DSL. + */ +@DslMarker +internal annotation class ShopDslMarker \ No newline at end of file diff --git a/game/plugin/shops/src/shop.plugin.kts b/game/plugin/shops/src/shop.plugin.kts deleted file mode 100644 index 644e96c34..000000000 --- a/game/plugin/shops/src/shop.plugin.kts +++ /dev/null @@ -1,50 +0,0 @@ -import org.apollo.game.message.handler.ItemVerificationHandler -import org.apollo.game.message.impl.ItemActionMessage -import org.apollo.game.message.impl.NpcActionMessage -import org.apollo.game.model.entity.Mob -import org.apollo.game.plugin.shops.Interfaces -import org.apollo.game.plugin.shops.OpenShopAction -import org.apollo.game.plugin.shops.PlayerInventorySupplier -import org.apollo.game.plugin.shops.SHOPS -import org.apollo.game.plugin.shops.Shop -import org.apollo.game.scheduling.ScheduledTask - -fun Mob.shop(): Shop? = SHOPS[definition.id] - -start { - ItemVerificationHandler.addInventory(Interfaces.SHOP_CONTAINER) { it.interactingMob?.shop()?.inventory } - ItemVerificationHandler.addInventory(Interfaces.INVENTORY_CONTAINER, PlayerInventorySupplier()) - - it.schedule(object : ScheduledTask(Shop.RESTOCK_INTERVAL, false) { - override fun execute() = SHOPS.values.distinct().forEach(Shop::restock) - }) -} - -on { NpcActionMessage::class } - .then { - val npc = it.world.npcRepository.get(index) - val shop = npc.shop() ?: return@then - - if (shop.action == option) { - it.startAction(OpenShopAction(it, shop, npc)) - terminate() - } - } - - -on { ItemActionMessage::class } - .where { interfaceId == Interfaces.SHOP_CONTAINER || interfaceId == Interfaces.INVENTORY_CONTAINER } - .then { - if (!it.interfaceSet.contains(Interfaces.SHOP_WINDOW)) { - return@then - } - - val shop = it.interactingMob?.shop() ?: return@then - when (interfaceId) { - Interfaces.INVENTORY_CONTAINER -> shop.buy(it, slot, option) - Interfaces.SHOP_CONTAINER -> shop.sell(it, slot, option) - else -> throw IllegalStateException("Supposedly unreacheable case.") - } - - terminate() - } \ No newline at end of file diff --git a/game/plugin/shops/test/org/apollo/game/plugin/shops/CurrencyTests.kt b/game/plugin/shops/test/org/apollo/game/plugin/shops/CurrencyTests.kt new file mode 100644 index 000000000..de897d0c2 --- /dev/null +++ b/game/plugin/shops/test/org/apollo/game/plugin/shops/CurrencyTests.kt @@ -0,0 +1,27 @@ +package org.apollo.game.plugin.shops + +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.annotations.ItemDefinitions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class CurrencyTests { + + @Test + fun `items used as currencies must have names in their definitions`() { + assertThrows("Should not be able to create a Currency with an item missing a name") { + Currency(id = ITEM_MISSING_NAME) + } + } + + private companion object { + private const val ITEM_MISSING_NAME = 0 + + @ItemDefinitions + private val unnamed = listOf(ItemDefinition(ITEM_MISSING_NAME)) + } + +} \ No newline at end of file diff --git a/game/plugin/shops/test/org/apollo/game/plugin/shops/ShopActionTests.kt b/game/plugin/shops/test/org/apollo/game/plugin/shops/ShopActionTests.kt new file mode 100644 index 000000000..643fcd5ff --- /dev/null +++ b/game/plugin/shops/test/org/apollo/game/plugin/shops/ShopActionTests.kt @@ -0,0 +1,21 @@ +package org.apollo.game.plugin.shops + +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.testing.junit.ApolloTestingExtension +import org.apollo.game.plugin.testing.junit.api.ActionCapture +import org.apollo.game.plugin.testing.junit.api.annotations.TestMock +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(ApolloTestingExtension::class) +class ShopActionTests { + + @TestMock + lateinit var player: Player + + @TestMock + lateinit var action: ActionCapture + + + + +} \ No newline at end of file From bb352225f3a853309f69edc8b809ab34a01fd796 Mon Sep 17 00:00:00 2001 From: "david.indova@gmail.com" Date: Fri, 26 Apr 2019 12:49:32 -0400 Subject: [PATCH 190/209] Add MagicOnMob MessageHandler --- game/data/messages.xml | 6 +++ .../MagicOnMobVerificationHandler.java | 51 +++++++++++++++++++ .../game/message/impl/MagicOnMobMessage.java | 5 ++ 3 files changed, 62 insertions(+) create mode 100644 game/src/main/java/org/apollo/game/message/handler/MagicOnMobVerificationHandler.java diff --git a/game/data/messages.xml b/game/data/messages.xml index 910c4a15a..f4a5bec2e 100644 --- a/game/data/messages.xml +++ b/game/data/messages.xml @@ -71,6 +71,12 @@ org.apollo.game.message.handler.ItemVerificationHandler + + org.apollo.game.message.impl.MagicOnMobMessage + + org.apollo.game.message.handler.MagicOnMobVerificationHandler + + org.apollo.game.message.impl.NpcActionMessage diff --git a/game/src/main/java/org/apollo/game/message/handler/MagicOnMobVerificationHandler.java b/game/src/main/java/org/apollo/game/message/handler/MagicOnMobVerificationHandler.java new file mode 100644 index 000000000..7df2ba757 --- /dev/null +++ b/game/src/main/java/org/apollo/game/message/handler/MagicOnMobVerificationHandler.java @@ -0,0 +1,51 @@ +package org.apollo.game.message.handler; + +import org.apollo.game.message.impl.MagicOnMobMessage; +import org.apollo.game.model.World; +import org.apollo.game.model.entity.EntityType; +import org.apollo.game.model.entity.Mob; +import org.apollo.game.model.entity.MobRepository; +import org.apollo.game.model.entity.Player; + +/** + * A verification {@link MessageHandler} for the {@link MagicOnMobMessage}. + * + * @author Tom + */ +public final class MagicOnMobVerificationHandler extends MessageHandler{ + + /** + * Creates the MessageListener. + * + * @param world The {@link World} the {@link MagicOnMobMessage} occurred in. + */ + public MagicOnMobVerificationHandler(World world) { + super(world); + } + + @Override + public void handle(Player player, MagicOnMobMessage message) { + int index = message.getIndex(); + MobRepository repository; + + if (message.getType() == EntityType.NPC) { + repository = world.getNpcRepository(); + } else if (message.getType() == EntityType.PLAYER) { + repository = world.getPlayerRepository(); + } else { + throw new IllegalStateException("Invalid mob type for message: " + message.toString()); + } + + if (index < 0 || index >= repository.capacity()) { + message.terminate(); + return; + } + + Mob mob = repository.get(index); + + if (mob == null || !player.getPosition().isWithinDistance(mob.getPosition(), player.getViewingDistance() + 1)) { + // +1 in case it was decremented after the player clicked the action. + message.terminate(); + } + } +} diff --git a/game/src/main/java/org/apollo/game/message/impl/MagicOnMobMessage.java b/game/src/main/java/org/apollo/game/message/impl/MagicOnMobMessage.java index f408f9b3f..fabdc16b8 100644 --- a/game/src/main/java/org/apollo/game/message/impl/MagicOnMobMessage.java +++ b/game/src/main/java/org/apollo/game/message/impl/MagicOnMobMessage.java @@ -1,5 +1,6 @@ package org.apollo.game.message.impl; +import com.google.common.base.MoreObjects; import org.apollo.game.model.entity.EntityType; import org.apollo.net.message.Message; @@ -65,4 +66,8 @@ public int getSpellId() { return spellId; } + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("type", getType()).add("index", getIndex()).add("spellId", getSpellId()).toString(); + } } \ No newline at end of file From 57fc49a42be807710b7e89939fe346533364bca4 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 16:35:32 +0100 Subject: [PATCH 191/209] Update test deps for Java 11 Prevent bytecode generation related test failures in tests that rely on PowerMock by updating to PowerMock 2. --- game/build.gradle | 2 +- game/plugin-detekt-rules/build.gradle | 1 + gradle/properties.gradle | 2 +- gradle/testing.gradle | 2 +- gradle/wrapper.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 3 ++- net/build.gradle | 1 + util/build.gradle | 1 + 8 files changed, 9 insertions(+), 5 deletions(-) diff --git a/game/build.gradle b/game/build.gradle index ac4d3f1c9..1a451eb99 100644 --- a/game/build.gradle +++ b/game/build.gradle @@ -28,7 +28,7 @@ dependencies { testImplementation group: 'junit', name: 'junit', version: junitVersion testImplementation group: 'org.powermock', name: 'powermock-module-junit4', version: powermockVersion - testImplementation group: 'org.powermock', name: 'powermock-api-mockito', version: powermockVersion + testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: powermockVersion testImplementation group: 'org.assertj', name: 'assertj-core', version: assertjVersion project(":game:plugin").subprojects { pluginProject -> diff --git a/game/plugin-detekt-rules/build.gradle b/game/plugin-detekt-rules/build.gradle index a57e036c7..2a459bb66 100644 --- a/game/plugin-detekt-rules/build.gradle +++ b/game/plugin-detekt-rules/build.gradle @@ -4,6 +4,7 @@ apply from: "$rootDir/gradle/kotlin.gradle" dependencies { api group: 'io.gitlab.arturbosch.detekt', name: 'detekt-api', version: detektVersion + api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8' test.useJUnitPlatform() testImplementation("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}") diff --git a/gradle/properties.gradle b/gradle/properties.gradle index 76f3789de..63d32988d 100644 --- a/gradle/properties.gradle +++ b/gradle/properties.gradle @@ -2,7 +2,7 @@ ext { kotlinVersion = '1.3.40' kotlinxCoroutinesVersion = '1.3.0-M2' junitVersion = '4.12' - powermockVersion = '1.6.4' + powermockVersion = '2.0.2' bouncycastleVersion = '1.54' c3p0Version = '0.9.5.2' scryptVersion = '1.4.0' diff --git a/gradle/testing.gradle b/gradle/testing.gradle index 838454d44..5b3a7cd17 100644 --- a/gradle/testing.gradle +++ b/gradle/testing.gradle @@ -10,7 +10,7 @@ gradle.projectsEvaluated { apply plugin: "jacoco" jacoco { - toolVersion = '0.8.1' + toolVersion = '0.8.4' } test { diff --git a/gradle/wrapper.gradle b/gradle/wrapper.gradle index 35e4d7ddd..19b869f71 100644 --- a/gradle/wrapper.gradle +++ b/gradle/wrapper.gradle @@ -1,3 +1,3 @@ wrapper { - gradleVersion = "4.9" + gradleVersion = "5.5" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a95009c3b..ce16fd39a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Tue Jul 16 03:37:52 BST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip diff --git a/net/build.gradle b/net/build.gradle index 939c6ff44..0b1045c36 100644 --- a/net/build.gradle +++ b/net/build.gradle @@ -11,6 +11,7 @@ dependencies { implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: bouncycastleVersion test.useJUnitPlatform() + testImplementation group: 'junit', name: 'junit', version: junitVersion testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitJupiterVersion testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitJupiterVersion testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVintageVersion diff --git a/util/build.gradle b/util/build.gradle index 996946275..aa4fb376e 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -10,6 +10,7 @@ dependencies { implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: bouncycastleVersion test.useJUnitPlatform() + testImplementation group: 'junit', name: 'junit', version: junitVersion testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitJupiterVersion testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitJupiterVersion testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVintageVersion From 04a69eac1226bf1c40fdd03f731223b5ca9ca47d Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 16:55:09 +0100 Subject: [PATCH 192/209] Add Azure DevOps pipeline configuration --- azure-pipelines.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 000000000..c524f1d5f --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,16 @@ +pool: + vmImage: 'ubuntu-latest' + +steps: + - task: Gradle@2 + displayName: "Gradle: build" + inputs: + workingDirectory: '' + gradleWrapperFile: 'gradlew' + gradleOptions: '-Xmx3072m' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + testResultsFiles: '**/TEST-*.xml' + tasks: 'build' From 91e38aa84ed7f37c08c76b368f31bf38ffe57fbb Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 17:02:45 +0100 Subject: [PATCH 193/209] Run builds in parallel on Azure CI --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c524f1d5f..8dd7c9aaa 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,7 @@ steps: inputs: workingDirectory: '' gradleWrapperFile: 'gradlew' - gradleOptions: '-Xmx3072m' + gradleOptions: '-Xmx3072m -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.8' jdkArchitectureOption: 'x64' From ab787dde14cf83b030ef8f45dae6cee3b22908f5 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 17:08:34 +0100 Subject: [PATCH 194/209] Enable Gradle build caching in CI --- azure-pipelines.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8dd7c9aaa..84e0be78c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,16 +1,28 @@ pool: vmImage: 'ubuntu-latest' +variables: + GRADLE_USER_HOME: $(Pipeline.Workspace)/.gradle + steps: + - task: CacheBeta@0 + inputs: + key: $(Agent.OS) + path: $(GRADLE_USER_HOME) + displayName: "Gradle: setup build cache" + - task: Gradle@2 displayName: "Gradle: build" inputs: workingDirectory: '' gradleWrapperFile: 'gradlew' - gradleOptions: '-Xmx3072m -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true' + gradleOptions: '-Xmx3072m -Dorg.gradle.parallel=true -Dorg.gradle.caching=true' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.8' jdkArchitectureOption: 'x64' publishJUnitResults: false testResultsFiles: '**/TEST-*.xml' tasks: 'build' + + - script: | + ./gradlew --stop From 28a4752f4773589608cbee1908e0c053773b22e5 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 17:20:07 +0100 Subject: [PATCH 195/209] Publish test results to CI --- azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 84e0be78c..f2efa7034 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,9 +20,10 @@ steps: javaHomeOption: 'JDKVersion' jdkVersionOption: '1.8' jdkArchitectureOption: 'x64' - publishJUnitResults: false + publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' tasks: 'build' - script: | ./gradlew --stop + displayName: "Gradle: stop daemon" \ No newline at end of file From 37e20c9a2552268ae622fae4da2881b66fcece02 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 17:37:58 +0100 Subject: [PATCH 196/209] Publish code coverage from Azure CI --- .travis.yml | 2 -- azure-pipelines.yml | 10 ++++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7760a6bc..8087cdf37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,6 @@ addons: organization: "apollo-rsps" after_success: - - ./gradlew jacocoTestReport - - bash <(curl -s https://codecov.io/bash) - git fetch --unshallow - ./gradlew -Dsonar.host.url=https://sonarcloud.io -Dsonar.login="$SONAR_TOKEN" sonarqube before_cache: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f2efa7034..af4cf36b8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,8 +22,14 @@ steps: jdkArchitectureOption: 'x64' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - tasks: 'build' + tasks: 'check jacocoTestReport' - script: | ./gradlew --stop - displayName: "Gradle: stop daemon" \ No newline at end of file + displayName: "Gradle: stop daemon" + + - script: | + bash <(curl -s https://codecov.io/bash) -t "${CODECOV_TOKEN}" + env: + CODECOV_TOKEN: $(CODECOV_TOKEN) + displayName: "Codecov: publish coverage" \ No newline at end of file From 36571a344f89e70ce700d370cc8b0ec754409631 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 17:55:20 +0100 Subject: [PATCH 197/209] Remove AppVeyor and Travis-CI configuration --- .travis.yml | 18 ------------------ appveyor.yml | 24 ------------------------ 2 files changed, 42 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8087cdf37..000000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: java -jdk: - - oraclejdk8 - -addons: - sonarcloud: - organization: "apollo-rsps" - -after_success: - - git fetch --unshallow - - ./gradlew -Dsonar.host.url=https://sonarcloud.io -Dsonar.login="$SONAR_TOKEN" sonarqube -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b00ccfac7..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: "{branch} {build}" - -build: - verbosity: detailed - -build_script: -- gradlew.bat assemble --info --no-daemon - -test_script: -- gradlew.bat check --info --no-daemon - -cache: -- C:\Users\appveyor\.gradle - -environment: - matrix: - - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - -matrix: - fast_finish: true - -artifacts: -- path: 'game\build\distributions\game-0.0.1.zip' - name: Apollo Server Distribution From cd013fc1eeb3df8ead18f699fc558797c7685723 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 18:27:40 +0100 Subject: [PATCH 198/209] Publish SonarQube analysis from Azure CI --- azure-pipelines.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index af4cf36b8..2167045f3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,23 +11,35 @@ steps: path: $(GRADLE_USER_HOME) displayName: "Gradle: setup build cache" + - task: SonarCloudPrepare@1 + inputs: + SonarCloud: 'apollo-rsps-sonarcloud' + organization: 'apollo-rsps' + scannerMode: 'Other' + displayName: "SonarCloud: prepare analysis" + - task: Gradle@2 displayName: "Gradle: build" inputs: workingDirectory: '' gradleWrapperFile: 'gradlew' - gradleOptions: '-Xmx3072m -Dorg.gradle.parallel=true -Dorg.gradle.caching=true' + gradleOptions: '-Xmx3072m -Dorg.gradle.parallel=true -Dorg.gradle.caching=true -Dsonar.host.url=https://sonarcloud.io' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.8' jdkArchitectureOption: 'x64' publishJUnitResults: true testResultsFiles: '**/TEST-*.xml' - tasks: 'check jacocoTestReport' + tasks: 'check jacocoTestReport sonarqube' - script: | ./gradlew --stop displayName: "Gradle: stop daemon" + - task: SonarCloudPublish@1 + inputs: + pollingTimeoutSec: '300' + displayName: "SonarCloud: publish quality gate" + - script: | bash <(curl -s https://codecov.io/bash) -t "${CODECOV_TOKEN}" env: From 809106b321fcca7d710960630a434d31165ee93f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2019 17:34:46 +0000 Subject: [PATCH 199/209] Bump org.jetbrains.kotlin.jvm from 1.3.40 to 1.3.41 Bumps org.jetbrains.kotlin.jvm from 1.3.40 to 1.3.41. Signed-off-by: dependabot-preview[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e0e1be55e..0e4db95cc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version '1.3.40' apply(false) + id 'org.jetbrains.kotlin.jvm' version '1.3.41' apply(false) id 'org.jetbrains.intellij' version '0.4.9' apply(false) id 'org.jmailen.kotlinter' version '1.16.0' apply(false) id 'org.sonarqube' version '2.6.2' From ac01419536a79bf7b8ed68c83bb9274f286ef5cb Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2019 17:35:02 +0000 Subject: [PATCH 200/209] Bump org.jmailen.kotlinter from 1.16.0 to 1.26.0 Bumps org.jmailen.kotlinter from 1.16.0 to 1.26.0. Signed-off-by: dependabot-preview[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e0e1be55e..add1683a5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'org.jetbrains.kotlin.jvm' version '1.3.40' apply(false) id 'org.jetbrains.intellij' version '0.4.9' apply(false) - id 'org.jmailen.kotlinter' version '1.16.0' apply(false) + id 'org.jmailen.kotlinter' version '1.26.0' apply(false) id 'org.sonarqube' version '2.6.2' id "io.gitlab.arturbosch.detekt" version '1.0.0-RC16' } From b84c6ab6418ed06dcb6fd16660f17a16d6d9da05 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 16 Jul 2019 18:47:28 +0100 Subject: [PATCH 201/209] Fix location of detekt report --- gradle/code-quality.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/code-quality.gradle b/gradle/code-quality.gradle index 0587c58af..98b7506f2 100644 --- a/gradle/code-quality.gradle +++ b/gradle/code-quality.gradle @@ -1,4 +1,4 @@ -def detektAggregateReport = "$buildDir/reports/detekt-report.xml" +def detektAggregateReport = "$buildDir/reports/detekt/detekt.xml" repositories { maven { url "https://repo.spring.io/plugins-release/" } From 76755465138221275cc801b4519280be6d6d1bc4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2019 18:12:19 +0000 Subject: [PATCH 202/209] Bump org.sonarqube from 2.6.2 to 2.7.1 Bumps org.sonarqube from 2.6.2 to 2.7.1. Signed-off-by: dependabot-preview[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a23213ed5..c1756fcf0 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'org.jetbrains.kotlin.jvm' version '1.3.41' apply(false) id 'org.jetbrains.intellij' version '0.4.9' apply(false) id 'org.jmailen.kotlinter' version '1.26.0' apply(false) - id 'org.sonarqube' version '2.6.2' + id 'org.sonarqube' version '2.7.1' id "io.gitlab.arturbosch.detekt" version '1.0.0-RC16' } From 0405639ed111da776080a6eef6b550174250bde7 Mon Sep 17 00:00:00 2001 From: Major Date: Mon, 22 Jul 2019 02:34:28 +0100 Subject: [PATCH 203/209] Implement new listener dsl for plugins --- .../plugin/kotlin/KotlinCommandHandler.kt | 29 +++ .../plugin/kotlin/KotlinMessageHandler.kt | 35 ++++ .../kotlin/KotlinPlayerHandlerProxyTrait.kt | 31 +++ .../game/plugin/kotlin/KotlinPluginScript.kt | 183 +++++++----------- .../apollo/game/plugin/kotlin/Listenable.kt | 32 +++ .../game/plugin/kotlin/ListenableContext.kt | 6 + .../plugin/kotlin/OldKotlinEventHandler.kt | 34 ++++ .../kotlin/OldKotlinPlayerEventHandler.kt | 21 ++ .../kotlin/action/ActionListenableContext.kt | 33 ++++ .../kotlin/action/obj/InteractiveObject.kt | 14 ++ .../plugin/kotlin/action/obj/ListenableDsl.kt | 79 ++++++++ .../plugin/kotlin/action/obj/ObjectAction.kt | 53 +++++ .../action/obj/ObjectActionListenable.kt | 17 ++ 13 files changed, 453 insertions(+), 114 deletions(-) create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPlayerHandlerProxyTrait.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinEventHandler.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinPlayerEventHandler.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/ActionListenableContext.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/InteractiveObject.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ListenableDsl.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectActionListenable.kt diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt new file mode 100644 index 000000000..a939e44c5 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt @@ -0,0 +1,29 @@ +package org.apollo.game.plugin.kotlin + +import org.apollo.game.command.Command +import org.apollo.game.command.CommandListener +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.setting.PrivilegeLevel + +/** + * A handler for [Command]s. + */ +class KotlinCommandHandler( + val world: World, + val command: String, + privileges: PrivilegeLevel +) : KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { + + override var callback: Command.(Player) -> Unit = {} + override var predicate: Command.() -> Boolean = { true } + + override fun execute(player: Player, command: Command) { + handleProxy(player, command) + } + + override fun register() { + world.commandDispatcher.register(command, this) + } + +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt new file mode 100644 index 000000000..f6e1ec4cc --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt @@ -0,0 +1,35 @@ +package org.apollo.game.plugin.kotlin + +import org.apollo.game.message.handler.MessageHandler +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.PluginContext +import org.apollo.net.message.Message +import kotlin.reflect.KClass + +class KotlinMessageHandler( + world: World, + private val listenable: MessageListenable, + private val callback: T.() -> Unit +) : MessageHandler(world) { + + override fun handle(player: Player, message: F) { + val context = listenable.from(player, message) + context.callback() + } + +} + +/** + * A handler for [Message]s. + */ +@Deprecated("To be removed") +class OldKotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : + KotlinPlayerHandlerProxyTrait, MessageHandler(world) { + + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } + + override fun handle(player: Player, message: T) = handleProxy(player, message) + override fun register() = context.addMessageHandler(type.java, this) +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPlayerHandlerProxyTrait.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPlayerHandlerProxyTrait.kt new file mode 100644 index 000000000..0de3a0f07 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPlayerHandlerProxyTrait.kt @@ -0,0 +1,31 @@ +package org.apollo.game.plugin.kotlin + +import org.apollo.game.model.entity.Player + +/** + * A proxy interface for any handler that operates on [Player]s. + */ +@Deprecated("To be removed") +interface KotlinPlayerHandlerProxyTrait { + + var callback: S.(Player) -> Unit + var predicate: S.() -> Boolean + + fun register() + + fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait { + this.predicate = predicate + return this + } + + fun then(callback: S.(Player) -> Unit) { + this.callback = callback + this.register() + } + + fun handleProxy(player: Player, subject: S) { + if (subject.predicate()) { + subject.callback(player) + } + } +} diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index b3e8eb346..51cfbd121 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -1,157 +1,112 @@ package org.apollo.game.plugin.kotlin -import kotlin.reflect.KClass -import kotlin.script.experimental.annotations.KotlinScript -import org.apollo.game.command.Command import org.apollo.game.command.CommandListener import org.apollo.game.message.handler.MessageHandler import org.apollo.game.message.impl.ButtonMessage import org.apollo.game.model.World -import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.setting.PrivilegeLevel import org.apollo.game.model.event.Event import org.apollo.game.model.event.EventListener import org.apollo.game.model.event.PlayerEvent import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message +import kotlin.reflect.KClass +import kotlin.script.experimental.annotations.KotlinScript @KotlinScript("Apollo Plugin Script", fileExtension = "plugin.kts") -abstract class KotlinPluginScript(private var world: World, val context: PluginContext) { - var startListener: (World) -> Unit = { _ -> } - var stopListener: (World) -> Unit = { _ -> } +abstract class KotlinPluginScript(var world: World, val context: PluginContext) { + + private var startListener: (World) -> Unit = { _ -> } + + private var stopListener: (World) -> Unit = { _ -> } + + fun on(listenable: Listenable, callback: T.() -> Unit) { + // Smart-casting/type-inference is completely broken in this function in intelliJ, so assign to otherwise + // pointless `l` values for now. + + return when (listenable) { + is MessageListenable -> { + @Suppress("UNCHECKED_CAST") + val l = listenable as MessageListenable + + val handler = KotlinMessageHandler(world, l, callback) + context.addMessageHandler(l.type.java, handler) + } + is PlayerEventListenable -> { + @Suppress("UNCHECKED_CAST") + val l = listenable as PlayerEventListenable + + world.listenFor(l.type.java) { event -> + val context = l.from(event) + context.callback() + } + } + is EventListenable -> { + @Suppress("UNCHECKED_CAST") + val l = listenable as EventListenable + + world.listenFor(l.type.java) { event -> + val context = l.from(event) + context.callback() + } + } + } + } /** - * Creates a [MessageHandler]. + * Create a [CommandListener] for the given [command] name, which only players with a [PrivilegeLevel] + * of [privileges] and above can use. */ - fun on(type: () -> KClass) = KotlinMessageHandler(world, context, type.invoke()) + fun on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { // TODO what to do with this? + return KotlinCommandHandler(world, command, privileges) + } /** - * Create an [EventListener] for a [PlayerEvent]. + * Creates a [MessageHandler]. */ - fun on_player_event(type: () -> KClass) = KotlinPlayerEventHandler(world, type.invoke()) + @Deprecated("Use new on(Type) listener") + fun on(type: () -> KClass): OldKotlinMessageHandler { + return OldKotlinMessageHandler(world, context, type()) + } /** - * Create an [EventListener] for an [Event]. + * Create an [EventListener] for a [PlayerEvent]. */ - fun on_event(type: () -> KClass) = KotlinEventHandler(world, type.invoke()) + @Deprecated("Use new on(Type) listener") + fun on_player_event(type: () -> KClass): OldKotlinPlayerEventHandler { + return OldKotlinPlayerEventHandler(world, type()) + } /** - * Create a [CommandListener] for the given [command] name, which only players with a [PrivilegeLevel] - * of [privileges] and above can use. + * Create an [EventListener] for an [Event]. */ - fun on_command(command: String, privileges: PrivilegeLevel) = KotlinCommandHandler(world, command, privileges) + @Deprecated("Use new on(Type) listener") + fun on_event(type: () -> KClass): OldKotlinEventHandler { + return OldKotlinEventHandler(world, type()) + } /** * Create a [ButtonMessage] [MessageHandler] for the given [id]. */ - fun on_button(id: Int) = on { ButtonMessage::class }.where { widgetId == id } + @Deprecated("Use new on(Type) listener") + fun on_button(id: Int): KotlinPlayerHandlerProxyTrait { + return on { ButtonMessage::class }.where { widgetId == id } + } fun start(callback: (World) -> Unit) { - this.startListener = callback + startListener = callback } fun stop(callback: (World) -> Unit) { - this.stopListener = callback + stopListener = callback } fun doStart(world: World) { - this.startListener.invoke(world) + startListener(world) } fun doStop(world: World) { - this.stopListener.invoke(world) + stopListener(world) } -} - -/** - * A proxy interface for any handler that operates on [Player]s. - */ -interface KotlinPlayerHandlerProxyTrait { - - var callback: S.(Player) -> Unit - var predicate: S.() -> Boolean - - fun register() - - fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait { - this.predicate = predicate - return this - } - - fun then(callback: S.(Player) -> Unit) { - this.callback = callback - this.register() - } - - fun handleProxy(player: Player, subject: S) { - if (subject.predicate()) { - subject.callback(player) - } - } -} - -/** - * A handler for [PlayerEvent]s. - */ -class KotlinPlayerEventHandler(val world: World, val type: KClass) : - KotlinPlayerHandlerProxyTrait, EventListener { - - override var callback: T.(Player) -> Unit = {} - override var predicate: T.() -> Boolean = { true } - - override fun handle(event: T) = handleProxy(event.player, event) - override fun register() = world.listenFor(type.java, this) -} - -/** - * A handler for [Event]s. - */ -class KotlinEventHandler(val world: World, val type: KClass) : EventListener { - - private var callback: S.() -> Unit = {} - private var predicate: S.() -> Boolean = { true } - - fun where(predicate: S.() -> Boolean): KotlinEventHandler { - this.predicate = predicate - return this - } - - fun then(callback: S.() -> Unit) { - this.callback = callback - this.register() - } - - override fun handle(event: S) { - if (event.predicate()) { - event.callback() - } - } - - fun register() = world.listenFor(type.java, this) -} - -/** - * A handler for [Message]s. - */ -class KotlinMessageHandler(val world: World, val context: PluginContext, val type: KClass) : - KotlinPlayerHandlerProxyTrait, MessageHandler(world) { - - override var callback: T.(Player) -> Unit = {} - override var predicate: T.() -> Boolean = { true } - - override fun handle(player: Player, message: T) = handleProxy(player, message) - override fun register() = context.addMessageHandler(type.java, this) -} - -/** - * A handler for [Command]s. - */ -class KotlinCommandHandler(val world: World, val command: String, privileges: PrivilegeLevel) : - KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { - - override var callback: Command.(Player) -> Unit = {} - override var predicate: Command.() -> Boolean = { true } - override fun execute(player: Player, command: Command) = handleProxy(player, command) - override fun register() = world.commandDispatcher.register(command, this) -} +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt new file mode 100644 index 000000000..17cef5a05 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt @@ -0,0 +1,32 @@ +package org.apollo.game.plugin.kotlin + +import org.apollo.game.model.entity.Player +import org.apollo.game.model.event.Event +import org.apollo.game.model.event.PlayerEvent +import org.apollo.net.message.Message +import kotlin.reflect.KClass + +/** + * A game occurrence that can be listened to. + */ +sealed class Listenable { + abstract val type: KClass +} + +abstract class EventListenable : Listenable() { + abstract fun from(event: F): T +} + +abstract class MessageListenable : Listenable() { + abstract fun from(player: Player, message: F): T +} + +abstract class PlayerEventListenable : EventListenable() { + + abstract fun from(player: Player, event: F): T + + override fun from(event: F): T { + return from(event.player, event) + } + +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt new file mode 100644 index 000000000..02ae45a3f --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt @@ -0,0 +1,6 @@ +package org.apollo.game.plugin.kotlin + +/** + * Contains contextual information for a [Listenable]. + */ +interface ListenableContext diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinEventHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinEventHandler.kt new file mode 100644 index 000000000..7269b96d1 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinEventHandler.kt @@ -0,0 +1,34 @@ +package org.apollo.game.plugin.kotlin + +import org.apollo.game.model.World +import org.apollo.game.model.event.Event +import org.apollo.game.model.event.EventListener +import kotlin.reflect.KClass + +/** + * A handler for [Event]s. + */ +@Deprecated("To be removed") +class OldKotlinEventHandler(val world: World, val type: KClass) : EventListener { + + private var callback: S.() -> Unit = {} + private var predicate: S.() -> Boolean = { true } + + fun where(predicate: S.() -> Boolean): OldKotlinEventHandler { + this.predicate = predicate + return this + } + + fun then(callback: S.() -> Unit) { + this.callback = callback + this.register() + } + + override fun handle(event: S) { + if (event.predicate()) { + event.callback() + } + } + + fun register() = world.listenFor(type.java, this) +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinPlayerEventHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinPlayerEventHandler.kt new file mode 100644 index 000000000..8a127037b --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/OldKotlinPlayerEventHandler.kt @@ -0,0 +1,21 @@ +package org.apollo.game.plugin.kotlin + +import org.apollo.game.model.World +import org.apollo.game.model.entity.Player +import org.apollo.game.model.event.EventListener +import org.apollo.game.model.event.PlayerEvent +import kotlin.reflect.KClass + +/** + * A handler for [PlayerEvent]s. + */ +@Deprecated("To be removed") +class OldKotlinPlayerEventHandler(val world: World, val type: KClass) : + KotlinPlayerHandlerProxyTrait, EventListener { + + override var callback: T.(Player) -> Unit = {} + override var predicate: T.() -> Boolean = { true } + + override fun handle(event: T) = handleProxy(event.player, event) + override fun register() = world.listenFor(type.java, this) +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/ActionListenableContext.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/ActionListenableContext.kt new file mode 100644 index 000000000..d362b7168 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/ActionListenableContext.kt @@ -0,0 +1,33 @@ +package org.apollo.game.plugin.kotlin.action + +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.kotlin.KotlinPluginScript +import org.apollo.game.plugin.kotlin.ListenableContext +import org.apollo.game.plugin.kotlin.MessageListenable +import org.apollo.net.message.Message + +/** + * Registers a listener for an action event that uses the given [option] (case-insensitive). + * + * ``` + * on(PlayerAction, option = "Trade") { + * player.sendMessage("Sending trade request...") + * } + * ``` + */ +inline fun KotlinPluginScript.on( + listenable: MessageListenable, + option: String, + crossinline callback: T.() -> Unit +) { + on(listenable) { + if (this.option.equals(option, ignoreCase = true)) { + callback() + } + } +} + +interface ActionListenableContext : ListenableContext { + val option: String + val player: Player +} diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/InteractiveObject.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/InteractiveObject.kt new file mode 100644 index 000000000..fe903ce5b --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/InteractiveObject.kt @@ -0,0 +1,14 @@ +package org.apollo.game.plugin.kotlin.action.obj + +import org.apollo.game.model.entity.obj.GameObject + +/** + * An object that can be interacted with. + */ +interface InteractiveObject { + + val id: Int + + fun instanceOf(other: GameObject): Boolean // TODO alternative name? + +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ListenableDsl.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ListenableDsl.kt new file mode 100644 index 000000000..2ed023c74 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ListenableDsl.kt @@ -0,0 +1,79 @@ +package org.apollo.game.plugin.kotlin.action.obj + +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.message.handler.MessageHandler +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.World +import org.apollo.game.model.entity.EntityType +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.kotlin.KotlinPluginScript +import org.apollo.game.plugin.kotlin.action.on + +@Deprecated("example function, remove") +fun KotlinPluginScript.x() { + on(ObjectAction, option = "Trade", objects = listOf()) { + + } + + on(ObjectAction, option = "Trade") { + + } +} + +/** + * Registers a listener for [ObjectActionMessage]s that occur on any of the given [InteractiveObject]s using the + * given [option] (case-insensitive). + * + * ``` + * on(ObjectAction, option = "Open", objects = DOORS.toList()) { + * player.sendMessage("You open the door") + * } + * ``` + */ +fun KotlinPluginScript.on( + listenable: ObjectActionListenable, + option: String, + objects: List, + callback: ObjectAction.() -> Unit +) { + if (objects.isEmpty()) { + on(listenable) { + if (this.option.equals(option, ignoreCase = true)) { + @Suppress("UNCHECKED_CAST") (this as ObjectAction) + callback() + } + } + } else { + val handler = ObjectActionMessageHandler(world, listenable, objects, option, callback) + context.addMessageHandler(listenable.type.java, handler) + } +} + +/** + * A [MessageHandler] + */ +class ObjectActionMessageHandler( + world: World, + private val listenable: ObjectActionListenable, + private val objects: List, + private val option: String, + private val callback: ObjectAction.() -> Unit +) : MessageHandler(world) { + + override fun handle(player: Player, message: ObjectActionMessage) { + val def = ObjectDefinition.lookup(message.id) + val selectedAction = def.menuActions[message.option] + + val obj = player.world.regionRepository + .fromPosition(message.position) + .getEntities(message.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) + .first { it.definition == def } + + if (option.equals(selectedAction, ignoreCase = true) && objects.any { it.instanceOf(obj) }) { + val context = listenable.from(player, message, objects) + context.callback() + } + } + +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt new file mode 100644 index 000000000..4533d20af --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt @@ -0,0 +1,53 @@ +package org.apollo.game.plugin.kotlin.action.obj + +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.entity.EntityType +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.kotlin.action.ActionListenableContext + +/** + * An interaction between a [Player] and an [interactive] [GameObject]. + */ +class ObjectAction( + override val option: String, + override val player: Player, + val target: GameObject, + val interactive: T +) : ActionListenableContext { + + companion object : ObjectActionListenable() { + + override fun from(player: Player, message: ObjectActionMessage): ObjectAction<*> { + val def = ObjectDefinition.lookup(message.id) + val selectedAction = def.menuActions[message.option] + + val obj = player.world.regionRepository + .fromPosition(message.position) + .getEntities(message.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) + .first { it.definition == def } + + return ObjectAction(selectedAction, player, obj, null) + } + + override val type = ObjectActionMessage::class + + override fun from( + player: Player, + other: ObjectActionMessage, + objects: List + ): ObjectAction { + val def = ObjectDefinition.lookup(other.id) + val selectedAction = def.menuActions[other.option] + + val obj = player.world.regionRepository + .fromPosition(other.position) + .getEntities(other.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) + .first { it.definition == def } + + return ObjectAction(selectedAction, player, obj, objects.first { it.instanceOf(obj) }) + } + } + +} diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectActionListenable.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectActionListenable.kt new file mode 100644 index 000000000..fc37d5596 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectActionListenable.kt @@ -0,0 +1,17 @@ +package org.apollo.game.plugin.kotlin.action.obj + +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.kotlin.MessageListenable + +abstract class ObjectActionListenable : MessageListenable, ObjectActionMessage>() { + + override val type = ObjectActionMessage::class + + abstract fun from( + player: Player, + other: ObjectActionMessage, + objects: List + ): ObjectAction + +} \ No newline at end of file From 8fb0c8f3dfd8056a3c848fc3e37d20024c5e5955 Mon Sep 17 00:00:00 2001 From: Major Date: Mon, 22 Jul 2019 23:55:12 +0100 Subject: [PATCH 204/209] Reorganise kotlin message handlers --- .../plugin/kotlin/KotlinCommandHandler.kt | 22 +++++-- .../plugin/kotlin/KotlinMessageHandler.kt | 8 +-- .../game/plugin/kotlin/KotlinPluginScript.kt | 16 ++--- .../apollo/game/plugin/kotlin/Listenable.kt | 20 +++---- .../game/plugin/kotlin/ListenableContext.kt | 11 +++- .../plugin/kotlin/action/obj/ObjectAction.kt | 53 ---------------- .../action/ActionContext.kt} | 12 ++-- .../action/obj/InteractiveObject.kt | 2 +- .../kotlin/message/action/obj/ObjectAction.kt | 60 +++++++++++++++++++ .../action/obj/ObjectActionListenable.kt | 8 +-- .../action/obj/ObjectActionMessageHandler.kt} | 29 ++------- 11 files changed, 125 insertions(+), 116 deletions(-) delete mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt rename game/src/main/kotlin/org/apollo/game/plugin/kotlin/{action/ActionListenableContext.kt => message/action/ActionContext.kt} (62%) rename game/src/main/kotlin/org/apollo/game/plugin/kotlin/{ => message}/action/obj/InteractiveObject.kt (79%) create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt rename game/src/main/kotlin/org/apollo/game/plugin/kotlin/{ => message}/action/obj/ObjectActionListenable.kt (67%) rename game/src/main/kotlin/org/apollo/game/plugin/kotlin/{action/obj/ListenableDsl.kt => message/action/obj/ObjectActionMessageHandler.kt} (74%) diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt index a939e44c5..4509eaa2f 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinCommandHandler.kt @@ -13,17 +13,29 @@ class KotlinCommandHandler( val world: World, val command: String, privileges: PrivilegeLevel -) : KotlinPlayerHandlerProxyTrait, CommandListener(privileges) { +) : CommandListener(privileges) { - override var callback: Command.(Player) -> Unit = {} - override var predicate: Command.() -> Boolean = { true } + var callback: Command.(Player) -> Unit = {} + var predicate: Command.() -> Boolean = { true } override fun execute(player: Player, command: Command) { - handleProxy(player, command) + if (command.predicate()) { + command.callback(player) + } } - override fun register() { + fun register() { world.commandDispatcher.register(command, this) } + fun where(predicate: Command.() -> Boolean): KotlinCommandHandler { + this.predicate = predicate + return this + } + + fun then(callback: Command.(Player) -> Unit) { + this.callback = callback + this.register() + } + } \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt index f6e1ec4cc..6882cc2ed 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt @@ -7,15 +7,15 @@ import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message import kotlin.reflect.KClass -class KotlinMessageHandler( +class KotlinMessageHandler( world: World, - private val listenable: MessageListenable, + private val listenable: MessageListenable, private val callback: T.() -> Unit ) : MessageHandler(world) { override fun handle(player: Player, message: F) { - val context = listenable.from(player, message) - context.callback() + val context = listenable.createContext(player, message) + context?.callback() } } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index 51cfbd121..cadd4629f 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -20,34 +20,34 @@ abstract class KotlinPluginScript(var world: World, val context: PluginContext) private var stopListener: (World) -> Unit = { _ -> } - fun on(listenable: Listenable, callback: T.() -> Unit) { + fun on(listenable: Listenable, callback: C.() -> Unit) { // Smart-casting/type-inference is completely broken in this function in intelliJ, so assign to otherwise // pointless `l` values for now. return when (listenable) { is MessageListenable -> { @Suppress("UNCHECKED_CAST") - val l = listenable as MessageListenable + val l = listenable as MessageListenable val handler = KotlinMessageHandler(world, l, callback) context.addMessageHandler(l.type.java, handler) } is PlayerEventListenable -> { @Suppress("UNCHECKED_CAST") - val l = listenable as PlayerEventListenable + val l = listenable as PlayerEventListenable world.listenFor(l.type.java) { event -> - val context = l.from(event) - context.callback() + val context = l.createContext(event) + context?.callback() } } is EventListenable -> { @Suppress("UNCHECKED_CAST") - val l = listenable as EventListenable + val l = listenable as EventListenable world.listenFor(l.type.java) { event -> - val context = l.from(event) - context.callback() + val context = l.createContext(event) + context?.callback() } } } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt index 17cef5a05..14e9efbe4 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt @@ -9,24 +9,24 @@ import kotlin.reflect.KClass /** * A game occurrence that can be listened to. */ -sealed class Listenable { - abstract val type: KClass +sealed class Listenable { + abstract val type: KClass } -abstract class EventListenable : Listenable() { - abstract fun from(event: F): T +abstract class EventListenable : Listenable() { + abstract fun createContext(event: T): C? } -abstract class MessageListenable : Listenable() { - abstract fun from(player: Player, message: F): T +abstract class MessageListenable : Listenable() { + abstract fun createContext(player: Player, message: T): C? } -abstract class PlayerEventListenable : EventListenable() { +abstract class PlayerEventListenable : EventListenable() { - abstract fun from(player: Player, event: F): T + abstract fun createContext(player: Player, event: T): C? - override fun from(event: F): T { - return from(event.player, event) + final override fun createContext(event: T): C? { + return createContext(event.player, event) } } \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt index 02ae45a3f..5f5fef957 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt @@ -1,6 +1,15 @@ package org.apollo.game.plugin.kotlin +import org.apollo.game.model.entity.Player + /** - * Contains contextual information for a [Listenable]. + * Contextual information for a [Listenable]. */ interface ListenableContext + +/** + * Contextual information for a [Listenable] involving a specific [Player]. + */ +interface PlayerContext : ListenableContext { + val player: Player +} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt deleted file mode 100644 index 4533d20af..000000000 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectAction.kt +++ /dev/null @@ -1,53 +0,0 @@ -package org.apollo.game.plugin.kotlin.action.obj - -import org.apollo.cache.def.ObjectDefinition -import org.apollo.game.message.impl.ObjectActionMessage -import org.apollo.game.model.entity.EntityType -import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.plugin.kotlin.action.ActionListenableContext - -/** - * An interaction between a [Player] and an [interactive] [GameObject]. - */ -class ObjectAction( - override val option: String, - override val player: Player, - val target: GameObject, - val interactive: T -) : ActionListenableContext { - - companion object : ObjectActionListenable() { - - override fun from(player: Player, message: ObjectActionMessage): ObjectAction<*> { - val def = ObjectDefinition.lookup(message.id) - val selectedAction = def.menuActions[message.option] - - val obj = player.world.regionRepository - .fromPosition(message.position) - .getEntities(message.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) - .first { it.definition == def } - - return ObjectAction(selectedAction, player, obj, null) - } - - override val type = ObjectActionMessage::class - - override fun from( - player: Player, - other: ObjectActionMessage, - objects: List - ): ObjectAction { - val def = ObjectDefinition.lookup(other.id) - val selectedAction = def.menuActions[other.option] - - val obj = player.world.regionRepository - .fromPosition(other.position) - .getEntities(other.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) - .first { it.definition == def } - - return ObjectAction(selectedAction, player, obj, objects.first { it.instanceOf(obj) }) - } - } - -} diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/ActionListenableContext.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/ActionContext.kt similarity index 62% rename from game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/ActionListenableContext.kt rename to game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/ActionContext.kt index d362b7168..95863ddd4 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/ActionListenableContext.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/ActionContext.kt @@ -1,9 +1,8 @@ -package org.apollo.game.plugin.kotlin.action +package org.apollo.game.plugin.kotlin.message.action -import org.apollo.game.model.entity.Player import org.apollo.game.plugin.kotlin.KotlinPluginScript -import org.apollo.game.plugin.kotlin.ListenableContext import org.apollo.game.plugin.kotlin.MessageListenable +import org.apollo.game.plugin.kotlin.PlayerContext import org.apollo.net.message.Message /** @@ -15,8 +14,8 @@ import org.apollo.net.message.Message * } * ``` */ -inline fun KotlinPluginScript.on( - listenable: MessageListenable, +inline fun KotlinPluginScript.on( + listenable: MessageListenable, option: String, crossinline callback: T.() -> Unit ) { @@ -27,7 +26,6 @@ inline fun KotlinPluginScript } } -interface ActionListenableContext : ListenableContext { +interface ActionContext : PlayerContext { val option: String - val player: Player } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/InteractiveObject.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/InteractiveObject.kt similarity index 79% rename from game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/InteractiveObject.kt rename to game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/InteractiveObject.kt index fe903ce5b..85e2c6957 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/InteractiveObject.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/InteractiveObject.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.kotlin.action.obj +package org.apollo.game.plugin.kotlin.message.action.obj import org.apollo.game.model.entity.obj.GameObject diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt new file mode 100644 index 000000000..db4bab0d8 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt @@ -0,0 +1,60 @@ +package org.apollo.game.plugin.kotlin.message.action.obj + +import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.entity.EntityType +import org.apollo.game.model.entity.Player +import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.kotlin.message.action.ActionContext + +/** + * An interaction between a [Player] and an [interactive] [GameObject]. + */ +class ObjectAction( // TODO split into two classes, one with T and one without? + override val player: Player, + override val option: String, + val target: GameObject, + val interactive: T +) : ActionContext { + + companion object : ObjectActionListenable() { + + override val type = ObjectActionMessage::class + + override fun createContext(player: Player, message: ObjectActionMessage): ObjectAction<*>? { + return create(player, message, objects = null) + } + + override fun createContext( + player: Player, + other: ObjectActionMessage, + objects: List + ): ObjectAction? { + @Suppress("UNCHECKED_CAST") + return create(player, other, objects) as ObjectAction + } + + private fun create( + player: Player, + other: ObjectActionMessage, + objects: List? + ): ObjectAction<*>? { + val def = ObjectDefinition.lookup(other.id) + val selectedAction = def.menuActions[other.option] + + val obj = player.world.regionRepository + .fromPosition(other.position) + .getEntities(other.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) + .find { it.definition == def } + ?: return null + + if (objects == null) { + return ObjectAction(player, selectedAction, obj, null) + } else { + val interactive = objects.find { it.instanceOf(obj) } ?: return null + return ObjectAction(player, selectedAction, obj, interactive) + } + } + } + +} diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectActionListenable.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionListenable.kt similarity index 67% rename from game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectActionListenable.kt rename to game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionListenable.kt index fc37d5596..bf9bfbf68 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ObjectActionListenable.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionListenable.kt @@ -1,17 +1,17 @@ -package org.apollo.game.plugin.kotlin.action.obj +package org.apollo.game.plugin.kotlin.message.action.obj import org.apollo.game.message.impl.ObjectActionMessage import org.apollo.game.model.entity.Player import org.apollo.game.plugin.kotlin.MessageListenable -abstract class ObjectActionListenable : MessageListenable, ObjectActionMessage>() { +abstract class ObjectActionListenable : MessageListenable>() { override val type = ObjectActionMessage::class - abstract fun from( + abstract fun createContext( player: Player, other: ObjectActionMessage, objects: List - ): ObjectAction + ): ObjectAction? } \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ListenableDsl.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionMessageHandler.kt similarity index 74% rename from game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ListenableDsl.kt rename to game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionMessageHandler.kt index 2ed023c74..fa3e5de74 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/action/obj/ListenableDsl.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionMessageHandler.kt @@ -1,4 +1,4 @@ -package org.apollo.game.plugin.kotlin.action.obj +package org.apollo.game.plugin.kotlin.message.action.obj import org.apollo.cache.def.ObjectDefinition import org.apollo.game.message.handler.MessageHandler @@ -8,18 +8,6 @@ import org.apollo.game.model.entity.EntityType import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.GameObject import org.apollo.game.plugin.kotlin.KotlinPluginScript -import org.apollo.game.plugin.kotlin.action.on - -@Deprecated("example function, remove") -fun KotlinPluginScript.x() { - on(ObjectAction, option = "Trade", objects = listOf()) { - - } - - on(ObjectAction, option = "Trade") { - - } -} /** * Registers a listener for [ObjectActionMessage]s that occur on any of the given [InteractiveObject]s using the @@ -27,7 +15,7 @@ fun KotlinPluginScript.x() { * * ``` * on(ObjectAction, option = "Open", objects = DOORS.toList()) { - * player.sendMessage("You open the door") + * player.sendMessage("You open the door.") * } * ``` */ @@ -39,10 +27,8 @@ fun KotlinPluginScript.on( ) { if (objects.isEmpty()) { on(listenable) { - if (this.option.equals(option, ignoreCase = true)) { - @Suppress("UNCHECKED_CAST") (this as ObjectAction) - callback() - } + @Suppress("UNCHECKED_CAST") (callback as ObjectAction<*>.() -> Unit) + callback(this) } } else { val handler = ObjectActionMessageHandler(world, listenable, objects, option, callback) @@ -50,9 +36,6 @@ fun KotlinPluginScript.on( } } -/** - * A [MessageHandler] - */ class ObjectActionMessageHandler( world: World, private val listenable: ObjectActionListenable, @@ -71,8 +54,8 @@ class ObjectActionMessageHandler( .first { it.definition == def } if (option.equals(selectedAction, ignoreCase = true) && objects.any { it.instanceOf(obj) }) { - val context = listenable.from(player, message, objects) - context.callback() + val context = listenable.createContext(player, message, objects) + context?.callback() } } From ed8611be01b824885f01b5a7327bd16404de5523 Mon Sep 17 00:00:00 2001 From: Major Date: Mon, 22 Jul 2019 23:55:39 +0100 Subject: [PATCH 205/209] Add ButtonClick message handler --- .../game/plugin/kotlin/message/ButtonClick.kt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt new file mode 100644 index 000000000..ae004e872 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt @@ -0,0 +1,40 @@ +package org.apollo.game.plugin.kotlin.message + +import org.apollo.game.message.impl.ButtonMessage +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.kotlin.KotlinPluginScript +import org.apollo.game.plugin.kotlin.MessageListenable +import org.apollo.game.plugin.kotlin.PlayerContext + +/** + * Registers a listener for [ButtonMessage]s that occur on the given [button] id. + * + * ``` + * on(ButtonClick, button = 416) { + * player.sendMessage("You click the button.") + * } + * ``` + */ +fun KotlinPluginScript.on( + listenable: ButtonClick.Companion, + button: Int, + callback: ButtonClick.() -> Unit +) { + on(listenable) { + if (this.button == button) { + callback() + } + } +} + +class ButtonClick(override val player: Player, val button: Int) : PlayerContext { + + companion object : MessageListenable() { + override val type = ButtonMessage::class + + override fun createContext(player: Player, message: ButtonMessage): ButtonClick { + return ButtonClick(player, message.widgetId) + } + } + +} \ No newline at end of file From 12b4bef1f828191fc0cdde82db6b21a3d75ca7d5 Mon Sep 17 00:00:00 2001 From: Major Date: Tue, 23 Jul 2019 02:03:28 +0100 Subject: [PATCH 206/209] Create raw handlers in plugin listener overloads --- .../plugin/kotlin/KotlinMessageHandler.kt | 13 --- .../game/plugin/kotlin/KotlinPluginScript.kt | 34 +++--- .../apollo/game/plugin/kotlin/Listenable.kt | 25 ++-- .../game/plugin/kotlin/ListenableContext.kt | 4 +- .../game/plugin/kotlin/message/ButtonClick.kt | 34 ++++-- .../kotlin/message/action/ActionContext.kt | 15 ++- .../kotlin/message/action/obj/ObjectAction.kt | 110 +++++++++++++----- .../action/obj/ObjectActionListenable.kt | 17 --- .../action/obj/ObjectActionMessageHandler.kt | 62 ---------- .../obj/ObjectActionPredicateContext.kt | 8 ++ 10 files changed, 149 insertions(+), 173 deletions(-) delete mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionListenable.kt delete mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionMessageHandler.kt create mode 100644 game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionPredicateContext.kt diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt index 6882cc2ed..799db9dc9 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinMessageHandler.kt @@ -7,19 +7,6 @@ import org.apollo.game.plugin.PluginContext import org.apollo.net.message.Message import kotlin.reflect.KClass -class KotlinMessageHandler( - world: World, - private val listenable: MessageListenable, - private val callback: T.() -> Unit -) : MessageHandler(world) { - - override fun handle(player: Player, message: F) { - val context = listenable.createContext(player, message) - context?.callback() - } - -} - /** * A handler for [Message]s. */ diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt index cadd4629f..37bdfdfca 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/KotlinPluginScript.kt @@ -20,35 +20,35 @@ abstract class KotlinPluginScript(var world: World, val context: PluginContext) private var stopListener: (World) -> Unit = { _ -> } - fun on(listenable: Listenable, callback: C.() -> Unit) { + fun on( + listenable: Listenable, + callback: C.() -> Unit + ) { + registerListener(listenable, null, callback) + } + + internal fun registerListener( + listenable: Listenable, + predicateContext: I?, + callback: C.() -> Unit + ) { // Smart-casting/type-inference is completely broken in this function in intelliJ, so assign to otherwise // pointless `l` values for now. return when (listenable) { is MessageListenable -> { @Suppress("UNCHECKED_CAST") - val l = listenable as MessageListenable + val l = listenable as MessageListenable - val handler = KotlinMessageHandler(world, l, callback) + val handler = l.createHandler(world, predicateContext, callback) context.addMessageHandler(l.type.java, handler) } - is PlayerEventListenable -> { - @Suppress("UNCHECKED_CAST") - val l = listenable as PlayerEventListenable - - world.listenFor(l.type.java) { event -> - val context = l.createContext(event) - context?.callback() - } - } is EventListenable -> { @Suppress("UNCHECKED_CAST") - val l = listenable as EventListenable + val l = listenable as EventListenable - world.listenFor(l.type.java) { event -> - val context = l.createContext(event) - context?.callback() - } + val handler = l.createHandler(world, predicateContext, callback) + world.listenFor(l.type.java, handler) } } } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt index 14e9efbe4..9a89fa641 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/Listenable.kt @@ -1,32 +1,27 @@ package org.apollo.game.plugin.kotlin -import org.apollo.game.model.entity.Player +import org.apollo.game.message.handler.MessageHandler +import org.apollo.game.model.World import org.apollo.game.model.event.Event -import org.apollo.game.model.event.PlayerEvent +import org.apollo.game.model.event.EventListener import org.apollo.net.message.Message import kotlin.reflect.KClass /** * A game occurrence that can be listened to. */ -sealed class Listenable { +sealed class Listenable { abstract val type: KClass } -abstract class EventListenable : Listenable() { - abstract fun createContext(event: T): C? -} +abstract class EventListenable : Listenable() { -abstract class MessageListenable : Listenable() { - abstract fun createContext(player: Player, message: T): C? -} + abstract fun createHandler(world: World, predicateContext: P?, callback: C.() -> Unit): EventListener -abstract class PlayerEventListenable : EventListenable() { +} - abstract fun createContext(player: Player, event: T): C? +abstract class MessageListenable : Listenable() { - final override fun createContext(event: T): C? { - return createContext(event.player, event) - } + abstract fun createHandler(world: World, predicateContext: P?, callback: C.() -> Unit): MessageHandler -} \ No newline at end of file +} diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt index 5f5fef957..760644a4f 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/ListenableContext.kt @@ -12,4 +12,6 @@ interface ListenableContext */ interface PlayerContext : ListenableContext { val player: Player -} \ No newline at end of file +} + +interface PredicateContext \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt index ae004e872..1b62dbf1f 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/ButtonClick.kt @@ -1,10 +1,13 @@ package org.apollo.game.plugin.kotlin.message +import org.apollo.game.message.handler.MessageHandler import org.apollo.game.message.impl.ButtonMessage +import org.apollo.game.model.World import org.apollo.game.model.entity.Player import org.apollo.game.plugin.kotlin.KotlinPluginScript import org.apollo.game.plugin.kotlin.MessageListenable import org.apollo.game.plugin.kotlin.PlayerContext +import org.apollo.game.plugin.kotlin.PredicateContext /** * Registers a listener for [ButtonMessage]s that occur on the given [button] id. @@ -20,21 +23,34 @@ fun KotlinPluginScript.on( button: Int, callback: ButtonClick.() -> Unit ) { - on(listenable) { - if (this.button == button) { - callback() - } - } + registerListener(listenable, ButtonPredicateContext(button), callback) } class ButtonClick(override val player: Player, val button: Int) : PlayerContext { - companion object : MessageListenable() { + companion object : MessageListenable() { + override val type = ButtonMessage::class + + override fun createHandler( + world: World, + predicateContext: ButtonPredicateContext?, + callback: ButtonClick.() -> Unit + ): MessageHandler { + return object : MessageHandler(world) { + + override fun handle(player: Player, message: ButtonMessage) { + if (predicateContext == null || predicateContext.button == message.widgetId) { + val context = ButtonClick(player, message.widgetId) + context.callback() + } + } - override fun createContext(player: Player, message: ButtonMessage): ButtonClick { - return ButtonClick(player, message.widgetId) + } } + } -} \ No newline at end of file +} + +class ButtonPredicateContext(val button: Int) : PredicateContext \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/ActionContext.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/ActionContext.kt index 95863ddd4..e8ddfb4a5 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/ActionContext.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/ActionContext.kt @@ -3,6 +3,7 @@ package org.apollo.game.plugin.kotlin.message.action import org.apollo.game.plugin.kotlin.KotlinPluginScript import org.apollo.game.plugin.kotlin.MessageListenable import org.apollo.game.plugin.kotlin.PlayerContext +import org.apollo.game.plugin.kotlin.PredicateContext import org.apollo.net.message.Message /** @@ -14,18 +15,16 @@ import org.apollo.net.message.Message * } * ``` */ -inline fun KotlinPluginScript.on( - listenable: MessageListenable, +fun KotlinPluginScript.on( + listenable: MessageListenable, option: String, - crossinline callback: T.() -> Unit + callback: T.() -> Unit ) { - on(listenable) { - if (this.option.equals(option, ignoreCase = true)) { - callback() - } - } + registerListener(listenable, ActionPredicateContext(option), callback) } interface ActionContext : PlayerContext { val option: String } + +open class ActionPredicateContext(open val option: String) : PredicateContext \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt index db4bab0d8..2bb0b7902 100644 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectAction.kt @@ -1,12 +1,60 @@ package org.apollo.game.plugin.kotlin.message.action.obj import org.apollo.cache.def.ObjectDefinition +import org.apollo.game.message.handler.MessageHandler import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.World import org.apollo.game.model.entity.EntityType import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.obj.GameObject +import org.apollo.game.plugin.kotlin.KotlinPluginScript +import org.apollo.game.plugin.kotlin.MessageListenable import org.apollo.game.plugin.kotlin.message.action.ActionContext +/** + * Registers a listener for [ObjectActionMessage]s that occur on any of the given [InteractiveObject]s using the + * given [option] (case-insensitive). + * + * ``` + * on(ObjectAction, option = "Open", objects = DOORS.toList()) { + * player.sendMessage("You open the door.") + * } + * ``` + */ +fun KotlinPluginScript.on( + listenable: ObjectAction.Companion, + option: String, + objects: List, + callback: ObjectAction.() -> Unit +) { + @Suppress("UNCHECKED_CAST") (callback as ObjectAction<*>.() -> Unit) + registerListener(listenable, ObjectActionPredicateContext(option, objects), callback) +} + +/** + * Registers a listener for [ObjectActionMessage]s that occur on any of the given [InteractiveObject]s using the + * given [option] (case-insensitive). + * + * ``` + * on(ObjectAction, option = "Open", objects = DOORS.toList()) { + * player.sendMessage("You open the door.") + * } + * ``` + */ +fun KotlinPluginScript.on( + listenable: ObjectAction.Companion, + option: String, + callback: ObjectAction<*>.() -> Unit +) { + registerListener(listenable, ObjectActionPredicateContext(option, emptyList()), callback) +} + +fun KotlinPluginScript.x() { + on(ObjectAction, "walk") { + + } +} + /** * An interaction between a [Player] and an [interactive] [GameObject]. */ @@ -17,44 +65,44 @@ class ObjectAction( // TODO split into two classes, one val interactive: T ) : ActionContext { - companion object : ObjectActionListenable() { + companion object : MessageListenable, ObjectActionPredicateContext<*>>() { override val type = ObjectActionMessage::class - override fun createContext(player: Player, message: ObjectActionMessage): ObjectAction<*>? { - return create(player, message, objects = null) - } + override fun createHandler( + world: World, + predicateContext: ObjectActionPredicateContext<*>?, + callback: ObjectAction<*>.() -> Unit + ): MessageHandler { + return object : MessageHandler(world) { - override fun createContext( - player: Player, - other: ObjectActionMessage, - objects: List - ): ObjectAction? { - @Suppress("UNCHECKED_CAST") - return create(player, other, objects) as ObjectAction - } + override fun handle(player: Player, message: ObjectActionMessage) { + val def = ObjectDefinition.lookup(message.id) + val option = def.menuActions[message.option] + + val target = world.regionRepository + .fromPosition(message.position) + .getEntities(message.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) + .find { it.definition == def } + ?: return // Could happen if object was despawned this tick, before calling this handle function + + val context = when { // Evaluation-order matters here. + predicateContext == null -> ObjectAction(player, option, target, null) + !predicateContext.option.equals(option, ignoreCase = true) -> return + predicateContext.objects.isEmpty() -> ObjectAction(player, option, target, null) + predicateContext.objects.any { it.instanceOf(target) } -> { + val interactive = predicateContext.objects.find { it.instanceOf(target) } ?: return + ObjectAction(player, option, target, interactive) + } + else -> return + } + + context.callback() + } - private fun create( - player: Player, - other: ObjectActionMessage, - objects: List? - ): ObjectAction<*>? { - val def = ObjectDefinition.lookup(other.id) - val selectedAction = def.menuActions[other.option] - - val obj = player.world.regionRepository - .fromPosition(other.position) - .getEntities(other.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) - .find { it.definition == def } - ?: return null - - if (objects == null) { - return ObjectAction(player, selectedAction, obj, null) - } else { - val interactive = objects.find { it.instanceOf(obj) } ?: return null - return ObjectAction(player, selectedAction, obj, interactive) } } + } } diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionListenable.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionListenable.kt deleted file mode 100644 index bf9bfbf68..000000000 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionListenable.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.apollo.game.plugin.kotlin.message.action.obj - -import org.apollo.game.message.impl.ObjectActionMessage -import org.apollo.game.model.entity.Player -import org.apollo.game.plugin.kotlin.MessageListenable - -abstract class ObjectActionListenable : MessageListenable>() { - - override val type = ObjectActionMessage::class - - abstract fun createContext( - player: Player, - other: ObjectActionMessage, - objects: List - ): ObjectAction? - -} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionMessageHandler.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionMessageHandler.kt deleted file mode 100644 index fa3e5de74..000000000 --- a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionMessageHandler.kt +++ /dev/null @@ -1,62 +0,0 @@ -package org.apollo.game.plugin.kotlin.message.action.obj - -import org.apollo.cache.def.ObjectDefinition -import org.apollo.game.message.handler.MessageHandler -import org.apollo.game.message.impl.ObjectActionMessage -import org.apollo.game.model.World -import org.apollo.game.model.entity.EntityType -import org.apollo.game.model.entity.Player -import org.apollo.game.model.entity.obj.GameObject -import org.apollo.game.plugin.kotlin.KotlinPluginScript - -/** - * Registers a listener for [ObjectActionMessage]s that occur on any of the given [InteractiveObject]s using the - * given [option] (case-insensitive). - * - * ``` - * on(ObjectAction, option = "Open", objects = DOORS.toList()) { - * player.sendMessage("You open the door.") - * } - * ``` - */ -fun KotlinPluginScript.on( - listenable: ObjectActionListenable, - option: String, - objects: List, - callback: ObjectAction.() -> Unit -) { - if (objects.isEmpty()) { - on(listenable) { - @Suppress("UNCHECKED_CAST") (callback as ObjectAction<*>.() -> Unit) - callback(this) - } - } else { - val handler = ObjectActionMessageHandler(world, listenable, objects, option, callback) - context.addMessageHandler(listenable.type.java, handler) - } -} - -class ObjectActionMessageHandler( - world: World, - private val listenable: ObjectActionListenable, - private val objects: List, - private val option: String, - private val callback: ObjectAction.() -> Unit -) : MessageHandler(world) { - - override fun handle(player: Player, message: ObjectActionMessage) { - val def = ObjectDefinition.lookup(message.id) - val selectedAction = def.menuActions[message.option] - - val obj = player.world.regionRepository - .fromPosition(message.position) - .getEntities(message.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT) - .first { it.definition == def } - - if (option.equals(selectedAction, ignoreCase = true) && objects.any { it.instanceOf(obj) }) { - val context = listenable.createContext(player, message, objects) - context?.callback() - } - } - -} \ No newline at end of file diff --git a/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionPredicateContext.kt b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionPredicateContext.kt new file mode 100644 index 000000000..42a643998 --- /dev/null +++ b/game/src/main/kotlin/org/apollo/game/plugin/kotlin/message/action/obj/ObjectActionPredicateContext.kt @@ -0,0 +1,8 @@ +package org.apollo.game.plugin.kotlin.message.action.obj + +import org.apollo.game.plugin.kotlin.message.action.ActionPredicateContext + +data class ObjectActionPredicateContext( + override val option: String, + val objects: List +) : ActionPredicateContext(option) \ No newline at end of file From 0e9104242872971a173b89bf52e9adebca370eba Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 12 Oct 2019 02:50:11 +0100 Subject: [PATCH 207/209] Update slack invite link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 208f7ba20..ff765949f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Apollo is a high-performance, modular RuneScape emulator with a collection of ut ### Developer information -Most discussion related to the development of Apollo happens on our [Slack team](https://join.slack.com/t/apollo-rsps/shared_invite/enQtMjQ0NTYwNzkwMjExLTI5NGVmOWZjZGRkYzY4NjM1MjgxNjYyYmEyZWQxMzcxZTA5NDM1MGJkNmRkMjc2ZDQ2NjUwMjAzOGI1NjY1Zjk). If you have a problem and can't get in touch with anyone, create a GitHub issue. If making a pull request, please make sure all tests are still passing after making your changes, and that your code style is consistent with the rest of Apollo. +Most discussion related to the development of Apollo happens on our [Slack team](https://join.slack.com/t/apollo-rsps/shared_invite/enQtMjQ0NTYwNzkwMjExLTdlZDJjZTUxODA5NDdjYTQ1ZGM0YjgwN2I3ZjlkZmVmMGIwZTA3Y2M3ZDI5NTk3N2ZjN2VmNzYwZDk4NmE4ZjE). If you have a problem and can't get in touch with anyone, create a GitHub issue. If making a pull request, please make sure all tests are still passing after making your changes, and that your code style is consistent with the rest of Apollo. ### Getting started From 2c57070e659035d1bc2d0f1f47002119f00afa3f Mon Sep 17 00:00:00 2001 From: Major Date: Sat, 29 Feb 2020 19:17:13 +0000 Subject: [PATCH 208/209] Add discord link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff765949f..fca367c15 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Apollo is a high-performance, modular RuneScape emulator with a collection of ut ### Developer information -Most discussion related to the development of Apollo happens on our [Slack team](https://join.slack.com/t/apollo-rsps/shared_invite/enQtMjQ0NTYwNzkwMjExLTdlZDJjZTUxODA5NDdjYTQ1ZGM0YjgwN2I3ZjlkZmVmMGIwZTA3Y2M3ZDI5NTk3N2ZjN2VmNzYwZDk4NmE4ZjE). If you have a problem and can't get in touch with anyone, create a GitHub issue. If making a pull request, please make sure all tests are still passing after making your changes, and that your code style is consistent with the rest of Apollo. +Most discussion related to the development of Apollo happens on our [Discord](https://discord.gg/Fuft67P). If you have a problem and can't get in touch with anyone, create a GitHub issue. If making a pull request, please make sure all tests are still passing after making your changes, and that your code style is consistent with the rest of Apollo. ### Getting started From 30d953448011147384cbea49c8e98d0cf45dbf74 Mon Sep 17 00:00:00 2001 From: Greg Date: Thu, 21 May 2020 19:52:41 +0100 Subject: [PATCH 209/209] Fix NPC vertical movement --- .../game/model/entity/path/SimplePathfindingAlgorithm.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/game/src/main/java/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java b/game/src/main/java/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java index 421315f83..1affd1278 100644 --- a/game/src/main/java/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java +++ b/game/src/main/java/org/apollo/game/model/entity/path/SimplePathfindingAlgorithm.java @@ -91,7 +91,7 @@ private Deque addHorizontal(Position start, Position target, Deque 0 ? Direction.SOUTH : Direction.NORTH)) { + if (!last.equals(target) && dy != 0 && traversable(last, boundaries, dy > 0 ? Direction.SOUTH : Direction.NORTH)) { return addVertical(last, target, positions); } @@ -143,4 +143,4 @@ && traversable(last, boundaries, dx > 0 ? Direction.WEST : Direction.EAST)) { return positions; } -} \ No newline at end of file +}