refactor: add isInWorld() and replace 119 inline state+socket checks

Add GameHandler::isInWorld() helper that encapsulates the repeated
'state == IN_WORLD && socket' guard. Replace 99 negative checks and
20 positive checks across game_handler.cpp, plus fix 2 remaining
C-style casts.
This commit is contained in:
Kelsi 2026-03-25 14:21:19 -07:00
parent 56f8f5c592
commit e4194b1fc0
2 changed files with 122 additions and 121 deletions

View file

@ -172,6 +172,7 @@ public:
* Check if connected to world server * Check if connected to world server
*/ */
bool isConnected() const; bool isConnected() const;
bool isInWorld() const { return state == WorldState::IN_WORLD && socket; }
/** /**
* Get current connection state * Get current connection state

View file

@ -880,7 +880,7 @@ void GameHandler::update(float deltaTime) {
} }
// Detect RX silence (server stopped sending packets but TCP still open) // Detect RX silence (server stopped sending packets but TCP still open)
if (state == WorldState::IN_WORLD && socket && socket->isConnected() && if (isInWorld() && socket->isConnected() &&
lastRxTime_.time_since_epoch().count() > 0) { lastRxTime_.time_since_epoch().count() > 0) {
auto silenceMs = std::chrono::duration_cast<std::chrono::milliseconds>( auto silenceMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - lastRxTime_).count(); std::chrono::steady_clock::now() - lastRxTime_).count();
@ -975,7 +975,7 @@ void GameHandler::update(float deltaTime) {
for (auto it = pendingGameObjectLootRetries_.begin(); it != pendingGameObjectLootRetries_.end();) { for (auto it = pendingGameObjectLootRetries_.begin(); it != pendingGameObjectLootRetries_.end();) {
it->timer -= deltaTime; it->timer -= deltaTime;
if (it->timer <= 0.0f) { if (it->timer <= 0.0f) {
if (it->remainingRetries > 0 && state == WorldState::IN_WORLD && socket) { if (it->remainingRetries > 0 && isInWorld()) {
// Keep server-side position/facing fresh before retrying GO use. // Keep server-side position/facing fresh before retrying GO use.
sendMovement(Opcode::MSG_MOVE_HEARTBEAT); sendMovement(Opcode::MSG_MOVE_HEARTBEAT);
auto usePacket = GameObjectUsePacket::build(it->guid); auto usePacket = GameObjectUsePacket::build(it->guid);
@ -998,7 +998,7 @@ void GameHandler::update(float deltaTime) {
for (auto it = pendingGameObjectLootOpens_.begin(); it != pendingGameObjectLootOpens_.end();) { for (auto it = pendingGameObjectLootOpens_.begin(); it != pendingGameObjectLootOpens_.end();) {
it->timer -= deltaTime; it->timer -= deltaTime;
if (it->timer <= 0.0f) { if (it->timer <= 0.0f) {
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
// Avoid sending CMSG_LOOT while a timed cast is active (e.g. gathering). // Avoid sending CMSG_LOOT while a timed cast is active (e.g. gathering).
// handleSpellGo will trigger loot after the cast completes. // handleSpellGo will trigger loot after the cast completes.
if (casting && currentCastSpellId != 0) { if (casting && currentCastSpellId != 0) {
@ -1017,7 +1017,7 @@ void GameHandler::update(float deltaTime) {
// Periodically re-query names for players whose initial CMSG_NAME_QUERY was // Periodically re-query names for players whose initial CMSG_NAME_QUERY was
// lost (server didn't respond) or whose entity was recreated while the query // lost (server didn't respond) or whose entity was recreated while the query
// was still pending. Runs every 5 seconds to keep overhead minimal. // was still pending. Runs every 5 seconds to keep overhead minimal.
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
static float nameResyncTimer = 0.0f; static float nameResyncTimer = 0.0f;
nameResyncTimer += deltaTime; nameResyncTimer += deltaTime;
if (nameResyncTimer >= 5.0f) { if (nameResyncTimer >= 5.0f) {
@ -1084,7 +1084,7 @@ void GameHandler::update(float deltaTime) {
if (inspectRateLimit_ > 0.0f) { if (inspectRateLimit_ > 0.0f) {
inspectRateLimit_ = std::max(0.0f, inspectRateLimit_ - deltaTime); inspectRateLimit_ = std::max(0.0f, inspectRateLimit_ - deltaTime);
} }
if (state == WorldState::IN_WORLD && socket && inspectRateLimit_ <= 0.0f && !pendingAutoInspect_.empty()) { if (isInWorld() && inspectRateLimit_ <= 0.0f && !pendingAutoInspect_.empty()) {
uint64_t guid = *pendingAutoInspect_.begin(); uint64_t guid = *pendingAutoInspect_.begin();
pendingAutoInspect_.erase(pendingAutoInspect_.begin()); pendingAutoInspect_.erase(pendingAutoInspect_.begin());
if (guid != 0 && guid != playerGuid && entityManager.hasEntity(guid)) { if (guid != 0 && guid != playerGuid && entityManager.hasEntity(guid)) {
@ -1368,7 +1368,7 @@ void GameHandler::update(float deltaTime) {
if (dist > 40.0f) { if (dist > 40.0f) {
stopAutoAttack(); stopAutoAttack();
LOG_INFO("Left combat: target too far (", dist, " yards)"); LOG_INFO("Left combat: target too far (", dist, " yards)");
} else if (state == WorldState::IN_WORLD && socket) { } else if (isInWorld()) {
bool allowResync = true; bool allowResync = true;
const float meleeRange = classicLike ? 5.25f : 5.75f; const float meleeRange = classicLike ? 5.25f : 5.75f;
if (dist3d > meleeRange) { if (dist3d > meleeRange) {
@ -10048,7 +10048,7 @@ bool GameHandler::supportsEquipmentSets() const {
} }
void GameHandler::useEquipmentSet(uint32_t setId) { void GameHandler::useEquipmentSet(uint32_t setId) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
uint16_t wire = wireOpcode(Opcode::CMSG_EQUIPMENT_SET_USE); uint16_t wire = wireOpcode(Opcode::CMSG_EQUIPMENT_SET_USE);
if (wire == 0xFFFF) { addUIError("Equipment sets not supported."); return; } if (wire == 0xFFFF) { addUIError("Equipment sets not supported."); return; }
// Find the equipment set to get target item GUIDs per slot // Find the equipment set to get target item GUIDs per slot
@ -12525,7 +12525,7 @@ void GameHandler::handleMessageChat(network::Packet& packet) {
} }
void GameHandler::sendTextEmote(uint32_t textEmoteId, uint64_t targetGuid) { void GameHandler::sendTextEmote(uint32_t textEmoteId, uint64_t targetGuid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = TextEmotePacket::build(textEmoteId, targetGuid); auto packet = TextEmotePacket::build(textEmoteId, targetGuid);
socket->send(packet); socket->send(packet);
} }
@ -12581,7 +12581,7 @@ void GameHandler::handleTextEmote(network::Packet& packet) {
} }
void GameHandler::joinChannel(const std::string& channelName, const std::string& password) { void GameHandler::joinChannel(const std::string& channelName, const std::string& password) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = packetParsers_ ? packetParsers_->buildJoinChannel(channelName, password) auto packet = packetParsers_ ? packetParsers_->buildJoinChannel(channelName, password)
: JoinChannelPacket::build(channelName, password); : JoinChannelPacket::build(channelName, password);
socket->send(packet); socket->send(packet);
@ -12589,7 +12589,7 @@ void GameHandler::joinChannel(const std::string& channelName, const std::string&
} }
void GameHandler::leaveChannel(const std::string& channelName) { void GameHandler::leaveChannel(const std::string& channelName) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = packetParsers_ ? packetParsers_->buildLeaveChannel(channelName) auto packet = packetParsers_ ? packetParsers_->buildLeaveChannel(channelName)
: LeaveChannelPacket::build(channelName); : LeaveChannelPacket::build(channelName);
socket->send(packet); socket->send(packet);
@ -12772,7 +12772,7 @@ void GameHandler::setTarget(uint64_t guid) {
// (the new target's cast state is naturally fetched from unitCastStates_ by GUID) // (the new target's cast state is naturally fetched from unitCastStates_ by GUID)
// Inform server of target selection (Phase 1) // Inform server of target selection (Phase 1)
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
auto packet = SetSelectionPacket::build(guid); auto packet = SetSelectionPacket::build(guid);
socket->send(packet); socket->send(packet);
} }
@ -12936,7 +12936,7 @@ void GameHandler::targetFriend(bool reverse) {
} }
void GameHandler::inspectTarget() { void GameHandler::inspectTarget() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot inspect: not in world or not connected"); LOG_WARNING("Cannot inspect: not in world or not connected");
return; return;
} }
@ -12968,7 +12968,7 @@ void GameHandler::inspectTarget() {
} }
void GameHandler::queryServerTime() { void GameHandler::queryServerTime() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot query time: not in world or not connected"); LOG_WARNING("Cannot query time: not in world or not connected");
return; return;
} }
@ -12979,7 +12979,7 @@ void GameHandler::queryServerTime() {
} }
void GameHandler::requestPlayedTime() { void GameHandler::requestPlayedTime() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot request played time: not in world or not connected"); LOG_WARNING("Cannot request played time: not in world or not connected");
return; return;
} }
@ -12990,7 +12990,7 @@ void GameHandler::requestPlayedTime() {
} }
void GameHandler::queryWho(const std::string& playerName) { void GameHandler::queryWho(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot query who: not in world or not connected"); LOG_WARNING("Cannot query who: not in world or not connected");
return; return;
} }
@ -13001,7 +13001,7 @@ void GameHandler::queryWho(const std::string& playerName) {
} }
void GameHandler::addFriend(const std::string& playerName, const std::string& note) { void GameHandler::addFriend(const std::string& playerName, const std::string& note) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot add friend: not in world or not connected"); LOG_WARNING("Cannot add friend: not in world or not connected");
return; return;
} }
@ -13018,7 +13018,7 @@ void GameHandler::addFriend(const std::string& playerName, const std::string& no
} }
void GameHandler::removeFriend(const std::string& playerName) { void GameHandler::removeFriend(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot remove friend: not in world or not connected"); LOG_WARNING("Cannot remove friend: not in world or not connected");
return; return;
} }
@ -13043,7 +13043,7 @@ void GameHandler::removeFriend(const std::string& playerName) {
} }
void GameHandler::setFriendNote(const std::string& playerName, const std::string& note) { void GameHandler::setFriendNote(const std::string& playerName, const std::string& note) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot set friend note: not in world or not connected"); LOG_WARNING("Cannot set friend note: not in world or not connected");
return; return;
} }
@ -13067,7 +13067,7 @@ void GameHandler::setFriendNote(const std::string& playerName, const std::string
} }
void GameHandler::randomRoll(uint32_t minRoll, uint32_t maxRoll) { void GameHandler::randomRoll(uint32_t minRoll, uint32_t maxRoll) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot roll: not in world or not connected"); LOG_WARNING("Cannot roll: not in world or not connected");
return; return;
} }
@ -13086,7 +13086,7 @@ void GameHandler::randomRoll(uint32_t minRoll, uint32_t maxRoll) {
} }
void GameHandler::addIgnore(const std::string& playerName) { void GameHandler::addIgnore(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot add ignore: not in world or not connected"); LOG_WARNING("Cannot add ignore: not in world or not connected");
return; return;
} }
@ -13103,7 +13103,7 @@ void GameHandler::addIgnore(const std::string& playerName) {
} }
void GameHandler::removeIgnore(const std::string& playerName) { void GameHandler::removeIgnore(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot remove ignore: not in world or not connected"); LOG_WARNING("Cannot remove ignore: not in world or not connected");
return; return;
} }
@ -13165,7 +13165,7 @@ void GameHandler::cancelLogout() {
} }
void GameHandler::setStandState(uint8_t standState) { void GameHandler::setStandState(uint8_t standState) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot change stand state: not in world or not connected"); LOG_WARNING("Cannot change stand state: not in world or not connected");
return; return;
} }
@ -13176,7 +13176,7 @@ void GameHandler::setStandState(uint8_t standState) {
} }
void GameHandler::toggleHelm() { void GameHandler::toggleHelm() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot toggle helm: not in world or not connected"); LOG_WARNING("Cannot toggle helm: not in world or not connected");
return; return;
} }
@ -13189,7 +13189,7 @@ void GameHandler::toggleHelm() {
} }
void GameHandler::toggleCloak() { void GameHandler::toggleCloak() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot toggle cloak: not in world or not connected"); LOG_WARNING("Cannot toggle cloak: not in world or not connected");
return; return;
} }
@ -13301,7 +13301,7 @@ void GameHandler::assistTarget() {
} }
void GameHandler::togglePvp() { void GameHandler::togglePvp() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot toggle PvP: not in world or not connected"); LOG_WARNING("Cannot toggle PvP: not in world or not connected");
return; return;
} }
@ -13325,7 +13325,7 @@ void GameHandler::togglePvp() {
} }
void GameHandler::requestGuildInfo() { void GameHandler::requestGuildInfo() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot request guild info: not in world or not connected"); LOG_WARNING("Cannot request guild info: not in world or not connected");
return; return;
} }
@ -13336,7 +13336,7 @@ void GameHandler::requestGuildInfo() {
} }
void GameHandler::requestGuildRoster() { void GameHandler::requestGuildRoster() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot request guild roster: not in world or not connected"); LOG_WARNING("Cannot request guild roster: not in world or not connected");
return; return;
} }
@ -13348,7 +13348,7 @@ void GameHandler::requestGuildRoster() {
} }
void GameHandler::setGuildMotd(const std::string& motd) { void GameHandler::setGuildMotd(const std::string& motd) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot set guild MOTD: not in world or not connected"); LOG_WARNING("Cannot set guild MOTD: not in world or not connected");
return; return;
} }
@ -13360,7 +13360,7 @@ void GameHandler::setGuildMotd(const std::string& motd) {
} }
void GameHandler::promoteGuildMember(const std::string& playerName) { void GameHandler::promoteGuildMember(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot promote guild member: not in world or not connected"); LOG_WARNING("Cannot promote guild member: not in world or not connected");
return; return;
} }
@ -13377,7 +13377,7 @@ void GameHandler::promoteGuildMember(const std::string& playerName) {
} }
void GameHandler::demoteGuildMember(const std::string& playerName) { void GameHandler::demoteGuildMember(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot demote guild member: not in world or not connected"); LOG_WARNING("Cannot demote guild member: not in world or not connected");
return; return;
} }
@ -13394,7 +13394,7 @@ void GameHandler::demoteGuildMember(const std::string& playerName) {
} }
void GameHandler::leaveGuild() { void GameHandler::leaveGuild() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot leave guild: not in world or not connected"); LOG_WARNING("Cannot leave guild: not in world or not connected");
return; return;
} }
@ -13406,7 +13406,7 @@ void GameHandler::leaveGuild() {
} }
void GameHandler::inviteToGuild(const std::string& playerName) { void GameHandler::inviteToGuild(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot invite to guild: not in world or not connected"); LOG_WARNING("Cannot invite to guild: not in world or not connected");
return; return;
} }
@ -13423,7 +13423,7 @@ void GameHandler::inviteToGuild(const std::string& playerName) {
} }
void GameHandler::initiateReadyCheck() { void GameHandler::initiateReadyCheck() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot initiate ready check: not in world or not connected"); LOG_WARNING("Cannot initiate ready check: not in world or not connected");
return; return;
} }
@ -13440,7 +13440,7 @@ void GameHandler::initiateReadyCheck() {
} }
void GameHandler::respondToReadyCheck(bool ready) { void GameHandler::respondToReadyCheck(bool ready) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot respond to ready check: not in world or not connected"); LOG_WARNING("Cannot respond to ready check: not in world or not connected");
return; return;
} }
@ -13461,7 +13461,7 @@ void GameHandler::acceptDuel() {
} }
void GameHandler::forfeitDuel() { void GameHandler::forfeitDuel() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot forfeit duel: not in world or not connected"); LOG_WARNING("Cannot forfeit duel: not in world or not connected");
return; return;
} }
@ -13579,7 +13579,7 @@ void GameHandler::toggleDnd(const std::string& message) {
} }
void GameHandler::replyToLastWhisper(const std::string& message) { void GameHandler::replyToLastWhisper(const std::string& message) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot send whisper: not in world or not connected"); LOG_WARNING("Cannot send whisper: not in world or not connected");
return; return;
} }
@ -13600,7 +13600,7 @@ void GameHandler::replyToLastWhisper(const std::string& message) {
} }
void GameHandler::uninvitePlayer(const std::string& playerName) { void GameHandler::uninvitePlayer(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot uninvite player: not in world or not connected"); LOG_WARNING("Cannot uninvite player: not in world or not connected");
return; return;
} }
@ -13617,7 +13617,7 @@ void GameHandler::uninvitePlayer(const std::string& playerName) {
} }
void GameHandler::leaveParty() { void GameHandler::leaveParty() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot leave party: not in world or not connected"); LOG_WARNING("Cannot leave party: not in world or not connected");
return; return;
} }
@ -13629,7 +13629,7 @@ void GameHandler::leaveParty() {
} }
void GameHandler::setMainTank(uint64_t targetGuid) { void GameHandler::setMainTank(uint64_t targetGuid) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot set main tank: not in world or not connected"); LOG_WARNING("Cannot set main tank: not in world or not connected");
return; return;
} }
@ -13647,7 +13647,7 @@ void GameHandler::setMainTank(uint64_t targetGuid) {
} }
void GameHandler::setMainAssist(uint64_t targetGuid) { void GameHandler::setMainAssist(uint64_t targetGuid) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot set main assist: not in world or not connected"); LOG_WARNING("Cannot set main assist: not in world or not connected");
return; return;
} }
@ -13665,7 +13665,7 @@ void GameHandler::setMainAssist(uint64_t targetGuid) {
} }
void GameHandler::clearMainTank() { void GameHandler::clearMainTank() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot clear main tank: not in world or not connected"); LOG_WARNING("Cannot clear main tank: not in world or not connected");
return; return;
} }
@ -13678,7 +13678,7 @@ void GameHandler::clearMainTank() {
} }
void GameHandler::clearMainAssist() { void GameHandler::clearMainAssist() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot clear main assist: not in world or not connected"); LOG_WARNING("Cannot clear main assist: not in world or not connected");
return; return;
} }
@ -13691,7 +13691,7 @@ void GameHandler::clearMainAssist() {
} }
void GameHandler::setRaidMark(uint64_t guid, uint8_t icon) { void GameHandler::setRaidMark(uint64_t guid, uint8_t icon) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
static const char* kMarkNames[] = { static const char* kMarkNames[] = {
"Star", "Circle", "Diamond", "Triangle", "Moon", "Square", "Cross", "Skull" "Star", "Circle", "Diamond", "Triangle", "Moon", "Square", "Cross", "Skull"
@ -13714,7 +13714,7 @@ void GameHandler::setRaidMark(uint64_t guid, uint8_t icon) {
} }
void GameHandler::requestRaidInfo() { void GameHandler::requestRaidInfo() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot request raid info: not in world or not connected"); LOG_WARNING("Cannot request raid info: not in world or not connected");
return; return;
} }
@ -13726,7 +13726,7 @@ void GameHandler::requestRaidInfo() {
} }
void GameHandler::proposeDuel(uint64_t targetGuid) { void GameHandler::proposeDuel(uint64_t targetGuid) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot propose duel: not in world or not connected"); LOG_WARNING("Cannot propose duel: not in world or not connected");
return; return;
} }
@ -13743,7 +13743,7 @@ void GameHandler::proposeDuel(uint64_t targetGuid) {
} }
void GameHandler::initiateTrade(uint64_t targetGuid) { void GameHandler::initiateTrade(uint64_t targetGuid) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot initiate trade: not in world or not connected"); LOG_WARNING("Cannot initiate trade: not in world or not connected");
return; return;
} }
@ -13760,7 +13760,7 @@ void GameHandler::initiateTrade(uint64_t targetGuid) {
} }
void GameHandler::stopCasting() { void GameHandler::stopCasting() {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("Cannot stop casting: not in world or not connected"); LOG_WARNING("Cannot stop casting: not in world or not connected");
return; return;
} }
@ -13860,7 +13860,7 @@ void GameHandler::useSelfRes() {
} }
void GameHandler::activateSpiritHealer(uint64_t npcGuid) { void GameHandler::activateSpiritHealer(uint64_t npcGuid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingSpiritHealerGuid_ = npcGuid; pendingSpiritHealerGuid_ = npcGuid;
auto packet = SpiritHealerActivatePacket::build(npcGuid); auto packet = SpiritHealerActivatePacket::build(npcGuid);
socket->send(packet); socket->send(packet);
@ -14018,7 +14018,7 @@ void GameHandler::queryPlayerName(uint64_t guid) {
return; return;
} }
if (pendingNameQueries.count(guid)) return; if (pendingNameQueries.count(guid)) return;
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_INFO("queryPlayerName: skipped guid=0x", std::hex, guid, std::dec, LOG_INFO("queryPlayerName: skipped guid=0x", std::hex, guid, std::dec,
" state=", worldStateName(state), " socket=", (socket ? "yes" : "no")); " state=", worldStateName(state), " socket=", (socket ? "yes" : "no"));
return; return;
@ -14032,7 +14032,7 @@ void GameHandler::queryPlayerName(uint64_t guid) {
void GameHandler::queryCreatureInfo(uint32_t entry, uint64_t guid) { void GameHandler::queryCreatureInfo(uint32_t entry, uint64_t guid) {
if (creatureInfoCache.count(entry) || pendingCreatureQueries.count(entry)) return; if (creatureInfoCache.count(entry) || pendingCreatureQueries.count(entry)) return;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingCreatureQueries.insert(entry); pendingCreatureQueries.insert(entry);
auto packet = CreatureQueryPacket::build(entry, guid); auto packet = CreatureQueryPacket::build(entry, guid);
@ -14041,7 +14041,7 @@ void GameHandler::queryCreatureInfo(uint32_t entry, uint64_t guid) {
void GameHandler::queryGameObjectInfo(uint32_t entry, uint64_t guid) { void GameHandler::queryGameObjectInfo(uint32_t entry, uint64_t guid) {
if (gameObjectInfoCache_.count(entry) || pendingGameObjectQueries_.count(entry)) return; if (gameObjectInfoCache_.count(entry) || pendingGameObjectQueries_.count(entry)) return;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingGameObjectQueries_.insert(entry); pendingGameObjectQueries_.insert(entry);
auto packet = GameObjectQueryPacket::build(entry, guid); auto packet = GameObjectQueryPacket::build(entry, guid);
@ -14247,7 +14247,7 @@ void GameHandler::handlePageTextQueryResponse(network::Packet& packet) {
void GameHandler::queryItemInfo(uint32_t entry, uint64_t guid) { void GameHandler::queryItemInfo(uint32_t entry, uint64_t guid) {
if (itemInfoCache_.count(entry) || pendingItemQueries_.count(entry)) return; if (itemInfoCache_.count(entry) || pendingItemQueries_.count(entry)) return;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingItemQueries_.insert(entry); pendingItemQueries_.insert(entry);
// Some cores reject CMSG_ITEM_QUERY_SINGLE when the GUID is 0. // Some cores reject CMSG_ITEM_QUERY_SINGLE when the GUID is 0.
@ -15298,7 +15298,7 @@ void GameHandler::startAutoAttack(uint64_t targetGuid) {
autoAttackOutOfRangeTime_ = 0.0f; autoAttackOutOfRangeTime_ = 0.0f;
autoAttackResendTimer_ = 0.0f; autoAttackResendTimer_ = 0.0f;
autoAttackFacingSyncTimer_ = 0.0f; autoAttackFacingSyncTimer_ = 0.0f;
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
auto packet = AttackSwingPacket::build(targetGuid); auto packet = AttackSwingPacket::build(targetGuid);
socket->send(packet); socket->send(packet);
} }
@ -15315,7 +15315,7 @@ void GameHandler::stopAutoAttack() {
autoAttackOutOfRangeTime_ = 0.0f; autoAttackOutOfRangeTime_ = 0.0f;
autoAttackResendTimer_ = 0.0f; autoAttackResendTimer_ = 0.0f;
autoAttackFacingSyncTimer_ = 0.0f; autoAttackFacingSyncTimer_ = 0.0f;
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
auto packet = AttackStopPacket::build(); auto packet = AttackStopPacket::build();
socket->send(packet); socket->send(packet);
} }
@ -16555,7 +16555,7 @@ void GameHandler::handleLfgTeleportDenied(network::Packet& packet) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
void GameHandler::lfgJoin(uint32_t dungeonId, uint8_t roles) { void GameHandler::lfgJoin(uint32_t dungeonId, uint8_t roles) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
network::Packet pkt(wireOpcode(Opcode::CMSG_LFG_JOIN)); network::Packet pkt(wireOpcode(Opcode::CMSG_LFG_JOIN));
pkt.writeUInt8(roles); pkt.writeUInt8(roles);
@ -16584,7 +16584,7 @@ void GameHandler::lfgLeave() {
} }
void GameHandler::lfgSetRoles(uint8_t roles) { void GameHandler::lfgSetRoles(uint8_t roles) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
const uint32_t wire = wireOpcode(Opcode::CMSG_LFG_SET_ROLES); const uint32_t wire = wireOpcode(Opcode::CMSG_LFG_SET_ROLES);
if (wire == 0xFFFF) return; if (wire == 0xFFFF) return;
@ -16661,7 +16661,7 @@ void GameHandler::loadAreaTriggerDbc() {
} }
void GameHandler::checkAreaTriggers() { void GameHandler::checkAreaTriggers() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
if (onTaxiFlight_ || taxiClientActive_) return; if (onTaxiFlight_ || taxiClientActive_) return;
loadAreaTriggerDbc(); loadAreaTriggerDbc();
@ -16977,7 +16977,7 @@ void GameHandler::handleArenaError(network::Packet& packet) {
} }
void GameHandler::requestPvpLog() { void GameHandler::requestPvpLog() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// MSG_PVP_LOG_DATA is bidirectional: client sends an empty packet to request // MSG_PVP_LOG_DATA is bidirectional: client sends an empty packet to request
network::Packet pkt(wireOpcode(Opcode::MSG_PVP_LOG_DATA)); network::Packet pkt(wireOpcode(Opcode::MSG_PVP_LOG_DATA));
socket->send(pkt); socket->send(pkt);
@ -17057,9 +17057,9 @@ void GameHandler::handlePvpLogData(network::Packet& packet) {
LOG_INFO("Arena log: ", bgScoreboard_.players.size(), " players, hasWinner=", LOG_INFO("Arena log: ", bgScoreboard_.players.size(), " players, hasWinner=",
bgScoreboard_.hasWinner, " winner=", static_cast<int>(bgScoreboard_.winner), bgScoreboard_.hasWinner, " winner=", static_cast<int>(bgScoreboard_.winner),
" team0='", bgScoreboard_.arenaTeams[0].teamName, " team0='", bgScoreboard_.arenaTeams[0].teamName,
"' ratingChange=", (int32_t)bgScoreboard_.arenaTeams[0].ratingChange, "' ratingChange=", static_cast<int32_t>(bgScoreboard_.arenaTeams[0].ratingChange),
" team1='", bgScoreboard_.arenaTeams[1].teamName, " team1='", bgScoreboard_.arenaTeams[1].teamName,
"' ratingChange=", (int32_t)bgScoreboard_.arenaTeams[1].ratingChange); "' ratingChange=", static_cast<int32_t>(bgScoreboard_.arenaTeams[1].ratingChange));
} else { } else {
LOG_INFO("PvP log: ", bgScoreboard_.players.size(), " players, hasWinner=", LOG_INFO("PvP log: ", bgScoreboard_.players.size(), " players, hasWinner=",
bgScoreboard_.hasWinner, " winner=", static_cast<int>(bgScoreboard_.winner)); bgScoreboard_.hasWinner, " winner=", static_cast<int>(bgScoreboard_.winner));
@ -17952,7 +17952,7 @@ void GameHandler::castSpell(uint32_t spellId, uint64_t targetGuid) {
return; return;
} }
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// Casting any spell while mounted → dismount instead // Casting any spell while mounted → dismount instead
if (isMounted()) { if (isMounted()) {
@ -18062,7 +18062,7 @@ void GameHandler::cancelCast() {
if (!casting) return; if (!casting) return;
// GameObject interaction cast is client-side timing only. // GameObject interaction cast is client-side timing only.
if (pendingGameObjectInteractGuid_ == 0 && if (pendingGameObjectInteractGuid_ == 0 &&
state == WorldState::IN_WORLD && socket && isInWorld() &&
currentCastSpellId != 0) { currentCastSpellId != 0) {
auto packet = CancelCastPacket::build(currentCastSpellId); auto packet = CancelCastPacket::build(currentCastSpellId);
socket->send(packet); socket->send(packet);
@ -18094,7 +18094,7 @@ void GameHandler::cancelCraftQueue() {
} }
void GameHandler::cancelAura(uint32_t spellId) { void GameHandler::cancelAura(uint32_t spellId) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = CancelAuraPacket::build(spellId); auto packet = CancelAuraPacket::build(spellId);
socket->send(packet); socket->send(packet);
} }
@ -18302,7 +18302,7 @@ void GameHandler::setActionBarSlot(int slot, ActionBarSlot::Type type, uint32_t
fireAddonEvent("ACTIONBAR_SLOT_CHANGED", {std::to_string(slot + 1)}); fireAddonEvent("ACTIONBAR_SLOT_CHANGED", {std::to_string(slot + 1)});
fireAddonEvent("ACTIONBAR_UPDATE_STATE", {}); fireAddonEvent("ACTIONBAR_UPDATE_STATE", {});
// Notify the server so the action bar persists across relogs. // Notify the server so the action bar persists across relogs.
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
const bool classic = isClassicLikeExpansion(); const bool classic = isClassicLikeExpansion();
auto pkt = SetActionButtonPacket::build( auto pkt = SetActionButtonPacket::build(
static_cast<uint8_t>(slot), static_cast<uint8_t>(slot),
@ -19012,7 +19012,7 @@ void GameHandler::handleTalentsInfo(network::Packet& packet) {
} }
void GameHandler::learnTalent(uint32_t talentId, uint32_t requestedRank) { void GameHandler::learnTalent(uint32_t talentId, uint32_t requestedRank) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("learnTalent: Not in world or no socket connection"); LOG_WARNING("learnTalent: Not in world or no socket connection");
return; return;
} }
@ -19039,7 +19039,7 @@ void GameHandler::switchTalentSpec(uint8_t newSpec) {
// and respond with SMSG_TALENTS_INFO for the newly active group. // and respond with SMSG_TALENTS_INFO for the newly active group.
// We optimistically update the local state so the UI reflects the change // We optimistically update the local state so the UI reflects the change
// immediately; the server response will correct us if needed. // immediately; the server response will correct us if needed.
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
auto pkt = ActivateTalentGroupPacket::build(static_cast<uint32_t>(newSpec)); auto pkt = ActivateTalentGroupPacket::build(static_cast<uint32_t>(newSpec));
socket->send(pkt); socket->send(pkt);
LOG_INFO("Sent CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE: group=", static_cast<int>(newSpec)); LOG_INFO("Sent CMSG_SET_ACTIVE_TALENT_GROUP_OBSOLETE: group=", static_cast<int>(newSpec));
@ -19062,7 +19062,7 @@ void GameHandler::switchTalentSpec(uint8_t newSpec) {
void GameHandler::confirmPetUnlearn() { void GameHandler::confirmPetUnlearn() {
if (!petUnlearnPending_) return; if (!petUnlearnPending_) return;
petUnlearnPending_ = false; petUnlearnPending_ = false;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// Respond with CMSG_PET_UNLEARN_TALENTS (no payload in 3.3.5a) // Respond with CMSG_PET_UNLEARN_TALENTS (no payload in 3.3.5a)
network::Packet pkt(wireOpcode(Opcode::CMSG_PET_UNLEARN_TALENTS)); network::Packet pkt(wireOpcode(Opcode::CMSG_PET_UNLEARN_TALENTS));
@ -19077,7 +19077,7 @@ void GameHandler::confirmTalentWipe() {
if (!talentWipePending_) return; if (!talentWipePending_) return;
talentWipePending_ = false; talentWipePending_ = false;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// Respond to MSG_TALENT_WIPE_CONFIRM with the trainer GUID to trigger the reset. // Respond to MSG_TALENT_WIPE_CONFIRM with the trainer GUID to trigger the reset.
// Packet: opcode(2) + uint64 npcGuid = 10 bytes. // Packet: opcode(2) + uint64 npcGuid = 10 bytes.
@ -19092,7 +19092,7 @@ void GameHandler::confirmTalentWipe() {
} }
void GameHandler::sendAlterAppearance(uint32_t hairStyle, uint32_t hairColor, uint32_t facialHair) { void GameHandler::sendAlterAppearance(uint32_t hairStyle, uint32_t hairColor, uint32_t facialHair) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto pkt = AlterAppearancePacket::build(hairStyle, hairColor, facialHair); auto pkt = AlterAppearancePacket::build(hairStyle, hairColor, facialHair);
socket->send(pkt); socket->send(pkt);
LOG_INFO("sendAlterAppearance: hair=", hairStyle, " color=", hairColor, " facial=", facialHair); LOG_INFO("sendAlterAppearance: hair=", hairStyle, " color=", hairColor, " facial=", facialHair);
@ -19103,14 +19103,14 @@ void GameHandler::sendAlterAppearance(uint32_t hairStyle, uint32_t hairColor, ui
// ============================================================ // ============================================================
void GameHandler::inviteToGroup(const std::string& playerName) { void GameHandler::inviteToGroup(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GroupInvitePacket::build(playerName); auto packet = GroupInvitePacket::build(playerName);
socket->send(packet); socket->send(packet);
LOG_INFO("Inviting ", playerName, " to group"); LOG_INFO("Inviting ", playerName, " to group");
} }
void GameHandler::acceptGroupInvite() { void GameHandler::acceptGroupInvite() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingGroupInvite = false; pendingGroupInvite = false;
auto packet = GroupAcceptPacket::build(); auto packet = GroupAcceptPacket::build();
socket->send(packet); socket->send(packet);
@ -19118,7 +19118,7 @@ void GameHandler::acceptGroupInvite() {
} }
void GameHandler::declineGroupInvite() { void GameHandler::declineGroupInvite() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingGroupInvite = false; pendingGroupInvite = false;
auto packet = GroupDeclinePacket::build(); auto packet = GroupDeclinePacket::build();
socket->send(packet); socket->send(packet);
@ -19126,7 +19126,7 @@ void GameHandler::declineGroupInvite() {
} }
void GameHandler::leaveGroup() { void GameHandler::leaveGroup() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GroupDisbandPacket::build(); auto packet = GroupDisbandPacket::build();
socket->send(packet); socket->send(packet);
partyData = GroupListData{}; partyData = GroupListData{};
@ -19483,42 +19483,42 @@ void GameHandler::handlePartyMemberStats(network::Packet& packet, bool isFull) {
// ============================================================ // ============================================================
void GameHandler::kickGuildMember(const std::string& playerName) { void GameHandler::kickGuildMember(const std::string& playerName) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildRemovePacket::build(playerName); auto packet = GuildRemovePacket::build(playerName);
socket->send(packet); socket->send(packet);
LOG_INFO("Kicking guild member: ", playerName); LOG_INFO("Kicking guild member: ", playerName);
} }
void GameHandler::disbandGuild() { void GameHandler::disbandGuild() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildDisbandPacket::build(); auto packet = GuildDisbandPacket::build();
socket->send(packet); socket->send(packet);
LOG_INFO("Disbanding guild"); LOG_INFO("Disbanding guild");
} }
void GameHandler::setGuildLeader(const std::string& name) { void GameHandler::setGuildLeader(const std::string& name) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildLeaderPacket::build(name); auto packet = GuildLeaderPacket::build(name);
socket->send(packet); socket->send(packet);
LOG_INFO("Setting guild leader: ", name); LOG_INFO("Setting guild leader: ", name);
} }
void GameHandler::setGuildPublicNote(const std::string& name, const std::string& note) { void GameHandler::setGuildPublicNote(const std::string& name, const std::string& note) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildSetPublicNotePacket::build(name, note); auto packet = GuildSetPublicNotePacket::build(name, note);
socket->send(packet); socket->send(packet);
LOG_INFO("Setting public note for ", name, ": ", note); LOG_INFO("Setting public note for ", name, ": ", note);
} }
void GameHandler::setGuildOfficerNote(const std::string& name, const std::string& note) { void GameHandler::setGuildOfficerNote(const std::string& name, const std::string& note) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildSetOfficerNotePacket::build(name, note); auto packet = GuildSetOfficerNotePacket::build(name, note);
socket->send(packet); socket->send(packet);
LOG_INFO("Setting officer note for ", name, ": ", note); LOG_INFO("Setting officer note for ", name, ": ", note);
} }
void GameHandler::acceptGuildInvite() { void GameHandler::acceptGuildInvite() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingGuildInvite_ = false; pendingGuildInvite_ = false;
auto packet = GuildAcceptPacket::build(); auto packet = GuildAcceptPacket::build();
socket->send(packet); socket->send(packet);
@ -19526,7 +19526,7 @@ void GameHandler::acceptGuildInvite() {
} }
void GameHandler::declineGuildInvite() { void GameHandler::declineGuildInvite() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingGuildInvite_ = false; pendingGuildInvite_ = false;
auto packet = GuildDeclineInvitationPacket::build(); auto packet = GuildDeclineInvitationPacket::build();
socket->send(packet); socket->send(packet);
@ -19534,7 +19534,7 @@ void GameHandler::declineGuildInvite() {
} }
void GameHandler::submitGmTicket(const std::string& text) { void GameHandler::submitGmTicket(const std::string& text) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// CMSG_GMTICKET_CREATE (WotLK 3.3.5a): // CMSG_GMTICKET_CREATE (WotLK 3.3.5a):
// string ticket_text // string ticket_text
@ -19555,7 +19555,7 @@ void GameHandler::submitGmTicket(const std::string& text) {
} }
void GameHandler::deleteGmTicket() { void GameHandler::deleteGmTicket() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
network::Packet pkt(wireOpcode(Opcode::CMSG_GMTICKET_DELETETICKET)); network::Packet pkt(wireOpcode(Opcode::CMSG_GMTICKET_DELETETICKET));
socket->send(pkt); socket->send(pkt);
gmTicketActive_ = false; gmTicketActive_ = false;
@ -19564,7 +19564,7 @@ void GameHandler::deleteGmTicket() {
} }
void GameHandler::requestGmTicket() { void GameHandler::requestGmTicket() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// CMSG_GMTICKET_GETTICKET has no payload — server responds with SMSG_GMTICKET_GETTICKET // CMSG_GMTICKET_GETTICKET has no payload — server responds with SMSG_GMTICKET_GETTICKET
network::Packet pkt(wireOpcode(Opcode::CMSG_GMTICKET_GETTICKET)); network::Packet pkt(wireOpcode(Opcode::CMSG_GMTICKET_GETTICKET));
socket->send(pkt); socket->send(pkt);
@ -19572,7 +19572,7 @@ void GameHandler::requestGmTicket() {
} }
void GameHandler::queryGuildInfo(uint32_t guildId) { void GameHandler::queryGuildInfo(uint32_t guildId) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildQueryPacket::build(guildId); auto packet = GuildQueryPacket::build(guildId);
socket->send(packet); socket->send(packet);
LOG_INFO("Querying guild info: guildId=", guildId); LOG_INFO("Querying guild info: guildId=", guildId);
@ -19601,14 +19601,14 @@ uint32_t GameHandler::getEntityGuildId(uint64_t guid) const {
} }
void GameHandler::createGuild(const std::string& guildName) { void GameHandler::createGuild(const std::string& guildName) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildCreatePacket::build(guildName); auto packet = GuildCreatePacket::build(guildName);
socket->send(packet); socket->send(packet);
LOG_INFO("Creating guild: ", guildName); LOG_INFO("Creating guild: ", guildName);
} }
void GameHandler::addGuildRank(const std::string& rankName) { void GameHandler::addGuildRank(const std::string& rankName) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildAddRankPacket::build(rankName); auto packet = GuildAddRankPacket::build(rankName);
socket->send(packet); socket->send(packet);
LOG_INFO("Adding guild rank: ", rankName); LOG_INFO("Adding guild rank: ", rankName);
@ -19617,7 +19617,7 @@ void GameHandler::addGuildRank(const std::string& rankName) {
} }
void GameHandler::deleteGuildRank() { void GameHandler::deleteGuildRank() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GuildDelRankPacket::build(); auto packet = GuildDelRankPacket::build();
socket->send(packet); socket->send(packet);
LOG_INFO("Deleting last guild rank"); LOG_INFO("Deleting last guild rank");
@ -19626,13 +19626,13 @@ void GameHandler::deleteGuildRank() {
} }
void GameHandler::requestPetitionShowlist(uint64_t npcGuid) { void GameHandler::requestPetitionShowlist(uint64_t npcGuid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = PetitionShowlistPacket::build(npcGuid); auto packet = PetitionShowlistPacket::build(npcGuid);
socket->send(packet); socket->send(packet);
} }
void GameHandler::buyPetition(uint64_t npcGuid, const std::string& guildName) { void GameHandler::buyPetition(uint64_t npcGuid, const std::string& guildName) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = PetitionBuyPacket::build(npcGuid, guildName); auto packet = PetitionBuyPacket::build(npcGuid, guildName);
socket->send(packet); socket->send(packet);
LOG_INFO("Buying guild petition: ", guildName); LOG_INFO("Buying guild petition: ", guildName);
@ -20019,13 +20019,13 @@ void GameHandler::handleGuildCommandResult(network::Packet& packet) {
// ============================================================ // ============================================================
void GameHandler::lootTarget(uint64_t guid) { void GameHandler::lootTarget(uint64_t guid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = LootPacket::build(guid); auto packet = LootPacket::build(guid);
socket->send(packet); socket->send(packet);
} }
void GameHandler::lootItem(uint8_t slotIndex) { void GameHandler::lootItem(uint8_t slotIndex) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = AutostoreLootItemPacket::build(slotIndex); auto packet = AutostoreLootItemPacket::build(slotIndex);
socket->send(packet); socket->send(packet);
} }
@ -20038,7 +20038,7 @@ void GameHandler::closeLoot() {
if (currentLoot.lootGuid != 0 && targetGuid == currentLoot.lootGuid) { if (currentLoot.lootGuid != 0 && targetGuid == currentLoot.lootGuid) {
clearTarget(); clearTarget();
} }
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
auto packet = LootReleasePacket::build(currentLoot.lootGuid); auto packet = LootReleasePacket::build(currentLoot.lootGuid);
socket->send(packet); socket->send(packet);
} }
@ -20046,7 +20046,7 @@ void GameHandler::closeLoot() {
} }
void GameHandler::lootMasterGive(uint8_t lootSlot, uint64_t targetGuid) { void GameHandler::lootMasterGive(uint8_t lootSlot, uint64_t targetGuid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// CMSG_LOOT_MASTER_GIVE: uint64 lootGuid + uint8 slotIndex + uint64 targetGuid // CMSG_LOOT_MASTER_GIVE: uint64 lootGuid + uint8 slotIndex + uint64 targetGuid
network::Packet pkt(wireOpcode(Opcode::CMSG_LOOT_MASTER_GIVE)); network::Packet pkt(wireOpcode(Opcode::CMSG_LOOT_MASTER_GIVE));
pkt.writeUInt64(currentLoot.lootGuid); pkt.writeUInt64(currentLoot.lootGuid);
@ -20056,14 +20056,14 @@ void GameHandler::lootMasterGive(uint8_t lootSlot, uint64_t targetGuid) {
} }
void GameHandler::interactWithNpc(uint64_t guid) { void GameHandler::interactWithNpc(uint64_t guid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = GossipHelloPacket::build(guid); auto packet = GossipHelloPacket::build(guid);
socket->send(packet); socket->send(packet);
} }
void GameHandler::interactWithGameObject(uint64_t guid) { void GameHandler::interactWithGameObject(uint64_t guid) {
if (guid == 0) return; if (guid == 0) return;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// Do not overlap an actual spell cast. // Do not overlap an actual spell cast.
if (casting && currentCastSpellId != 0) return; if (casting && currentCastSpellId != 0) return;
// Always clear melee intent before GO interactions. // Always clear melee intent before GO interactions.
@ -20075,7 +20075,7 @@ void GameHandler::interactWithGameObject(uint64_t guid) {
void GameHandler::performGameObjectInteractionNow(uint64_t guid) { void GameHandler::performGameObjectInteractionNow(uint64_t guid) {
if (guid == 0) return; if (guid == 0) return;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// Rate-limit to prevent spamming the server // Rate-limit to prevent spamming the server
static uint64_t lastInteractGuid = 0; static uint64_t lastInteractGuid = 0;
static std::chrono::steady_clock::time_point lastInteractTime{}; static std::chrono::steady_clock::time_point lastInteractTime{};
@ -20795,7 +20795,7 @@ void GameHandler::abandonQuest(uint32_t questId) {
} }
if (slotIndex >= 0 && slotIndex < 25) { if (slotIndex >= 0 && slotIndex < 25) {
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
network::Packet pkt(wireOpcode(Opcode::CMSG_QUESTLOG_REMOVE_QUEST)); network::Packet pkt(wireOpcode(Opcode::CMSG_QUESTLOG_REMOVE_QUEST));
pkt.writeUInt8(static_cast<uint8_t>(slotIndex)); pkt.writeUInt8(static_cast<uint8_t>(slotIndex));
socket->send(pkt); socket->send(pkt);
@ -20819,7 +20819,7 @@ void GameHandler::abandonQuest(uint32_t questId) {
} }
void GameHandler::shareQuestWithParty(uint32_t questId) { void GameHandler::shareQuestWithParty(uint32_t questId) {
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
addSystemChatMessage("Cannot share quest: not in world."); addSystemChatMessage("Cannot share quest: not in world.");
return; return;
} }
@ -20983,7 +20983,7 @@ void GameHandler::closeGossip() {
} }
void GameHandler::offerQuestFromItem(uint64_t itemGuid, uint32_t questId) { void GameHandler::offerQuestFromItem(uint64_t itemGuid, uint32_t questId) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
if (itemGuid == 0 || questId == 0) { if (itemGuid == 0 || questId == 0) {
addSystemChatMessage("Cannot start quest right now."); addSystemChatMessage("Cannot start quest right now.");
return; return;
@ -21011,7 +21011,7 @@ uint64_t GameHandler::getBagItemGuid(int bagIndex, int slotIndex) const {
} }
void GameHandler::openVendor(uint64_t npcGuid) { void GameHandler::openVendor(uint64_t npcGuid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
buybackItems_.clear(); buybackItems_.clear();
auto packet = ListInventoryPacket::build(npcGuid); auto packet = ListInventoryPacket::build(npcGuid);
socket->send(packet); socket->send(packet);
@ -21031,7 +21031,7 @@ void GameHandler::closeVendor() {
} }
void GameHandler::buyItem(uint64_t vendorGuid, uint32_t itemId, uint32_t slot, uint32_t count) { void GameHandler::buyItem(uint64_t vendorGuid, uint32_t itemId, uint32_t slot, uint32_t count) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
LOG_INFO("Buy request: vendorGuid=0x", std::hex, vendorGuid, std::dec, LOG_INFO("Buy request: vendorGuid=0x", std::hex, vendorGuid, std::dec,
" itemId=", itemId, " slot=", slot, " count=", count, " itemId=", itemId, " slot=", slot, " count=", count,
" wire=0x", std::hex, wireOpcode(Opcode::CMSG_BUY_ITEM), std::dec); " wire=0x", std::hex, wireOpcode(Opcode::CMSG_BUY_ITEM), std::dec);
@ -21076,7 +21076,7 @@ void GameHandler::buyBackItem(uint32_t buybackSlot) {
} }
void GameHandler::repairItem(uint64_t vendorGuid, uint64_t itemGuid) { void GameHandler::repairItem(uint64_t vendorGuid, uint64_t itemGuid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// CMSG_REPAIR_ITEM: npcGuid(8) + itemGuid(8) + useGuildBank(uint8) // CMSG_REPAIR_ITEM: npcGuid(8) + itemGuid(8) + useGuildBank(uint8)
network::Packet packet(wireOpcode(Opcode::CMSG_REPAIR_ITEM)); network::Packet packet(wireOpcode(Opcode::CMSG_REPAIR_ITEM));
packet.writeUInt64(vendorGuid); packet.writeUInt64(vendorGuid);
@ -21086,7 +21086,7 @@ void GameHandler::repairItem(uint64_t vendorGuid, uint64_t itemGuid) {
} }
void GameHandler::repairAll(uint64_t vendorGuid, bool useGuildBank) { void GameHandler::repairAll(uint64_t vendorGuid, bool useGuildBank) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// itemGuid = 0 signals "repair all equipped" to the server // itemGuid = 0 signals "repair all equipped" to the server
network::Packet packet(wireOpcode(Opcode::CMSG_REPAIR_ITEM)); network::Packet packet(wireOpcode(Opcode::CMSG_REPAIR_ITEM));
packet.writeUInt64(vendorGuid); packet.writeUInt64(vendorGuid);
@ -21096,7 +21096,7 @@ void GameHandler::repairAll(uint64_t vendorGuid, bool useGuildBank) {
} }
void GameHandler::sellItem(uint64_t vendorGuid, uint64_t itemGuid, uint32_t count) { void GameHandler::sellItem(uint64_t vendorGuid, uint64_t itemGuid, uint32_t count) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
LOG_INFO("Sell request: vendorGuid=0x", std::hex, vendorGuid, LOG_INFO("Sell request: vendorGuid=0x", std::hex, vendorGuid,
" itemGuid=0x", itemGuid, std::dec, " itemGuid=0x", itemGuid, std::dec,
" count=", count, " wire=0x", std::hex, wireOpcode(Opcode::CMSG_SELL_ITEM), std::dec); " count=", count, " wire=0x", std::hex, wireOpcode(Opcode::CMSG_SELL_ITEM), std::dec);
@ -21150,7 +21150,7 @@ void GameHandler::autoEquipItemBySlot(int backpackIndex) {
const auto& slot = inventory.getBackpackSlot(backpackIndex); const auto& slot = inventory.getBackpackSlot(backpackIndex);
if (slot.empty()) return; if (slot.empty()) return;
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
// WoW inventory: equipment 0-18, bags 19-22, backpack 23-38 // WoW inventory: equipment 0-18, bags 19-22, backpack 23-38
auto packet = AutoEquipItemPacket::build(0xFF, static_cast<uint8_t>(23 + backpackIndex)); auto packet = AutoEquipItemPacket::build(0xFF, static_cast<uint8_t>(23 + backpackIndex));
socket->send(packet); socket->send(packet);
@ -21161,7 +21161,7 @@ void GameHandler::autoEquipItemInBag(int bagIndex, int slotIndex) {
if (bagIndex < 0 || bagIndex >= inventory.NUM_BAG_SLOTS) return; if (bagIndex < 0 || bagIndex >= inventory.NUM_BAG_SLOTS) return;
if (slotIndex < 0 || slotIndex >= inventory.getBagSize(bagIndex)) return; if (slotIndex < 0 || slotIndex >= inventory.getBagSize(bagIndex)) return;
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
// Bag items: bag = equip slot 19+bagIndex, slot = index within bag // Bag items: bag = equip slot 19+bagIndex, slot = index within bag
auto packet = AutoEquipItemPacket::build( auto packet = AutoEquipItemPacket::build(
static_cast<uint8_t>(19 + bagIndex), static_cast<uint8_t>(slotIndex)); static_cast<uint8_t>(19 + bagIndex), static_cast<uint8_t>(slotIndex));
@ -21216,7 +21216,7 @@ void GameHandler::sellItemInBag(int bagIndex, int slotIndex) {
} }
void GameHandler::unequipToBackpack(EquipSlot equipSlot) { void GameHandler::unequipToBackpack(EquipSlot equipSlot) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
int freeSlot = inventory.findFreeBackpackSlot(); int freeSlot = inventory.findFreeBackpackSlot();
if (freeSlot < 0) { if (freeSlot < 0) {
@ -21273,7 +21273,7 @@ void GameHandler::swapBagSlots(int srcBagIndex, int dstBagIndex) {
} }
void GameHandler::destroyItem(uint8_t bag, uint8_t slot, uint8_t count) { void GameHandler::destroyItem(uint8_t bag, uint8_t slot, uint8_t count) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
if (count == 0) count = 1; if (count == 0) count = 1;
// AzerothCore WotLK expects CMSG_DESTROYITEM(bag:u8, slot:u8, count:u32). // AzerothCore WotLK expects CMSG_DESTROYITEM(bag:u8, slot:u8, count:u32).
@ -21289,7 +21289,7 @@ void GameHandler::destroyItem(uint8_t bag, uint8_t slot, uint8_t count) {
} }
void GameHandler::splitItem(uint8_t srcBag, uint8_t srcSlot, uint8_t count) { void GameHandler::splitItem(uint8_t srcBag, uint8_t srcSlot, uint8_t count) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
if (count == 0) return; if (count == 0) return;
// Find a free slot for the split destination: try backpack first, then bags // Find a free slot for the split destination: try backpack first, then bags
@ -21332,7 +21332,7 @@ void GameHandler::useItemBySlot(int backpackIndex) {
itemGuid = resolveOnlineItemGuid(slot.item.itemId); itemGuid = resolveOnlineItemGuid(slot.item.itemId);
} }
if (itemGuid != 0 && state == WorldState::IN_WORLD && socket) { if (itemGuid != 0 && isInWorld()) {
// Find the item's on-use spell ID from cached item info // Find the item's on-use spell ID from cached item info
uint32_t useSpellId = 0; uint32_t useSpellId = 0;
if (auto* info = getItemInfo(slot.item.itemId)) { if (auto* info = getItemInfo(slot.item.itemId)) {
@ -21377,7 +21377,7 @@ void GameHandler::useItemInBag(int bagIndex, int slotIndex) {
LOG_INFO("useItemInBag: bag=", bagIndex, " slot=", slotIndex, " itemId=", slot.item.itemId, LOG_INFO("useItemInBag: bag=", bagIndex, " slot=", slotIndex, " itemId=", slot.item.itemId,
" itemGuid=0x", std::hex, itemGuid, std::dec); " itemGuid=0x", std::hex, itemGuid, std::dec);
if (itemGuid != 0 && state == WorldState::IN_WORLD && socket) { if (itemGuid != 0 && isInWorld()) {
// Find the item's on-use spell ID // Find the item's on-use spell ID
uint32_t useSpellId = 0; uint32_t useSpellId = 0;
if (auto* info = getItemInfo(slot.item.itemId)) { if (auto* info = getItemInfo(slot.item.itemId)) {
@ -21407,7 +21407,7 @@ void GameHandler::useItemInBag(int bagIndex, int slotIndex) {
void GameHandler::openItemBySlot(int backpackIndex) { void GameHandler::openItemBySlot(int backpackIndex) {
if (backpackIndex < 0 || backpackIndex >= inventory.getBackpackSize()) return; if (backpackIndex < 0 || backpackIndex >= inventory.getBackpackSize()) return;
if (inventory.getBackpackSlot(backpackIndex).empty()) return; if (inventory.getBackpackSlot(backpackIndex).empty()) return;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = OpenItemPacket::build(0xFF, static_cast<uint8_t>(23 + backpackIndex)); auto packet = OpenItemPacket::build(0xFF, static_cast<uint8_t>(23 + backpackIndex));
LOG_INFO("openItemBySlot: CMSG_OPEN_ITEM bag=0xFF slot=", (23 + backpackIndex)); LOG_INFO("openItemBySlot: CMSG_OPEN_ITEM bag=0xFF slot=", (23 + backpackIndex));
socket->send(packet); socket->send(packet);
@ -21417,7 +21417,7 @@ void GameHandler::openItemInBag(int bagIndex, int slotIndex) {
if (bagIndex < 0 || bagIndex >= inventory.NUM_BAG_SLOTS) return; if (bagIndex < 0 || bagIndex >= inventory.NUM_BAG_SLOTS) return;
if (slotIndex < 0 || slotIndex >= inventory.getBagSize(bagIndex)) return; if (slotIndex < 0 || slotIndex >= inventory.getBagSize(bagIndex)) return;
if (inventory.getBagSlot(bagIndex, slotIndex).empty()) return; if (inventory.getBagSlot(bagIndex, slotIndex).empty()) return;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
uint8_t wowBag = static_cast<uint8_t>(19 + bagIndex); uint8_t wowBag = static_cast<uint8_t>(19 + bagIndex);
auto packet = OpenItemPacket::build(wowBag, static_cast<uint8_t>(slotIndex)); auto packet = OpenItemPacket::build(wowBag, static_cast<uint8_t>(slotIndex));
LOG_INFO("openItemInBag: CMSG_OPEN_ITEM bag=", static_cast<int>(wowBag), " slot=", slotIndex); LOG_INFO("openItemInBag: CMSG_OPEN_ITEM bag=", static_cast<int>(wowBag), " slot=", slotIndex);
@ -21503,7 +21503,7 @@ void GameHandler::handleLootResponse(network::Packet& packet) {
} }
if (currentLoot.gold > 0) { if (currentLoot.gold > 0) {
if (state == WorldState::IN_WORLD && socket) { if (isInWorld()) {
// Auto-loot gold by sending CMSG_LOOT_MONEY (server handles the rest) // Auto-loot gold by sending CMSG_LOOT_MONEY (server handles the rest)
bool suppressFallback = false; bool suppressFallback = false;
auto cooldownIt = recentLootMoneyAnnounceCooldowns_.find(currentLoot.lootGuid); auto cooldownIt = recentLootMoneyAnnounceCooldowns_.find(currentLoot.lootGuid);
@ -21520,7 +21520,7 @@ void GameHandler::handleLootResponse(network::Packet& packet) {
} }
// Auto-loot items when enabled // Auto-loot items when enabled
if (autoLoot_ && state == WorldState::IN_WORLD && socket && !localLoot.itemAutoLootSent) { if (autoLoot_ && isInWorld() && !localLoot.itemAutoLootSent) {
for (const auto& item : currentLoot.items) { for (const auto& item : currentLoot.items) {
auto pkt = AutostoreLootItemPacket::build(item.slotIndex); auto pkt = AutostoreLootItemPacket::build(item.slotIndex);
socket->send(pkt); socket->send(pkt);
@ -21891,7 +21891,7 @@ void GameHandler::handleTrainerList(network::Packet& packet) {
void GameHandler::trainSpell(uint32_t spellId) { void GameHandler::trainSpell(uint32_t spellId) {
LOG_INFO("trainSpell called: spellId=", spellId, " state=", static_cast<int>(state), " socket=", (socket ? "yes" : "no")); LOG_INFO("trainSpell called: spellId=", spellId, " state=", static_cast<int>(state), " socket=", (socket ? "yes" : "no"));
if (state != WorldState::IN_WORLD || !socket) { if (!isInWorld()) {
LOG_WARNING("trainSpell: Not in world or no socket connection"); LOG_WARNING("trainSpell: Not in world or no socket connection");
return; return;
} }
@ -24986,7 +24986,7 @@ void GameHandler::handleItemTextQueryResponse(network::Packet& packet) {
} }
void GameHandler::queryItemText(uint64_t itemGuid) { void GameHandler::queryItemText(uint64_t itemGuid) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
network::Packet pkt(wireOpcode(Opcode::CMSG_ITEM_TEXT_QUERY)); network::Packet pkt(wireOpcode(Opcode::CMSG_ITEM_TEXT_QUERY));
pkt.writeUInt64(itemGuid); pkt.writeUInt64(itemGuid);
socket->send(pkt); socket->send(pkt);
@ -25448,7 +25448,7 @@ void GameHandler::handleLootRollWon(network::Packet& packet) {
} }
void GameHandler::sendLootRoll(uint64_t objectGuid, uint32_t slot, uint8_t rollType) { void GameHandler::sendLootRoll(uint64_t objectGuid, uint32_t slot, uint8_t rollType) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
pendingLootRollActive_ = false; pendingLootRollActive_ = false;
network::Packet pkt(wireOpcode(Opcode::CMSG_LOOT_ROLL)); network::Packet pkt(wireOpcode(Opcode::CMSG_LOOT_ROLL));
@ -25514,7 +25514,7 @@ std::string GameHandler::getFormattedTitle(uint32_t bit) const {
} }
void GameHandler::sendSetTitle(int32_t bit) { void GameHandler::sendSetTitle(int32_t bit) {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
auto packet = SetTitlePacket::build(bit); auto packet = SetTitlePacket::build(bit);
socket->send(packet); socket->send(packet);
chosenTitleBit_ = bit; chosenTitleBit_ = bit;
@ -25776,7 +25776,7 @@ uint32_t GameHandler::getRepListIdByFactionId(uint32_t factionId) const {
void GameHandler::setWatchedFactionId(uint32_t factionId) { void GameHandler::setWatchedFactionId(uint32_t factionId) {
watchedFactionId_ = factionId; watchedFactionId_ = factionId;
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// CMSG_SET_WATCHED_FACTION: int32 repListId (-1 = unwatch) // CMSG_SET_WATCHED_FACTION: int32 repListId (-1 = unwatch)
int32_t repListId = -1; int32_t repListId = -1;
if (factionId != 0) { if (factionId != 0) {
@ -26009,7 +26009,7 @@ void GameHandler::declineBfMgrInvite() {
// ---- WotLK Calendar ---- // ---- WotLK Calendar ----
void GameHandler::requestCalendar() { void GameHandler::requestCalendar() {
if (state != WorldState::IN_WORLD || !socket) return; if (!isInWorld()) return;
// CMSG_CALENDAR_GET_CALENDAR has no payload // CMSG_CALENDAR_GET_CALENDAR has no payload
network::Packet pkt(wireOpcode(Opcode::CMSG_CALENDAR_GET_CALENDAR)); network::Packet pkt(wireOpcode(Opcode::CMSG_CALENDAR_GET_CALENDAR));
socket->send(pkt); socket->send(pkt);