From b303791028b23d8875e4bf333c57edbf871ca23a Mon Sep 17 00:00:00 2001 From: Tom0017 Date: Mon, 27 May 2019 21:01:29 -0400 Subject: [PATCH] Add OPNPCU message and its implementation Close issue https://github.com/Tomm0017/rsmod/issues/148 --- data/packets.yml | 30 ++++++++--- .../gg/rsmod/game/action/PawnPathAction.kt | 35 +++++++++++- .../rsmod/game/message/MessageDecoderSet.kt | 4 +- .../game/message/decoder/OpNpcUDecoder.kt | 19 +++++++ .../game/message/handler/OpNpcUHandler.kt | 54 +++++++++++++++++++ .../rsmod/game/message/impl/OpNpcUMessage.kt | 8 +++ 6 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 game/src/main/kotlin/gg/rsmod/game/message/decoder/OpNpcUDecoder.kt create mode 100644 game/src/main/kotlin/gg/rsmod/game/message/handler/OpNpcUHandler.kt create mode 100644 game/src/main/kotlin/gg/rsmod/game/message/impl/OpNpcUMessage.kt diff --git a/data/packets.yml b/data/packets.yml index 4bfac8e580..e8431da1db 100644 --- a/data/packets.yml +++ b/data/packets.yml @@ -597,6 +597,30 @@ in-packets: type: SHORT trans: ADD + - message: gg.rsmod.game.message.impl.OpNpcUMessage + type: FIXED + opcode: 23 + length: 11 + structure: + - name: item + sign: UNSIGNED + order: LITTLE + type: SHORT + trans: ADD + - name: slot + sign: UNSIGNED + type: SHORT + - name: npc_index + sign: UNSIGNED + order: LITTLE + type: SHORT + trans: ADD + - name: movement_type + type: BYTE + trans: NEGATE + - name: component_hash + type: INT + - message: gg.rsmod.game.message.impl.OpNpc1Message type: FIXED opcode: 71 @@ -1266,12 +1290,6 @@ in-packets: type: VARIABLE_SHORT opcode: 16 - - message: gg.rsmod.game.message.impl.IgnoreMessage # TODO: OPNPCU - type: FIXED - opcode: 23 - length: 11 - ignore: true - - message: gg.rsmod.game.message.impl.IgnoreMessage # TODO: MESSAGE_PRIVATE type: VARIABLE_SHORT opcode: 25 diff --git a/game/src/main/kotlin/gg/rsmod/game/action/PawnPathAction.kt b/game/src/main/kotlin/gg/rsmod/game/action/PawnPathAction.kt index 3537abad8f..d69412c38d 100644 --- a/game/src/main/kotlin/gg/rsmod/game/action/PawnPathAction.kt +++ b/game/src/main/kotlin/gg/rsmod/game/action/PawnPathAction.kt @@ -23,6 +23,8 @@ import java.lang.ref.WeakReference */ object PawnPathAction { + private const val ITEM_USE_OPCODE = -1 + val walkPlugin: Plugin.() -> Unit = { val pawn = ctx as Pawn val world = pawn.world @@ -49,6 +51,31 @@ object PawnPathAction { } } + val itemUsePlugin: Plugin.() -> Unit = s@ { + val pawn = ctx as Pawn + val world = pawn.world + val other = pawn.attr[INTERACTING_NPC_ATTR]?.get() ?: pawn.attr[INTERACTING_PLAYER_ATTR]?.get()!! + + /* + * Some interactions only require line-of-sight range, such as npcs + * behind cells or booths. This allows for diagonal interaction. + * + * Set to null for default interaction range. + */ + val lineOfSightRange = if (other is Npc) world.plugins.getNpcInteractionDistance(other.id) else null + + pawn.queue(TaskPriority.STANDARD) { + terminateAction = { + pawn.stopMovement() + if (pawn is Player) { + pawn.write(SetMapFlagMessage(255, 255)) + } + } + + walk(this, pawn, other, ITEM_USE_OPCODE, lineOfSightRange) + } + } + private suspend fun walk(it: QueueTask, pawn: Pawn, other: Pawn, opt: Int, lineOfSightRange: Int?) { val world = pawn.world val initialTile = Tile(other.tile) @@ -111,7 +138,13 @@ object PawnPathAction { } val npcId = other.getTransform(pawn) - val handled = world.plugins.executeNpc(pawn, npcId, opt) + val handled = if (opt != ITEM_USE_OPCODE) { + world.plugins.executeNpc(pawn, npcId, opt) + } else { + val item = pawn.attr[INTERACTING_ITEM]?.get() ?: return + world.plugins.executeItemOnNpc(pawn, npcId, item.id) + } + if (!handled) { pawn.writeMessage(Entity.NOTHING_INTERESTING_HAPPENS) } diff --git a/game/src/main/kotlin/gg/rsmod/game/message/MessageDecoderSet.kt b/game/src/main/kotlin/gg/rsmod/game/message/MessageDecoderSet.kt index ac0bec597c..0b117c1523 100644 --- a/game/src/main/kotlin/gg/rsmod/game/message/MessageDecoderSet.kt +++ b/game/src/main/kotlin/gg/rsmod/game/message/MessageDecoderSet.kt @@ -84,6 +84,8 @@ class MessageDecoderSet { put(OpNpc4Message::class.java, OpNpc4Decoder(), OpNpc4Handler(), structures) put(OpNpc5Message::class.java, OpNpc5Decoder(), OpNpc5Handler(), structures) put(OpNpc6Message::class.java, OpNpc6Decoder(), OpNpc6Handler(), structures) + put(OpNpcTMessage::class.java, OpNpcTDecoder(), OpNpcTHandler(), structures) + put(OpNpcUMessage::class.java, OpNpcUDecoder(), OpNpcUHandler(), structures) put(OpPlayer1Message::class.java, OpPlayer1Decoder(), OpPlayer1Handler(), structures) put(OpPlayer2Message::class.java, OpPlayer2Decoder(), OpPlayer2Handler(), structures) @@ -93,8 +95,6 @@ class MessageDecoderSet { put(OpPlayer6Message::class.java, OpPlayer6Decoder(), OpPlayer6Handler(), structures) put(OpPlayer7Message::class.java, OpPlayer7Decoder(), OpPlayer7Handler(), structures) put(OpPlayer8Message::class.java, OpPlayer8Decoder(), OpPlayer8Handler(), structures) - - put(OpNpcTMessage::class.java, OpNpcTDecoder(), OpNpcTHandler(), structures) } private fun put(messageType: Class, decoderType: MessageDecoder, handlerType: MessageHandler, structures: MessageStructureSet) { diff --git a/game/src/main/kotlin/gg/rsmod/game/message/decoder/OpNpcUDecoder.kt b/game/src/main/kotlin/gg/rsmod/game/message/decoder/OpNpcUDecoder.kt new file mode 100644 index 0000000000..0144cecc8f --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/message/decoder/OpNpcUDecoder.kt @@ -0,0 +1,19 @@ +package gg.rsmod.game.message.decoder + +import gg.rsmod.game.message.MessageDecoder +import gg.rsmod.game.message.impl.OpNpcUMessage + +/** + * @author Tom + */ +class OpNpcUDecoder : MessageDecoder() { + + override fun decode(opcode: Int, opcodeIndex: Int, values: HashMap, stringValues: HashMap): OpNpcUMessage { + val item = values["item"]!!.toInt() + val slot = values["slot"]!!.toInt() + val componentHash = values["component_hash"]!!.toInt() + val npcIndex = values["npc_index"]!!.toInt() + val movementType = values["movement_type"]!!.toInt() + return OpNpcUMessage(componentHash, npcIndex, item, slot, movementType) + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/gg/rsmod/game/message/handler/OpNpcUHandler.kt b/game/src/main/kotlin/gg/rsmod/game/message/handler/OpNpcUHandler.kt new file mode 100644 index 0000000000..6538d7c06f --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/message/handler/OpNpcUHandler.kt @@ -0,0 +1,54 @@ +package gg.rsmod.game.message.handler + +import gg.rsmod.game.action.PawnPathAction +import gg.rsmod.game.message.MessageHandler +import gg.rsmod.game.message.impl.OpNpcUMessage +import gg.rsmod.game.model.World +import gg.rsmod.game.model.attr.INTERACTING_ITEM +import gg.rsmod.game.model.attr.INTERACTING_ITEM_ID +import gg.rsmod.game.model.attr.INTERACTING_ITEM_SLOT +import gg.rsmod.game.model.attr.INTERACTING_NPC_ATTR +import gg.rsmod.game.model.entity.Client +import gg.rsmod.game.model.priv.Privilege +import java.lang.ref.WeakReference + +/** + * @author Tom + */ +class OpNpcUHandler : MessageHandler { + + override fun handle(client: Client, world: World, message: OpNpcUMessage) { + val index = message.npcIndex + val npc = world.npcs[index] ?: return + + if (!client.lock.canNpcInteract() || !client.lock.canItemInteract()) { + return + } + + val movementType = message.movementType + val itemId = message.item + val itemSlot = message.slot + + val item = client.inventory[itemSlot] ?: return + + if (item.id != itemId) { + return + } + + log(client, "Item on npc: movement=%d, item=%s, slot=%d, npc=%s, index=%d", movementType, item, itemSlot, npc, index) + + if (movementType == 1 && world.privileges.isEligible(client.privilege, Privilege.ADMIN_POWER)) { + client.moveTo(world.findRandomTileAround(npc.tile, 1) ?: npc.tile) + } + + client.closeInterfaceModal() + client.interruptQueues() + client.resetInteractions() + + client.attr[INTERACTING_NPC_ATTR] = WeakReference(npc) + client.attr[INTERACTING_ITEM] = WeakReference(item) + client.attr[INTERACTING_ITEM_ID] = item.id + client.attr[INTERACTING_ITEM_SLOT] = itemSlot + client.executePlugin(PawnPathAction.itemUsePlugin) + } +} \ No newline at end of file diff --git a/game/src/main/kotlin/gg/rsmod/game/message/impl/OpNpcUMessage.kt b/game/src/main/kotlin/gg/rsmod/game/message/impl/OpNpcUMessage.kt new file mode 100644 index 0000000000..5c5fb22033 --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/message/impl/OpNpcUMessage.kt @@ -0,0 +1,8 @@ +package gg.rsmod.game.message.impl + +import gg.rsmod.game.message.Message + +/** + * @author Tom + */ +data class OpNpcUMessage(val componentHash: Int, val npcIndex: Int, val item: Int, val slot: Int, val movementType: Int) : Message \ No newline at end of file