diff --git a/common/servertalk.h b/common/servertalk.h index 94eece8ca..3ad7c0cc2 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -80,6 +80,7 @@ #define ServerOP_GroupJoin 0x003e //for joining ooz folks #define ServerOP_UpdateSpawn 0x003f #define ServerOP_SpawnStatusChange 0x0040 +#define ServerOP_DropClient 0x0041 // DropClient #define ServerOP_ReloadTasks 0x0060 #define ServerOP_DepopAllPlayersCorpses 0x0061 #define ServerOP_ReloadTitles 0x0062 @@ -317,11 +318,17 @@ struct ServerZoneIncomingClient_Struct { uint32 accid; int16 admin; uint32 charid; + uint32 lsid; bool tellsoff; char charname[64]; char lskey[30]; }; +struct ServerZoneDropClient_Struct +{ + uint32 lsid; +}; + struct ServerChangeWID_Struct { uint32 charid; uint32 newwid; diff --git a/world/cliententry.cpp b/world/cliententry.cpp index be8916676..1402b1420 100644 --- a/world/cliententry.cpp +++ b/world/cliententry.cpp @@ -121,6 +121,8 @@ void ClientListEntry::SetOnline(ZoneServer* iZS, int8 iOnline) { } void ClientListEntry::SetOnline(int8 iOnline) { + Log(Logs::Detail, Logs::World_Server, "ClientListEntry::SetOnline for %s(%i) = %i", AccountName(), AccountID(), iOnline); + if (iOnline >= CLE_Status_Online && pOnline < CLE_Status_Online) numplayers++; else if (iOnline < CLE_Status_Online && pOnline >= CLE_Status_Online) { diff --git a/world/clientlist.cpp b/world/clientlist.cpp index 2c3a958d2..cc783affd 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -64,8 +64,6 @@ void ClientList::Process() { struct in_addr in; in.s_addr = iterator.GetData()->GetIP(); Log(Logs::Detail, Logs::World_Server,"Removing client from %s:%d", inet_ntoa(in), iterator.GetData()->GetPort()); -//the client destructor should take care of this. -// iterator.GetData()->Free(); iterator.RemoveCurrent(); } else diff --git a/world/login_server.cpp b/world/login_server.cpp index 73cb8a3eb..e0990d964 100644 --- a/world/login_server.cpp +++ b/world/login_server.cpp @@ -109,14 +109,14 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) { auto cle = client_list.FindCLEByLSID(utwr->lsaccountid); if (cle != nullptr) { auto status = cle->GetOnline(); - if (CLE_Status_Zoning == status || CLE_Status_InZone == status) { + if (CLE_Status_InZone == status) { utwrs->response = UserToWorldStatusAlreadyOnline; SendPacket(&outpack); return; } else { - //our existing cle is in a state we can login to, mark the old as stale and remove it. - client_list.RemoveCLEByLSID(utwr->lsaccountid); + zoneserver_list.DropClient(utwrs->lsaccountid); + client_list.RemoveCLEByLSID(utwrs->lsaccountid); } } } diff --git a/world/zonelist.cpp b/world/zonelist.cpp index 84cd87842..1d06071c4 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -708,6 +708,13 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval) } } +void ZSList::DropClient(uint32 lsid) { + ServerPacket packet(ServerOP_DropClient, sizeof(ServerZoneDropClient_Struct)); + auto drop = (ServerZoneDropClient_Struct*)packet.pBuffer; + drop->lsid = lsid; + SendPacket(&packet); +} + void ZSList::OnTick(EQ::Timer *t) { if (!EventSubscriptionWatcher::Get()->IsSubscribed("EQW::ZoneUpdate")) { diff --git a/world/zonelist.h b/world/zonelist.h index 947f75a2b..b99a88e09 100644 --- a/world/zonelist.h +++ b/world/zonelist.h @@ -57,6 +57,7 @@ public: void SOPZoneBootup(const char *adminname, uint32 ZoneServerID, const char *zonename, bool iMakeStatic = false); void UpdateUCSServerAvailable(bool ucss_available = true); void WorldShutDown(uint32 time, uint32 interval); + void DropClient(uint32 lsid); ZoneServer* FindByPort(uint16 port); ZoneServer* FindByID(uint32 ZoneID); diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 0d0ba2f5d..bb856c75a 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1457,6 +1457,7 @@ void ZoneServer::IncomingClient(Client* client) { s->accid = client->GetAccountID(); s->admin = client->GetAdmin(); s->charid = client->GetCharID(); + s->lsid = client->GetLSID(); if (client->GetCLE()) s->tellsoff = client->GetCLE()->TellsOff(); strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname)); diff --git a/zone/client.cpp b/zone/client.cpp index e90dafa8a..baf75b0fe 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -446,7 +446,7 @@ Client::~Client() { numclients--; UpdateWindowTitle(); if(zone) - zone->RemoveAuth(GetName()); + zone->RemoveAuth(GetName()); //let the stream factory know were done with this stream eqs->Close(); diff --git a/zone/entity.cpp b/zone/entity.cpp index f7fea532b..1c8de0780 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -1713,6 +1713,18 @@ Client *EntityList::GetClientByWID(uint32 iWID) return nullptr; } +Client *EntityList::GetClientByLSID(uint32 iLSID) +{ + auto it = client_list.begin(); + while (it != client_list.end()) { + if (it->second->LSAccountID() == iLSID) { + return it->second; + } + ++it; + } + return nullptr; +} + Client *EntityList::GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient) { std::vector ClientsInRange; diff --git a/zone/entity.h b/zone/entity.h index c50575b5b..a02a8be2e 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -176,6 +176,7 @@ public: } Client *GetClientByCharID(uint32 iCharID); Client *GetClientByWID(uint32 iWID); + Client *GetClientByLSID(uint32 iLSID); Client *GetClient(uint32 ip, uint16 port); Client *GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient = nullptr); Group *GetGroupByMob(Mob* mob); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 94be0eb14..54040ca5c 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -547,6 +547,23 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } break; } + case ServerOP_DropClient: { + if (pack->size != sizeof(ServerZoneDropClient_Struct)) { + break; + } + + ServerZoneDropClient_Struct* drop = (ServerZoneDropClient_Struct*)pack->pBuffer; + if (zone) { + zone->RemoveAuth(drop->lsid); + + auto client = entity_list.GetClientByLSID(drop->lsid); + if (client) { + client->Kick(); + client->Save(); + } + } + break; + } case ServerOP_ZonePlayer: { ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)pack->pBuffer; Client* client = entity_list.GetClientByName(szp->name); diff --git a/zone/zone.cpp b/zone/zone.cpp index 88b0253a2..01e6ad42e 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1106,6 +1106,7 @@ void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) { zca->accid = szic->accid; zca->admin = szic->admin; zca->charid = szic->charid; + zca->lsid = szic->lsid; zca->tellsoff = szic->tellsoff; strn0cpy(zca->charname, szic->charname, sizeof(zca->charname)); strn0cpy(zca->lskey, szic->lskey, sizeof(zca->lskey)); @@ -1128,6 +1129,21 @@ void Zone::RemoveAuth(const char* iCharName) } } +void Zone::RemoveAuth(uint32 lsid) +{ + LinkedListIterator iterator(client_auth_list); + + iterator.Reset(); + while (iterator.MoreElements()) { + ZoneClientAuth_Struct* zca = iterator.GetData(); + if (zca->lsid == lsid) { + iterator.RemoveCurrent(); + return; + } + iterator.Advance(); + } +} + void Zone::ResetAuth() { LinkedListIterator iterator(client_auth_list); diff --git a/zone/zone.h b/zone/zone.h index e86fdc339..78bcef0f3 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -52,6 +52,7 @@ struct ZoneClientAuth_Struct { uint32 accid; int16 admin; uint32 charid; + uint32 lsid; bool tellsoff; char charname[64]; char lskey[30]; @@ -244,6 +245,7 @@ public: void ReloadStaticData(); void ReloadWorld(uint32 Option); void RemoveAuth(const char *iCharName); + void RemoveAuth(uint32 lsid); void Repop(uint32 delay = 0); void RepopClose(const glm::vec4 &client_position, uint32 repop_distance); void RequestUCSServerStatus();