From 16cfad1966cacd63e0d0ab93be9ec48762312d69 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Tue, 14 Apr 2020 23:28:43 -0500 Subject: [PATCH] UCS / Raid / Zone Fixes (#1033) * Cache EntityList::GetRaidByClient * Adjustments [skip ci] * Update entity [skip ci] * More cleanup [skip ci] * More tweaks [skip ci] * Cleanup [skip ci] * Fix bugs with UCS reconnection on crash / exit, not adding soft deleted characters, put main loop on UV lib * Reduce log spam that should be debugging; send keepalives to clients so that they properly prune from the connection list * Shutdown the eventloop to properly shutdown the zone versus calling a hard exit --- ucs/chatchannel.cpp | 29 ++++++++++++++----------- ucs/clientlist.cpp | 51 ++++++++++++++++++++++++++++++-------------- ucs/clientlist.h | 4 +++- ucs/database.cpp | 6 +++--- ucs/ucs.cpp | 24 ++++++++++++++------- ucs/worldserver.cpp | 2 +- world/ucs.cpp | 41 +++++++++++++++++++++++++---------- world/ucs.h | 13 ++++++++--- zone/client.cpp | 1 + zone/client.h | 3 +++ zone/entity.cpp | 23 ++++++++++++++------ zone/raids.cpp | 10 +++++---- zone/worldserver.cpp | 6 ++++-- zone/zone.cpp | 2 +- 14 files changed, 146 insertions(+), 69 deletions(-) diff --git a/ucs/chatchannel.cpp b/ucs/chatchannel.cpp index 001f7b1e7..efac898d5 100644 --- a/ucs/chatchannel.cpp +++ b/ucs/chatchannel.cpp @@ -47,8 +47,13 @@ ChatChannel::ChatChannel(std::string inName, std::string inOwner, std::string in Moderated = false; - LogInfo("New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]", - Name.c_str(), Owner.c_str(), Password.c_str(), MinimumStatus); + LogDebug( + "New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]", + Name.c_str(), + Owner.c_str(), + Password.c_str(), + MinimumStatus + ); } @@ -154,7 +159,7 @@ void ChatChannelList::SendAllChannels(Client *c) { void ChatChannelList::RemoveChannel(ChatChannel *Channel) { - LogInfo("RemoveChannel([{}])", Channel->GetName().c_str()); + LogDebug("RemoveChannel ([{}])", Channel->GetName().c_str()); LinkedListIterator iterator(ChatChannels); @@ -175,7 +180,7 @@ void ChatChannelList::RemoveChannel(ChatChannel *Channel) { void ChatChannelList::RemoveAllChannels() { - LogInfo("RemoveAllChannels"); + LogDebug("RemoveAllChannels"); LinkedListIterator iterator(ChatChannels); @@ -242,7 +247,7 @@ void ChatChannel::AddClient(Client *c) { int AccountStatus = c->GetAccountStatus(); - LogInfo("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str()); + LogDebug("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str()); LinkedListIterator iterator(ClientsInChannel); @@ -267,7 +272,7 @@ bool ChatChannel::RemoveClient(Client *c) { if(!c) return false; - LogInfo("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str()); + LogDebug("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str()); bool HideMe = c->GetHideMe(); @@ -304,7 +309,7 @@ bool ChatChannel::RemoveClient(Client *c) { if((Password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0)) return false; - LogInfo("Starting delete timer for empty password protected channel [{}]", Name.c_str()); + LogDebug("Starting delete timer for empty password protected channel [{}]", Name.c_str()); DeleteTimer.Start(RuleI(Channels, DeleteTimer) * 60000); } @@ -402,7 +407,7 @@ void ChatChannel::SendMessageToChannel(std::string Message, Client* Sender) { if(ChannelClient) { - LogInfo("Sending message to [{}] from [{}]", + LogDebug("Sending message to [{}] from [{}]", ChannelClient->GetName().c_str(), Sender->GetName().c_str()); if (cv_messages[static_cast(ChannelClient->GetClientVersion())].length() == 0) { @@ -505,7 +510,7 @@ ChatChannel *ChatChannelList::AddClientToChannel(std::string ChannelName, Client return nullptr; } - LogInfo("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str()); + LogDebug("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str()); ChatChannel *RequiredChannel = FindChannel(NormalisedName); @@ -581,7 +586,7 @@ void ChatChannelList::Process() { if(CurrentChannel && CurrentChannel->ReadyToDelete()) { - LogInfo("Empty temporary password protected channel [{}] being destroyed", + LogDebug("Empty temporary password protected channel [{}] being destroyed", CurrentChannel->GetName().c_str()); RemoveChannel(CurrentChannel); @@ -597,7 +602,7 @@ void ChatChannel::AddInvitee(const std::string &Invitee) if (!IsInvitee(Invitee)) { Invitees.push_back(Invitee); - LogInfo("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); + LogDebug("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); } } @@ -608,7 +613,7 @@ void ChatChannel::RemoveInvitee(std::string Invitee) if(it != std::end(Invitees)) { Invitees.erase(it); - LogInfo("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); + LogDebug("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); } } diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp index 429f28fbf..0b1d43262 100644 --- a/ucs/clientlist.cpp +++ b/ucs/clientlist.cpp @@ -235,7 +235,7 @@ std::vector ParseRecipients(std::string RecipientString) { static void ProcessMailTo(Client *c, std::string MailMessage) { - LogInfo("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str()); + LogDebug("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str()); std::vector Recipients; @@ -304,7 +304,7 @@ static void ProcessMailTo(Client *c, std::string MailMessage) { if (!database.SendMail(Recipient, c->MailBoxName(), Subject, Body, RecipientsString)) { - LogInfo("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(), + LogError("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(), c->MailBoxName().c_str(), Subject.c_str(), RecipientsString.c_str()); int PacketLength = 10 + Recipient.length() + Subject.length(); @@ -556,6 +556,17 @@ void Client::CloseConnection() { ClientStream->ReleaseFromUse(); } +void Clientlist::CheckForStaleConnectionsAll() +{ + LogDebug("Checking for stale connections"); + + auto it = ClientChatConnections.begin(); + while (it != ClientChatConnections.end()) { + (*it)->SendKeepAlive(); + ++it; + } +} + void Clientlist::CheckForStaleConnections(Client *c) { if (!c) return; @@ -634,10 +645,12 @@ void Clientlist::Process() // std::string::size_type LastPeriod = MailBoxString.find_last_of("."); - if (LastPeriod == std::string::npos) + if (LastPeriod == std::string::npos) { CharacterName = MailBoxString; - else + } + else { CharacterName = MailBoxString.substr(LastPeriod + 1); + } LogInfo("Received login for user [{}] with key [{}]", MailBox, Key); @@ -652,8 +665,9 @@ void Clientlist::Process() database.GetAccountStatus((*it)); - if ((*it)->GetConnectionType() == ConnectionTypeCombined) + if ((*it)->GetConnectionType() == ConnectionTypeCombined) { (*it)->SendFriends(); + } (*it)->SendMailBoxes(); @@ -865,7 +879,9 @@ void Clientlist::CloseAllConnections() { void Client::AddCharacter(int CharID, const char *CharacterName, int Level) { if (!CharacterName) return; - LogInfo("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str()); + + LogDebug("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str()); + CharacterEntry NewCharacter; NewCharacter.CharID = CharID; NewCharacter.Name = CharacterName; @@ -874,6 +890,10 @@ void Client::AddCharacter(int CharID, const char *CharacterName, int Level) { Characters.push_back(NewCharacter); } +void Client::SendKeepAlive() { + QueuePacket(new EQApplicationPacket(OP_SessionReady, 0)); +} + void Client::SendMailBoxes() { int Count = Characters.size(); @@ -930,7 +950,7 @@ void Client::AddToChannelList(ChatChannel *JoinedChannel) { for (int i = 0; i < MAX_JOINED_CHANNELS; i++) if (JoinedChannels[i] == nullptr) { JoinedChannels[i] = JoinedChannel; - LogInfo("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str()); + LogDebug("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str()); return; } } @@ -2346,18 +2366,17 @@ void Client::SendFriends() { } } -std::string Client::MailBoxName() { +std::string Client::MailBoxName() +{ + if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) { + LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", + CurrentMailBox, Characters.size()); - if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) - { - LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", - CurrentMailBox, Characters.size()); - - return ""; + return std::string(); } - LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", - CurrentMailBox, Characters.size()); + LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", + CurrentMailBox, Characters.size()); return Characters[CurrentMailBox].Name; diff --git a/ucs/clientlist.h b/ucs/clientlist.h index 6021c5c0e..548fb170c 100644 --- a/ucs/clientlist.h +++ b/ucs/clientlist.h @@ -143,7 +143,7 @@ public: void SetConnectionType(char c); ConnectionType GetConnectionType() { return TypeOfConnection; } EQEmu::versions::ClientVersion GetClientVersion() { return ClientVersion_; } - + inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); } void SendNotification(int MailBoxNumber, std::string From, std::string Subject, int MessageID); void ChangeMailBox(int NewMailBox); @@ -151,6 +151,7 @@ public: void SendFriends(); int GetCharID(); void SendUptime(); + void SendKeepAlive(); private: unsigned int CurrentMailBox; @@ -183,6 +184,7 @@ public: void Process(); void CloseAllConnections(); Client *FindCharacter(std::string CharacterName); + void CheckForStaleConnectionsAll(); void CheckForStaleConnections(Client *c); Client *IsCharacterOnline(std::string CharacterName); void ProcessOPMailCommand(Client *c, std::string CommandString); diff --git a/ucs/database.cpp b/ucs/database.cpp index d756f1ff4..108b17871 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -108,7 +108,7 @@ void Database::GetAccountStatus(Client *client) { std::string query = StringFormat( - "SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = '%i' LIMIT 1", + "SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = %i LIMIT 1", client->GetAccountID() ); @@ -173,7 +173,7 @@ int Database::FindAccount(const char *characterName, Client *client) query = StringFormat( "SELECT `id`, `name`, `level` FROM `character_data` " - "WHERE `account_id` = %i AND `name` != '%s'", + "WHERE `account_id` = %i AND `name` != '%s' AND deleted_at is NULL", accountID, characterName ); @@ -320,7 +320,7 @@ void Database::SendHeaders(Client *client) int unknownField3 = 1; int characterID = FindCharacter(client->MailBoxName().c_str()); - LogInfo("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID); + LogDebug("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID); if (characterID <= 0) { return; diff --git a/ucs/ucs.cpp b/ucs/ucs.cpp index 0f396252b..46bda530c 100644 --- a/ucs/ucs.cpp +++ b/ucs/ucs.cpp @@ -70,17 +70,18 @@ int main() { // Check every minute for unused channels we can delete // Timer ChannelListProcessTimer(60000); + Timer ClientConnectionPruneTimer(60000); Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect LogInfo("Starting EQEmu Universal Chat Server"); - if (!ucsconfig::LoadConfig()) { - LogInfo("Loading server configuration failed"); + if (!ucsconfig::LoadConfig()) { + LogInfo("Loading server configuration failed"); return 1; } - Config = ucsconfig::get(); + Config = ucsconfig::get(); WorldShortName = Config->ShortName; @@ -144,19 +145,26 @@ int main() { worldserver = new WorldServer; - while(RunLoops) { + auto loop_fn = [&](EQ::Timer* t) { Timer::SetCurrentTime(); g_Clientlist->Process(); - if(ChannelListProcessTimer.Check()) + if (ChannelListProcessTimer.Check()) { ChannelList->Process(); + } - EQ::EventLoop::Get().Process(); + if (ClientConnectionPruneTimer.Check()) { + g_Clientlist->CheckForStaleConnectionsAll(); + } - Sleep(5); - } + }; + + EQ::Timer process_timer(loop_fn); + process_timer.Start(32, true); + + EQ::EventLoop::Get().Run(); ChannelList->RemoveAllChannels(); diff --git a/ucs/worldserver.cpp b/ucs/worldserver.cpp index 72865e416..107624a0d 100644 --- a/ucs/worldserver.cpp +++ b/ucs/worldserver.cpp @@ -61,7 +61,7 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p) ServerPacket tpack(opcode, p); ServerPacket *pack = &tpack; - LogInfo("Received Opcode: {:#04x}", opcode); + LogNetcode("Received Opcode: {:#04x}", opcode); switch (opcode) { diff --git a/world/ucs.cpp b/world/ucs.cpp index f5910da80..cde94b8d9 100644 --- a/world/ucs.cpp +++ b/world/ucs.cpp @@ -6,29 +6,38 @@ #include "../common/misc_functions.h" #include "../common/md5.h" #include "../common/packet_dump.h" +#include "../common/event/timer.h" UCSConnection::UCSConnection() { - Stream = 0; + connection = 0; } void UCSConnection::SetConnection(std::shared_ptr inStream) { - if (Stream && Stream->Handle()) - { + if (inStream && connection && connection->Handle()) { LogInfo("Incoming UCS Connection while we were already connected to a UCS"); - Stream->Handle()->Disconnect(); + connection->Handle()->Disconnect(); + } + + connection = inStream; + if (connection) { + connection->OnMessage( + std::bind( + &UCSConnection::ProcessPacket, + this, + std::placeholders::_1, + std::placeholders::_2 + ) + ); } - Stream = inStream; - if (Stream) { - Stream->OnMessage(std::bind(&UCSConnection::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2)); - } + m_keepalive.reset(new EQ::Timer(5000, true, std::bind(&UCSConnection::OnKeepAlive, this, std::placeholders::_1))); } void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p) { - if (!Stream) + if (!connection) return; ServerPacket tpack(opcode, p); @@ -60,10 +69,10 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p) void UCSConnection::SendPacket(ServerPacket* pack) { - if (!Stream) + if (!connection) return; - Stream->SendPacket(pack); + connection->SendPacket(pack); } void UCSConnection::SendMessage(const char *From, const char *Message) @@ -78,3 +87,13 @@ void UCSConnection::SendMessage(const char *From, const char *Message) SendPacket(pack); safe_delete(pack); } + +void UCSConnection::OnKeepAlive(EQ::Timer *t) +{ + if (!connection) { + return; + } + + ServerPacket pack(ServerOP_KeepAlive, 0); + connection->SendPacket(&pack); +} diff --git a/world/ucs.h b/world/ucs.h index d2051c0be..c32872ccb 100644 --- a/world/ucs.h +++ b/world/ucs.h @@ -4,6 +4,7 @@ #include "../common/types.h" #include "../common/net/servertalk_server_connection.h" #include "../common/servertalk.h" +#include "../common/event/timer.h" #include class UCSConnection @@ -13,11 +14,17 @@ public: void SetConnection(std::shared_ptr connection); void ProcessPacket(uint16 opcode, EQ::Net::Packet &p); void SendPacket(ServerPacket* pack); - void Disconnect() { if(Stream && Stream->Handle()) Stream->Handle()->Disconnect(); } + void Disconnect() { if(connection && connection->Handle()) connection->Handle()->Disconnect(); } void SendMessage(const char *From, const char *Message); private: - inline std::string GetIP() const { return (Stream && Stream->Handle()) ? Stream->Handle()->RemoteIP() : 0; } - std::shared_ptr Stream; + inline std::string GetIP() const { return (connection && connection->Handle()) ? connection->Handle()->RemoteIP() : 0; } + std::shared_ptr connection; + + /** + * Keepalive + */ + std::unique_ptr m_keepalive; + void OnKeepAlive(EQ::Timer *t); }; #endif /*UCS_H_*/ diff --git a/zone/client.cpp b/zone/client.cpp index 4a7a66954..e730b32ee 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -256,6 +256,7 @@ Client::Client(EQStreamInterface* ieqs) TotalSecondsPlayed = 0; keyring.clear(); bind_sight_target = nullptr; + p_raid_instance = nullptr; mercid = 0; mercSlot = 0; InitializeMercInfo(); diff --git a/zone/client.h b/zone/client.h index 0986a31f5..be842ff50 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1304,6 +1304,8 @@ public: void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update); glm::vec4 &GetLastPositionBeforeBulkUpdate(); + Raid *p_raid_instance; + protected: friend class Mob; void CalcItemBonuses(StatBonuses* newbon); @@ -1343,6 +1345,7 @@ protected: char *adv_data; private: + eqFilterMode ClientFilters[_FilterCount]; int32 HandlePacket(const EQApplicationPacket *app); void OPTGB(const EQApplicationPacket *app); diff --git a/zone/entity.cpp b/zone/entity.cpp index b3805ad63..23ff268fc 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -498,7 +498,7 @@ void EntityList::MobProcess() size_t sz = mob_list.size(); #ifdef IDLE_WHEN_EMPTY - if (numclients > 0 || + if (numclients > 0 || mob->GetWanderType() == 4 || mob->GetWanderType() == 6) { // Normal processing, or assuring that spawns that should // path and depop do that. Otherwise all of these type mobs @@ -931,12 +931,12 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client) memcpy(new_door.name, door->GetDoorName(), 32); auto position = door->GetPosition(); - + new_door.xPos = position.x; new_door.yPos = position.y; new_door.zPos = position.z; new_door.heading = position.w; - + new_door.incline = door->GetIncline(); new_door.size = door->GetSize(); new_door.doorId = door->GetDoorID(); @@ -1984,17 +1984,26 @@ Raid *EntityList::GetRaidByID(uint32 id) Raid *EntityList::GetRaidByClient(Client* client) { - std::list::iterator iterator; + if (client->p_raid_instance) { + return client->p_raid_instance; + } + std::list::iterator iterator; iterator = raid_list.begin(); while (iterator != raid_list.end()) { - for (int x = 0; x < MAX_RAID_MEMBERS; x++) - if ((*iterator)->members[x].member) - if((*iterator)->members[x].member == client) + for (auto &member : (*iterator)->members) { + if (member.member) { + if (member.member == client) { + client->p_raid_instance = *iterator; return *iterator; + } + } + } + ++iterator; } + return nullptr; } diff --git a/zone/raids.cpp b/zone/raids.cpp index a4e1535d3..428b17843 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -177,6 +177,7 @@ void Raid::RemoveMember(const char *characterName) if(client) { client->SetRaidGrouped(false); client->LeaveRaidXTargets(this); + client->p_raid_instance = nullptr; } auto pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct)); @@ -1078,8 +1079,9 @@ void Raid::SendRaidRemoveAll(const char *who) void Raid::SendRaidDisband(Client *to) { - if(!to) + if (!to) { return; + } auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; @@ -1614,7 +1616,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) return; uint32 group_id = 0; - + if(mob->IsClient()) group_id = this->GetGroup(mob->CastToClient()); @@ -1622,7 +1624,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); mob->CreateHPPacket(&hpapp); - + for(int x = 0; x < MAX_RAID_MEMBERS; x++) { if(members[x].member) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { @@ -1633,7 +1635,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mana_update->spawn_id = mob->GetID(); mana_update->mana = mob->GetManaPercent(); members[x].member->QueuePacket(&outapp, false); - + outapp.SetOpcode(OP_MobEnduranceUpdate); MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer; endurance_update->endurance = mob->GetEndurancePercent(); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 87cfb13ef..4b2034067 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1881,9 +1881,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_UCSServerStatusReply: { - auto ucsss = (UCSServerStatus_Struct*)pack->pBuffer; - if (zone) + auto ucsss = (UCSServerStatus_Struct *) pack->pBuffer; + if (zone) { zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp); + LogInfo("UCS Server is now [{}]", (ucsss->available == 1 ? "online" : "offline")); + } break; } case ServerOP_CZSetEntityVariableByNPCTypeID: diff --git a/zone/zone.cpp b/zone/zone.cpp index 55de2b291..398c985c6 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -734,7 +734,7 @@ void Zone::Shutdown(bool quiet) if (RuleB(Zone, KillProcessOnDynamicShutdown)) { LogInfo("[KillProcessOnDynamicShutdown] Shutting down"); - std::exit(EXIT_SUCCESS); + EQ::EventLoop::Get().Shutdown(); } }