DB async query synching to peers, code/logging cleanup

This commit is contained in:
Emagi 2025-06-29 14:03:23 -04:00
parent 2a133292b0
commit 1ba65aba78
12 changed files with 127 additions and 157 deletions

View File

@ -7360,7 +7360,7 @@ void Player::SaveCustomSpellFields(LuaSpell* luaspell) {
default: continue; 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(), GetCharacterID(),
luaspell->spell->GetSpellData()->inherited_spell_id, luaspell->spell->GetSpellData()->inherited_spell_id,
database.getSafeEscapeString(field.c_str()).c_str(), database.getSafeEscapeString(field.c_str()).c_str(),
@ -7407,7 +7407,7 @@ void Player::SaveCustomSpellDataIndex(LuaSpell* luaspell) {
continue; 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, luaspell->spell->GetSpellData()->inherited_spell_id,
i, i,
type.c_str(), value1.c_str(), value2.c_str()); 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()); 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, GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i,
database.getSafeEscapeString(eff->description.c_str()).c_str()); 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); 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); GetCharacterID(), luaspell->spell->GetSpellData()->inherited_spell_id, i, eff->percentage);
} }
} }
@ -7443,7 +7443,7 @@ void Player::SaveSpellEffects()
{ {
if(stop_save_spell_effects) 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; return;
} }

View File

@ -906,25 +906,6 @@ int32 PlayerGroupManager::GetGroupSize(int32 group_id) {
return ret; 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<GroupMemberInfo*>* members = m_groups[group_id]->GetMembers();
deque<GroupMemberInfo*>::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) { bool PlayerGroupManager::HasGroupCompletedQuest(int32 group_id, int32 quest_id) {
std::shared_lock lock(MGroups); std::shared_lock lock(MGroups);
bool questComplete = true; bool questComplete = true;

View File

@ -220,7 +220,6 @@ public:
int32 GetGroupSize(int32 group_id); int32 GetGroupSize(int32 group_id);
void SendGroupQuests(int32 group_id, Client* client);
bool HasGroupCompletedQuest(int32 group_id, int32 quest_id); bool HasGroupCompletedQuest(int32 group_id, int32 quest_id);
void SimpleGroupMessage(int32 group_id, const char* message); void SimpleGroupMessage(int32 group_id, const char* message);

View File

@ -838,3 +838,21 @@ 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); 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);
}
}

View File

@ -220,6 +220,7 @@ public:
std::shared_ptr<Peer> getCurrentPrimary(); std::shared_ptr<Peer> getCurrentPrimary();
void sendPeersMessage(const std::string& endpoint, int32 command, int32 sub_command = 0); void sendPeersMessage(const std::string& endpoint, int32 command, int32 sub_command = 0);
void sendPeersActiveQuery(int32 character_id, bool remove = false);
void sendZonePlayerList(std::vector<string>* queries, std::vector<WhoAllPeerPlayer>* peer_list, bool isGM); void sendZonePlayerList(std::vector<string>* queries, std::vector<WhoAllPeerPlayer>* peer_list, bool isGM);

View File

@ -1377,3 +1377,29 @@ void World::Web_worldhandle_peerstatus(const http::request<http::string_body>& r
res.body() = json; res.body() = json;
res.prepare_payload(); res.prepare_payload();
} }
void World::Web_worldhandle_activequery(const http::request<http::string_body>& req, http::response<http::string_body>& 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<int32>("char_id")) {
character_id = char_id.get();
}
if (auto remove = json_tree.get_optional<bool>("remove")) {
remove_query = remove.get();
}
if(character_id) {
if(remove_query) {
database.RemovePeerActiveQuery(character_id);
}
else {
database.AddPeerActiveQuery(character_id);
}
}
}

View File

