From 9b6a817c9dd2b16b981504796974242aad8302f5 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Fri, 23 Dec 2022 06:35:06 +0000 Subject: [PATCH] Assorted bugfixes Corrected a confidential issue involving random events Added Lumbridge tree patch to the farming handler Rewrote seedling handling in new systems Fixed the incorrect definition for telegrab's spell ID Fixed an issue that prevented leaving a clan Close interfaces when applicable when a walk packet is received Made the penguin state more reliable Fixed a somewhat rare concurrency bug with the packet processor Refactored DialogueOption packet to ContinueOption, due to a revelation that it was not particular to dialogue Fixed a new, unreported issue with the stats interface --- .../activity/mta/TelekineticGrabSpell.java | 2 +- Server/src/main/kotlin/api/ApiExtensions.kt | 7 + .../game/content/ame/RandomEventManager.kt | 17 ++- .../worldevents/penguinhns/PenguinManager.kt | 4 +- .../game/interaction/npc/NPCTalkListener.kt | 2 +- .../entity/skill/farming/SeedOnPlantPot.kt | 136 +++++++++++++----- .../entity/skill/farming/SeedlingWaterer.kt | 54 ------- .../skill/farming/UseWithPatchHandler.kt | 2 +- .../kotlin/rs09/net/packet/PacketProcessor.kt | 35 ++++- .../kotlin/rs09/net/packet/in/Decoders530.kt | 8 +- .../main/kotlin/rs09/net/packet/in/Packet.kt | 2 +- 11 files changed, 164 insertions(+), 105 deletions(-) delete mode 100644 Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedlingWaterer.kt diff --git a/Server/src/main/java/core/game/content/activity/mta/TelekineticGrabSpell.java b/Server/src/main/java/core/game/content/activity/mta/TelekineticGrabSpell.java index 581341e25..b0b881b2c 100644 --- a/Server/src/main/java/core/game/content/activity/mta/TelekineticGrabSpell.java +++ b/Server/src/main/java/core/game/content/activity/mta/TelekineticGrabSpell.java @@ -79,7 +79,7 @@ public final class TelekineticGrabSpell extends MagicSpell { /** * Represents the spell id. */ - public static final int SPELL_ID = 65535; + public static final int SPELL_ID = 19; /** * Constructs a new {@code TelekineticGrabSpell} {@code Object}. diff --git a/Server/src/main/kotlin/api/ApiExtensions.kt b/Server/src/main/kotlin/api/ApiExtensions.kt index 43d695337..814337b02 100644 --- a/Server/src/main/kotlin/api/ApiExtensions.kt +++ b/Server/src/main/kotlin/api/ApiExtensions.kt @@ -1,6 +1,8 @@ package api import core.game.node.item.Item +import java.util.* +import kotlin.collections.ArrayList fun IntRange.toIntArray(): IntArray { if (last < first) @@ -53,4 +55,9 @@ fun IntArray.getNext(element: Int) : Int { fun IntArray.isNextLast(element: Int) : Boolean { return this.isLast(this.getNext(element)) +} + +fun LinkedList.tryPop(default: T) : T { + this.peek() ?: return default + return this.pop() } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/content/ame/RandomEventManager.kt b/Server/src/main/kotlin/rs09/game/content/ame/RandomEventManager.kt index 478c1259c..bc0c62847 100644 --- a/Server/src/main/kotlin/rs09/game/content/ame/RandomEventManager.kt +++ b/Server/src/main/kotlin/rs09/game/content/ame/RandomEventManager.kt @@ -1,5 +1,6 @@ package rs09.game.content.ame +import api.Commands import api.LoginListener import api.events.EventHook import api.events.TickEvent @@ -11,10 +12,12 @@ import core.game.world.map.zone.ZoneRestriction import core.tools.RandomFunction import rs09.game.Event import rs09.game.system.SystemLogger +import rs09.game.system.command.Privilege import rs09.game.world.GameWorld +import rs09.game.world.repository.Repository import kotlin.random.Random -class RandomEventManager(val player: Player? = null) : LoginListener, EventHook { +class RandomEventManager(val player: Player? = null) : LoginListener, EventHook, Commands { var event: RandomEventNPC? = null var enabled: Boolean = false var nextSpawn = 0 @@ -71,6 +74,18 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook< nextSpawn = GameWorld.ticks + RandomFunction.random(MIN_DELAY_TICKS, MAX_DELAY_TICKS) } + override fun defineCommands() { + define("targeted-ame", Privilege.ADMIN, "targeted-ame username", "Summons a random for the given user") {player, args -> + val username = args[1] + val target = Repository.getPlayerByName(username) + + if (target == null) + reject(player, "Unable to find player $username!") + + getInstance(target!!)?.fireEvent() + } + } + companion object { const val AVG_DELAY_TICKS = 6000 // 60 minutes const val MIN_DELAY_TICKS = AVG_DELAY_TICKS / 2 diff --git a/Server/src/main/kotlin/rs09/game/content/global/worldevents/penguinhns/PenguinManager.kt b/Server/src/main/kotlin/rs09/game/content/global/worldevents/penguinhns/PenguinManager.kt index 56d60c23c..55fc568c6 100644 --- a/Server/src/main/kotlin/rs09/game/content/global/worldevents/penguinhns/PenguinManager.kt +++ b/Server/src/main/kotlin/rs09/game/content/global/worldevents/penguinhns/PenguinManager.kt @@ -43,12 +43,14 @@ class PenguinManager{ } fun rebuildVars() { - if(PenguinHNSEvent.getStoreFile().isEmpty()) { + if(!PenguinHNSEvent.getStoreFile().containsKey("spawned-penguins")) { penguins = spawner.spawnPenguins(10) PenguinHNSEvent.getStoreFile()["spawned-penguins"] = penguins.toJSONArray() + tagMapping.clear() for (p in penguins) { tagMapping.put(p, JSONArray()) } + updateStoreFile() } else { val spawnedOrdinals = (PenguinHNSEvent.getStoreFile()["spawned-penguins"] as JSONArray).map { it.toString().toInt() } spawner.spawnPenguins(spawnedOrdinals) diff --git a/Server/src/main/kotlin/rs09/game/interaction/npc/NPCTalkListener.kt b/Server/src/main/kotlin/rs09/game/interaction/npc/NPCTalkListener.kt index 85c18822d..204f7da09 100644 --- a/Server/src/main/kotlin/rs09/game/interaction/npc/NPCTalkListener.kt +++ b/Server/src/main/kotlin/rs09/game/interaction/npc/NPCTalkListener.kt @@ -33,7 +33,7 @@ class NPCTalkListener : InteractionListener { on(IntType.NPC,"talk-to","talk","talk to"){player,node -> val npc = node.asNpc() if(RandomEvents.randomIDs.contains(node.id)){ - if(RandomEventManager.getInstance(player)!!.event == null || RandomEventManager.getInstance(player)!!.event!!.id != node.id){ + if(RandomEventManager.getInstance(player)!!.event == null || RandomEventManager.getInstance(player)!!.event!! != node.asNpc()){ player.sendMessage("They aren't interested in talking to you.") } else { RandomEventManager.getInstance(player)!!.event!!.talkTo(node.asNpc()) diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedOnPlantPot.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedOnPlantPot.kt index dfd02095a..6035cc18c 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedOnPlantPot.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedOnPlantPot.kt @@ -1,50 +1,118 @@ package rs09.game.node.entity.skill.farming -import core.game.interaction.NodeUsageEvent -import core.game.interaction.UseWithHandler -import core.game.node.item.Item -import core.plugin.Initializable -import core.plugin.Plugin +import api.addItem +import api.inInventory +import api.removeItem +import api.sendDialogue +import core.game.node.Node +import core.game.node.entity.player.Player import org.rs09.consts.Items +import rs09.game.interaction.IntType +import rs09.game.interaction.InteractionListener +import rs09.game.node.entity.state.newsys.states.SeedlingState -@Initializable -class SeedOnPlantPot : UseWithHandler(Items.ACORN_5312, - Items.WILLOW_SEED_5313,Items.MAPLE_SEED_5314,Items.YEW_SEED_5315,Items.MAGIC_SEED_5316,Items.APPLE_TREE_SEED_5283,Items.BANANA_TREE_SEED_5284,Items.ORANGE_TREE_SEED_5285,Items.CURRY_TREE_SEED_5286,Items.PINEAPPLE_SEED_5287,Items.PAPAYA_TREE_SEED_5288,Items.PALM_TREE_SEED_5289) { - override fun newInstance(arg: Any?): Plugin { - addHandler(Items.PLANT_POT_5354, ITEM_TYPE,this) - return this +class SeedlingListener : InteractionListener { + override fun defineListeners() { + onUseWith(IntType.ITEM, TREE_SEEDS, Items.PLANT_POT_5354, handler = ::addSeedToPot) + onUseWith(IntType.ITEM, TREE_SEEDLINGS, *WATERING_CANS, handler = ::waterSeedling) } - override fun handle(event: NodeUsageEvent?): Boolean { - val player = event?.player ?: return false - val pot = event.usedItem ?: return false - val seed = event.usedWith.asItem() ?: return false + fun addSeedToPot(player: Player, used: Node, with: Node) : Boolean { + val seed = used.asItem() ?: return false + val pot = with.asItem() ?: return false - if(!player.inventory.contains(Items.GARDENING_TROWEL_5325,1)){ - player.dialogueInterpreter.sendDialogue("You need a gardening trowel on you to do this.") + if(!inInventory(player, Items.GARDENING_TROWEL_5325)){ + sendDialogue(player, "You need a gardening trowel on you to do this.") return false } - val seedling = when(seed.id){ - Items.ACORN_5312 -> Items.OAK_SEEDLING_5358 - Items.WILLOW_SEED_5313 -> Items.WILLOW_SEEDLING_5359 - Items.MAPLE_SEED_5314 -> Items.MAPLE_SEEDLING_5360 - Items.YEW_SEED_5315 -> Items.YEW_SEEDLING_5361 - Items.MAGIC_SEED_5316 -> Items.MAGIC_SEEDLING_5362 - Items.APPLE_TREE_SEED_5283 -> Items.APPLE_SEEDLING_5480 - Items.BANANA_TREE_SEED_5284 -> Items.BANANA_SEEDLING_5481 - Items.ORANGE_TREE_SEED_5285 -> Items.ORANGE_SEEDLING_5482 - Items.CURRY_TREE_SEED_5286 -> Items.CURRY_SEEDLING_5483 - Items.PINEAPPLE_SEED_5287 -> Items.PINEAPPLE_SEEDLING_5484 - Items.PAPAYA_TREE_SEED_5288 -> Items.PAPAYA_SEEDLING_5485 - Items.PALM_TREE_SEED_5289 -> Items.PALM_SEEDLING_5486 - else -> return false + val seedling = getSeedling(seed.id) + if (seedling == -1) return false + if (!removeItem(player, seed) || !removeItem(player, pot)) return true + addItem(player, seedling) + return true + } + + fun waterSeedling(player: Player, used: Node, with: Node) : Boolean { + val seedling = used.asItem() ?: return false + val can = with.asItem() ?: return false + + val nextCan = can.id.getNext() + val wateredSeedling = if (seedling.id > 5400) seedling.id + 8 else seedling.id + 6 + + if (!removeItem(player, can) || !removeItem(player, seedling)) return false + addItem(player, wateredSeedling) + addItem(player, nextCan) + + var state = player.states["seedling"] as SeedlingState? + + if (state != null) { + state.addSeedling(wateredSeedling) + return true } - if(player.inventory.remove(pot) && player.inventory.remove(Item(seed.id,1))){ - player.inventory.add(Item(seedling)) - } + state = player.registerState("seedling") as SeedlingState? + state?.addSeedling(wateredSeedling) + state?.init() return true } + + private fun Int.getNext(): Int{ + val index = WATERING_CANS.indexOf(this) + if (index == -1) return Items.WATERING_CAN_5331 + return if (index != WATERING_CANS.size -1) WATERING_CANS[index + 1] else Items.WATERING_CAN_5331 + } + fun getSeedling(id: Int) : Int { + return when (id) { + Items.ACORN_5312 -> Items.OAK_SEEDLING_5358 + Items.WILLOW_SEED_5313 -> Items.WILLOW_SEEDLING_5359 + Items.MAPLE_SEED_5314 -> Items.MAPLE_SEEDLING_5360 + Items.YEW_SEED_5315 -> Items.YEW_SEEDLING_5361 + Items.MAGIC_SEED_5316 -> Items.MAGIC_SEEDLING_5362 + Items.APPLE_TREE_SEED_5283 -> Items.APPLE_SEEDLING_5480 + Items.BANANA_TREE_SEED_5284 -> Items.BANANA_SEEDLING_5481 + Items.ORANGE_TREE_SEED_5285 -> Items.ORANGE_SEEDLING_5482 + Items.CURRY_TREE_SEED_5286 -> Items.CURRY_SEEDLING_5483 + Items.PINEAPPLE_SEED_5287 -> Items.PINEAPPLE_SEEDLING_5484 + Items.PAPAYA_TREE_SEED_5288 -> Items.PAPAYA_SEEDLING_5485 + Items.PALM_TREE_SEED_5289 -> Items.PALM_SEEDLING_5486 + Items.SPIRIT_SEED_5317 -> Items.SPIRIT_SEEDLING_5363 + else -> -1 + } + } + + val TREE_SEEDS = intArrayOf( + Items.ACORN_5312, + Items.WILLOW_SEED_5313, + Items.MAPLE_SEED_5314, + Items.YEW_SEED_5315, + Items.MAGIC_SEED_5316, + Items.APPLE_TREE_SEED_5283, + Items.BANANA_TREE_SEED_5284, + Items.ORANGE_TREE_SEED_5285, + Items.CURRY_TREE_SEED_5286, + Items.PINEAPPLE_SEED_5287, + Items.PAPAYA_TREE_SEED_5288, + Items.PALM_TREE_SEED_5289, + Items.SPIRIT_SEED_5317 + ) + + val TREE_SEEDLINGS = intArrayOf( + Items.OAK_SEEDLING_5358, + Items.WILLOW_SEEDLING_5359, + Items.MAPLE_SEEDLING_5360, + Items.YEW_SEEDLING_5361, + Items.MAGIC_SEEDLING_5362, + Items.APPLE_SEEDLING_5480, + Items.BANANA_SEEDLING_5481, + Items.ORANGE_SEEDLING_5482, + Items.CURRY_SEEDLING_5483, + Items.PINEAPPLE_SEEDLING_5484, + Items.PAPAYA_SEEDLING_5485, + Items.PALM_SEEDLING_5486, + Items.SPIRIT_SEEDLING_5363 + ) + + private val WATERING_CANS = intArrayOf(Items.WATERING_CAN8_5340,Items.WATERING_CAN7_5339,Items.WATERING_CAN6_5338,Items.WATERING_CAN5_5337,Items.WATERING_CAN4_5336,Items.WATERING_CAN3_5335,Items.WATERING_CAN2_5334,Items.WATERING_CAN1_5333) } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedlingWaterer.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedlingWaterer.kt deleted file mode 100644 index 1630ffcd0..000000000 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/SeedlingWaterer.kt +++ /dev/null @@ -1,54 +0,0 @@ -package rs09.game.node.entity.skill.farming - -import core.game.interaction.NodeUsageEvent -import core.game.interaction.UseWithHandler -import core.game.node.item.Item -import core.plugin.Initializable -import core.plugin.Plugin -import org.rs09.consts.Items -import rs09.game.node.entity.state.newsys.states.SeedlingState - -private val cans = arrayListOf(Items.WATERING_CAN8_5340,Items.WATERING_CAN7_5339,Items.WATERING_CAN6_5338,Items.WATERING_CAN5_5337,Items.WATERING_CAN4_5336,Items.WATERING_CAN3_5335,Items.WATERING_CAN2_5334,Items.WATERING_CAN1_5333) -private val seedlings = arrayListOf(Items.OAK_SEEDLING_5358,Items.WILLOW_SEEDLING_5359,Items.MAPLE_SEEDLING_5360,Items.YEW_SEEDLING_5361,Items.MAGIC_SEEDLING_5362,Items.APPLE_SEEDLING_5480,Items.BANANA_SEEDLING_5481,Items.ORANGE_SEEDLING_5482,Items.CURRY_SEEDLING_5483,Items.PINEAPPLE_SEEDLING_5484,Items.PAPAYA_SEEDLING_5485,Items.PALM_SEEDLING_5486) - -@Initializable -class SeedlingWaterer : UseWithHandler(*cans.toIntArray()) { - - override fun newInstance(arg: Any?): Plugin { - for(seed in seedlings) addHandler(seed, ITEM_TYPE,this) - return this - } - - override fun handle(event: NodeUsageEvent?): Boolean { - val player = event?.player ?: return false - val seedling = event.used.asItem() ?: return false - val can = event.usedWith.asItem() ?: return false - - val nextCan = can.id.getNext() - val wateredSeedling = if(seedling.id > 5400 ) seedling.id + 8 else seedling.id + 6 - - if(player.inventory.remove(can) && player.inventory.remove(seedling)){ - player.inventory.add(Item(wateredSeedling)) - player.inventory.add(Item(nextCan)) - - var state = player.states["seedling"] as SeedlingState? - if(state == null){ - state = player.registerState("seedling") as SeedlingState? - state?.addSeedling(wateredSeedling) - state?.init() - } else { - state.addSeedling(wateredSeedling) - } - - player.sendMessage("You water the seedling.") - } - return true - } - - private fun Int.getNext(): Int{ - var index = cans.indexOf(this) - if(index == -1) return Items.WATERING_CAN_5331 - if(index != cans.size -1) return cans[index + 1] else return Items.WATERING_CAN_5331 - } - -} \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt index 237bd39f4..949fcee7c 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/UseWithPatchHandler.kt @@ -232,7 +232,7 @@ class UseWithPatchHandler : InteractionListener { patches.addAll(8550..8557) //allotment wrappers patches.addAll(7847..7853) //flower patch wrappers patches.addAll(8150..8156) //herb patch wrappers - patches.addAll(8388..8390) // Tree patches + patches.addAll(8388..8391) // Tree patches patches.add(19147) //Tree patch patches.addAll(7962..7965) //fruit trees patches.addAll(8173..8176) //hops diff --git a/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt b/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt index 8a3e81f94..a394e2e80 100644 --- a/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt +++ b/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt @@ -3,6 +3,7 @@ package rs09.net.packet import api.events.ButtonClickEvent import api.getAttribute import api.sendMessage +import api.tryPop import core.cache.def.impl.ItemDefinition import core.cache.def.impl.NPCDefinition import core.cache.def.impl.SceneryDefinition @@ -17,7 +18,6 @@ import core.game.interaction.NodeUsageEvent import core.game.interaction.Option import core.game.interaction.UseWithHandler import core.game.node.Node -import core.game.node.entity.impl.PulseType import core.game.node.entity.player.Player import core.game.node.entity.player.info.Rights import core.game.node.entity.player.info.login.LoginConfiguration @@ -43,8 +43,8 @@ import discord.Discord import org.rs09.consts.Components import proto.management.ClanMessage import proto.management.JoinClanRequest +import proto.management.LeaveClanRequest import rs09.ServerConstants -import rs09.game.ge.GrandExchange import rs09.game.ge.GrandExchange.Companion.getOfferStats import rs09.game.ge.GrandExchange.Companion.getRecommendedPrice import rs09.game.ge.GrandExchangeOffer @@ -81,7 +81,7 @@ object PacketProcessor { val pw = PrintWriter(sw) var pkt: Packet while (countThisCycle-- > 0) { - pkt = queue.pop() + pkt = queue.tryPop(Packet.NoProcess()) try { process(pkt) } catch (e: Exception) { @@ -127,8 +127,14 @@ object PacketProcessor { is Packet.PlayerPrefsUpdate -> {/*TODO implement something that cares about this */} is Packet.Ping -> pkt.player.session.lastPing = System.currentTimeMillis() is Packet.JoinClan -> { - if (pkt.clanName.isNotEmpty()) - sendMessage(pkt.player, "Attempting to join channel....:clan:") + if (pkt.clanName.isEmpty() && pkt.player.communication.currentClan.isNotEmpty()) { + val builder = LeaveClanRequest.newBuilder() + builder.clanName = pkt.player.communication.currentClan + builder.username = pkt.player.name + ManagementEvents.publish(builder.build()) + return + } + sendMessage(pkt.player, "Attempting to join channel....:clan:") val builder = JoinClanRequest.newBuilder() builder.clanName = pkt.clanName builder.username = pkt.player.name @@ -228,11 +234,19 @@ object PacketProcessor { val final = pkt.count - pkt.player.interfaceManager.getPacketCount(0) pkt.player.interfaceManager.getPacketCount(final) } - is Packet.DialogueOption -> { + is Packet.ContinueOption -> { val player = pkt.player + player.debug("[CONTINUE OPT]----------") + player.debug("Iface: ${pkt.iface}") + player.debug("Child: ${pkt.child}") + player.debug("Slot: ${pkt.slot}") + player.debug("------------------------") if (player.dialogueInterpreter.dialogue == null) { player.interfaceManager.closeChatbox() player.dialogueInterpreter.actions.removeFirstOrNull()?.handle(player, pkt.child) + val component = player.interfaceManager.getComponent(pkt.iface) ?: return + if (!InterfaceListeners.run(player, component, pkt.opcode, pkt.child, pkt.slot, -1)) + component.plugin?.handle(player, component, pkt.opcode, pkt.child, pkt.slot, -1) return } player.dialogueInterpreter.handle(pkt.iface, pkt.child) @@ -427,7 +441,14 @@ object PacketProcessor { //there's more data in this packet, we're just not using it } - if (player.locks.isMovementLocked || !player.interfaceManager.close() || !player.interfaceManager.closeSingleTab() || !player.dialogueInterpreter.close()) { + var canWalk = !player.locks.isMovementLocked + + if (canWalk && player.interfaceManager.isOpened && !player.interfaceManager.opened.definition.isWalkable) + canWalk = canWalk && player.interfaceManager.close() + if (canWalk && player.interfaceManager.hasChatbox() && !player.interfaceManager.chatbox.definition.isWalkable) + player.interfaceManager.closeChatbox() + + if (!canWalk || !player.dialogueInterpreter.close()) { player.debug("[WALK ACTION]-- NO HANDLE: PLAYER LOCKED OR INTERFACES SAY NO") return sendClearMinimap(player) } diff --git a/Server/src/main/kotlin/rs09/net/packet/in/Decoders530.kt b/Server/src/main/kotlin/rs09/net/packet/in/Decoders530.kt index d70407db0..5137d8da9 100644 --- a/Server/src/main/kotlin/rs09/net/packet/in/Decoders530.kt +++ b/Server/src/main/kotlin/rs09/net/packet/in/Decoders530.kt @@ -349,12 +349,12 @@ enum class Decoders530(val opcode: Int) { return Packet.IfAction(player, opcode, -1, iface, button, -1, -1) } }, - DIALOGUE_OPT(132) { + CONTINUE_OPT(132) { override fun decode(player: Player, buffer: IoBuffer): Packet { val ifHash = buffer.intA val slot = buffer.leShort val (iface, button) = deHash(ifHash) - return Packet.DialogueOption(player, iface, button) + return Packet.ContinueOption(player, iface, button, slot, 132) } }, CLOSE_IFACE(184) { @@ -364,8 +364,8 @@ enum class Decoders530(val opcode: Int) { }, IF_GROUNDITEM_ACTION(73) { override fun decode(player: Player, buffer: IoBuffer): Packet { - val child = buffer.short - val iface = buffer.short + val ifHash = buffer.intA + val (iface, child) = deHash(ifHash) val y = buffer.short val itemId = buffer.leShortA val x = buffer.leShortA diff --git a/Server/src/main/kotlin/rs09/net/packet/in/Packet.kt b/Server/src/main/kotlin/rs09/net/packet/in/Packet.kt index d06b4d69f..3e1b27216 100644 --- a/Server/src/main/kotlin/rs09/net/packet/in/Packet.kt +++ b/Server/src/main/kotlin/rs09/net/packet/in/Packet.kt @@ -17,7 +17,7 @@ sealed class Packet { data class UseWithScenery(val player: Player, val itemId: Int, val slot: Int, val sceneryId: Int, val x: Int, val y: Int) : Packet() data class UseWithGroundItem(val player: Player, val usedId: Int, val withId: Int, val iface: Int, val child: Int, val slot: Int, val x: Int, val y: Int) : Packet() data class IfAction(val player: Player, val opcode: Int, val optIndex: Int, val iface: Int, val child: Int, val slot: Int, val itemId: Int = -1) : Packet() - data class DialogueOption(val player: Player, val iface: Int, val child: Int) : Packet() + data class ContinueOption(val player: Player, val iface: Int, val child: Int, val slot: Int, val opcode: Int) : Packet() data class CloseIface(val player: Player) : Packet() data class JoinClan(val player: Player, val clanName: String) : Packet() data class SetClanRank(val player: Player, val username: String, val rank: Int) : Packet()