diff --git a/ucs/ucs.cpp b/ucs/ucs.cpp index 5914b4fcc..1e365f41e 100644 --- a/ucs/ucs.cpp +++ b/ucs/ucs.cpp @@ -32,6 +32,8 @@ #include "worldserver.h" #include #include +#include +#include #include "../common/net/tcp_server.h" #include "../common/net/servertalk_client_connection.h" @@ -49,19 +51,43 @@ std::string WorldShortName; uint32 ChatMessagesSent = 0; uint32 MailMessagesSent = 0; -volatile bool RunLoops = true; - -void CatchSignal(int sig_num) { - - RunLoops = false; -} - std::string GetMailPrefix() { return "SOE.EQ." + WorldShortName + "."; } +void crash_func() { + std::this_thread::sleep_for(std::chrono::milliseconds(10000)); + int* p=0; + *p=0; +} + +void Shutdown() { + LogInfo("Shutting down..."); + ChannelList->RemoveAllChannels(); + g_Clientlist->CloseAllConnections(); + LogSys.CloseFileLogs(); +} + +int caught_loop = 0; +void CatchSignal(int sig_num) { + LogInfo("Caught signal [{}]", sig_num); + + EQ::EventLoop::Get().Shutdown(); + + caught_loop++; + // when signal handler is incapable of exiting properly + if (caught_loop > 1) { + LogInfo("In a signal handler loop and process is incapable of exiting properly, forcefully cleaning up"); + ChannelList->RemoveAllChannels(); + g_Clientlist->CloseAllConnections(); + LogSys.CloseFileLogs(); + std::exit(0); + } +} + + int main() { RegisterExecutablePlatform(ExePlatformUCS); LogSys.LoadLogSettingsDefaults(); @@ -134,17 +160,17 @@ int main() { database.LoadChatChannels(); - if (signal(SIGINT, CatchSignal) == SIG_ERR) { - LogInfo("Could not set signal handler"); - return 1; - } - if (signal(SIGTERM, CatchSignal) == SIG_ERR) { - LogInfo("Could not set signal handler"); - return 1; - } + std::signal(SIGINT, CatchSignal); + std::signal(SIGTERM, CatchSignal); + std::signal(SIGKILL, CatchSignal); + std::signal(SIGSEGV, CatchSignal); worldserver = new WorldServer; + // uncomment to simulate timed crash for catching SIGSEV +// std::thread crash_test(crash_func); +// crash_test.detach(); + auto loop_fn = [&](EQ::Timer* t) { Timer::SetCurrentTime(); @@ -166,12 +192,7 @@ int main() { EQ::EventLoop::Get().Run(); - ChannelList->RemoveAllChannels(); - - g_Clientlist->CloseAllConnections(); - - LogSys.CloseFileLogs(); - + Shutdown(); } void UpdateWindowTitle(char* iNewTitle) { diff --git a/zone/client.cpp b/zone/client.cpp index f990701a7..70f66521c 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -10971,3 +10971,80 @@ uint16 Client::GetClassTrackingDistanceMultiplier(uint16 class_) { bool Client::CanThisClassTrack() { return (GetClassTrackingDistanceMultiplier(GetClass()) > 0) ? true : false; } + +void Client::ReconnectUCS() +{ + EQApplicationPacket *outapp = nullptr; + std::string buffer; + std::string mail_key = database.GetMailKey(CharacterID(), true); + EQ::versions::UCSVersion connection_type = EQ::versions::ucsUnknown; + + // chat server packet + switch (ClientVersion()) { + case EQ::versions::ClientVersion::Titanium: + connection_type = EQ::versions::ucsTitaniumChat; + break; + case EQ::versions::ClientVersion::SoF: + connection_type = EQ::versions::ucsSoFCombined; + break; + case EQ::versions::ClientVersion::SoD: + connection_type = EQ::versions::ucsSoDCombined; + break; + case EQ::versions::ClientVersion::UF: + connection_type = EQ::versions::ucsUFCombined; + break; + case EQ::versions::ClientVersion::RoF: + connection_type = EQ::versions::ucsRoFCombined; + break; + case EQ::versions::ClientVersion::RoF2: + connection_type = EQ::versions::ucsRoF2Combined; + break; + default: + connection_type = EQ::versions::ucsUnknown; + break; + } + + buffer = StringFormat( + "%s,%i,%s.%s,%c%s", + Config->ChatHost.c_str(), + Config->ChatPort, + Config->ShortName.c_str(), + GetName(), + connection_type, + mail_key.c_str() + ); + + outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; + + QueuePacket(outapp); + safe_delete(outapp); + + // mail server packet + switch (ClientVersion()) { + case EQ::versions::ClientVersion::Titanium: + connection_type = EQ::versions::ucsTitaniumMail; + break; + default: + // retain value from previous switch + break; + } + + buffer = StringFormat( + "%s,%i,%s.%s,%c%s", + Config->MailHost.c_str(), + Config->MailPort, + Config->ShortName.c_str(), + GetName(), + connection_type, + mail_key.c_str() + ); + + outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1)); + memcpy(outapp->pBuffer, buffer.c_str(), buffer.length()); + outapp->pBuffer[buffer.length()] = '\0'; + + QueuePacket(outapp); + safe_delete(outapp); +} diff --git a/zone/client.h b/zone/client.h index 2622efcc4..a3ce93782 100644 --- a/zone/client.h +++ b/zone/client.h @@ -231,6 +231,8 @@ public: bool is_client_moving; + void ReconnectUCS(); + void SetDisplayMobInfoWindow(bool display_mob_info_window); bool GetDisplayMobInfoWindow() const; @@ -1025,7 +1027,7 @@ public: void SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration); bool IsLinkedSpellReuseTimerReady(uint32 timer_id); - + void ResetCastbarCooldownBySlot(int slot); void ResetAllCastbarCooldowns(); void ResetCastbarCooldownBySpellID(uint32 spell_id); @@ -1894,7 +1896,7 @@ private: Timer pick_lock_timer; Timer heroforge_wearchange_timer; - + glm::vec3 m_Proximity; glm::vec4 last_position_before_bulk_update; diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 58b25cbfc..db361dd6e 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -659,7 +659,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) if (database.GetInstanceID(client->CharacterID(), ZoneID(szp->zone))) { client->RemoveFromInstance(database.GetInstanceID(client->CharacterID(), ZoneID(szp->zone))); } - + client->AssignToInstance(szp->instance_id); client->MovePC(ZoneID(szp->zone), szp->instance_id, szp->x_pos, szp->y_pos, szp->z_pos, client->GetHeading(), szp->ignorerestrictions, GMSummon); } @@ -1917,7 +1917,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) LogSys.LoadLogDatabaseSettings(); break; } - case ServerOP_ReloadMerchants: { + case ServerOP_ReloadMerchants: { zone->SendReloadMessage("Merchants"); entity_list.ReloadMerchants(); break; @@ -2016,6 +2016,10 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) if (zone) { zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp); LogInfo("UCS Server is now [{}]", (ucsss->available == 1 ? "online" : "offline")); + + for (auto &e : entity_list.GetClientList()) { + e.second->ReconnectUCS(); + } } break; }