mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Added 'server ready' broadcast to UCS server so clients will reconnect after crash
This commit is contained in:
parent
c469571f62
commit
e547a1e778
@ -615,6 +615,7 @@ RULE_INT(Chat, KarmaGlobalChatLimit, 72) //amount of karma you need to be able t
|
||||
RULE_INT(Chat, GlobalChatLevelLimit, 8) //level limit you need to of reached to talk in ooc/auction/chat if your karma is too low.
|
||||
RULE_INT(Chat, ExpireClientVersionRequests, 3) // time in seconds to keep current cv requests active
|
||||
RULE_INT(Chat, ExpireClientVersionReplies, 30) // time in seconds to keep current cv replies active
|
||||
RULE_INT(Chat, UCSBroadcastServerReadyDelay, 60) // time in seconds to delay broadcast `server ready` after start-up
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Merchant)
|
||||
|
||||
@ -192,6 +192,7 @@
|
||||
#define ServerOP_CZSetEntityVariableByClientName 0x4012
|
||||
#define ServerOP_UCSClientVersionRequest 0x4013
|
||||
#define ServerOP_UCSClientVersionReply 0x4014
|
||||
#define ServerOP_UCSBroadcastServerReady 0x4015
|
||||
/* Query Server OP Codes */
|
||||
#define ServerOP_QSPlayerLogTrades 0x5010
|
||||
#define ServerOP_QSPlayerLogHandins 0x5011
|
||||
@ -1289,6 +1290,11 @@ struct UCSClientVersionReply_Struct {
|
||||
EQEmu::versions::ClientVersion client_version;
|
||||
};
|
||||
|
||||
struct UCSBroadcastServerReady_Struct {
|
||||
char chat_prefix[128];
|
||||
char mail_prefix[128];
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
|
||||
@ -110,6 +110,23 @@ uint32 SharedDatabase::GetTotalTimeEntitledOnAccount(uint32 AccountID) {
|
||||
return EntitledTime;
|
||||
}
|
||||
|
||||
void SharedDatabase::SetMailKey(int CharID, int IPAddress, int MailKey)
|
||||
{
|
||||
char MailKeyString[17];
|
||||
|
||||
if (RuleB(Chat, EnableMailKeyIPVerification) == true)
|
||||
sprintf(MailKeyString, "%08X%08X", IPAddress, MailKey);
|
||||
else
|
||||
sprintf(MailKeyString, "%08X", MailKey);
|
||||
|
||||
std::string query = StringFormat("UPDATE character_data SET mailkey = '%s' WHERE id = '%i'",
|
||||
MailKeyString, CharID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
Log(Logs::General, Logs::Error, "SharedDatabase::SetMailKey(%i, %s) : %s", CharID, MailKeyString, results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
bool SharedDatabase::SaveCursor(uint32 char_id, std::list<EQEmu::ItemInstance*>::const_iterator &start, std::list<EQEmu::ItemInstance*>::const_iterator &end)
|
||||
{
|
||||
// Delete cursor items
|
||||
|
||||
@ -72,6 +72,7 @@ class SharedDatabase : public Database
|
||||
void SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* message);
|
||||
bool GetCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &command_settings);
|
||||
uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID);
|
||||
void SetMailKey(int CharID, int IPAddress, int MailKey);
|
||||
|
||||
/*
|
||||
Character InventoryProfile
|
||||
|
||||
@ -140,10 +140,12 @@ int main() {
|
||||
|
||||
worldserver = new WorldServer;
|
||||
|
||||
// now that we can send packets to world, see if there's a
|
||||
// broadcast opcode that tells the client to relog into ucs
|
||||
worldserver->ActivateBroadcastServerReadyTimer();
|
||||
|
||||
while(RunLoops) {
|
||||
// this triggers clients to 'reconnect' to ucs after server crash
|
||||
if (worldserver->HasBroadcastServerReadyTimer())
|
||||
worldserver->ProcessBroadcastServerReady();
|
||||
|
||||
Timer::SetCurrentTime();
|
||||
|
||||
|
||||
@ -45,6 +45,8 @@ WorldServer::WorldServer()
|
||||
{
|
||||
m_connection.reset(new EQ::Net::ServertalkClient(Config->WorldIP, Config->WorldTCPPort, false, "UCS", Config->SharedKey));
|
||||
m_connection->OnMessage(std::bind(&WorldServer::ProcessMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
m_bsr_timer = nullptr;
|
||||
}
|
||||
|
||||
WorldServer::~WorldServer()
|
||||
@ -134,3 +136,37 @@ void WorldServer::ProcessClientVersionRequests(std::list<uint32>& id_list) {
|
||||
}
|
||||
id_list.clear();
|
||||
}
|
||||
|
||||
void WorldServer::ProcessBroadcastServerReady() {
|
||||
if (m_bsr_timer && (*m_bsr_timer) <= Timer::GetCurrentTime()) {
|
||||
UCSBroadcastServerReady_Struct bsr;
|
||||
memset(&bsr, 0, sizeof(UCSBroadcastServerReady_Struct));
|
||||
|
||||
sprintf(bsr.chat_prefix, "%s,%i,%s.",
|
||||
Config->ChatHost.c_str(),
|
||||
Config->ChatPort,
|
||||
Config->ShortName.c_str()
|
||||
);
|
||||
sprintf(bsr.mail_prefix, "%s,%i,%s.",
|
||||
Config->ChatHost.c_str(),
|
||||
Config->MailPort,
|
||||
Config->ShortName.c_str()
|
||||
);
|
||||
|
||||
EQ::Net::DynamicPacket dp_bsr;
|
||||
dp_bsr.PutData(0, &bsr, sizeof(UCSBroadcastServerReady_Struct));
|
||||
m_connection->Send(ServerOP_UCSBroadcastServerReady, dp_bsr);
|
||||
|
||||
safe_delete(m_bsr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldServer::ActivateBroadcastServerReadyTimer() {
|
||||
safe_delete(m_bsr_timer);
|
||||
m_bsr_timer = new uint32;
|
||||
|
||||
// clients do not drop their connection to ucs immediately...
|
||||
// it can take upwards of 60 seconds to process the drop
|
||||
// and clients will not re-connect to ucs until that occurs
|
||||
*m_bsr_timer = (Timer::GetCurrentTime() + (RuleI(Chat, UCSBroadcastServerReadyDelay) * 1000));
|
||||
}
|
||||
|
||||
@ -30,8 +30,13 @@ public:
|
||||
void ProcessMessage(uint16 opcode, EQ::Net::Packet &);
|
||||
|
||||
void ProcessClientVersionRequests(std::list<uint32>& id_list);
|
||||
|
||||
void ProcessBroadcastServerReady();
|
||||
bool HasBroadcastServerReadyTimer() { return (m_bsr_timer != nullptr); }
|
||||
void ActivateBroadcastServerReadyTimer();
|
||||
|
||||
private:
|
||||
uint32* m_bsr_timer;
|
||||
|
||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||
};
|
||||
|
||||
@ -52,6 +52,7 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p)
|
||||
Log(Logs::Detail, Logs::UCS_Server, "Got authentication from UCS when they are already authenticated.");
|
||||
break;
|
||||
}
|
||||
case ServerOP_UCSBroadcastServerReady:
|
||||
case ServerOP_UCSClientVersionRequest:
|
||||
{
|
||||
zoneserver_list.SendPacket(pack);
|
||||
|
||||
@ -516,23 +516,6 @@ void WorldDatabase::GetLauncherList(std::vector<std::string> &rl) {
|
||||
|
||||
}
|
||||
|
||||
void WorldDatabase::SetMailKey(int CharID, int IPAddress, int MailKey)
|
||||
{
|
||||
char MailKeyString[17];
|
||||
|
||||
if(RuleB(Chat, EnableMailKeyIPVerification) == true)
|
||||
sprintf(MailKeyString, "%08X%08X", IPAddress, MailKey);
|
||||
else
|
||||
sprintf(MailKeyString, "%08X", MailKey);
|
||||
|
||||
std::string query = StringFormat("UPDATE character_data SET mailkey = '%s' WHERE id = '%i'",
|
||||
MailKeyString, CharID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
Log(Logs::General, Logs::Error, "WorldDatabase::SetMailKey(%i, %s) : %s", CharID, MailKeyString, results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
bool WorldDatabase::GetCharacterLevel(const char *name, int &level)
|
||||
{
|
||||
std::string query = StringFormat("SELECT level FROM character_data WHERE name = '%s'", name);
|
||||
|
||||
@ -34,7 +34,6 @@ public:
|
||||
int MoveCharacterToBind(int CharID, uint8 bindnum = 0);
|
||||
|
||||
void GetLauncherList(std::vector<std::string> &result);
|
||||
void SetMailKey(int CharID, int IPAddress, int MailKey);
|
||||
bool GetCharacterLevel(const char *name, int &level);
|
||||
|
||||
bool LoadCharacterCreateAllocations();
|
||||
|
||||
@ -1813,6 +1813,57 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_UCSBroadcastServerReady:
|
||||
{
|
||||
UCSBroadcastServerReady_Struct* bsr = (UCSBroadcastServerReady_Struct*)pack->pBuffer;
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
std::string buffer;
|
||||
|
||||
for (auto liter : entity_list.GetClientList()) {
|
||||
auto c = liter.second;
|
||||
if (!c)
|
||||
continue;
|
||||
|
||||
int MailKey = zone->random.Int(1, INT_MAX);
|
||||
|
||||
database.SetMailKey(c->CharacterID(), c->GetIP(), MailKey);
|
||||
|
||||
char ConnectionType;
|
||||
|
||||
// chat server packet
|
||||
if (c->ClientVersionBit() & EQEmu::versions::bit_UFAndLater)
|
||||
ConnectionType = 'U';
|
||||
else if (c->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)
|
||||
ConnectionType = 'S';
|
||||
else
|
||||
ConnectionType = 'C';
|
||||
|
||||
buffer = bsr->chat_prefix;
|
||||
buffer.append(StringFormat("%s,%c%08X", c->GetName(), ConnectionType, MailKey));
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1));
|
||||
memcpy(outapp->pBuffer, buffer.c_str(), buffer.length());
|
||||
outapp->pBuffer[buffer.length()] = '\0';
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// mail server packet
|
||||
if (c->ClientVersionBit() & EQEmu::versions::bit_TitaniumAndEarlier)
|
||||
ConnectionType = 'M';
|
||||
|
||||
buffer = bsr->mail_prefix;
|
||||
buffer.append(StringFormat("%s,%c%08X", c->GetName(), ConnectionType, MailKey));
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1));
|
||||
memcpy(outapp->pBuffer, buffer.c_str(), buffer.length());
|
||||
outapp->pBuffer[buffer.length()] = '\0';
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_UCSClientVersionRequest:
|
||||
{
|
||||
UCSClientVersionRequest_Struct* cvreq = (UCSClientVersionRequest_Struct*)pack->pBuffer;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user