mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-03 00:38:21 +00:00
Merge pull request #366 from apollo-rsps/kotlin-experiments-areas
Port the area actions plugin
This commit is contained in:
@@ -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
|
||||
@@ -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"]
|
||||
}
|
||||
@@ -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<Pair<Area, AreaAction>>()
|
||||
|
||||
class AreaAction(val entrance: AreaListener, val inside: AreaListener, val exit: AreaListener)
|
||||
@@ -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<Area, AreaAction> {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = { _ -> };
|
||||
var startListener: (World) -> Unit = { _ -> }
|
||||
var stopListener: (World) -> Unit = { _ -> }
|
||||
|
||||
/**
|
||||
* Create a new [MessageHandler].
|
||||
*/
|
||||
fun <T : Message> on(type: () -> KClass<T>) = KotlinMessageHandler<T>(world, context, type.invoke())
|
||||
/**
|
||||
* Creates a [MessageHandler].
|
||||
*/
|
||||
fun <T : Message> on(type: () -> KClass<T>) = KotlinMessageHandler(world, context, type.invoke())
|
||||
|
||||
/**
|
||||
* Create a new [EventListener] for a type of [PlayerEvent].
|
||||
*/
|
||||
fun <T : PlayerEvent> on_player_event(type: () -> KClass<T>) = KotlinPlayerEventHandler(world, type.invoke())
|
||||
/**
|
||||
* Create an [EventListener] for a [PlayerEvent].
|
||||
*/
|
||||
fun <T : PlayerEvent> on_player_event(type: () -> KClass<T>) = 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 an [EventListener] for an [Event].
|
||||
*/
|
||||
fun <T : Event> on_event(type: () -> KClass<T>) = KotlinEventHandler(world, type.invoke())
|
||||
|
||||
/**
|
||||
* Create a new [ButtonMessage] [MessageHandler] for the given _button_ id.
|
||||
*/
|
||||
fun on_button(button: Int) = on { ButtonMessage::class }.where { widgetId == button }
|
||||
/**
|
||||
* 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)
|
||||
|
||||
fun start(callback: (World) -> Unit) {
|
||||
this.startListener = callback
|
||||
}
|
||||
/**
|
||||
* Create a [ButtonMessage] [MessageHandler] for the given [id].
|
||||
*/
|
||||
fun on_button(id: Int) = on { ButtonMessage::class }.where { widgetId == id }
|
||||
|
||||
fun stop(callback: (World) -> Unit) {
|
||||
this.stopListener = callback
|
||||
}
|
||||
fun start(callback: (World) -> Unit) {
|
||||
this.startListener = callback
|
||||
}
|
||||
|
||||
fun doStart(world: World) {
|
||||
this.startListener.invoke(world)
|
||||
}
|
||||
fun stop(callback: (World) -> Unit) {
|
||||
this.stopListener = callback
|
||||
}
|
||||
|
||||
fun doStart(world: World) {
|
||||
this.startListener.invoke(world)
|
||||
}
|
||||
|
||||
fun doStop(world: World) {
|
||||
this.stopListener.invoke(world)
|
||||
}
|
||||
|
||||
fun doStop(world: World) {
|
||||
this.stopListener.invoke(world)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A proxy interface for any handler that operates on [Player]s.
|
||||
*/
|
||||
interface KotlinPlayerHandlerProxyTrait<S : Any> {
|
||||
|
||||
var callback: S.(Player) -> Unit
|
||||
var predicate: S.() -> Boolean
|
||||
var callback: S.(Player) -> Unit
|
||||
var predicate: S.() -> Boolean
|
||||
|
||||
fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait<S> {
|
||||
this.predicate = predicate
|
||||
return this
|
||||
}
|
||||
fun register()
|
||||
|
||||
fun then(callback: S.(Player) -> Unit) {
|
||||
this.callback = callback
|
||||
this.register()
|
||||
}
|
||||
fun where(predicate: S.() -> Boolean): KotlinPlayerHandlerProxyTrait<S> {
|
||||
this.predicate = predicate
|
||||
return this
|
||||
}
|
||||
|
||||
fun register()
|
||||
fun then(callback: S.(Player) -> Unit) {
|
||||
this.callback = callback
|
||||
this.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<T : PlayerEvent>(val world: World, val type: KClass<T>) :
|
||||
KotlinPlayerHandlerProxyTrait<T>, EventListener<T> {
|
||||
KotlinPlayerHandlerProxyTrait<T>, EventListener<T> {
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A handler for [Event]s.
|
||||
*/
|
||||
class KotlinEventHandler<S : Event>(val world: World, val type: KClass<S>) : EventListener<S> {
|
||||
|
||||
private var callback: S.() -> Unit = {}
|
||||
private var predicate: S.() -> Boolean = { true }
|
||||
|
||||
fun where(predicate: S.() -> Boolean): KotlinEventHandler<S> {
|
||||
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<T : Message>(val world: World, val context: PluginContext, val type: KClass<T>) :
|
||||
KotlinPlayerHandlerProxyTrait<T>, MessageHandler<T>(world) {
|
||||
KotlinPlayerHandlerProxyTrait<T>, MessageHandler<T>(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<Command>, CommandListener(privileges) {
|
||||
KotlinPlayerHandlerProxyTrait<Command>, 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)
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <T : Message> on(type: () -> KClass<T>): KotlinPlayerHandlerProxyTrait<T> = null!!
|
||||
fun <T : PlayerEvent> on_player_event(type: () -> KClass<T>): KotlinPlayerHandlerProxyTrait<T> = null!!
|
||||
fun <T : Event> on_event(type: () -> KClass<T>): KotlinEventHandler<T> = null!!
|
||||
fun on_command(command: String, privileges: PrivilegeLevel): KotlinPlayerHandlerProxyTrait<Command> = null!!
|
||||
fun on_button(button: Int): KotlinPlayerHandlerProxyTrait<ButtonMessage> = null!!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user