@ -1,6 +1,6 @@
/* /*
EQ2Emulator: Everquest II Server Emulator 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. 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("/setguildeventfilter", World::Web_worldhandle_setguildeventfilter);
world_webserver->register_route("/peerstatus", World::Web_worldhandle_peerstatus); world_webserver->register_route("/peerstatus", World::Web_worldhandle_peerstatus);
world_webserver->register_route("/activequery", World::Web_worldhandle_activequery);
world_webserver->run(); world_webserver->run();
LogWrite(INIT__INFO, 0, "Init", "World Web Server is listening on %s:%u..", web_ipaddr.c_str(), web_port); LogWrite(INIT__INFO, 0, "Init", "World Web Server is listening on %s:%u..", web_ipaddr.c_str(), web_port);
web_success = true; web_success = true;
@ -377,8 +378,6 @@ void World::Process(){
WritePlayerStatistics(); WritePlayerStatistics();
if (server_stats_timer.Check()) if (server_stats_timer.Check())
WriteServerStatistics(); WriteServerStatistics();
/*if(remove_grouped_player.Check())
CheckRemoveGroupedPlayer();*/
if (group_buff_updates.Check()) if (group_buff_updates.Check())
GetGroupManager()->UpdateGroupBuffs(); GetGroupManager()->UpdateGroupBuffs();
if (guilds_timer.Check()) if (guilds_timer.Check())
@ -2104,57 +2103,11 @@ void World::DeleteMerchantsInfo(){
void World::DeleteSpawns(){ void World::DeleteSpawns(){
//reloading = true;
//ClearLootTables();
/*
map<int32, NPC*>::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<int32, Object*>::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<int32, GroundSpawn*>::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<int32, Widget*>::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<int32, Sign*>::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<int32, AppearanceData*>::iterator appearance_list_iter; map<int32, AppearanceData*>::iterator appearance_list_iter;
for(appearance_list_iter=npc_appearance_list.begin();appearance_list_iter!=npc_appearance_list.end();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); safe_delete(appearance_list_iter->second);
} }
npc_appearance_list.clear(); npc_appearance_list.clear();
/*
map<int32, vector<EntityCommand*>* >::iterator command_list_iter;
for(command_list_iter=entity_command_list.begin();command_list_iter!=entity_command_list.end();command_list_iter++) {
vector<EntityCommand*>* v = command_list_iter->second;
if(v){
for(int32 i=0;i<v->size();i++){
safe_delete(v->at(i));
}
safe_delete(v);
}
}
entity_command_list.clear();
*/
//DeleteGroundSpawnItems();
//DeleteTransporters();
//DeleteTransporterMaps();
} }
void World::ReloadGuilds() { void World::ReloadGuilds() {
@ -2216,46 +2169,6 @@ void World::RemoveServerStatistics() {
server_statistics.clear(); server_statistics.clear();
} }
void World::SendGroupQuests(PlayerGroup* group, Client* client){
return;
/*if(!group)
return;
GroupMemberInfo* info = 0;
MGroups.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>::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<GroupMemberInfo*, int32>::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){ bool World::RejoinGroup(Client* client, int32 group_id){
if (!group_id) // no need if no group id! if (!group_id) // no need if no group id!
return false; return false;

View File

@ -627,24 +627,7 @@ public:
sint32 GetServerStatisticValue(int32 stat_id); sint32 GetServerStatisticValue(int32 stat_id);
void RemoveServerStatistics(); 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 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); 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); 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<http::string_body>& req, http::response<http::string_body>& res); static void Web_worldhandle_setguildpermission(const http::request<http::string_body>& req, http::response<http::string_body>& res);
static void Web_worldhandle_setguildeventfilter(const http::request<http::string_body>& req, http::response<http::string_body>& res); static void Web_worldhandle_setguildeventfilter(const http::request<http::string_body>& req, http::response<http::string_body>& res);
static void Web_worldhandle_peerstatus(const http::request<http::string_body>& req, http::response<http::string_body>& res); static void Web_worldhandle_peerstatus(const http::request<http::string_body>& req, http::response<http::string_body>& res);
static void Web_worldhandle_activequery(const http::request<http::string_body>& req, http::response<http::string_body>& res);
static void Web_populate_status(boost::property_tree::ptree& pt); static void Web_populate_status(boost::property_tree::ptree& pt);

View File

@ -420,7 +420,7 @@ void Client::SendLoginInfo() {
database.LoadCharacterQuestRewards(this); database.LoadCharacterQuestRewards(this);
database.LoadPlayerMail(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); SendQuestJournal(true, 0, false);
if (version > 561) // right version? possibly not! 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->SetPlayer(player);
quest->SetSaveNeeded(true); 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(); current_quest_id = quest->GetQuestID();
if (send_packets && quest->GetQuestGiver() > 0) if (send_packets && quest->GetQuestGiver() > 0)
GetCurrentZone()->SendSpawnChangesByDBID(quest->GetQuestGiver(), this, false, true); GetCurrentZone()->SendSpawnChangesByDBID(quest->GetQuestGiver(), this, false, true);
if (lua_interface && call_accepted) if (lua_interface && call_accepted)
lua_interface->CallQuestFunction(quest, "Accepted", player); lua_interface->CallQuestFunction(quest, "Accepted", player);
if (send_packets) { if (send_packets) {
LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
//SendQuestJournal();
SendQuestJournalUpdate(quest); SendQuestJournalUpdate(quest);
// sent twice to match live // 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(); int32 quest_giver = player->player_quests[id]->GetQuestGiver();
GetPlayer()->MPlayerQuests.releasewritelock(__FUNCTION__, __LINE__); 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) if (send_update && quest_giver > 0)
GetCurrentZone()->SendSpawnChangesByDBID(quest_giver, this, false, true); GetCurrentZone()->SendSpawnChangesByDBID(quest_giver, this, false, true);
if (send_update) { if (send_update) {
LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
SendQuestJournal(false, 0, true); SendQuestJournal(false, 0, true);
} }
player->RemoveQuest(id, delete_quest); player->RemoveQuest(id, delete_quest);
if (send_update) { if (send_update) {
LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
SendQuestJournal(false, 0, true); SendQuestJournal(false, 0, true);
GetCurrentZone()->SendAllSpawnsForVisChange(this); GetCurrentZone()->SendAllSpawnsForVisChange(this);
} }
@ -7290,7 +7291,7 @@ void Client::SendQuestFailure(Quest* quest) {
for (int32 i = 0; i < failures->size(); i++) { for (int32 i = 0; i < failures->size(); i++) {
step = failures->at(i); step = failures->at(i);
QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, step, 1, false, true)); 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); SendQuestJournal(false, 0, true);
} }
failures->clear(); failures->clear();
@ -7318,8 +7319,9 @@ void Client::SendQuestUpdate(Quest* quest) {
QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, step)); QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, step));
updated = true; 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()) { if (lua_interface && quest->GetCompleted() && quest->GetCompleteAction()) {
lua_interface->CallQuestFunction(quest, quest->GetCompleteAction(), player); lua_interface->CallQuestFunction(quest, quest->GetCompleteAction(), player);
@ -7810,8 +7812,10 @@ void Client::GiveQuestReward(Quest* quest, bool has_displayed) {
AddPendingQuestAcceptReward(quest); 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()); DisplayQuestComplete(quest, quest->GetQuestTemporaryState(), quest->GetQuestTemporaryDescription());
LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
SendQuestJournal(); SendQuestJournal();
if (quest->GetQuestTemporaryState()) { if (quest->GetQuestTemporaryState()) {

View File

@ -3243,7 +3243,7 @@ bool ZoneServer::CallSpawnScript(Spawn* npc, int8 type, Spawn* spawn, const char
bool fileExists = (stat(tmpScript.c_str(), &buffer) == 0); bool fileExists = (stat(tmpScript.c_str(), &buffer) == 0);
if (fileExists) 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); npc->SetSpawnScript(tmpScript);
script = npc->GetSpawnScript(); script = npc->GetSpawnScript();
} }

View File

@ -49,7 +49,9 @@ using namespace std;
#include "emu_opcodes.h" #include "emu_opcodes.h"
#ifdef WORLD #ifdef WORLD
#include "../WorldServer/WorldDatabase.h" #include "../WorldServer/WorldDatabase.h"
#include "../WorldServer/Web/PeerManager.h"
extern WorldDatabase database; extern WorldDatabase database;
extern PeerManager peer_manager;
#endif #endif
#ifdef LOGIN #ifdef LOGIN
#include "../LoginServer/LoginDatabase.h" #include "../LoginServer/LoginDatabase.h"
@ -401,7 +403,7 @@ void Database::RunAsyncQueries(int32 queryid)
} }
FreeDBInstance(asyncdb); FreeDBInstance(asyncdb);
bool isActive = IsActiveQuery(queryid); bool isActive = LocalIsActiveQuery(queryid);
if (isActive) if (isActive)
{ {
continueAsync = true; continueAsync = true;
@ -444,7 +446,7 @@ void Database::AddAsyncQuery(Query* query)
asyncQueriesMutex[query->GetQueryID()]->releasewritelock(); asyncQueriesMutex[query->GetQueryID()]->releasewritelock();
DBAsyncMutex.releasewritelock(); DBAsyncMutex.releasewritelock();
bool isActive = IsActiveQuery(query->GetQueryID(), query); bool isActive = LocalIsActiveQuery(query->GetQueryID(), query);
if (!isActive) if (!isActive)
{ {
continueAsync = true; continueAsync = true;
@ -533,35 +535,68 @@ void Database::RemoveActiveQuery(Query* query)
} }
} }
DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__); DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__);
bool isActive = LocalIsActiveQuery(query->GetQueryID());
if(!isActive) {
peer_manager.sendPeersActiveQuery(query->GetQueryID(), true);
}
} }
void Database::AddActiveQuery(Query* query) void Database::AddActiveQuery(Query* query)
{ {
peer_manager.sendPeersActiveQuery(query->GetQueryID(), false);
DBQueryMutex.writelock(__FUNCTION__, __LINE__); DBQueryMutex.writelock(__FUNCTION__, __LINE__);
activeQuerySessions.push_back(query); activeQuerySessions.push_back(query);
DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__); 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<std::mutex> 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; bool isActive = false;
DBQueryMutex.readlock(__FUNCTION__, __LINE__); DBQueryMutex.readlock(__FUNCTION__, __LINE__);
vector<Query*>::iterator itr; for (auto query : activeQuerySessions) {
for (itr = activeQuerySessions.begin(); itr != activeQuerySessions.end(); itr++) if (query == skip) continue;
{ if (query->GetQueryID() == id) {
Query* query = *itr;
if (query == skip)
continue;
if (query->GetQueryID() == id)
{
isActive = true; isActive = true;
break; break;
} }
} }
DBQueryMutex.releasereadlock(__FUNCTION__, __LINE__); DBQueryMutex.releasereadlock(__FUNCTION__, __LINE__);
return isActive; return isActive;
} }
void Database::AddPeerActiveQuery(int32 charID) {
auto now = std::chrono::steady_clock::now();
std::lock_guard<std::mutex> lock(_peerMtx);
_peerActive[charID] = now; // inserts or updates timestamp
}
void Database::RemovePeerActiveQuery(int32 charID) {
std::lock_guard<std::mutex> lock(_peerMtx);
_peerActive.erase(charID);
}
#endif #endif

View File

@ -35,6 +35,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
#include <mutex>
#include <unordered_map>
#include <chrono>
using namespace std; using namespace std;
class Query; class Query;
@ -60,12 +63,15 @@ public:
void AddActiveQuery(Query* query); void AddActiveQuery(Query* query);
bool IsActiveQuery(int32 id, Query* skip=0); bool IsActiveQuery(int32 id, Query* skip=0);
void PingAsyncDatabase(); void PingAsyncDatabase();
void AddPeerActiveQuery(int32 charID);
void RemovePeerActiveQuery(int32 charID);
#endif #endif
protected: protected:
private: private:
void InitVars(); void InitVars();
bool LocalIsActiveQuery(int32 id, Query* skip = nullptr);
#ifdef WORLD #ifdef WORLD
void PurgeDBInstances(); void PurgeDBInstances();
void FreeDBInstance(Database* cur); void FreeDBInstance(Database* cur);
@ -77,6 +83,9 @@ private:
Mutex DBAsyncMutex; Mutex DBAsyncMutex;
Mutex DBInstanceMutex; Mutex DBInstanceMutex;
Mutex DBQueryMutex; Mutex DBQueryMutex;
std::unordered_map<int32, std::chrono::steady_clock::time_point> _peerActive;
std::mutex _peerMtx;
static constexpr std::chrono::seconds kStaleTimeout{30};
#endif #endif
}; };