diff --git a/source/WorldServer/Player.cpp b/source/WorldServer/Player.cpp index cdf716e..322e3c4 100644 --- a/source/WorldServer/Player.cpp +++ b/source/WorldServer/Player.cpp @@ -7360,7 +7360,7 @@ void Player::SaveCustomSpellFields(LuaSpell* luaspell) { default: continue; } - savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_data (charid, spell_id, field, type, value) VALUES (%u, %u, '%s', '%s', '%s')", + savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT IGNORE INTO character_custom_spell_data (charid, spell_id, field, type, value) VALUES (%u, %u, '%s', '%s', '%s')", GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, database.getSafeEscapeString(field.c_str()).c_str(), @@ -7407,7 +7407,7 @@ void Player::SaveCustomSpellDataIndex(LuaSpell* luaspell) { continue; } - savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_dataindex (charid, spell_id, idx, type, value1, value2) VALUES (%u, %u, %d, '%s', '%s', '%s')", GetCharacterID(), + savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT IGNORE INTO character_custom_spell_dataindex (charid, spell_id, idx, type, value1, value2) VALUES (%u, %u, %d, '%s', '%s', '%s')", GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i, type.c_str(), value1.c_str(), value2.c_str()); @@ -7428,14 +7428,14 @@ void Player::SaveCustomSpellEffectsDisplay(LuaSpell* luaspell) { std::string charid = std::to_string(GetCharacterID()); - savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'description', '%s')", + savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT IGNORE INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'description', '%s')", GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i, database.getSafeEscapeString(eff->description.c_str()).c_str()); - savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'bullet', '%d')", + savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT IGNORE INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'bullet', '%d')", GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i, eff->subbullet); - savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'percentage', '%d')", + savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, "INSERT IGNORE INTO character_custom_spell_display (charid, spell_id, idx, field, value) VALUES (%u, %u, %d, 'percentage', '%d')", GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i, eff->percentage); } } @@ -7443,7 +7443,7 @@ void Player::SaveSpellEffects() { if(stop_save_spell_effects) { - LogWrite(PLAYER__WARNING, 0, "Player", "SaveSpellEffects called while player constructing / deconstructing!"); + LogWrite(PLAYER__WARNING, 0, "Player", "%s: SaveSpellEffects called while player constructing / deconstructing!", GetName()); return; } diff --git a/source/WorldServer/PlayerGroups.cpp b/source/WorldServer/PlayerGroups.cpp index d6edb63..c1251d0 100644 --- a/source/WorldServer/PlayerGroups.cpp +++ b/source/WorldServer/PlayerGroups.cpp @@ -906,25 +906,6 @@ int32 PlayerGroupManager::GetGroupSize(int32 group_id) { return ret; } -void PlayerGroupManager::SendGroupQuests(int32 group_id, Client* client) { - std::shared_lock lock(MGroups); - GroupMemberInfo* info = 0; - if (m_groups.count(group_id) > 0) { - m_groups[group_id]->MGroupMembers.readlock(__FUNCTION__, __LINE__); - deque* members = m_groups[group_id]->GetMembers(); - deque::iterator itr; - for (itr = members->begin(); itr != members->end(); itr++) { - info = *itr; - if (info->client) { - LogWrite(PLAYER__DEBUG, 0, "Player", "Send Quest Journal..."); - info->client->SendQuestJournal(false, client); - client->SendQuestJournal(false, info->client); - } - } - m_groups[group_id]->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__); - } -} - bool PlayerGroupManager::HasGroupCompletedQuest(int32 group_id, int32 quest_id) { std::shared_lock lock(MGroups); bool questComplete = true; diff --git a/source/WorldServer/PlayerGroups.h b/source/WorldServer/PlayerGroups.h index 2b23c01..f65c8cc 100644 --- a/source/WorldServer/PlayerGroups.h +++ b/source/WorldServer/PlayerGroups.h @@ -220,7 +220,6 @@ public: int32 GetGroupSize(int32 group_id); - void SendGroupQuests(int32 group_id, Client* client); bool HasGroupCompletedQuest(int32 group_id, int32 quest_id); void SimpleGroupMessage(int32 group_id, const char* message); diff --git a/source/WorldServer/Web/PeerManager.cpp b/source/WorldServer/Web/PeerManager.cpp index c0fbbdf..28a5c1e 100644 --- a/source/WorldServer/Web/PeerManager.cpp +++ b/source/WorldServer/Web/PeerManager.cpp @@ -837,4 +837,22 @@ void PeerManager::sendPeersMessage(const std::string& endpoint, int32 command, i peer_https_pool.sendPostRequestToPeerAsync(peer->id, peer->webAddr, std::to_string(peer->webPort), endpoint.c_str(), jsonPayload); } +} + +void PeerManager::sendPeersActiveQuery(int32 character_id, bool remove) { + + boost::property_tree::ptree root; + + root.put("char_id", character_id); + root.put("remove", remove); + + std::ostringstream jsonStream; + boost::property_tree::write_json(jsonStream, root); + std::string jsonPayload = jsonStream.str(); + for (const auto& [id, peer] : peers) { + if (peer->healthCheck.status != HealthStatus::OK) + continue; + + peer_https_pool.sendPostRequestToPeerAsync(peer->id, peer->webAddr, std::to_string(peer->webPort), "/activequery", jsonPayload); + } } \ No newline at end of file diff --git a/source/WorldServer/Web/PeerManager.h b/source/WorldServer/Web/PeerManager.h index aa603cb..90488a7 100644 --- a/source/WorldServer/Web/PeerManager.h +++ b/source/WorldServer/Web/PeerManager.h @@ -220,6 +220,7 @@ public: std::shared_ptr getCurrentPrimary(); void sendPeersMessage(const std::string& endpoint, int32 command, int32 sub_command = 0); + void sendPeersActiveQuery(int32 character_id, bool remove = false); void sendZonePlayerList(std::vector* queries, std::vector* peer_list, bool isGM); diff --git a/source/WorldServer/Web/WorldWeb.cpp b/source/WorldServer/Web/WorldWeb.cpp index b432234..1a00e98 100644 --- a/source/WorldServer/Web/WorldWeb.cpp +++ b/source/WorldServer/Web/WorldWeb.cpp @@ -1376,4 +1376,30 @@ void World::Web_worldhandle_peerstatus(const http::request& r std::string json = oss.str(); res.body() = json; res.prepare_payload(); +} + +void World::Web_worldhandle_activequery(const http::request& req, http::response& res) { + res.set(http::field::content_type, "application/json; charset=utf-8"); + boost::property_tree::ptree pt, json_tree; + + std::istringstream json_stream(req.body()); + boost::property_tree::read_json(json_stream, json_tree); + + int32 character_id = 0; + bool remove_query = false; + if (auto char_id = json_tree.get_optional("char_id")) { + character_id = char_id.get(); + } + if (auto remove = json_tree.get_optional("remove")) { + remove_query = remove.get(); + } + + if(character_id) { + if(remove_query) { + database.RemovePeerActiveQuery(character_id); + } + else { + database.AddPeerActiveQuery(character_id); + } + } } \ No newline at end of file diff --git a/source/WorldServer/World.cpp b/source/WorldServer/World.cpp index 7e76c66..e2283f1 100644 --- a/source/WorldServer/World.cpp +++ b/source/WorldServer/World.cpp @@ -1,6 +1,6 @@ /* EQ2Emulator: Everquest II Server Emulator - Copyright (C) 2005 - 2025 EQ2EMulator Development Team (http://www.eq2emu.com formerly http://www.eq2emulator.net) + Copyright (C) 2005 - 2026 EQ2EMulator Development Team (http://www.eq2emu.com formerly http://www.eq2emulator.net) This file is part of EQ2Emulator. @@ -282,6 +282,7 @@ void World::init(std::string web_ipaddr, int16 web_port, std::string cert_file, world_webserver->register_route("/setguildeventfilter", World::Web_worldhandle_setguildeventfilter); world_webserver->register_route("/peerstatus", World::Web_worldhandle_peerstatus); + world_webserver->register_route("/activequery", World::Web_worldhandle_activequery); world_webserver->run(); LogWrite(INIT__INFO, 0, "Init", "World Web Server is listening on %s:%u..", web_ipaddr.c_str(), web_port); web_success = true; @@ -377,8 +378,6 @@ void World::Process(){ WritePlayerStatistics(); if (server_stats_timer.Check()) WriteServerStatistics(); - /*if(remove_grouped_player.Check()) - CheckRemoveGroupedPlayer();*/ if (group_buff_updates.Check()) GetGroupManager()->UpdateGroupBuffs(); if (guilds_timer.Check()) @@ -2104,57 +2103,11 @@ void World::DeleteMerchantsInfo(){ void World::DeleteSpawns(){ - //reloading = true; - //ClearLootTables(); - /* - map::iterator npc_list_iter; - for(npc_list_iter=npc_list.begin();npc_list_iter!=npc_list.end();npc_list_iter++) { - safe_delete(npc_list_iter->second); - } - npc_list.clear(); - map::iterator object_list_iter; - for(object_list_iter=object_list.begin();object_list_iter!=object_list.end();object_list_iter++) { - safe_delete(object_list_iter->second); - } - object_list.clear(); - map::iterator groundspawn_list_iter; - for(groundspawn_list_iter=groundspawn_list.begin();groundspawn_list_iter!=groundspawn_list.end();groundspawn_list_iter++) { - safe_delete(groundspawn_list_iter->second); - } - groundspawn_list.clear(); - map::iterator widget_list_iter; - for(widget_list_iter=widget_list.begin();widget_list_iter!=widget_list.end();widget_list_iter++) { - safe_delete(widget_list_iter->second); - } - widget_list.clear(); - map::iterator sign_list_iter; - for(sign_list_iter=sign_list.begin();sign_list_iter!=sign_list.end();sign_list_iter++) { - safe_delete(sign_list_iter->second); - } - sign_list.clear();*/ map::iterator appearance_list_iter; for(appearance_list_iter=npc_appearance_list.begin();appearance_list_iter!=npc_appearance_list.end();appearance_list_iter++) { safe_delete(appearance_list_iter->second); } npc_appearance_list.clear(); - - /* - map* >::iterator command_list_iter; - for(command_list_iter=entity_command_list.begin();command_list_iter!=entity_command_list.end();command_list_iter++) { - vector* v = command_list_iter->second; - if(v){ - for(int32 i=0;isize();i++){ - safe_delete(v->at(i)); - } - safe_delete(v); - } - } - entity_command_list.clear(); - */ - - //DeleteGroundSpawnItems(); - //DeleteTransporters(); - //DeleteTransporterMaps(); } void World::ReloadGuilds() { @@ -2216,46 +2169,6 @@ void World::RemoveServerStatistics() { server_statistics.clear(); } -void World::SendGroupQuests(PlayerGroup* group, Client* client){ - return; - /*if(!group) - return; - GroupMemberInfo* info = 0; - MGroups.readlock(__FUNCTION__, __LINE__); - deque::iterator itr; - for(itr = group->members.begin(); itr != group->members.end(); itr++){ - info = *itr; - if(info->client){ - LogWrite(PLAYER__DEBUG, 0, "Player", "Send Quest Journal..."); - info->client->SendQuestJournal(false, client); - client->SendQuestJournal(false, info->client); - } - } - MGroups.releasereadlock(__FUNCTION__, __LINE__);*/ -} - -/*void World::CheckRemoveGroupedPlayer(){ - map::iterator itr; - GroupMemberInfo* found = 0; - MGroups.readlock(__FUNCTION__, __LINE__); - for(itr = group_removal_pending.begin(); itr != group_removal_pending.end(); itr++){ - if(itr->second < Timer::GetCurrentTime2()){ - found = itr->first; - break; - } - } - MGroups.releasereadlock(__FUNCTION__, __LINE__); - if(found){ - if(!found->client || (found->client && found->client->IsConnected() == false)) - DeleteGroupMember(found); - else{ - MGroups.writelock(__FUNCTION__, __LINE__); - group_removal_pending.erase(found); - MGroups.releasewritelock(__FUNCTION__, __LINE__); - } - } -}*/ - bool World::RejoinGroup(Client* client, int32 group_id){ if (!group_id) // no need if no group id! return false; diff --git a/source/WorldServer/World.h b/source/WorldServer/World.h index 3936d1b..f3bbca3 100644 --- a/source/WorldServer/World.h +++ b/source/WorldServer/World.h @@ -627,24 +627,7 @@ public: sint32 GetServerStatisticValue(int32 stat_id); void RemoveServerStatistics(); - //PlayerGroup* AddGroup(Client* leader); - //void AddGroupMember(PlayerGroup* group, Client* member); - //void RemoveGroupMember(Client* member, bool immediate = false); - //void DisbandGroup(PlayerGroup* group, bool lock = true); - void SendGroupQuests(PlayerGroup* group, Client* client); - //void UpdateGroupBuffs(); - //void RemoveGroupBuffs(PlayerGroup *group, Client *client); - //void SetPendingGroup(char* name, char* leader); - //void GroupMessage(PlayerGroup* group, const char* message, ...); - //void SimpleGroupMessage(PlayerGroup* group, const char* message); - //void GroupChatMessage(PlayerGroup* group, Spawn* from, const char* message); - //const char* GetPendingGroup(string name); - //void GroupReadLock(); - //void GroupReadUnLock(); - //void CheckRemoveGroupedPlayer(); - //void SendGroupUpdate(PlayerGroup* group, Client* exclude = 0); bool RejoinGroup(Client* client, int32 group_id); - //bool MakeLeader(Client* leader, string new_leader); void AddBonuses(Item* item, ItemStatsValues* values, int16 type, float value, Entity* entity); int32 CreateGuild(const char* guild_name, Client* leader = 0, int32 group_id = 0); @@ -754,6 +737,7 @@ public: static void Web_worldhandle_setguildpermission(const http::request& req, http::response& res); static void Web_worldhandle_setguildeventfilter(const http::request& req, http::response& res); static void Web_worldhandle_peerstatus(const http::request& req, http::response& res); + static void Web_worldhandle_activequery(const http::request& req, http::response& res); static void Web_populate_status(boost::property_tree::ptree& pt); diff --git a/source/WorldServer/client.cpp b/source/WorldServer/client.cpp index 8346a60..0899576 100644 --- a/source/WorldServer/client.cpp +++ b/source/WorldServer/client.cpp @@ -420,7 +420,7 @@ void Client::SendLoginInfo() { database.LoadCharacterQuestRewards(this); database.LoadPlayerMail(this); } - LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal..."); + LogWrite(CCLIENT__DEBUG, 0, "Client", "Client::SendLoginInfo %s Send Quest Journal...", GetPlayer()->GetName()); SendQuestJournal(true, 0, false); if (version > 561) // right version? possibly not! @@ -7204,14 +7204,15 @@ void Client::AddPlayerQuest(Quest* quest, bool call_accepted, bool send_packets) quest->SetPlayer(player); quest->SetSaveNeeded(true); + LogWrite(CCLIENT__DEBUG, 0, "Client", "Client::AddPlayerQuest %s added quest %s id %u...", GetPlayer()->GetName(), quest->GetName(), quest->GetQuestID()); + current_quest_id = quest->GetQuestID(); if (send_packets && quest->GetQuestGiver() > 0) GetCurrentZone()->SendSpawnChangesByDBID(quest->GetQuestGiver(), this, false, true); if (lua_interface && call_accepted) lua_interface->CallQuestFunction(quest, "Accepted", player); + if (send_packets) { - LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal..."); - //SendQuestJournal(); SendQuestJournalUpdate(quest); // sent twice to match live @@ -7240,15 +7241,15 @@ void Client::RemovePlayerQuest(int32 id, bool send_update, bool delete_quest) { int32 quest_giver = player->player_quests[id]->GetQuestGiver(); GetPlayer()->MPlayerQuests.releasewritelock(__FUNCTION__, __LINE__); + LogWrite(CCLIENT__DEBUG, 0, "Client", "Client::RemovePlayerQuest %s remove quest id %u...", GetPlayer()->GetName(), id); + if (send_update && quest_giver > 0) GetCurrentZone()->SendSpawnChangesByDBID(quest_giver, this, false, true); if (send_update) { - LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal..."); SendQuestJournal(false, 0, true); } player->RemoveQuest(id, delete_quest); if (send_update) { - LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal..."); SendQuestJournal(false, 0, true); GetCurrentZone()->SendAllSpawnsForVisChange(this); } @@ -7290,7 +7291,7 @@ void Client::SendQuestFailure(Quest* quest) { for (int32 i = 0; i < failures->size(); i++) { step = failures->at(i); QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, step, 1, false, true)); - LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal..."); + LogWrite(CCLIENT__DEBUG, 0, "Client", "Client::SendQuestFailure %s quest failure for %s id %u...", GetPlayer()->GetName(), quest->GetName(), quest->GetQuestID()); SendQuestJournal(false, 0, true); } failures->clear(); @@ -7318,8 +7319,9 @@ void Client::SendQuestUpdate(Quest* quest) { QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, step)); updated = true; } - LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal..."); - + if(updated) { + LogWrite(CCLIENT__DEBUG, 0, "Client", "Client::SendQuestUpdate %s step %u updated %s id %u...", GetPlayer()->GetName(), step->GetStepID(), quest->GetName(), quest->GetQuestID()); + } } if (lua_interface && quest->GetCompleted() && quest->GetCompleteAction()) { lua_interface->CallQuestFunction(quest, quest->GetCompleteAction(), player); @@ -7810,8 +7812,10 @@ void Client::GiveQuestReward(Quest* quest, bool has_displayed) { AddPendingQuestAcceptReward(quest); + LogWrite(CCLIENT__DEBUG, 0, "Client", "Client::GiveQuestReward %s completed quest, displaying reward for %s id %u...", GetPlayer()->GetName(), quest->GetName(), quest->GetQuestID()); + DisplayQuestComplete(quest, quest->GetQuestTemporaryState(), quest->GetQuestTemporaryDescription()); - LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal..."); + SendQuestJournal(); if (quest->GetQuestTemporaryState()) { diff --git a/source/WorldServer/zoneserver.cpp b/source/WorldServer/zoneserver.cpp index b1dc652..f5fafa8 100644 --- a/source/WorldServer/zoneserver.cpp +++ b/source/WorldServer/zoneserver.cpp @@ -3243,7 +3243,7 @@ bool ZoneServer::CallSpawnScript(Spawn* npc, int8 type, Spawn* spawn, const char bool fileExists = (stat(tmpScript.c_str(), &buffer) == 0); if (fileExists) { - LogWrite(SPAWN__WARNING, 0, "Spawn", "No script file described in the database, overriding with SpawnScript at %s", (char*)tmpScript.c_str()); + LogWrite(SPAWN__WARNING, 0, "Spawn", "No script file described in the database for spawn %s with database spawn id %u, overriding with SpawnScript at %s", npc->GetName(), npc->GetDatabaseID(), (char*)tmpScript.c_str()); npc->SetSpawnScript(tmpScript); script = npc->GetSpawnScript(); } diff --git a/source/common/database.cpp b/source/common/database.cpp index 9a88a5e..8369701 100644 --- a/source/common/database.cpp +++ b/source/common/database.cpp @@ -49,7 +49,9 @@ using namespace std; #include "emu_opcodes.h" #ifdef WORLD #include "../WorldServer/WorldDatabase.h" + #include "../WorldServer/Web/PeerManager.h" extern WorldDatabase database; + extern PeerManager peer_manager; #endif #ifdef LOGIN #include "../LoginServer/LoginDatabase.h" @@ -401,7 +403,7 @@ void Database::RunAsyncQueries(int32 queryid) } FreeDBInstance(asyncdb); - bool isActive = IsActiveQuery(queryid); + bool isActive = LocalIsActiveQuery(queryid); if (isActive) { continueAsync = true; @@ -444,7 +446,7 @@ void Database::AddAsyncQuery(Query* query) asyncQueriesMutex[query->GetQueryID()]->releasewritelock(); DBAsyncMutex.releasewritelock(); - bool isActive = IsActiveQuery(query->GetQueryID(), query); + bool isActive = LocalIsActiveQuery(query->GetQueryID(), query); if (!isActive) { continueAsync = true; @@ -533,35 +535,68 @@ void Database::RemoveActiveQuery(Query* query) } } DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__); + + bool isActive = LocalIsActiveQuery(query->GetQueryID()); + if(!isActive) { + peer_manager.sendPeersActiveQuery(query->GetQueryID(), true); + } } void Database::AddActiveQuery(Query* query) { + peer_manager.sendPeersActiveQuery(query->GetQueryID(), false); DBQueryMutex.writelock(__FUNCTION__, __LINE__); activeQuerySessions.push_back(query); DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__); } -bool Database::IsActiveQuery(int32 id, Query* skip) +bool Database::IsActiveQuery(int32 id, Query* skip) { + if (LocalIsActiveQuery(id, skip)) + return true; + + { + auto now = std::chrono::steady_clock::now(); + std::lock_guard lock(_peerMtx); + + // remove any entries older than timeout + for (auto it = _peerActive.begin(); it != _peerActive.end(); ) { + if (now - it->second > kStaleTimeout) + it = _peerActive.erase(it); + else + ++it; + } + + // if this id is still in the map, it's active + if (_peerActive.find(id) != _peerActive.end()) + return true; + } + + return false; +} + +bool Database::LocalIsActiveQuery(int32 id, Query* skip) { bool isActive = false; - DBQueryMutex.readlock(__FUNCTION__, __LINE__); - vector::iterator itr; - for (itr = activeQuerySessions.begin(); itr != activeQuerySessions.end(); itr++) - { - Query* query = *itr; - if (query == skip) - continue; - - if (query->GetQueryID() == id) - { + for (auto query : activeQuerySessions) { + if (query == skip) continue; + if (query->GetQueryID() == id) { isActive = true; break; } } DBQueryMutex.releasereadlock(__FUNCTION__, __LINE__); - return isActive; } + +void Database::AddPeerActiveQuery(int32 charID) { + auto now = std::chrono::steady_clock::now(); + std::lock_guard lock(_peerMtx); + _peerActive[charID] = now; // inserts or updates timestamp +} + +void Database::RemovePeerActiveQuery(int32 charID) { + std::lock_guard lock(_peerMtx); + _peerActive.erase(charID); +} #endif \ No newline at end of file diff --git a/source/common/database.h b/source/common/database.h index 4a5fbd2..52115e2 100644 --- a/source/common/database.h +++ b/source/common/database.h @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include using namespace std; class Query; @@ -60,12 +63,15 @@ public: void AddActiveQuery(Query* query); bool IsActiveQuery(int32 id, Query* skip=0); void PingAsyncDatabase(); + + void AddPeerActiveQuery(int32 charID); + void RemovePeerActiveQuery(int32 charID); #endif protected: private: void InitVars(); - + bool LocalIsActiveQuery(int32 id, Query* skip = nullptr); #ifdef WORLD void PurgeDBInstances(); void FreeDBInstance(Database* cur); @@ -77,6 +83,9 @@ private: Mutex DBAsyncMutex; Mutex DBInstanceMutex; Mutex DBQueryMutex; + std::unordered_map _peerActive; + std::mutex _peerMtx; + static constexpr std::chrono::seconds kStaleTimeout{30}; #endif };