From 0405639ed111da776080a6eef6b550174250bde7 Mon Sep 17 00:00:00 2001 From: Major Date: Mon, 22 Jul 2019 02:34:28 +0100 Subject: [PATCH] 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 | 191 +++++++----------- .../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, 457 insertions(+), 118 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 00000000..a939e44c --- /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 00000000..f6e1ec4c --- /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 00000000..0de3a0f0 --- /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 b3e8eb34..51cfbd12 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) { - /** - * Creates a [MessageHandler]. - */ - fun on(type: () -> KClass) = KotlinMessageHandler(world, context, type.invoke()) + private var startListener: (World) -> Unit = { _ -> } - /** - * Create an [EventListener] for a [PlayerEvent]. - */ - fun on_player_event(type: () -> KClass) = KotlinPlayerEventHandler(world, type.invoke()) + private var stopListener: (World) -> Unit = { _ -> } - /** - * Create an [EventListener] for an [Event]. - */ - fun on_event(type: () -> KClass) = KotlinEventHandler(world, type.invoke()) + 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() + } + } + } + } /** * 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 on_command(command: String, privileges: PrivilegeLevel): KotlinCommandHandler { // TODO what to do with this? + return KotlinCommandHandler(world, command, privileges) + } + + /** + * Creates a [MessageHandler]. + */ + @Deprecated("Use new on(Type) listener") + fun on(type: () -> KClass): OldKotlinMessageHandler { + return OldKotlinMessageHandler(world, context, type()) + } + + /** + * Create an [EventListener] for a [PlayerEvent]. + */ + @Deprecated("Use new on(Type) listener") + fun on_player_event(type: () -> KClass): OldKotlinPlayerEventHandler { + return OldKotlinPlayerEventHandler(world, type()) + } + + /** + * Create an [EventListener] for an [Event]. + */ + @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) - } -} - -/** - * 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 + stopListener(world) } - 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 00000000..17cef5a0 --- /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 00000000..02ae45a3 --- /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 00000000..7269b96d --- /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 00000000..8a127037 --- /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 00000000..d362b716 --- /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 00000000..fe903ce5 --- /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 00000000..2ed023c7 --- /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 00000000..4533d20a --- /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 00000000..fc37d559 --- /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