diff --git a/docs/build.gradle b/docs/build.gradle new file mode 100644 index 00000000..3c0f4a76 --- /dev/null +++ b/docs/build.gradle @@ -0,0 +1,26 @@ +group 'apollo' +version '0.0.1' + +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3' + } +} + +apply plugin: 'org.asciidoctor.convert' +apply plugin: 'java' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +asciidoctor { + sourceDir = file('src/asciidoc') + outputDir = file('build/docs') +} \ No newline at end of file diff --git a/docs/src/asciidoc/basics/what-is-apollo.adoc b/docs/src/asciidoc/basics/what-is-apollo.adoc new file mode 100644 index 00000000..0100c6d0 --- /dev/null +++ b/docs/src/asciidoc/basics/what-is-apollo.adoc @@ -0,0 +1,10 @@ += What is Apollo? + +Apollo is a high-performance, modular RuneScape emulator with a collection of utilities for managing data files and plugins. +Apollo targets revision 377 of the RuneScape client from late 2006. +It aims to achieve parity with the game server of that time and preserve the history of the game in doing so. + +== Is Apollo free? + +Apollo is open source and made available under the ISC license. +The git repository for the project is hosted under the https://github.com/apollo-rsps[Apollo RSPS organization] on GitHub. diff --git a/docs/src/asciidoc/index.adoc b/docs/src/asciidoc/index.adoc new file mode 100644 index 00000000..513bd217 --- /dev/null +++ b/docs/src/asciidoc/index.adoc @@ -0,0 +1,26 @@ += Apollo Documentation +ifdef::env-github,env-browser[:outfilesuffix: .adoc] + +This is the home of Apollo's documentation. +Below you will find various links + +== The Basics + +* <> + +== Getting Started + +* <> +* <> + +== Authoring plugins for Apollo + +* <> +* <> +* <> +* <> + +== References and Developer Resources + +* Apollo API Documentation[TODO] +* Plugin API Documentation[TODO] diff --git a/docs/src/asciidoc/plugins/creating-a-plugin.adoc b/docs/src/asciidoc/plugins/creating-a-plugin.adoc new file mode 100644 index 00000000..4548ebf7 --- /dev/null +++ b/docs/src/asciidoc/plugins/creating-a-plugin.adoc @@ -0,0 +1,136 @@ +[[getting-started-with-plugins]] += Creating a plugin + +Apollo's plugins are written in http://kotlinlang.org[Kotlin] and are +primarily for content, not core code (if you aren't sure where your code +should go, ask in irc). Note that this tutorial assumes some familiarity +with Kotlin, although good Java knowledge will probably be enough. + +Note: This tutorial is for developing Plugins for the kotlin-experiments +branch prior to the release of the Kotlin plugin system for Apollo. + +[[create-the-working-environment]] +== Create a working environment + +The project maintainers strongly recommend +https://www.jetbrains.com/idea/[IntelliJ IDEA]. + +After starting IDEA, select *checkout project* with the URL: +https://github.com/apollo-rsps/apollo.git and continue. Make sure to +*import using gradle* on the next interface. + +Next, checkout the kotlin-experiments branch. To do this via IntelliJ, +use the navigation bar at the top and 'VCS > Git > Branches > +origin/kotlin-experiments > Checkout as new branch'. Name the new branch +something like kotlin-experiments-my-plugin. + +[[create-the-plugin-metadata]] +== Create the plugin metadata + +Apollo's plugins are stored in */game/plugin*, and each plugin has its +own directory. Create one for your plugin - something like 'myplugin'. + +Inside that, create a directory called 'src', then right click it and +'Mark Directory as > Sources Root'. It should turn blue. + +Inside your plugin's directory (*not* in src) you'll want a +*build.gradle* file, containing something like: + +.... +plugin { + name = "myplugin" + authors = [ "your name" ] +} +.... + + +Sometimes you need to use code from another plugin, which can be done +like so: `dependencies = [ "util:lookup" ]` + +This imports the `lookup` plugin from `util`. + +[[write-the-plugin]] +== Write the plugin + +Plugins are written in kotlin script (_.kts_), which is then transpiled +into Java (bytecode) at compile time. Kotlin script is designed to be +executed like a scripting language: you do *not* need a main function (a +kotlin script consisting of nothing more than `println("Hello, world!")` +will indeed compile and print "Hello, world!"). + +Apollo uses the _.plugin.kts_ extension to mark files as plugin scripts. + +Add a file named 'myplugin.plugin.kts' inside `src` and add the +following code: + +[source,kotlin] +---- +import org.apollo.game.action.Action +import org.apollo.game.message.impl.InventoryItemMessage +import org.apollo.game.model.Item +import org.apollo.game.model.entity.Entity +import org.apollo.game.model.entity.EntityType +import org.apollo.game.model.entity.GroundItem +import org.apollo.game.model.entity.Player + +class DropItemAction(val player: Player, val slot: Int): Action(delay = 0, immediate = true, player) { + + override fun execute() { + val region = player.world.regionRepository.fromPosition(player.position) + + if (region.getEntities(player.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT).isEmpty()) { + val amount = player.inventory.reset(slot)?.amount + if (amount == null) { + return + } + + val item = GroundItem.create(player.world, player.position, Item(item, amount), player) + player.world.spawn(item) + } else { + player.sendMessage("You cannot drop this here.") + } + + stop() + } + +} + +val DROP_OPTION_ID = 5 +val INVENTORY_INTERFACE_ID = 3214 + +on { InventoryItemMessage::class } + .where { option == DROP_OPTION_ID && interfaceId == INVENTORY_INTERFACE_ID } + .then { player -> + player.startAction(DropItemAction(player, slot)) + terminate() + } +---- + +Here we have an *action*, and a *listener*, the two core features of +plugins. + +The `on {...}` lambda at the end is the listener, and listens for +specific event types (typically a *Message* subclass) Here we are +listening to `InventoryItemMessage`s, which are called whenever a player +performs an action on an item in an inventory. + +The `where` clause is used to filter out requests that don't match what +we're looking for: here, we only care about messages where the player +selected the fifth option (used for dropping), and when they selected +that option on an item in the inventory (i.e. the interfaceId matches +the inventory interface id). `where` is executed from the context of the +intercepted message, so `option` and `interfaceId` are actually fields +inside `InventoryItemMessage`. + +The 'then' clause is executed if the `where` lambda evaluates to `true`. + +*Actions* are used to schedule player (or NPC)-related code to be +executed in the future (and optionally, periodically). Plugins also have +actions that can be used to suspend/asynchronously execute code. Here +we're creating an `Action` that removes an item from the player's +inventory and spawns a `GroundItem`. Because `Action`s are scheduled, +`execute()` will be called every server pulse (tick), until the `stop()` +function is called. + +Now you can build it by running `gradle build` in the command line, or +in IntelliJ via 'View > Tool Windows > Gradle > Execute Gradle Task' +(type 'build' for the command). + +Voila! diff --git a/settings.gradle b/settings.gradle index b9ba28b0..c2efa6a8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,6 +3,7 @@ import java.nio.file.Path rootProject.name = 'org.apollo' include ':cache' +include ':docs' include ':game' include ':game:plugin' include ':game:plugin-detekt-rules'