diff --git a/zone/aa.cpp b/zone/aa.cpp index 48ee715f7..4d9854d86 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -489,7 +489,7 @@ void Client::ResetAA() { database.DeleteCharacterLeadershipAAs(CharacterID()); // undefined for these clients if (ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier) - Kick(); + Kick("AA Reset on client that doesn't support it"); } void Client::SendClearAA() diff --git a/zone/client.cpp b/zone/client.cpp index 57f6ba865..17521b769 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -845,7 +845,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s { if(AttemptedMessages > RuleI(Chat, MaxMessagesBeforeKick)) { - Kick(); + Kick("Sent too many chat messages at once."); return; } if(GlobalChatLimiterTimer) @@ -2586,13 +2586,19 @@ void Client::SetPVP(bool toggle, bool message) { Save(); } +void Client::Kick(const std::string &reason) { + client_state = CLIENT_KICKED; + + database.CreateKickEvent(GetName(), reason); +} + void Client::WorldKick() { auto outapp = new EQApplicationPacket(OP_GMKick, sizeof(GMKick_Struct)); GMKick_Struct* gmk = (GMKick_Struct *)outapp->pBuffer; strcpy(gmk->name,GetName()); QueuePacket(outapp); safe_delete(outapp); - Kick(); + Kick("World kick issued"); } void Client::GMKill() { diff --git a/zone/client.h b/zone/client.h index 0272fb21b..586541ca6 100644 --- a/zone/client.h +++ b/zone/client.h @@ -371,9 +371,9 @@ public: inline bool ClientDataLoaded() const { return client_data_loaded; } inline bool Connected() const { return (client_state == CLIENT_CONNECTED); } inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); } - inline void Kick() { client_state = CLIENT_KICKED; } inline void Disconnect() { eqs->Close(); client_state = DISCONNECTED; } inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); } + void Kick(const std::string &reason); void WorldKick(); inline uint8 GetAnon() const { return m_pp.anon; } inline PlayerProfile_Struct& GetPP() { return m_pp; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f0eb00d13..2c8636014 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1169,10 +1169,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) Log(Logs::General, Logs::Client_Login, "%s failed zone auth check.", cze->char_name); if (nullptr != client) { client->Save(); - client->Kick(); + client->Kick("Failed auth check"); } - //ret = false; // TODO: Can we tell the client to get lost in a good way - client_state = CLIENT_KICKED; return; } @@ -9756,7 +9754,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) casting_spell_id); database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName()); safe_delete_array(detect); - Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots + Kick("Inventory desync"); // Kick client to prevent client and server from getting out-of-sync inventory slots return; } } @@ -9800,7 +9798,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app) { - Kick(); // TODO: lets not desync though + Kick("Unimplemented move multiple items"); // TODO: lets not desync though } void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app) diff --git a/zone/command.cpp b/zone/command.cpp index bd5aa71c9..16e4edd55 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -1912,7 +1912,7 @@ void command_permaclass(Client *c, const Seperator *sep) Log(Logs::General, Logs::Normal, "Class change request from %s for %s, requested class:%i", c->GetName(), t->GetName(), atoi(sep->arg[1]) ); t->SetBaseClass(atoi(sep->arg[1])); t->Save(); - t->Kick(); + t->Kick("Class was changed."); } } @@ -3895,7 +3895,7 @@ void command_kick(Client *c, const Seperator *sep) client->Message(0, "You have been kicked by %s", c->GetName()); auto outapp = new EQApplicationPacket(OP_GMKick, 0); client->QueuePacket(outapp); - client->Kick(); + client->Kick("Ordered kicked by command"); c->Message(0, "Kick: local: kicking %s", sep->arg[1]); } } @@ -5187,7 +5187,7 @@ void command_name(Client *c, const Seperator *sep) c->Message(0, "Successfully renamed %s to %s", oldname, sep->arg[1]); // until we get the name packet working right this will work c->Message(0, "Sending player to char select."); - target->Kick(); + target->Kick("Name was changed"); } else c->Message(13, "ERROR: Unable to rename %s. Check that the new name '%s' isn't already taken.", oldname, sep->arg[2]); diff --git a/zone/inventory.cpp b/zone/inventory.cpp index ec4f095b0..96f0fe15b 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1608,7 +1608,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { banker ? banker->GetName() : "UNKNOWN NPC", distance); database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName()); safe_delete_array(hacked_string); - Kick(); // Kicking player to avoid item loss do to client and server inventories not being sync'd + Kick("Inventory desync"); // Kicking player to avoid item loss do to client and server inventories not being sync'd return false; } } @@ -1822,7 +1822,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // Step 4: Check for entity trade if (dst_slot_id >= EQEmu::invslot::TRADE_BEGIN && dst_slot_id <= EQEmu::invslot::TRADE_END) { if (src_slot_id != EQEmu::invslot::slotCursor) { - Kick(); + Kick("Trade with non-cursor item"); return false; } if (with) { diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 9447c48af..c50f6b2f3 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -47,7 +47,7 @@ bool Lua_Client::InZone() { void Lua_Client::Kick() { Lua_Safe_Call_Void(); - self->Kick(); + self->Kick("Lua Quest"); } void Lua_Client::Disconnect() { diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index be1bf2a8e..f86228feb 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -174,7 +174,7 @@ XS(XS_Client_Kick) { if (THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->Kick(); + THIS->Kick("Perl Quest"); } XSRETURN_EMPTY; } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 79f5af8a5..dafc3f1e6 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -809,7 +809,7 @@ void QuestManager::changedeity(int diety_id) { initiator->SetDeity(diety_id); initiator->Message(15,"Your Deity has been changed/set to: %i", diety_id); initiator->Save(1); - initiator->Kick(); + initiator->Kick("Deity change by QuestManager"); } else { @@ -943,7 +943,7 @@ void QuestManager::permaclass(int class_id) { //Makes the client the class specified initiator->SetBaseClass(class_id); initiator->Save(2); - initiator->Kick(); + initiator->Kick("Base class change by QuestManager"); } void QuestManager::permarace(int race_id) { @@ -951,7 +951,7 @@ void QuestManager::permarace(int race_id) { //Makes the client the race specified initiator->SetBaseRace(race_id); initiator->Save(2); - initiator->Kick(); + initiator->Kick("Base race change by QuestManager"); } void QuestManager::permagender(int gender_id) { @@ -959,7 +959,7 @@ void QuestManager::permagender(int gender_id) { //Makes the client the gender specified initiator->SetBaseGender(gender_id); initiator->Save(2); - initiator->Kick(); + initiator->Kick("Base gender change by QuestManager"); } uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { diff --git a/zone/trading.cpp b/zone/trading.cpp index 154fdf148..fe9a72daa 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -112,7 +112,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { // (it just didn't handle partial stack move actions) if (stack_size > 0) { if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) { - client->Kick(); + client->Kick("Error stacking item in trade"); return; } @@ -138,7 +138,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { } else { if (inst2 && inst2->GetID()) { - client->Kick(); + client->Kick("Attempting to add null item to trade"); return; } diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 864f11448..c2f913d7d 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -559,7 +559,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) auto client = entity_list.GetClientByLSID(drop->lsid); if (client) { - client->Kick(); + client->Kick("Dropped by world CLE subsystem"); client->Save(); } } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e2825da5a..acf619aba 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3835,6 +3835,14 @@ void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type QueryDatabase(query); } +void ZoneDatabase::CreateKickEvent(const std::string &character_name, const std::string &reason) +{ + std::string query = + StringFormat("INSERT INTO character_kick_events (Name, Reason) VALUES ('%s', '%s')", character_name.c_str(), reason.c_str()); + + QueryDatabase(query); +} + void ZoneDatabase::LoadPetInfo(Client *client) { diff --git a/zone/zonedb.h b/zone/zonedb.h index f2103715a..285166042 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -292,6 +292,7 @@ public: void SavePetInfo(Client *c); void RemoveTempFactions(Client *c); void UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp); + void CreateKickEvent(const std::string &character_name, const std::string &reason); bool DeleteCharacterAAs(uint32 character_id); bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);