From 8f7c4a58cd30ce6b0eb84eabe8d937986b47d00c Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Mar 2026 13:36:23 -0700 Subject: [PATCH] Implement SMSG_RAID_INSTANCE_INFO handler to track instance lockouts Parse and store dungeon/raid lockout data sent on login: - mapId, difficulty, resetTime (Unix timestamp), locked, extended flags - Stored in instanceLockouts_ vector for UI / LFG / dungeon state queries - Public InstanceLockout struct + getInstanceLockouts() accessor --- include/game/game_handler.hpp | 16 ++++++++++++++++ src/game/game_handler.cpp | 28 ++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 1cc31fb1..5e0e5908 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -707,6 +707,16 @@ public: bool hasPendingGroupInvite() const { return pendingGroupInvite; } const std::string& getPendingInviterName() const { return pendingInviterName; } + // ---- Instance lockouts ---- + struct InstanceLockout { + uint32_t mapId = 0; + uint32_t difficulty = 0; // 0=normal,1=heroic/10man,2=25man,3=25man heroic + uint64_t resetTime = 0; // Unix timestamp of instance reset + bool locked = false; + bool extended = false; + }; + const std::vector& getInstanceLockouts() const { return instanceLockouts_; } + // ---- LFG / Dungeon Finder ---- enum class LfgState : uint8_t { None = 0, @@ -1230,6 +1240,9 @@ private: void loadAreaTriggerDbc(); void checkAreaTriggers(); + // ---- Instance lockout handler ---- + void handleRaidInstanceInfo(network::Packet& packet); + // ---- LFG / Dungeon Finder handlers ---- void handleLfgJoinResult(network::Packet& packet); void handleLfgQueueStatus(network::Packet& packet); @@ -1566,6 +1579,9 @@ private: uint32_t instanceDifficulty_ = 0; bool instanceIsHeroic_ = false; + // Instance / raid lockouts + std::vector instanceLockouts_; + // LFG / Dungeon Finder state LfgState lfgState_ = LfgState::None; uint32_t lfgDungeonId_ = 0; // current dungeon entry diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 9b4cf15a..7e81553e 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -1848,8 +1848,7 @@ void GameHandler::handlePacket(network::Packet& packet) { packet.setReadPos(packet.getSize()); break; case Opcode::SMSG_RAID_INSTANCE_INFO: - // Raid lockout list (not yet surfaced in UI). - packet.setReadPos(packet.getSize()); + handleRaidInstanceInfo(packet); break; case Opcode::SMSG_DUEL_REQUESTED: // Duel request UI flow not implemented yet. @@ -8847,6 +8846,31 @@ void GameHandler::acceptBattlefield(uint32_t queueSlot) { LOG_INFO("Sent CMSG_BATTLEFIELD_PORT: accept bgTypeId=", slot->bgTypeId); } +void GameHandler::handleRaidInstanceInfo(network::Packet& packet) { + // SMSG_RAID_INSTANCE_INFO: uint32 count, then for each: + // mapId(u32) + difficulty(u32) + resetTime(u64) + locked(u8) + extended(u8) + if (packet.getSize() - packet.getReadPos() < 4) return; + uint32_t count = packet.readUInt32(); + + instanceLockouts_.clear(); + instanceLockouts_.reserve(count); + + constexpr size_t kEntrySize = 4 + 4 + 8 + 1 + 1; + for (uint32_t i = 0; i < count; ++i) { + if (packet.getSize() - packet.getReadPos() < kEntrySize) break; + InstanceLockout lo; + lo.mapId = packet.readUInt32(); + lo.difficulty = packet.readUInt32(); + lo.resetTime = packet.readUInt64(); + lo.locked = packet.readUInt8() != 0; + lo.extended = packet.readUInt8() != 0; + instanceLockouts_.push_back(lo); + LOG_INFO("Instance lockout: mapId=", lo.mapId, " diff=", lo.difficulty, + " reset=", lo.resetTime, " locked=", lo.locked, " extended=", lo.extended); + } + LOG_INFO("SMSG_RAID_INSTANCE_INFO: ", instanceLockouts_.size(), " lockout(s)"); +} + void GameHandler::handleInstanceDifficulty(network::Packet& packet) { if (packet.getSize() - packet.getReadPos() < 8) return; instanceDifficulty_ = packet.readUInt32();