From 1dd911b150e4ece1f14ef40f8d6f878867c864ad Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 30 Oct 2015 16:45:34 -0400 Subject: [PATCH 01/35] Correct charm invis breaking --- zone/mob.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/zone/mob.cpp b/zone/mob.cpp index fc46aac75..82875d451 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -503,13 +503,9 @@ void Mob::SetInvisible(uint8 state) SendAppearancePacket(AT_Invis, invisible); // Invis and hide breaks charms - if ((this->GetPetType() == petCharmed) && (invisible || hidden || improved_hidden)) - { - Mob* formerpet = this->GetPet(); - - if(formerpet) - formerpet->BuffFadeByEffect(SE_Charm); - } + auto formerpet = GetPet(); + if (formerpet && formerpet->GetPetType() == petCharmed && (invisible || hidden || improved_hidden)) + formerpet->BuffFadeByEffect(SE_Charm); } //check to see if `this` is invisible to `other` From ab3e31154cce7ce947205b0eda565cdf3018ea7c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 31 Oct 2015 18:32:23 -0500 Subject: [PATCH 02/35] Adjust AI Aggro check timers for NPC's with npc_aggro flag set to be far less excessive (Performance increase) --- common/features.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/features.h b/common/features.h index 0860788e1..44f83c648 100644 --- a/common/features.h +++ b/common/features.h @@ -154,7 +154,7 @@ enum { //reuse times enum { //timer settings, all in milliseconds AImovement_duration = 100, AIthink_duration = 150, - AIscanarea_delay = 500, + AIscanarea_delay = 6000, AIfeignremember_delay = 500, AItarget_check_duration = 500, AIClientScanarea_delay = 750, //used in REVERSE_AGGRO From 33917fe2a94aafa7e4160d09a6abd03dcff0a633 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 31 Oct 2015 20:19:57 -0500 Subject: [PATCH 03/35] - Add Zone Process ID (OS PID) as information passed back to world, ultimately with the ability to display it in the telnet console under 'zonestatus' - Refactored some zoneserver/worldserver code for readability --- common/servertalk.h | 1 + world/zonelist.cpp | 116 ++++++++++++++++++++++++++-------------- world/zoneserver.cpp | 80 ++++++++++++++------------- world/zoneserver.h | 54 ++++++++++--------- zone/bot.cpp | 2 +- zone/client.cpp | 4 +- zone/client_packet.cpp | 2 +- zone/client_process.cpp | 2 +- zone/entity.cpp | 4 +- zone/guild_mgr.cpp | 10 ++-- zone/merc.cpp | 4 +- zone/net.cpp | 6 +-- zone/npc.cpp | 2 +- zone/spell_effects.cpp | 2 +- zone/spells.cpp | 2 +- zone/worldserver.cpp | 63 ++++++++++++---------- zone/worldserver.h | 2 +- zone/zone.cpp | 20 +++---- 18 files changed, 216 insertions(+), 160 deletions(-) diff --git a/common/servertalk.h b/common/servertalk.h index 0945d500d..ee5e41a52 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -548,6 +548,7 @@ struct ServerConnectInfo { char address[250]; char local_address[250]; uint16 port; + uint32 process_id; }; struct ServerGMGoto_Struct { diff --git a/world/zonelist.cpp b/world/zonelist.cpp index 22d783f5d..a887a4d43 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -283,57 +283,84 @@ void ZSList::ListLockedZones(const char* to, WorldTCPConnection* connection) { } void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* connection) { + LinkedListIterator iterator(list); struct in_addr in; iterator.Reset(); char locked[4]; - if (WorldConfig::get()->Locked == true) + if (WorldConfig::get()->Locked == true){ strcpy(locked, "Yes"); - else + } + else { strcpy(locked, "No"); + } char* output = 0; uint32 outsize = 0, outlen = 0; - if (connection->IsConsole()) + + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "World Locked: %s\r\n", locked); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "World Locked: %s^", locked); - if (connection->IsConsole()) + } + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "Zoneservers online:\r\n"); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "Zoneservers online:^"); -// connection->SendEmoteMessage(to, 0, 0, 0, "World Locked: %s", locked); -// connection->SendEmoteMessage(to, 0, 0, 0, "Zoneservers online:"); - int v=0, w=0, x=0, y=0, z=0; - char tmpStatic[2] = { 0, 0 }, tmpZone[64]; - memset(tmpZone, 0, sizeof(tmpZone)); - ZoneServer* zs = 0; - while(iterator.MoreElements()) { - zs = iterator.GetData(); - in.s_addr = zs->GetIP(); + } - if(zs->IsStaticZone()) + int v = 0, w = 0, x = 0, y = 0, z = 0; + char is_static_string[2] = { 0, 0 }, zone_data_string[64]; + memset(zone_data_string, 0, sizeof(zone_data_string)); + + ZoneServer* zone_server_data = 0; + + while (iterator.MoreElements()) { + zone_server_data = iterator.GetData(); + in.s_addr = zone_server_data->GetIP(); + + if (zone_server_data->IsStaticZone()){ z++; - else if (zs->GetZoneID() != 0) + } + else if (zone_server_data->GetZoneID() != 0){ w++; - else if(zs->GetZoneID() == 0 && !zs->IsBootingUp()) + } + else if (zone_server_data->GetZoneID() == 0 && !zone_server_data->IsBootingUp()){ v++; + } - if (zs->IsStaticZone()) - tmpStatic[0] = 'S'; + if (zone_server_data->IsStaticZone()) + is_static_string[0] = 'S'; else - tmpStatic[0] = ' '; + is_static_string[0] = 'D'; if (admin >= 150) { - if (zs->GetZoneID()) - snprintf(tmpZone, sizeof(tmpZone), "%s (%i)", zs->GetZoneName(), zs->GetZoneID()); - else if (zs->IsBootingUp()) - strcpy(tmpZone, "..."); - else - tmpZone[0] = 0; + if (zone_server_data->GetZoneID()){ + snprintf(zone_data_string, sizeof(zone_data_string), "%s (%i)", zone_server_data->GetZoneName(), zone_server_data->GetZoneID()); + } + else if (zone_server_data->IsBootingUp()){ + strcpy(zone_data_string, "..."); + } + else{ + zone_data_string[0] = 0; + } - AppendAnyLenString(&output, &outsize, &outlen, " #%-3i %s %15s:%-5i %2i %s:%i %s", zs->GetID(), tmpStatic, inet_ntoa(in), zs->GetPort(), zs->NumPlayers(), zs->GetCAddress(), zs->GetCPort(), tmpZone); + AppendAnyLenString(&output, &outsize, &outlen, + "#%-3i :: %s :: %15s:%-5i :: %2i :: %s:%i :: %s :: (%u)", + zone_server_data->GetID(), + is_static_string, + inet_ntoa(in), + zone_server_data->GetPort(), + zone_server_data->NumPlayers(), + zone_server_data->GetCAddress(), + zone_server_data->GetCPort(), + zone_data_string, + zone_server_data->GetZoneOSProcessID() + ); + if (outlen >= 3584) { connection->SendEmoteMessageRaw(to, 0, 0, 10, output); safe_delete(output); @@ -348,12 +375,12 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con } x++; } - else if (zs->GetZoneID() != 0) { - if (zs->GetZoneID()) - strcpy(tmpZone, zs->GetZoneName()); + else if (zone_server_data->GetZoneID() != 0) { + if (zone_server_data->GetZoneID()) + strcpy(zone_data_string, zone_server_data->GetZoneName()); else - tmpZone[0] = 0; - AppendAnyLenString(&output, &outsize, &outlen, " #%i %s %s", zs->GetID(), tmpStatic, tmpZone); + zone_data_string[0] = 0; + AppendAnyLenString(&output, &outsize, &outlen, " #%i %s %s", zone_server_data->GetID(), is_static_string, zone_data_string); if (outlen >= 3584) { connection->SendEmoteMessageRaw(to, 0, 0, 10, output); safe_delete(output); @@ -361,25 +388,32 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con outlen = 0; } else { - if (connection->IsConsole()) + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "\r\n"); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "^"); + } } x++; } y++; iterator.Advance(); } - if (connection->IsConsole()) + + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "%i servers listed. %i servers online.\r\n", x, y); - else + } + else { AppendAnyLenString(&output, &outsize, &outlen, "%i servers listed. %i servers online.^", x, y); - AppendAnyLenString(&output, &outsize, &outlen, "%i zones are static zones, %i zones are booted zones, %i zones available.",z,w,v); -// connection->SendEmoteMessage(to, 0, 0, "%i servers listed. %i servers online.", x, y); -// connection->SendEmoteMessage(to,0,0,"%i zones are static zones, %i zones are booted zones, %i zones available.",z,w,v); - if (output) + } + + AppendAnyLenString(&output, &outsize, &outlen, "%i zones are static zones, %i zones are booted zones, %i zones available.", z, w, v); + + if (output){ connection->SendEmoteMessageRaw(to, 0, 0, 10, output); + } + safe_delete(output); } diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index d36507f04..207beacd1 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -49,20 +49,24 @@ extern QueryServConnection QSLink; void CatchSignal(int sig_num); ZoneServer::ZoneServer(EmuTCPConnection* itcpc) -: WorldTCPConnection(), tcpc(itcpc), ls_zboot(5000) { - ID = zoneserver_list.GetNextID(); +: WorldTCPConnection(), tcpc(itcpc), zone_boot_timer(5000) { + + /* Set Process tracking variable defaults */ + memset(zone_name, 0, sizeof(zone_name)); memset(compiled, 0, sizeof(compiled)); - zoneID = 0; - instanceID = 0; + memset(client_address, 0, sizeof(client_address)); + memset(client_local_address, 0, sizeof(client_local_address)); - memset(clientaddress, 0, sizeof(clientaddress)); - memset(clientlocaladdress, 0, sizeof(clientlocaladdress)); - clientport = 0; - BootingUp = false; - authenticated = false; - staticzone = false; - pNumPlayers = 0; + zone_server_id = zoneserver_list.GetNextID(); + zone_server_zone_id = 0; + instance_id = 0; + zone_os_process_id = 0; + client_port = 0; + is_booting_up = false; + is_authenticated = false; + is_static_zone = false; + zone_player_count = 0; } ZoneServer::~ZoneServer() { @@ -72,7 +76,7 @@ ZoneServer::~ZoneServer() { } bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { - BootingUp = false; + is_booting_up = false; const char* zn = MakeLowerString(database.GetZoneName(iZoneID)); char* longname; @@ -81,17 +85,17 @@ bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { Log.Out(Logs::Detail, Logs::World_Server,"Setting to '%s' (%d:%d)%s",(zn) ? zn : "",iZoneID, iInstanceID, iStaticZone ? " (Static)" : ""); - zoneID = iZoneID; - instanceID = iInstanceID; + zone_server_zone_id = iZoneID; + instance_id = iInstanceID; if(iZoneID!=0) - oldZoneID = iZoneID; - if (zoneID == 0) { + zone_server_previous_zone_id = iZoneID; + if (zone_server_zone_id == 0) { client_list.CLERemoveZSRef(this); - pNumPlayers = 0; + zone_player_count = 0; LSSleepUpdate(GetPrevZoneID()); } - staticzone = iStaticZone; + is_static_zone = iStaticZone; if (zn) { @@ -111,7 +115,7 @@ bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { } client_list.ZoneBootup(this); - ls_zboot.Start(); + zone_boot_timer.Start(); return true; } @@ -172,19 +176,19 @@ void ZoneServer::LSSleepUpdate(uint32 zoneid){ bool ZoneServer::Process() { if (!tcpc->Connected()) return false; - if(ls_zboot.Check()){ + if(zone_boot_timer.Check()){ LSBootUpdate(GetZoneID(), true); - ls_zboot.Disable(); + zone_boot_timer.Disable(); } ServerPacket *pack = 0; while((pack = tcpc->PopPacket())) { - if (!authenticated) { + if (!is_authenticated) { if (WorldConfig::get()->SharedKey.length() > 0) { if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) { uint8 tmppass[16]; MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass); if (memcmp(pack->pBuffer, tmppass, 16) == 0) - authenticated = true; + is_authenticated = true; else { struct in_addr in; in.s_addr = GetIP(); @@ -210,7 +214,7 @@ bool ZoneServer::Process() { else { Log.Out(Logs::Detail, Logs::World_Server,"**WARNING** You have not configured a world shared key in your config file. You should add a STRING element to your element to prevent unauthroized zone access."); - authenticated = true; + is_authenticated = true; } } switch(pack->opcode) { @@ -582,29 +586,33 @@ bool ZoneServer::Process() { ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer; if (!sci->port) { - clientport = zoneserver_list.GetAvailableZonePort(); + client_port = zoneserver_list.GetAvailableZonePort(); ServerPacket p(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo)); memset(p.pBuffer,0,sizeof(ServerConnectInfo)); ServerConnectInfo* sci = (ServerConnectInfo*) p.pBuffer; - sci->port = clientport; + sci->port = client_port; SendPacket(&p); - Log.Out(Logs::Detail, Logs::World_Server,"Auto zone port configuration. Telling zone to use port %d",clientport); + Log.Out(Logs::Detail, Logs::World_Server,"Auto zone port configuration. Telling zone to use port %d",client_port); } else { - clientport = sci->port; - Log.Out(Logs::Detail, Logs::World_Server,"Zone specified port %d.",clientport); + client_port = sci->port; + Log.Out(Logs::Detail, Logs::World_Server,"Zone specified port %d.",client_port); } if(sci->address[0]) { - strn0cpy(clientaddress, sci->address, 250); + strn0cpy(client_address, sci->address, 250); Log.Out(Logs::Detail, Logs::World_Server, "Zone specified address %s.", sci->address); } if(sci->local_address[0]) { - strn0cpy(clientlocaladdress, sci->local_address, 250); + strn0cpy(client_local_address, sci->local_address, 250); Log.Out(Logs::Detail, Logs::World_Server, "Zone specified local address %s.", sci->address); } + if (sci->process_id){ + zone_os_process_id = sci->process_id; + } + } case ServerOP_SetLaunchName: { if(pack->size != sizeof(LaunchName_Struct)) @@ -1411,13 +1419,13 @@ void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) { void ZoneServer::TriggerBootup(uint32 iZoneID, uint32 iInstanceID, const char* adminname, bool iMakeStatic) { - BootingUp = true; - zoneID = iZoneID; - instanceID = iInstanceID; + is_booting_up = true; + zone_server_zone_id = iZoneID; + instance_id = iInstanceID; auto pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct)); ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer; - s->ZoneServerID = ID; + s->ZoneServerID = zone_server_id; if (adminname != 0) strcpy(s->adminname, adminname); @@ -1434,7 +1442,7 @@ void ZoneServer::TriggerBootup(uint32 iZoneID, uint32 iInstanceID, const char* a } void ZoneServer::IncomingClient(Client* client) { - BootingUp = true; + is_booting_up = true; auto pack = new ServerPacket(ServerOP_ZoneIncClient, sizeof(ServerZoneIncomingClient_Struct)); ServerZoneIncomingClient_Struct* s = (ServerZoneIncomingClient_Struct*) pack->pBuffer; s->zoneid = GetZoneID(); diff --git a/world/zoneserver.h b/world/zoneserver.h index 125ac33f9..8d26271d1 100644 --- a/world/zoneserver.h +++ b/world/zoneserver.h @@ -44,7 +44,7 @@ public: void LSBootUpdate(uint32 zoneid, uint32 iInstanceID = 0, bool startup = false); void LSSleepUpdate(uint32 zoneid); void LSShutDownUpdate(uint32 zoneid); - uint32 GetPrevZoneID() { return oldZoneID; } + uint32 GetPrevZoneID() { return zone_server_previous_zone_id; } void ChangeWID(uint32 iCharID, uint32 iWID); void SendGroupIDs(); @@ -52,41 +52,45 @@ public: inline const char* GetZoneLongName() const { return long_name; } const char* GetCompileTime() const{ return compiled; } void SetCompile(char* in_compile){ strcpy(compiled,in_compile); } - inline uint32 GetZoneID() const { return zoneID; } + inline uint32 GetZoneID() const { return zone_server_zone_id; } inline uint32 GetIP() const { return tcpc->GetrIP(); } inline uint16 GetPort() const { return tcpc->GetrPort(); } - inline const char* GetCAddress() const { return clientaddress; } - inline const char* GetCLocalAddress() const { return clientlocaladdress; } - inline uint16 GetCPort() const { return clientport; } - inline uint32 GetID() const { return ID; } - inline bool IsBootingUp() const { return BootingUp; } - inline bool IsStaticZone() const{ return staticzone; } - inline uint32 NumPlayers() const { return pNumPlayers; } - inline void AddPlayer() { pNumPlayers++; } - inline void RemovePlayer() { pNumPlayers--; } + inline const char* GetCAddress() const { return client_address; } + inline const char* GetCLocalAddress() const { return client_local_address; } + inline uint16 GetCPort() const { return client_port; } + inline uint32 GetID() const { return zone_server_id; } + inline bool IsBootingUp() const { return is_booting_up; } + inline bool IsStaticZone() const{ return is_static_zone; } + inline uint32 NumPlayers() const { return zone_player_count; } + inline void AddPlayer() { zone_player_count++; } + inline void RemovePlayer() { zone_player_count--; } inline const char * GetLaunchName() const { return(launcher_name.c_str()); } inline const char * GetLaunchedName() const { return(launched_name.c_str()); } - inline uint32 GetInstanceID() { return instanceID; } - inline void SetInstanceID(uint32 i) { instanceID = i; } + inline uint32 GetInstanceID() { return instance_id; } + inline void SetInstanceID(uint32 i) { instance_id = i; } + + inline uint32 GetZoneOSProcessID() { return zone_os_process_id; } + private: EmuTCPConnection* const tcpc; - uint32 ID; - char clientaddress[250]; - char clientlocaladdress[250]; - uint16 clientport; - bool BootingUp; - bool staticzone; - bool authenticated; - uint32 pNumPlayers; + uint32 zone_server_id; + char client_address[250]; + char client_local_address[250]; + uint16 client_port; + bool is_booting_up; + bool is_static_zone; + bool is_authenticated; + uint32 zone_player_count; char compiled[25]; char zone_name[32]; char long_name[256]; - uint32 zoneID; - uint32 oldZoneID; - Timer ls_zboot; - uint32 instanceID; //instance ids contain a zone id, and a zone version + uint32 zone_server_zone_id; + uint32 zone_server_previous_zone_id; + Timer zone_boot_timer; + uint32 instance_id; //instance ids contain a zone id, and a zone version + uint32 zone_os_process_id; std::string launcher_name; //the launcher which started us std::string launched_name; //the name of the zone we launched. }; diff --git a/zone/bot.cpp b/zone/bot.cpp index ac84ffc5c..29e5e0614 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -6,7 +6,7 @@ #include "quest_parser_collection.h" #include "../common/string_util.h" -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; // This constructor is used during the bot create command Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm::vec4(), 0, false), rest_timer(1) { diff --git a/zone/client.cpp b/zone/client.cpp index 24a916b2a..f65a30350 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -53,7 +53,7 @@ extern volatile bool RunLoops; extern QueryServ* QServ; extern EntityList entity_list; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern uint32 numclients; extern PetitionList petition_list; @@ -371,7 +371,7 @@ Client::~Client() { GetTarget()->IsTargeted(-1); //if we are in a group and we are not zoning, force leave the group - if(isgrouped && !zoning && ZoneLoaded) + if(isgrouped && !zoning && is_zone_loaded) LeaveGroup(); UpdateWho(2); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d8ffb6a68..2ee01fe25 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -66,7 +66,7 @@ extern QueryServ* QServ; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern PetitionList petition_list; extern EntityList entity_list; diff --git a/zone/client_process.cpp b/zone/client_process.cpp index f7fb46d12..a0be235a7 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -55,7 +55,7 @@ extern QueryServ* QServ; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern PetitionList petition_list; extern EntityList entity_list; diff --git a/zone/entity.cpp b/zone/entity.cpp index 69b13e6eb..c427d82d7 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -51,7 +51,7 @@ #endif extern Zone *zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern NetConnection net; extern uint32 numclients; @@ -2340,7 +2340,7 @@ void EntityList::Clear() void EntityList::UpdateWho(bool iSendFullUpdate) { - if ((!worldserver.Connected()) || !ZoneLoaded) + if ((!worldserver.Connected()) || !is_zone_loaded) return; uint32 tmpNumUpdates = numclients + 5; ServerPacket* pack = 0; diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index a5188def9..8754a60e8 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -29,7 +29,7 @@ ZoneGuildManager guild_mgr; GuildBankManager *GuildBanks; extern WorldServer worldserver; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; void ZoneGuildManager::SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation) { Log.Out(Logs::Detail, Logs::Guilds, "Sending guild refresh for %d to world, changes: name=%d, motd=%d, rank=d, relation=%d", guild_id, name, motd, rank, relation); @@ -334,7 +334,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { case ServerOP_GuildRankUpdate: { - if(ZoneLoaded) + if(is_zone_loaded) { if(pack->size != sizeof(ServerGuildRankUpdate_Struct)) { @@ -388,7 +388,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { { ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer; - if(ZoneLoaded) + if(is_zone_loaded) { EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct)); @@ -407,7 +407,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { break; } case ServerOP_OnlineGuildMembersResponse: - if (ZoneLoaded) + if (is_zone_loaded) { char *Buffer = (char *)pack->pBuffer; @@ -443,7 +443,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { case ServerOP_LFGuildUpdate: { - if(ZoneLoaded) + if(is_zone_loaded) { char GuildName[33]; char Comments[257]; diff --git a/zone/merc.cpp b/zone/merc.cpp index 68907fb5b..84f29634b 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -18,7 +18,7 @@ #include "../common/string_util.h" #include "../common/rulesys.h" -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; Merc::Merc(const NPCType* d, float x, float y, float z, float heading) : NPC(d, nullptr, glm::vec4(x, y, z, heading), 0, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000) @@ -5777,7 +5777,7 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { { merc->SetFollowID(0); - if (group->GroupCount() <= 2 && merc->GetGroup() == group && ZoneLoaded) + if (group->GroupCount() <= 2 && merc->GetGroup() == group && is_zone_loaded) { group->DisbandGroup(); } diff --git a/zone/net.cpp b/zone/net.cpp index acf217b84..84d338a28 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -84,7 +84,7 @@ #endif volatile bool RunLoops = true; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; TimeoutManager timeout_manager; NetConnection net; @@ -437,12 +437,12 @@ int main(int argc, char** argv) { worldwasconnected = true; } else { - if (worldwasconnected && ZoneLoaded) + if (worldwasconnected && is_zone_loaded) entity_list.ChannelMessageFromWorld(0, 0, 6, 0, 0, "WARNING: World server connection lost"); worldwasconnected = false; } - if (ZoneLoaded && zoneupdate_timer.Check()) { + if (is_zone_loaded && zoneupdate_timer.Check()) { { if(net.group_timer.Enabled() && net.group_timer.Check()) entity_list.GroupProcess(); diff --git a/zone/npc.cpp b/zone/npc.cpp index 72264a1a2..02b85a2e3 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -53,7 +53,7 @@ #endif extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern EntityList entity_list; NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int iflymode, bool IsCorpse) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index ecb0698e0..c1c3dffda 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -38,7 +38,7 @@ extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; diff --git a/zone/spells.cpp b/zone/spells.cpp index 86c489185..6b5707278 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -101,7 +101,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; // this is run constantly for every mob diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 029975efe..daf450bff 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -53,7 +53,7 @@ extern EntityList entity_list; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern void CatchSignal(int); extern WorldServer worldserver; extern NetConnection net; @@ -85,7 +85,7 @@ WorldServer::~WorldServer() { safe_delete(pack); }*/ -void WorldServer::SetZone(uint32 iZoneID, uint32 iInstanceID) { +void WorldServer::SetZoneData(uint32 iZoneID, uint32 iInstanceID) { ServerPacket* pack = new ServerPacket(ServerOP_SetZone, sizeof(SetZone_Struct)); SetZone_Struct* szs = (SetZone_Struct*) pack->pBuffer; szs->zoneid = iZoneID; @@ -99,10 +99,9 @@ void WorldServer::SetZone(uint32 iZoneID, uint32 iInstanceID) { void WorldServer::OnConnected() { WorldConnection::OnConnected(); - ServerPacket* pack; - //tell the launcher what name we were started with. + /* Tell the launcher what our information is */ pack = new ServerPacket(ServerOP_SetLaunchName,sizeof(LaunchName_Struct)); LaunchName_Struct* ln = (LaunchName_Struct*)pack->pBuffer; strn0cpy(ln->launcher_name, m_launcherName.c_str(), 32); @@ -110,28 +109,38 @@ void WorldServer::OnConnected() { SendPacket(pack); safe_delete(pack); + /* Tell the Worldserver basic information about this zone process */ pack = new ServerPacket(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo)); ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer; + auto config = ZoneConfig::get(); sci->port = ZoneConfig::get()->ZonePort; if(config->WorldAddress.length() > 0) { strn0cpy(sci->address, config->WorldAddress.c_str(), 250); } - if(config->LocalAddress.length() > 0) { strn0cpy(sci->local_address, config->LocalAddress.c_str(), 250); } + /* Fetch process ID */ + if (getpid()){ + sci->process_id = getpid(); + } + else { + sci->process_id = 0; + } + SendPacket(pack); safe_delete(pack); - if (ZoneLoaded) { - this->SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + this->SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); entity_list.UpdateWho(true); this->SendEmoteMessage(0, 0, 15, "Zone connect: %s", zone->GetLongName()); - zone->GetTimeSync(); - } else { - this->SetZone(0); + zone->GetTimeSync(); + } + else { + this->SetZoneData(0); } pack = new ServerPacket(ServerOP_LSZoneBoot,sizeof(ZoneBoot_Struct)); @@ -174,7 +183,7 @@ void WorldServer::Process() { break; } case ServerOP_ChannelMessage: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer; if (scm->deliverto[0] == 0) { @@ -207,7 +216,7 @@ void WorldServer::Process() { } case ServerOP_VoiceMacro: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*) pack->pBuffer; @@ -264,7 +273,7 @@ void WorldServer::Process() { case ServerOP_SpawnCondition: { if(pack->size != sizeof(ServerSpawnCondition_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*) pack->pBuffer; @@ -274,7 +283,7 @@ void WorldServer::Process() { case ServerOP_SpawnEvent: { if(pack->size != sizeof(ServerSpawnEvent_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*) pack->pBuffer; @@ -285,7 +294,7 @@ void WorldServer::Process() { case ServerOP_AcceptWorldEntrance: { if(pack->size != sizeof(WorldToZone_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer; @@ -300,7 +309,7 @@ void WorldServer::Process() { case ServerOP_ZoneToZoneRequest: { if(pack->size != sizeof(ZoneToZone_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer; @@ -376,7 +385,7 @@ void WorldServer::Process() { break; } case ServerOP_WhoAllReply:{ - if(!ZoneLoaded) + if(!is_zone_loaded) break; @@ -403,7 +412,7 @@ void WorldServer::Process() { break; } case ServerOP_EmoteMessage: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer; if (sem->to[0] != 0) { @@ -461,8 +470,8 @@ void WorldServer::Process() { break; } // Annouce the change to the world - if (!ZoneLoaded) { - SetZone(0); + if (!is_zone_loaded) { + SetZoneData(0); } else { SendEmoteMessage(0, 0, 15, "Zone shutdown: %s", zone->GetLongName()); @@ -479,8 +488,8 @@ void WorldServer::Process() { break; } ServerZoneStateChange_struct* zst = (ServerZoneStateChange_struct *) pack->pBuffer; - if (ZoneLoaded) { - SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); if (zst->zoneid == zone->GetZoneID()) { // This packet also doubles as "incoming client" notification, lets not shut down before they get here zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000); @@ -503,8 +512,8 @@ void WorldServer::Process() { break; } ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*) pack->pBuffer; - if (ZoneLoaded) { - SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); if (szic->zoneid == zone->GetZoneID()) { zone->AddAuth(szic); // This packet also doubles as "incoming client" notification, lets not shut down before they get here @@ -540,7 +549,7 @@ void WorldServer::Process() { if (client != 0) { if (skp->adminrank >= client->Admin()) { client->WorldKick(); - if (ZoneLoaded) + if (is_zone_loaded) SendEmoteMessage(skp->adminname, 0, 0, "Remote Kick: %s booted in zone %s.", skp->name, zone->GetShortName()); else SendEmoteMessage(skp->adminname, 0, 0, "Remote Kick: %s booted.", skp->name); @@ -556,7 +565,7 @@ void WorldServer::Process() { if (client != 0) { if (skp->admin >= client->Admin()) { client->GMKill(); - if (ZoneLoaded) + if (is_zone_loaded) SendEmoteMessage(skp->gmname, 0, 0, "Remote Kill: %s killed in zone %s.", skp->target, zone->GetShortName()); else SendEmoteMessage(skp->gmname, 0, 0, "Remote Kill: %s killed.", skp->target); @@ -594,7 +603,7 @@ void WorldServer::Process() { std::cout << "Wrong size on ServerOP_GMGoto. Got: " << pack->size << ", Expected: " << sizeof(ServerGMGoto_Struct) << std::endl; break; } - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*) pack->pBuffer; Client* client = entity_list.GetClientByName(gmg->gotoname); diff --git a/zone/worldserver.h b/zone/worldserver.h index c1e86421f..e1831ea4c 100644 --- a/zone/worldserver.h +++ b/zone/worldserver.h @@ -37,7 +37,7 @@ public: bool SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...); bool SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...); bool SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 MacroNumber, uint32 GroupOrRaidID = 0); - void SetZone(uint32 iZoneID, uint32 iInstanceID = 0); + void SetZoneData(uint32 iZoneID, uint32 iInstanceID = 0); uint32 SendGroupIdRequest(); bool RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 dbid, uint16 opcode); bool IsOOCMuted() const { return(oocmuted); } diff --git a/zone/zone.cpp b/zone/zone.cpp index 63730d0aa..14c0674c6 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -74,7 +74,7 @@ extern Zone* zone; Mutex MZoneShutdown; -volatile bool ZoneLoaded = false; +volatile bool is_zone_loaded = false; Zone* zone = 0; bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { @@ -82,9 +82,9 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { if (iZoneID == 0 || zonename == 0) return false; - if (zone != 0 || ZoneLoaded) { + if (zone != 0 || is_zone_loaded) { std::cerr << "Error: Zone::Bootup call when zone already booted!" << std::endl; - worldserver.SetZone(0); + worldserver.SetZoneData(0); return false; } @@ -97,7 +97,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { if (!zone->Init(iStaticZone)) { safe_delete(zone); std::cerr << "Zone->Init failed" << std::endl; - worldserver.SetZone(0); + worldserver.SetZoneData(0); return false; } zone->zonemap = Map::LoadMapFile(zone->map_name); @@ -131,9 +131,9 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { } } - ZoneLoaded = true; + is_zone_loaded = true; - worldserver.SetZone(iZoneID, iInstanceID); + worldserver.SetZoneData(iZoneID, iInstanceID); if(iInstanceID != 0) { ServerPacket *pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16)); @@ -660,12 +660,12 @@ void Zone::LoadMercSpells(){ } bool Zone::IsLoaded() { - return ZoneLoaded; + return is_zone_loaded; } void Zone::Shutdown(bool quite) { - if (!ZoneLoaded) + if (!is_zone_loaded) return; entity_list.StopMobAI(); @@ -699,7 +699,7 @@ void Zone::Shutdown(bool quite) zone->SetZoneHasCurrentTime(false); if (!quite) Log.Out(Logs::General, Logs::Normal, "Zone shutdown: going to sleep"); - ZoneLoaded = false; + is_zone_loaded = false; zone->ResetAuth(); safe_delete(zone); @@ -846,7 +846,7 @@ Zone::~Zone() { safe_delete(watermap); safe_delete(pathing); if (worldserver.Connected()) { - worldserver.SetZone(0); + worldserver.SetZoneData(0); } safe_delete_array(short_name); safe_delete_array(long_name); From 53c8d63981e7068555cffdd6e1a6a9280fcaf543 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 15:59:24 -0600 Subject: [PATCH 04/35] Implement Perl Export Variable settings map (Huge performance boost) (Preliminary) --- common/database.h | 1 + common/eqemu_logsys.cpp | 2 +- common/servertalk.h | 1 + world/zonelist.cpp | 2 +- world/zoneserver.cpp | 5 ++++ zone/command.cpp | 13 +++++++++++ zone/command.h | 1 + zone/embparser.cpp | 35 ++++++++++++++++++++-------- zone/embparser.h | 1 + zone/net.cpp | 5 ++++ zone/quest_parser_collection.cpp | 39 ++++++++++++++++++++++++++++++++ zone/quest_parser_collection.h | 21 +++++++++++++++++ zone/worldserver.cpp | 8 +++++++ zone/zonedb.cpp | 6 ++--- zone/zonedb.h | 1 + 15 files changed, 126 insertions(+), 15 deletions(-) diff --git a/common/database.h b/common/database.h index c3771f67c..f066cb417 100644 --- a/common/database.h +++ b/common/database.h @@ -23,6 +23,7 @@ #include "global_define.h" #include "eqemu_logsys.h" + #include "types.h" #include "dbcore.h" #include "linked_list.h" diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index 36176c399..189c45bf6 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -116,7 +116,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults() platform_file_name = "ucs"; else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) platform_file_name = "login"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) platform_file_name = "launcher"; } diff --git a/common/servertalk.h b/common/servertalk.h index ee5e41a52..e7ce947c5 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -182,6 +182,7 @@ #define ServerOP_CZMessagePlayer 0x4008 #define ServerOP_ReloadWorld 0x4009 #define ServerOP_ReloadLogs 0x4010 +#define ServerOP_ReloadPerlExportSettings 0x4011 /* Query Server OP Codes */ #define ServerOP_QSPlayerLogTrades 0x5010 #define ServerOP_QSPlayerLogHandins 0x5011 diff --git a/world/zonelist.cpp b/world/zonelist.cpp index a887a4d43..3332e0578 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -349,7 +349,7 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con } AppendAnyLenString(&output, &outsize, &outlen, - "#%-3i :: %s :: %15s:%-5i :: %2i :: %s:%i :: %s :: (%u)", + "#%-3i :: %s :: %15s:%-5i :: %2i :: %s:%i :: %s :: (%u)", zone_server_data->GetID(), is_static_string, inet_ntoa(in), diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 207beacd1..f6447f3f4 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -826,6 +826,11 @@ bool ZoneServer::Process() { RuleManager::Instance()->LoadRules(&database, "default"); break; } + case ServerOP_ReloadPerlExportSettings: + { + zoneserver_list.SendPacket(pack); + break; + } case ServerOP_CameraShake: { zoneserver_list.SendPacket(pack); diff --git a/zone/command.cpp b/zone/command.cpp index 5fe6244ad..db41619f4 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -334,6 +334,7 @@ int command_init(void) { command_add("reloadallrules", "Executes a reload of all rules.", 80, command_reloadallrules) || command_add("reloademote", "Reloads NPC Emotes", 80, command_reloademote) || command_add("reloadlevelmods", nullptr,255, command_reloadlevelmods) || + command_add("reloadperlexportsettings", nullptr, 255, command_reloadperlexportsettings) || command_add("reloadqst", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) || command_add("reloadquest", " - Clear quest cache (any argument causes it to also stop all timers)", 150, command_reloadqst) || command_add("reloadrulesworld", "Executes a reload of all rules in world specifically.", 80, command_reloadworldrules) || @@ -10768,4 +10769,16 @@ void command_apply_shared_memory(Client *c, const Seperator *sep) { strcpy((char*)pack.pBuffer, hotfix_name.c_str()); } worldserver.SendPacket(&pack); +} + +void command_reloadperlexportsettings(Client *c, const Seperator *sep) +{ + if (c) + { + ServerPacket *pack = new ServerPacket(ServerOP_ReloadPerlExportSettings, 0); + worldserver.SendPacket(pack); + c->Message(13, "Successfully sent the packet to world to reload Perl Export settings"); + safe_delete(pack); + + } } \ No newline at end of file diff --git a/zone/command.h b/zone/command.h index 03e30a786..e4130cfff 100644 --- a/zone/command.h +++ b/zone/command.h @@ -332,6 +332,7 @@ void command_load_shared_memory(Client *c, const Seperator *sep); void command_apply_shared_memory(Client *c, const Seperator *sep); void command_untraindisc(Client *c, const Seperator *sep); void command_untraindiscs(Client *c, const Seperator *sep); +void command_reloadperlexportsettings(Client *c, const Seperator *sep); #ifdef EQPROFILE void command_profiledump(Client *c, const Seperator *sep); diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 389f93d1f..617d17d2e 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -183,15 +183,31 @@ int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * da int char_id = 0; ExportCharID(package_name, char_id, npcmob, mob); - ExportQGlobals(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, - package_name, npcmob, mob, char_id); + + /* Check for QGlobal export event enable */ + if (parse->perl_event_export_settings[event].qglobals){ + ExportQGlobals(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, package_name, npcmob, mob, char_id); + } - //ExportGenericVariables(); - ExportMobVariables(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, - package_name, mob, npcmob); - ExportZoneVariables(package_name); - ExportItemVariables(package_name, mob); - ExportEventVariables(package_name, event, objid, data, npcmob, iteminst, mob, extradata, extra_pointers); + /* Check for Mob export event enable */ + if (parse->perl_event_export_settings[event].mob){ + ExportMobVariables(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, package_name, mob, npcmob); + } + + /* Check for Zone export event enable */ + if (parse->perl_event_export_settings[event].zone){ + ExportZoneVariables(package_name); + } + + /* Check for Item export event enable */ + if (parse->perl_event_export_settings[event].item){ + ExportItemVariables(package_name, mob); + } + + /* Check for Event export event enable */ + if (parse->perl_event_export_settings[event].event_variables){ + ExportEventVariables(package_name, event, objid, data, npcmob, iteminst, mob, extradata, extra_pointers); + } if(isPlayerQuest || isGlobalPlayerQuest){ return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, nullptr); @@ -199,8 +215,7 @@ int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * da else if(isItemQuest) { return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, iteminst); } - else if(isSpellQuest) - { + else if(isSpellQuest){ if(mob) { return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, nullptr); } else { diff --git a/zone/embparser.h b/zone/embparser.h index 1357ae20b..9b33b1ad2 100644 --- a/zone/embparser.h +++ b/zone/embparser.h @@ -75,6 +75,7 @@ public: virtual std::string GetVar(std::string name); virtual void ReloadQuests(); virtual uint32 GetIdentifier() { return 0xf8b05c11; } + private: Embperl *perl; diff --git a/zone/net.cpp b/zone/net.cpp index 84d338a28..d950fc15a 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -110,6 +110,7 @@ extern void MapOpcodes(); int main(int argc, char** argv) { RegisterExecutablePlatform(ExePlatformZone); Log.LoadLogSettingsDefaults(); + set_exception_handler(); QServ = new QueryServ; @@ -339,6 +340,10 @@ int main(int argc, char** argv) { #ifdef EMBPERL PerlembParser *perl_parser = new PerlembParser(); parse->RegisterQuestInterface(perl_parser, "pl"); + + /* Load Perl Event Export Settings */ + parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); + #endif //now we have our parser, load the quests diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 845769532..1f4f99c0e 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -1032,3 +1032,42 @@ int QuestParserCollection::DispatchEventSpell(QuestEventID evt, NPC* npc, Client } return ret; } + +void QuestParserCollection::LoadPerlEventExportSettings(PerlEventExportSettings* perl_event_export_settings) { + + Log.Out(Logs::General, Logs::Zone_Server, "Loading Perl Event Export Settings..."); + + /* Write Defaults First (All Enabled) */ + for (int i = 0; i < _LargestEventID; i++){ + perl_event_export_settings[i].qglobals = 1; + perl_event_export_settings[i].mob = 1; + perl_event_export_settings[i].zone = 1; + perl_event_export_settings[i].item = 1; + perl_event_export_settings[i].event_variables = 1; + } + + std::string query = + "SELECT " + "event_id, " + "event_description, " + "export_qglobals, " + "export_mob, " + "export_zone, " + "export_item, " + "export_event " + "FROM " + "perl_event_export_settings " + "ORDER BY event_id"; + + int event_id = 0; + auto results = database.QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + event_id = atoi(row[0]); + perl_event_export_settings[event_id].qglobals = atoi(row[2]); + perl_event_export_settings[event_id].mob = atoi(row[3]); + perl_event_export_settings[event_id].zone = atoi(row[4]); + perl_event_export_settings[event_id].item = atoi(row[5]); + perl_event_export_settings[event_id].event_variables = atoi(row[6]); + } + +} \ No newline at end of file diff --git a/zone/quest_parser_collection.h b/zone/quest_parser_collection.h index 3ebce378c..7a0cec274 100644 --- a/zone/quest_parser_collection.h +++ b/zone/quest_parser_collection.h @@ -77,6 +77,27 @@ public: void GetErrors(std::list &err); + /* + Internally used memory reference for all Perl Event Export Settings + Some exports are very taxing on CPU given how much an event is called. + + These are loaded via DB and have defaults loaded in PerlEventExportSettingsDefaults. + + Database loaded via Database::LoadPerlEventExportSettings(log_settings) + */ + + struct PerlEventExportSettings { + uint8 qglobals; + uint8 mob; + uint8 zone; + uint8 item; + uint8 event_variables; + }; + + PerlEventExportSettings perl_event_export_settings[_LargestEventID]; + + void LoadPerlEventExportSettings(PerlEventExportSettings* perl_event_export_settings); + private: bool HasQuestSubLocal(uint32 npcid, QuestEventID evt); bool HasQuestSubGlobal(QuestEventID evt); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index daf450bff..5f32992bc 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -39,6 +39,7 @@ #include "client.h" #include "corpse.h" #include "entity.h" +#include "quest_parser_collection.h" #include "guild_mgr.h" #include "mob.h" #include "net.h" @@ -60,6 +61,9 @@ extern NetConnection net; extern PetitionList petition_list; extern uint32 numclients; extern volatile bool RunLoops; +extern QuestParserCollection *parse; + +// QuestParserCollection *parse = 0; WorldServer::WorldServer() : WorldConnection(EmuTCPConnection::packetModeZone) @@ -1742,6 +1746,10 @@ void WorldServer::Process() { database.LoadLogSettings(Log.log_settings); break; } + case ServerOP_ReloadPerlExportSettings: { + parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); + break; + } case ServerOP_CameraShake: { if(zone) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e92704fe6..591f8c3d3 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -46,7 +46,7 @@ void ZoneDatabase::ZDBInitVars() { ZoneDatabase::~ZoneDatabase() { unsigned int x; if (npc_spells_cache) { - for (x=0; x<=npc_spells_maxid; x++) { + for (x = 0; x <= npc_spells_maxid; x++) { safe_delete_array(npc_spells_cache[x]); } safe_delete_array(npc_spells_cache); @@ -54,7 +54,7 @@ ZoneDatabase::~ZoneDatabase() { safe_delete_array(npc_spells_loadtried); if (npc_spellseffects_cache) { - for (x=0; x<=npc_spellseffects_maxid; x++) { + for (x = 0; x <= npc_spellseffects_maxid; x++) { safe_delete_array(npc_spellseffects_cache[x]); } safe_delete_array(npc_spellseffects_cache); @@ -62,7 +62,7 @@ ZoneDatabase::~ZoneDatabase() { safe_delete_array(npc_spellseffects_loadtried); if (faction_array != nullptr) { - for (x=0; x <= max_faction; x++) { + for (x = 0; x <= max_faction; x++) { if (faction_array[x] != 0) safe_delete(faction_array[x]); } diff --git a/zone/zonedb.h b/zone/zonedb.h index 9b2a5105b..f49a9bf0d 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -7,6 +7,7 @@ #include "../common/faction.h" #include "../common/eqemu_logsys.h" #include "aa_ability.h" +#include "event_codes.h" class Client; class Corpse; From 624c7341c5a5ad8d86fb768dc0607e004a306fd1 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 16:02:41 -0600 Subject: [PATCH 05/35] Refactor cfp to currently_fleeing for readability --- zone/bot.cpp | 2 +- zone/fearpath.cpp | 14 +++++++------- zone/merc.cpp | 2 +- zone/mob.cpp | 4 ++-- zone/mob.h | 2 +- zone/mob_ai.cpp | 4 ++-- zone/npc.cpp | 2 +- zone/spell_effects.cpp | 12 ++++++------ 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 29e5e0614..c57d17aaf 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2286,7 +2286,7 @@ bool Bot::Process() { BuffProcess(); CalcRestState(); - if(curfp) + if(currently_fleeing) ProcessFlee(); if(GetHP() < GetMaxHP()) diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 0fd5ffa98..bbcf4d4c6 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -33,7 +33,7 @@ extern Zone* zone; //this is called whenever we are damaged to process possible fleeing void Mob::CheckFlee() { //if were allready fleeing, dont need to check more... - if(flee_mode && curfp) + if(flee_mode && currently_fleeing) return; //dont bother if we are immune to fleeing @@ -101,7 +101,7 @@ void Mob::ProcessFlee() //When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee. if (flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) && !spellbonuses.IsFeared && !spellbonuses.IsBlind) { - curfp = false; + currently_fleeing = false; return; } @@ -118,7 +118,7 @@ void Mob::ProcessFlee() //see if we are legitimately feared or blind now if (!spellbonuses.IsFeared && !spellbonuses.IsBlind) { //not feared or blind... were done... - curfp = false; + currently_fleeing = false; return; } } @@ -140,7 +140,7 @@ void Mob::CalculateNewFearpoint() if(Route.size() > 0) { m_FearWalkTarget = glm::vec3(Loc.x, Loc.y, Loc.z); - curfp = true; + currently_fleeing = true; Log.Out(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, Loc.x, Loc.y, Loc.z); return; @@ -151,7 +151,7 @@ void Mob::CalculateNewFearpoint() int loop = 0; float ranx, rany, ranz; - curfp = false; + currently_fleeing = false; while (loop < 100) //Max 100 tries { int ran = 250 - (loop*2); @@ -164,11 +164,11 @@ void Mob::CalculateNewFearpoint() float fdist = ranz - GetZ(); if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz)) { - curfp = true; + currently_fleeing = true; break; } } - if (curfp) + if (currently_fleeing) m_FearWalkTarget = glm::vec3(ranx, rany, ranz); else //Break fear BuffFadeByEffect(SE_Fear); diff --git a/zone/merc.cpp b/zone/merc.cpp index 84f29634b..18ca17abd 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1428,7 +1428,7 @@ void Merc::AI_Process() { if(RuleB(Combat, EnableFearPathing)) { CalculateNewFearpoint(); - if(curfp) { + if(currently_fleeing) { return; } } diff --git a/zone/mob.cpp b/zone/mob.cpp index 82875d451..eccf04a76 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -113,7 +113,7 @@ Mob::Mob(const char* in_name, targeted = 0; tar_ndx=0; tar_vector=0; - curfp = false; + currently_fleeing = false; AI_Init(); SetMoving(false); @@ -371,7 +371,7 @@ Mob::Mob(const char* in_name, follow=0; follow_dist = 100; // Default Distance for Follow flee_mode = false; - curfp = false; + currently_fleeing = false; flee_timer.Start(); permarooted = (runspeed > 0) ? false : true; diff --git a/zone/mob.h b/zone/mob.h index 5032abcf6..7fff5a1c4 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1295,7 +1295,7 @@ protected: int patrol; glm::vec3 m_FearWalkTarget; - bool curfp; + bool currently_fleeing; // Pathing // diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 3f3911c8d..4ac408055 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -759,7 +759,7 @@ void Client::AI_Process() } if(RuleB(Combat, EnableFearPathing)){ - if(curfp) { + if(currently_fleeing) { if(IsRooted()) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) @@ -955,7 +955,7 @@ void Mob::AI_Process() { // Begin: Additions for Wiz Fear Code // if(RuleB(Combat, EnableFearPathing)){ - if(curfp) { + if(currently_fleeing) { if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) diff --git a/zone/npc.cpp b/zone/npc.cpp index 02b85a2e3..ebdd8a79d 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -605,7 +605,7 @@ bool NPC::Process() parse->EventNPC(EVENT_TICK, this, nullptr, "", 0); BuffProcess(); - if(curfp) + if(currently_fleeing) ProcessFlee(); uint32 bonus = 0; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index c1c3dffda..4b92fc688 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -864,7 +864,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove } CalculateNewFearpoint(); - if(curfp) + if(currently_fleeing) { break; } @@ -3944,8 +3944,8 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } case SE_Blind: - if (curfp && !FindType(SE_Fear)) - curfp = false; + if (currently_fleeing && !FindType(SE_Fear)) + currently_fleeing = false; break; case SE_Fear: @@ -3958,8 +3958,8 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) CastToClient()->AI_Stop(); } - if(curfp) { - curfp = false; + if(currently_fleeing) { + currently_fleeing = false; break; } } @@ -3974,7 +3974,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) { if(RuleB(Combat, EnableFearPathing)){ if(flee_mode) { - curfp = true; + currently_fleeing = true; CheckFlee(); break; } From e5ad5e13db7042cf847df92d324bf79e53ad3c2f Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 16:11:25 -0600 Subject: [PATCH 06/35] Comment out Log.Out super hot path line --- zone/waypoints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index e900c6838..34ec6eef7 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -484,7 +484,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): Jumping pure Z.", x, y, z); return true; } - Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater); + // Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater); return false; } else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) { Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): X/Y difference <0.1, Jumping to target.", x, y, z); From 2a69ae42ee36853bfa13f9685cdd72ab699234c3 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 17:02:52 -0600 Subject: [PATCH 07/35] (Performance) Rate limit the rate in which signals are processed for NPC's --- common/features.h | 1 + zone/mob.h | 1 + zone/mob_ai.cpp | 7 ++++++- zone/net.cpp | 8 ++++---- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/common/features.h b/common/features.h index 44f83c648..2ede4b4be 100644 --- a/common/features.h +++ b/common/features.h @@ -159,6 +159,7 @@ enum { //timer settings, all in milliseconds AItarget_check_duration = 500, AIClientScanarea_delay = 750, //used in REVERSE_AGGRO AIassistcheck_delay = 3000, //now often a fighting NPC will yell for help + AI_check_signal_timer_delay = 500, // How often EVENT_SIGNAL checks are processed ClientProximity_interval = 150, CombatEventTimer_expire = 12000, Tribute_duration = 600000, diff --git a/zone/mob.h b/zone/mob.h index 7fff5a1c4..a45dd464d 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1262,6 +1262,7 @@ protected: std::unique_ptr AIscanarea_timer; std::unique_ptr AIwalking_timer; std::unique_ptr AIfeignremember_timer; + std::unique_ptr AI_check_signal_timer; uint32 pLastFightingDelayMoving; HateList hate_list; std::set feign_memory_list; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 4ac408055..fca550499 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -429,6 +429,8 @@ void Mob::AI_Init() AItarget_check_timer.reset(nullptr); AIfeignremember_timer.reset(nullptr); AIscanarea_timer.reset(nullptr); + AI_check_signal_timer.reset(nullptr); + minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); @@ -479,6 +481,8 @@ void Mob::AI_Start(uint32 iMoveDelay) { AItarget_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); AIfeignremember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); AIscanarea_timer = std::unique_ptr(new Timer(AIscanarea_delay)); + AI_check_signal_timer = std::unique_ptr(new Timer(AI_check_signal_timer_delay)); + #ifdef REVERSE_AGGRO if(IsNPC() && !CastToNPC()->WillAggroNPCs()) AIscanarea_timer->Disable(); @@ -544,6 +548,7 @@ void Mob::AI_Stop() { AItarget_check_timer.reset(nullptr); AIscanarea_timer.reset(nullptr); AIfeignremember_timer.reset(nullptr); + AI_check_signal_timer.reset(nullptr); hate_list.WipeHateList(); } @@ -998,7 +1003,7 @@ void Mob::AI_Process() { } // trigger EVENT_SIGNAL if required - if(IsNPC()) { + if (AI_check_signal_timer->Check() && IsNPC()) { CastToNPC()->CheckSignal(); } diff --git a/zone/net.cpp b/zone/net.cpp index d950fc15a..0d5d546d6 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -393,10 +393,10 @@ int main(int argc, char** argv) { worldserver.Process(); - if (!eqsf.IsOpen() && Config->ZonePort!=0) { - Log.Out(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d",Config->ZonePort); + if (!eqsf.IsOpen() && Config->ZonePort != 0) { + Log.Out(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d", Config->ZonePort); if (!eqsf.Open(Config->ZonePort)) { - Log.Out(Logs::General, Logs::Error, "Failed to open port %d",Config->ZonePort); + Log.Out(Logs::General, Logs::Error, "Failed to open port %d", Config->ZonePort); ZoneConfig::SetZonePort(0); worldserver.Disconnect(); worldwasconnected = false; @@ -410,7 +410,7 @@ int main(int argc, char** argv) { //structures and opcodes for that patch. struct in_addr in; in.s_addr = eqss->GetRemoteIP(); - Log.Out(Logs::Detail, Logs::World_Server, "New connection from %s:%d", inet_ntoa(in),ntohs(eqss->GetRemotePort())); + Log.Out(Logs::Detail, Logs::World_Server, "New connection from %s:%d", inet_ntoa(in), ntohs(eqss->GetRemotePort())); stream_identifier.AddStream(eqss); //takes the stream } From ce0011ab1872c4a5b7d5dccda695eaced252c3da Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 17:12:14 -0600 Subject: [PATCH 08/35] Renaming of some timers --- zone/aggro.cpp | 16 ++++----- zone/bot.cpp | 10 +++--- zone/merc.cpp | 8 ++--- zone/mob.h | 16 ++++----- zone/mob_ai.cpp | 82 +++++++++++++++++++++++----------------------- zone/waypoints.cpp | 24 +++++++------- 6 files changed, 78 insertions(+), 78 deletions(-) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 574ac335d..a1903c8ca 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -1189,21 +1189,21 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib } void Mob::AddFeignMemory(Client* attacker) { - if(feign_memory_list.empty() && AIfeignremember_timer != nullptr) - AIfeignremember_timer->Start(AIfeignremember_delay); + if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Start(AIfeignremember_delay); feign_memory_list.insert(attacker->CharacterID()); } void Mob::RemoveFromFeignMemory(Client* attacker) { feign_memory_list.erase(attacker->CharacterID()); - if(feign_memory_list.empty() && AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); if(feign_memory_list.empty()) { minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); } } @@ -1220,8 +1220,8 @@ void Mob::ClearFeignMemory() { feign_memory_list.clear(); minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); } bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) { diff --git a/zone/bot.cpp b/zone/bot.cpp index c57d17aaf..6a684aeac 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2685,7 +2685,7 @@ void Bot::AI_Process() { if(GetHasBeenSummoned()) { if(IsBotCaster() || IsBotArcher()) { - if (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if(!GetTarget() || (IsBotCaster() && !IsBotCasterCombatRange(GetTarget())) || (IsBotArcher() && IsArcheryRange(GetTarget())) || (DistanceSquaredNoZ(static_cast(m_Position), m_PreSummonLocation) < 10)) { if(GetTarget()) FaceTarget(GetTarget()); @@ -2831,7 +2831,7 @@ void Bot::AI_Process() { } } - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { if(!IsMoving() && GetClass() == ROGUE && !BehindMob(GetTarget(), GetX(), GetY())) { // Move the rogue to behind the mob float newX = 0; @@ -2967,7 +2967,7 @@ void Bot::AI_Process() { AI_PursueCastCheck(); } - if (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed()); @@ -2995,7 +2995,7 @@ void Bot::AI_Process() { if (m_PlayerState & static_cast(PlayerState::Aggressive)) SendRemovePlayerState(PlayerState::Aggressive); - if(!IsMoving() && AIthink_timer->Check() && !spellend_timer.Enabled()) { + if(!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { if(GetBotStance() != BotStancePassive) { if(!AI_IdleCastCheck() && !IsCasting()) BotMeditate(true); @@ -3004,7 +3004,7 @@ void Bot::AI_Process() { BotMeditate(true); } - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { if(GetFollowID()) { Mob* follow = entity_list.GetMob(GetFollowID()); if(follow) { diff --git a/zone/merc.cpp b/zone/merc.cpp index 18ca17abd..b4125735e 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1500,7 +1500,7 @@ void Merc::AI_Process() { } } - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { if(!IsMoving() && GetClass() == ROGUE && !BehindMob(GetTarget(), GetX(), GetY())) { @@ -1645,7 +1645,7 @@ void Merc::AI_Process() { AI_PursueCastCheck(); } - if (AImovement_timer->Check()) + if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); @@ -1687,7 +1687,7 @@ void Merc::AI_Process() { if(!check_target_timer.Enabled()) check_target_timer.Start(2000, false); - if(!IsMoving() && AIthink_timer->Check() && !spellend_timer.Enabled()) + if(!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { //TODO: Implement passive stances. //if(GetStance() != MercStancePassive) { @@ -1698,7 +1698,7 @@ void Merc::AI_Process() { } } - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { if(GetFollowID()) { diff --git a/zone/mob.h b/zone/mob.h index a45dd464d..2ca027023 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -925,8 +925,8 @@ public: virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; } inline bool IsTrackable() const { return(trackable); } - Timer* GetAIThinkTimer() { return AIthink_timer.get(); } - Timer* GetAIMovementTimer() { return AImovement_timer.get(); } + Timer* GetAIThinkTimer() { return AI_think_timer.get(); } + Timer* GetAIMovementTimer() { return AI_movement_timer.get(); } Timer GetAttackTimer() { return attack_timer; } Timer GetAttackDWTimer() { return attack_dw_timer; } inline bool IsFindable() { return findable; } @@ -1254,14 +1254,14 @@ protected: uint32 maxLastFightingDelayMoving; float pAggroRange; float pAssistRange; - std::unique_ptr AIthink_timer; - std::unique_ptr AImovement_timer; - std::unique_ptr AItarget_check_timer; + std::unique_ptr AI_think_timer; + std::unique_ptr AI_movement_timer; + std::unique_ptr AI_target_check_timer; bool movetimercompleted; bool permarooted; - std::unique_ptr AIscanarea_timer; - std::unique_ptr AIwalking_timer; - std::unique_ptr AIfeignremember_timer; + std::unique_ptr AI_scan_area_timer; + std::unique_ptr AI_walking_timer; + std::unique_ptr AI_feign_remember_timer; std::unique_ptr AI_check_signal_timer; uint32 pLastFightingDelayMoving; HateList hate_list; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index fca550499..b16a3819e 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -423,12 +423,12 @@ bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float void Mob::AI_Init() { pAIControlled = false; - AIthink_timer.reset(nullptr); - AIwalking_timer.reset(nullptr); - AImovement_timer.reset(nullptr); - AItarget_check_timer.reset(nullptr); - AIfeignremember_timer.reset(nullptr); - AIscanarea_timer.reset(nullptr); + AI_think_timer.reset(nullptr); + AI_walking_timer.reset(nullptr); + AI_movement_timer.reset(nullptr); + AI_target_check_timer.reset(nullptr); + AI_feign_remember_timer.reset(nullptr); + AI_scan_area_timer.reset(nullptr); AI_check_signal_timer.reset(nullptr); minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); @@ -474,18 +474,18 @@ void Mob::AI_Start(uint32 iMoveDelay) { pLastFightingDelayMoving = 0; pAIControlled = true; - AIthink_timer = std::unique_ptr(new Timer(AIthink_duration)); - AIthink_timer->Trigger(); - AIwalking_timer = std::unique_ptr(new Timer(0)); - AImovement_timer = std::unique_ptr(new Timer(AImovement_duration)); - AItarget_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); - AIfeignremember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); - AIscanarea_timer = std::unique_ptr(new Timer(AIscanarea_delay)); + AI_think_timer = std::unique_ptr(new Timer(AIthink_duration)); + AI_think_timer->Trigger(); + AI_walking_timer = std::unique_ptr(new Timer(0)); + AI_movement_timer = std::unique_ptr(new Timer(AImovement_duration)); + AI_target_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); + AI_feign_remember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); + AI_scan_area_timer = std::unique_ptr(new Timer(AIscanarea_delay)); AI_check_signal_timer = std::unique_ptr(new Timer(AI_check_signal_timer_delay)); #ifdef REVERSE_AGGRO if(IsNPC() && !CastToNPC()->WillAggroNPCs()) - AIscanarea_timer->Disable(); + AI_scan_area_timer->Disable(); #endif if (GetAggroRange() == 0) @@ -542,12 +542,12 @@ void Mob::AI_Stop() { pAIControlled = false; - AIthink_timer.reset(nullptr); - AIwalking_timer.reset(nullptr); - AImovement_timer.reset(nullptr); - AItarget_check_timer.reset(nullptr); - AIscanarea_timer.reset(nullptr); - AIfeignremember_timer.reset(nullptr); + AI_think_timer.reset(nullptr); + AI_walking_timer.reset(nullptr); + AI_movement_timer.reset(nullptr); + AI_target_check_timer.reset(nullptr); + AI_scan_area_timer.reset(nullptr); + AI_feign_remember_timer.reset(nullptr); AI_check_signal_timer.reset(nullptr); hate_list.WipeHateList(); @@ -730,7 +730,7 @@ void Client::AI_Process() if (!IsAIControlled()) return; - if (!(AIthink_timer->Check() || attack_timer.Check(false))) + if (!(AI_think_timer->Check() || attack_timer.Check(false))) return; if (IsCasting()) @@ -776,7 +776,7 @@ void Client::AI_Process() //continue on to attack code, ensuring that we execute the engaged code engaged = true; } else { - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { int speed = GetFearSpeed(); animation = speed; speed *= 2; @@ -813,7 +813,7 @@ void Client::AI_Process() SetTarget(hate_list.GetClosestEntOnHateList(this)); else { - if(AItarget_check_timer->Check()) + if(AI_target_check_timer->Check()) { SetTarget(hate_list.GetEntWithMostHateOnList(this)); } @@ -837,7 +837,7 @@ void Client::AI_Process() DoClassAttacks(GetTarget()); } - if (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); @@ -863,7 +863,7 @@ void Client::AI_Process() } else { if(!IsRooted()) { - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { int newspeed = GetRunspeed(); animation = newspeed; @@ -894,7 +894,7 @@ void Client::AI_Process() } else { - if(AIfeignremember_timer->Check()) { + if(AI_feign_remember_timer->Check()) { std::set::iterator RememberedCharID; RememberedCharID = feign_memory_list.begin(); while (RememberedCharID != feign_memory_list.end()) { @@ -922,7 +922,7 @@ void Client::AI_Process() float dist = DistanceSquared(m_Position, owner->GetPosition()); if (dist >= 400) { - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { int nspeed = (dist >= 5625 ? GetRunspeed() : GetWalkspeed()); animation = nspeed; @@ -948,7 +948,7 @@ void Mob::AI_Process() { if (!IsAIControlled()) return; - if (!(AIthink_timer->Check() || attack_timer.Check(false))) + if (!(AI_think_timer->Check() || attack_timer.Check(false))) return; if (IsCasting()) @@ -973,7 +973,7 @@ void Mob::AI_Process() { //continue on to attack code, ensuring that we execute the engaged code engaged = true; } else { - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { // Check if we have reached the last fear point if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { @@ -1017,7 +1017,7 @@ void Mob::AI_Process() { SetTarget(hate_list.GetClosestEntOnHateList(this)); else { - if(AItarget_check_timer->Check()) + if(AI_target_check_timer->Check()) { if (IsFocused()) { if (!target) { @@ -1079,7 +1079,7 @@ void Mob::AI_Process() { if (is_combat_range) { - if (AImovement_timer->Check()) + if (AI_movement_timer->Check()) { if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) { @@ -1273,7 +1273,7 @@ void Mob::AI_Process() { WipeHateList(); Heal(); BuffFadeAll(); - AIwalking_timer->Start(100); + AI_walking_timer->Start(100); pLastFightingDelayMoving = Timer::GetCurrentTime(); return; } else if(tar != nullptr) { @@ -1295,7 +1295,7 @@ void Mob::AI_Process() { if(AI_PursueCastCheck()){ //we did something, so do not process movement. } - else if (AImovement_timer->Check()) + else if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName()); @@ -1328,7 +1328,7 @@ void Mob::AI_Process() { { if (m_PlayerState & static_cast(PlayerState::Aggressive)) SendRemovePlayerState(PlayerState::Aggressive); - if(AIfeignremember_timer->Check()) { + if(AI_feign_remember_timer->Check()) { // 6/14/06 // Improved Feign Death Memory // check to see if any of our previous feigned targets have gotten up. @@ -1353,7 +1353,7 @@ void Mob::AI_Process() { { //we processed a spell action, so do nothing else. } - else if (AIscanarea_timer->Check()) + else if (AI_scan_area_timer->Check()) { /* * This is where NPCs look around to see if they want to attack anybody. @@ -1368,7 +1368,7 @@ void Mob::AI_Process() { if (tmptar) AddToHateList(tmptar); } - else if (AImovement_timer->Check() && !IsRooted()) + else if (AI_movement_timer->Check() && !IsRooted()) { if (IsPet()) { @@ -1539,10 +1539,10 @@ void NPC::AI_DoMovement() { } else if (roamer) { - if (AIwalking_timer->Check()) + if (AI_walking_timer->Check()) { movetimercompleted=true; - AIwalking_timer->Disable(); + AI_walking_timer->Disable(); } @@ -1552,7 +1552,7 @@ void NPC::AI_DoMovement() { if (movetimercompleted==true) { // time to pause at wp is over AI_SetupNextWaypoint(); } // endif (movetimercompleted==true) - else if (!(AIwalking_timer->Enabled())) + else if (!(AI_walking_timer->Enabled())) { // currently moving bool doMove = true; if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) @@ -1573,7 +1573,7 @@ void NPC::AI_DoMovement() { sprintf(temp, "%d", cur_wp); parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0); // start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted. - if (!AIwalking_timer->Enabled()) + if (!AI_walking_timer->Enabled()) AI_SetupNextWaypoint(); else doMove = false; @@ -1764,7 +1764,7 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) { void Mob::AI_Event_NoLongerEngaged() { if (!IsAIControlled()) return; - this->AIwalking_timer->Start(RandomTimer(3000,20000)); + this->AI_walking_timer->Start(RandomTimer(3000,20000)); pLastFightingDelayMoving = Timer::GetCurrentTime(); if (minLastFightingDelayMoving == maxLastFightingDelayMoving) pLastFightingDelayMoving += minLastFightingDelayMoving; diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 34ec6eef7..5ab46dc1f 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -94,7 +94,7 @@ void NPC::ResumeWandering() { if (GetGrid() < 0) { // we were paused by a quest - AIwalking_timer->Disable(); + AI_walking_timer->Disable(); SetGrid( 0 - GetGrid()); if (cur_wp==-1) { // got here by a MoveTo() @@ -103,10 +103,10 @@ void NPC::ResumeWandering() } Log.Out(Logs::Detail, Logs::Pathing, "Resume Wandering requested. Grid %d, wp %d", GetGrid(), cur_wp); } - else if (AIwalking_timer->Enabled()) + else if (AI_walking_timer->Enabled()) { // we are at a waypoint paused normally Log.Out(Logs::Detail, Logs::Pathing, "Resume Wandering on timed pause. Grid %d, wp %d", GetGrid(), cur_wp); - AIwalking_timer->Trigger(); // disable timer to end pause now + AI_walking_timer->Trigger(); // disable timer to end pause now } else { @@ -145,7 +145,7 @@ void NPC::PauseWandering(int pausetime) } else { // specified waiting time, he'll resume after that - AIwalking_timer->Start(pausetime*1000); // set the timer + AI_walking_timer->Start(pausetime*1000); // set the timer } } else { Log.Out(Logs::General, Logs::Error, "NPC not on grid - can't pause wandering: %lu", (unsigned long)GetNPCTypeID()); @@ -162,7 +162,7 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) SetGrid( 0 - GetGrid()); // get him moving again Log.Out(Logs::Detail, Logs::AI, "MoveTo during quest wandering. Canceling quest wandering and going back to grid %d when MoveTo is done.", GetGrid()); } - AIwalking_timer->Disable(); // disable timer in case he is paused at a wp + AI_walking_timer->Disable(); // disable timer in case he is paused at a wp if (cur_wp>=0) { // we've not already done a MoveTo() save_wp=cur_wp; // save the current waypoint @@ -193,8 +193,8 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) m_CurrentWayPoint = position; cur_wp_pause = 0; pLastFightingDelayMoving = 0; - if(AIwalking_timer->Enabled()) - AIwalking_timer->Start(100); + if(AI_walking_timer->Enabled()) + AI_walking_timer->Start(100); } void NPC::UpdateWaypoint(int wp_index) @@ -393,8 +393,8 @@ void NPC::SetWaypointPause() //Declare time to wait on current WP if (cur_wp_pause == 0) { - AIwalking_timer->Start(100); - AIwalking_timer->Trigger(); + AI_walking_timer->Start(100); + AI_walking_timer->Trigger(); } else { @@ -402,13 +402,13 @@ void NPC::SetWaypointPause() switch (pausetype) { case 0: //Random Half - AIwalking_timer->Start((cur_wp_pause - zone->random.Int(0, cur_wp_pause-1)/2)*1000); + AI_walking_timer->Start((cur_wp_pause - zone->random.Int(0, cur_wp_pause-1)/2)*1000); break; case 1: //Full - AIwalking_timer->Start(cur_wp_pause*1000); + AI_walking_timer->Start(cur_wp_pause*1000); break; case 2: //Random Full - AIwalking_timer->Start(zone->random.Int(0, cur_wp_pause-1)*1000); + AI_walking_timer->Start(zone->random.Int(0, cur_wp_pause-1)*1000); break; } } From 66c7deb2ac4ecb2e8edc8906f5fc78b6933c9900 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 17:46:00 -0600 Subject: [PATCH 09/35] Remove some debug junk --- zone/mob_ai.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index b16a3819e..36bddf809 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1861,9 +1861,6 @@ bool NPC::AI_PursueCastCheck() { bool NPC::AI_IdleCastCheck() { if (AIautocastspell_timer->Check(false)) { -#if MobAI_DEBUG_Spells >= 25 - std::cout << "Non-Engaged autocast check triggered: " << this->GetName() << std::endl; -#endif AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. if (!AICastSpell(this, AISpellVar.idle_beneficial_chance, SpellType_Heal | SpellType_Buff | SpellType_Pet)) { if(!entity_list.AICheckCloseBeneficialSpells(this, 33, MobAISpellRange, SpellType_Heal | SpellType_Buff)) { From 6de2bb720fc46a5fa02334c1627c8ca9756ce602 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 17:49:45 -0600 Subject: [PATCH 10/35] Adjust AI_scan_area_timer to randomly start between 1-3 ticks (6-18 seconds) --- zone/mob_ai.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 36bddf809..1602699a2 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -480,7 +480,7 @@ void Mob::AI_Start(uint32 iMoveDelay) { AI_movement_timer = std::unique_ptr(new Timer(AImovement_duration)); AI_target_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); AI_feign_remember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); - AI_scan_area_timer = std::unique_ptr(new Timer(AIscanarea_delay)); + AI_scan_area_timer = std::unique_ptr(new Timer(RandomTimer(6000, 18000))); AI_check_signal_timer = std::unique_ptr(new Timer(AI_check_signal_timer_delay)); #ifdef REVERSE_AGGRO From e8d18cb014fc2123518056fe5dbf9d8f17360da6 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 20:29:51 -0600 Subject: [PATCH 11/35] Made many performance optimizing oriented code changes in the source - Added Rate limit the rate in which signals are processed for NPC's (.5 seconds instead of .01 seconds) Added Perl Export Settings which should heavily reduce the Perl footprint - Normally when any sub EVENT_ gets triggered, all kinds of variables have to get exported every single time an event is triggered and this can make Perl very slow when events are triggered constantly - The two most taxing variable exports are the item variables ($itemcount{} $hasitem{} $oncursor{}) and qglobals ($qglobals{}) - qglobals can pose to be an issue quickly when global qglobals build up, it is highly recommend to use the GetGlobal() and SetGlobal() methods instead as they don't reference the hashmap $qglobals{} that is rebuilt every single time a sub event is triggered - A stress test conducted with 10,000 samples shows an excess of time taken to export variables: http://i.imgur.com/NEpW1tS.png - After the Perl Export Settings table is implemented, and all exports are shut off you see the following test result: http://i.imgur.com/Du5hth9.png - The difference of eliminating uneeded exports brings the overhead and footprint of 10,000 triggers from 54 seconds to 2 seconds - In a 10,000 sample test (10,000 sub event triggers), exporting item variables adds 12 seconds alone, when item variables are only needed in EVENT_ITEM and EVENT_SAY a majority of the time if at all - In a 10,000 sample test (10,000 sub event triggers), exporting qglobals with approximately 1,000 global qglobals in the database creates about 11-20 seconds of delay on its own (Depending on hardware of course) - I've written a parser that has determined which of these exports are needed in which sub routines and have turned off all of the unneeded exports in sub routines that do not need them and used it to create the default table that will be installed in the database. - The export table is called 'perl_event_export_settings' and it resembles the following structure and contains all current 81 EVENTS - If an entry doesn't exist in this table and a new subroutine is added to the source, all exports will be on by default for that routine +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ | event_id | event_description | export_qglobals | export_mob | export_zone | export_item | export_event | +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ | 0 | EVENT_SAY | 1 | 1 | 1 | 1 | 1 | | 1 | EVENT_ITEM | 1 | 1 | 1 | 0 | 1 | | 2 | EVENT_DEATH | 1 | 1 | 1 | 0 | 1 | | 3 | EVENT_SPAWN | 1 | 1 | 1 | 0 | 1 | | 4 | EVENT_ATTACK | 0 | 1 | 1 | 0 | 1 | | 5 | EVENT_COMBAT | 1 | 1 | 1 | 0 | 1 | +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ - If a change is made to this table while the server is live and running, you can hot reload all zone process settings via: #reloadperlexportsettings - For those who wonder what "exports" are, they are reference to variables that are made available at runtime of the sub event, such as: (export_qglobals) (Heavy) : $qglobals https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L916 (export_item) (Heavy) : $itemcount{} $hasitem{} $oncursor{} https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1103 (export_zone) : $zoneid, $instanceid, $zoneln etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1083 (export_mob) : $x, $y, $z, $h, $hpratio etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1032 (export_event) : (event specific) IE: EVENT_SAY ($text) https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1141 --- changelog.txt | 42 +++++++ common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../2015_11_01_perl_event_export_settings.sql | 116 ++++++++++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 utils/sql/git/required/2015_11_01_perl_event_export_settings.sql diff --git a/changelog.txt b/changelog.txt index e3f74ce08..7aa6ee7e1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,47 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 11/1/2015 == +Akkadius: Made many performance optimizing oriented code changes in the source + - Added Rate limit the rate in which signals are processed for NPC's (.5 seconds instead of .01 seconds) +Akkadius: Added Perl Export Settings which should heavily reduce the Perl footprint + - Normally when any sub EVENT_ gets triggered, all kinds of variables have to get exported every single time an event is triggered and + this can make Perl very slow when events are triggered constantly + - The two most taxing variable exports are the item variables ($itemcount{} $hasitem{} $oncursor{}) and qglobals ($qglobals{}) + - qglobals can pose to be an issue quickly when global qglobals build up, it is highly recommend to use the GetGlobal() and SetGlobal() + methods instead as they don't reference the hashmap $qglobals{} that is rebuilt every single time a sub event is triggered + - A stress test conducted with 10,000 samples shows an excess of time taken to export variables: http://i.imgur.com/NEpW1tS.png + - After the Perl Export Settings table is implemented, and all exports are shut off you see the following test result: + http://i.imgur.com/Du5hth9.png + - The difference of eliminating uneeded exports brings the overhead and footprint of 10,000 triggers from 54 seconds to 2 seconds + - In a 10,000 sample test (10,000 sub event triggers), exporting item variables adds 12 seconds alone, when item variables are only needed in + EVENT_ITEM and EVENT_SAY a majority of the time if at all + - In a 10,000 sample test (10,000 sub event triggers), exporting qglobals with approximately 1,000 global qglobals in the database creates + about 11-20 seconds of delay on its own (Depending on hardware of course) + - I've written a parser that has determined which of these exports are needed in which sub routines and have turned off all of the unneeded + exports in sub routines that do not need them and used it to create the default table that will be installed in the database. + - The export table is called 'perl_event_export_settings' and it resembles the following structure and contains all current 81 EVENTS + - If an entry doesn't exist in this table and a new subroutine is added to the source, all exports will be on by default for that routine + + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + | event_id | event_description | export_qglobals | export_mob | export_zone | export_item | export_event | + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + | 0 | EVENT_SAY | 1 | 1 | 1 | 1 | 1 | + | 1 | EVENT_ITEM | 1 | 1 | 1 | 0 | 1 | + | 2 | EVENT_DEATH | 1 | 1 | 1 | 0 | 1 | + | 3 | EVENT_SPAWN | 1 | 1 | 1 | 0 | 1 | + | 4 | EVENT_ATTACK | 0 | 1 | 1 | 0 | 1 | + | 5 | EVENT_COMBAT | 1 | 1 | 1 | 0 | 1 | + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + + - If a change is made to this table while the server is live and running, you can hot reload all zone process settings via: + #reloadperlexportsettings + - For those who wonder what "exports" are, they are reference to variables that are made available at runtime of the sub event, such as: + (export_qglobals) (Heavy) : $qglobals https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L916 + (export_item) (Heavy) : $itemcount{} $hasitem{} $oncursor{} https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1103 + (export_zone) : $zoneid, $instanceid, $zoneln etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1083 + (export_mob) : $x, $y, $z, $h, $hpratio etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1032 + (export_event) : (event specific) IE: EVENT_SAY ($text) https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1141 + == 10/16/2015 == Uleat: Added command '#bot clearfollowdistance [ | spawned | all ]' to coincide with the activation of the load/save feature for follow_distance diff --git a/common/version.h b/common/version.h index d8a6b6077..3a3969ec1 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9087 +#define CURRENT_BINARY_DATABASE_VERSION 9088 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 239fdbb67..2ffc2f452 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -341,6 +341,7 @@ 9085|2015_07_01_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty| 9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty| 9087|2015_09_25_inventory_snapshots.sql|SHOW TABLES LIKE 'inventory_snapshots'|empty| +9088|2015_11_01_perl_event_export_settings.sql|SHOW TABLES LIKE 'perl_event_export_settings'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql new file mode 100644 index 000000000..1a06535d0 --- /dev/null +++ b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql @@ -0,0 +1,116 @@ +/* +Navicat MySQL Data Transfer + +Source Server : localhost +Source Server Version : 50505 +Source Host : localhost:3306 +Source Database : peq + +Target Server Type : MYSQL +Target Server Version : 50505 +File Encoding : 65001 + +Date: 2015-11-01 20:28:21 +*/ + +SET FOREIGN_KEY_CHECKS=0; + +-- ---------------------------- +-- Table structure for perl_event_export_settings +-- ---------------------------- +DROP TABLE IF EXISTS `perl_event_export_settings`; +CREATE TABLE `perl_event_export_settings` ( + `event_id` int(11) NOT NULL, + `event_description` varchar(150) DEFAULT NULL, + `export_qglobals` smallint(11) DEFAULT '0', + `export_mob` smallint(11) DEFAULT '0', + `export_zone` smallint(11) DEFAULT '0', + `export_item` smallint(11) DEFAULT '0', + `export_event` smallint(11) DEFAULT '0', + PRIMARY KEY (`event_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- ---------------------------- +-- Records of perl_event_export_settings +-- ---------------------------- +INSERT INTO `perl_event_export_settings` VALUES ('0', 'EVENT_SAY', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('1', 'EVENT_ITEM', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('2', 'EVENT_DEATH', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('3', 'EVENT_SPAWN', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('4', 'EVENT_ATTACK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('5', 'EVENT_COMBAT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('6', 'EVENT_AGGRO', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('7', 'EVENT_SLAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('8', 'EVENT_NPC_SLAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('9', 'EVENT_WAYPOINT_ARRIVE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('10', 'EVENT_WAYPOINT_DEPART', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('11', 'EVENT_TIMER', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('12', 'EVENT_SIGNAL', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('13', 'EVENT_HP', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('14', 'EVENT_ENTER', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('15', 'EVENT_EXIT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('16', 'EVENT_ENTERZONE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('17', 'EVENT_CLICKDOOR', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('18', 'EVENT_LOOT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('19', 'EVENT_ZONE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('20', 'EVENT_LEVEL_UP', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('21', 'EVENT_KILLED_MERIT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('22', 'EVENT_CAST_ON', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('23', 'EVENT_TASKACCEPTED', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('24', 'EVENT_TASK_STAGE_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('25', 'EVENT_TASK_UPDATE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('26', 'EVENT_TASK_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('27', 'EVENT_TASK_FAIL', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('28', 'EVENT_AGGRO_SAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('29', 'EVENT_PLAYER_PICKUP', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('30', 'EVENT_POPUPRESPONSE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('31', 'EVENT_ENVIRONMENTAL_DAMAGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('32', 'EVENT_PROXIMITY_SAY', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('33', 'EVENT_CAST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('34', 'EVENT_CAST_BEGIN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('35', 'EVENT_SCALE_CALC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('36', 'EVENT_ITEM_ENTER_ZONE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('37', 'EVENT_TARGET_CHANGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('38', 'EVENT_HATE_LIST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('39', 'EVENT_SPELL_EFFECT_CLIENT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('40', 'EVENT_SPELL_EFFECT_NPC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('41', 'EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('42', 'EVENT_SPELL_EFFECT_BUFF_TIC_NPC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('43', 'EVENT_SPELL_FADE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('44', 'EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('45', 'EVENT_COMBINE_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('46', 'EVENT_COMBINE_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('47', 'EVENT_ITEM_CLICK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('48', 'EVENT_ITEM_CLICK_CAST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('49', 'EVENT_GROUP_CHANGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('50', 'EVENT_FORAGE_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('51', 'EVENT_FORAGE_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('52', 'EVENT_FISH_START', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('53', 'EVENT_FISH_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('54', 'EVENT_FISH_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('55', 'EVENT_CLICK_OBJECT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('56', 'EVENT_DISCOVER_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('57', 'EVENT_DISCONNECT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('58', 'EVENT_CONNECT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('59', 'EVENT_ITEM_TICK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('60', 'EVENT_DUEL_WIN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('61', 'EVENT_DUEL_LOSE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('62', 'EVENT_ENCOUNTER_LOAD', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('63', 'EVENT_ENCOUNTER_UNLOAD', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('64', 'EVENT_SAY', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('65', 'EVENT_DROP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('66', 'EVENT_DESTROY_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('67', 'EVENT_FEIGN_DEATH', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('68', 'EVENT_WEAPON_PROC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('69', 'EVENT_EQUIP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('70', 'EVENT_UNEQUIP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('71', 'EVENT_AUGMENT_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('72', 'EVENT_UNAUGMENT_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('73', 'EVENT_AUGMENT_INSERT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('74', 'EVENT_AUGMENT_REMOVE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('75', 'EVENT_ENTER_AREA', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('76', 'EVENT_LEAVE_AREA', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('77', 'EVENT_RESPAWN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('78', 'EVENT_DEATH_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('79', 'EVENT_UNHANDLED_OPCODE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('80', 'EVENT_TICK', '0', '1', '1', '0', '1'); From 0ee70a663ccb04e1c692c593d541c903121559e6 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 20:31:01 -0600 Subject: [PATCH 12/35] Small adjustments to my rushing [skip ci] --- .../2015_11_01_perl_event_export_settings.sql | 21 ------------------- zone/mob_ai.cpp | 2 ++ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql index 1a06535d0..14efd90a5 100644 --- a/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql +++ b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql @@ -1,24 +1,3 @@ -/* -Navicat MySQL Data Transfer - -Source Server : localhost -Source Server Version : 50505 -Source Host : localhost:3306 -Source Database : peq - -Target Server Type : MYSQL -Target Server Version : 50505 -File Encoding : 65001 - -Date: 2015-11-01 20:28:21 -*/ - -SET FOREIGN_KEY_CHECKS=0; - --- ---------------------------- --- Table structure for perl_event_export_settings --- ---------------------------- -DROP TABLE IF EXISTS `perl_event_export_settings`; CREATE TABLE `perl_event_export_settings` ( `event_id` int(11) NOT NULL, `event_description` varchar(150) DEFAULT NULL, diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 1602699a2..06a9fdbfb 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1364,6 +1364,8 @@ void Mob::AI_Process() { * */ + Log.Out(Logs::General, Logs::Zone_Server, "AI Scan area timer check for :: %s", this->GetCleanName()); + Mob* tmptar = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); if (tmptar) AddToHateList(tmptar); From f4983f090d4e3f38d3f5db0eca0cac5e1cac1120 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Nov 2015 20:56:03 -0600 Subject: [PATCH 13/35] Once again another adjustment to npc to npc aggro check timer [skip cki] --- common/ruletypes.h | 2 ++ zone/mob_ai.cpp | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 1b4baa371..456c9f378 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -475,6 +475,8 @@ RULE_BOOL(NPC, ReturnNonQuestNoDropItems, false) // Returns NO DROP items on NPC RULE_INT(NPC, StartEnrageValue, 9) // % HP that an NPC will begin to enrage RULE_BOOL(NPC, LiveLikeEnrage, false) // If set to true then only player controlled pets will enrage RULE_BOOL(NPC, EnableMeritBasedFaction, false) // If set to true, faction will given in the same way as experience (solo/group/raid) +RULE_INT(NPC, NPCToNPCAggroTimerMin, 500) +RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000) RULE_CATEGORY_END() RULE_CATEGORY(Aggro) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 06a9fdbfb..0a2219428 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -480,7 +480,7 @@ void Mob::AI_Start(uint32 iMoveDelay) { AI_movement_timer = std::unique_ptr(new Timer(AImovement_duration)); AI_target_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); AI_feign_remember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); - AI_scan_area_timer = std::unique_ptr(new Timer(RandomTimer(6000, 18000))); + AI_scan_area_timer = std::unique_ptr(new Timer(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)))); AI_check_signal_timer = std::unique_ptr(new Timer(AI_check_signal_timer_delay)); #ifdef REVERSE_AGGRO @@ -1364,8 +1364,6 @@ void Mob::AI_Process() { * */ - Log.Out(Logs::General, Logs::Zone_Server, "AI Scan area timer check for :: %s", this->GetCleanName()); - Mob* tmptar = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); if (tmptar) AddToHateList(tmptar); From 21acd79acf381f53111b8be6390311a84018daf4 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 2 Nov 2015 17:58:35 -0500 Subject: [PATCH 14/35] Fix procs that have end cost from consuming end --- zone/spells.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 6b5707278..9ec68c3ff 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2267,7 +2267,9 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } } // one may want to check if this is a disc or not, but we actually don't, there are non disc stuff that have end cost - if (spells[spell_id].EndurCost) { + // lets not consume end for custom items that have disc procs. + // One might also want to filter out USE_ITEM_SPELL_SLOT, but DISCIPLINE_SPELL_SLOT are both #defined to the same thing ... + if (spells[spell_id].EndurCost && !isproc) { auto end_cost = spells[spell_id].EndurCost; if (mgb) end_cost *= 2; From f884d8d7388f000c8db024e63bf2311d4ddb30e5 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 2 Nov 2015 21:33:36 -0600 Subject: [PATCH 15/35] Fix an issue where during a depop cycle and NPC's are engaged by wiping hatelist before issuing NPC depop --- zone/entity.cpp | 2 ++ zone/mob_ai.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/zone/entity.cpp b/zone/entity.cpp index c427d82d7..643b27177 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2438,6 +2438,8 @@ void EntityList::Depop(bool StartSpawnTimer) if (pnpc->IsFindable()) UpdateFindableNPCState(pnpc, true); + pnpc->WipeHateList(); + pnpc->Depop(StartSpawnTimer); } } diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 0a2219428..6bde54d0a 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1867,6 +1867,9 @@ bool NPC::AI_IdleCastCheck() { //if we didnt cast any spells, our autocast timer just resets to the //last duration it was set to... try to put up a more reasonable timer... AIautocastspell_timer->Start(RandomTimer(AISpellVar.idle_no_sp_recast_min, AISpellVar.idle_no_sp_recast_max), false); + + Log.Out(Logs::Moderate, Logs::Spells, "Triggering AI_IdleCastCheck :: Mob %s - Min : %u Max : %u", this->GetCleanName(), AISpellVar.idle_no_sp_recast_min, AISpellVar.idle_no_sp_recast_max); + } //else, spell casting finishing will reset the timer. } //else, spell casting finishing will reset the timer. return(true); From 63051dda9c438290dce276e75caa5a64d9761e05 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 2 Nov 2015 22:12:41 -0600 Subject: [PATCH 16/35] Performance boost (exponential) - Adjusted default idle cast check timers in rules - NPC:NPCToNPCAggroTimerMin 500 (Now 6000) 6 seconds - NPC:NPCToNPCAggroTimerMax 2000 (Now 60000) 60 seconds - Database version 9089 will take care of this update automatically only if you used the default values - The CPU cost of NPC's checking the entire entity list to cast beneficial spells (Heals/Buffs) becomes extremely high when higher NPC count zones exist (Based off of process profiling) - Distance checks for every single NPC to every single other NPC who are casting beneficial spells occur every .5 - 2 seconds unless npc_spells dictates other values, which most of the time it does not - Zones that once fluctuated from 1-8% CPU with no activity (Idle but players present) now idle at .5% based on my testings due to this change in conjunction with the past few performance commits, these are zones that have 600-800 NPC's in them - These values normally are overidden by the spells table (npc_spells), fields (idle_no_sp_recast_min, idle_no_sp_recast_max) --- changelog.txt | 13 +++++++++++++ common/ruletypes.h | 4 ++-- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + ...1_02_ai_idle_no_spell_recast_default_changes.sql | 2 ++ 5 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql diff --git a/changelog.txt b/changelog.txt index 7aa6ee7e1..1b1e9630a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,18 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 11/2/2015 == +Akkadius: Performance boost (exponential) - Adjusted default idle cast check timers in rules + - NPC:NPCToNPCAggroTimerMin 500 (Now 6000) 6 seconds + - NPC:NPCToNPCAggroTimerMax 2000 (Now 60000) 60 seconds + - Database version 9089 will take care of this update automatically only if you used the default values + - The CPU cost of NPC's checking the entire entity list to cast beneficial spells (Heals/Buffs) becomes extremely high when + higher NPC count zones exist (Based off of process profiling) + - Distance checks for every single NPC to every single other NPC who are casting beneficial spells occur every .5 - 2 seconds unless + npc_spells dictates other values, which most of the time it does not + - Zones that once fluctuated from 1-8% CPU with no activity (Idle but players present) now idle at .5% based on my testings due + to this change in conjunction with the past few performance commits, these are zones that have 600-800 NPC's in them + - These values normally are overidden by the spells table (npc_spells), fields (idle_no_sp_recast_min, idle_no_sp_recast_max) + == 11/1/2015 == Akkadius: Made many performance optimizing oriented code changes in the source - Added Rate limit the rate in which signals are processed for NPC's (.5 seconds instead of .01 seconds) diff --git a/common/ruletypes.h b/common/ruletypes.h index 456c9f378..411489ca1 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -347,8 +347,8 @@ RULE_INT(Spells, AI_EngagedDetrimentalChance, 20) // Chance during third AI Cast RULE_INT(Spells, AI_PursueNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while chasing target. (min time in random) RULE_INT(Spells, AI_PursueNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) RULE_INT(Spells, AI_PursueDetrimentalChance, 90) // Chance while chasing target to cast a detrimental spell. -RULE_INT(Spells, AI_IdleNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random) -RULE_INT(Spells, AI_IdleNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) +RULE_INT(Spells, AI_IdleNoSpellMinRecast, 6000) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random) +RULE_INT(Spells, AI_IdleNoSpellMaxRecast, 60000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) RULE_INT(Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others. RULE_BOOL(Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false) RULE_BOOL(Spells, Jun182014HundredHandsRevamp, false) // this should be true for if you import a spell file newer than June 18, 2014 diff --git a/common/version.h b/common/version.h index 3a3969ec1..4f39b595c 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9088 +#define CURRENT_BINARY_DATABASE_VERSION 9089 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 2ffc2f452..aa1e46be9 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -342,6 +342,7 @@ 9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty| 9087|2015_09_25_inventory_snapshots.sql|SHOW TABLES LIKE 'inventory_snapshots'|empty| 9088|2015_11_01_perl_event_export_settings.sql|SHOW TABLES LIKE 'perl_event_export_settings'|empty| +9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql b/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql new file mode 100644 index 000000000..fe09523c7 --- /dev/null +++ b/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql @@ -0,0 +1,2 @@ +UPDATE `rule_values` SET `rule_value` = '6000' WHERE `rule_value` = '500' AND `rule_name` = 'Spells:AI_IdleNoSpellMinRecast'; +UPDATE `rule_values` SET `rule_value` = '60000' WHERE `rule_value` = '2000' AND `rule_name` = 'Spells:AI_IdleNoSpellMaxRecast'; \ No newline at end of file From 9304e09eca12e7bd412f4a40122b1aa4f9841c8a Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 2 Nov 2015 22:15:40 -0600 Subject: [PATCH 17/35] Adjust changelog.txt [skip ci] --- changelog.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1b1e9630a..0b93e015c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,10 +5,8 @@ Akkadius: Performance boost (exponential) - Adjusted default idle cast check tim - NPC:NPCToNPCAggroTimerMin 500 (Now 6000) 6 seconds - NPC:NPCToNPCAggroTimerMax 2000 (Now 60000) 60 seconds - Database version 9089 will take care of this update automatically only if you used the default values - - The CPU cost of NPC's checking the entire entity list to cast beneficial spells (Heals/Buffs) becomes extremely high when - higher NPC count zones exist (Based off of process profiling) - - Distance checks for every single NPC to every single other NPC who are casting beneficial spells occur every .5 - 2 seconds unless - npc_spells dictates other values, which most of the time it does not + - The CPU cost of NPC's checking the entire entity list to cast beneficial spells (Heals/Buffs) becomes extremely high when higher NPC count zones exist (Based off of process profiling) + - Distance checks for every single NPC to every single other NPC who are casting beneficial spells occur every .5 - 2 seconds unless npc_spells dictates other values, which most of the time it does not - Zones that once fluctuated from 1-8% CPU with no activity (Idle but players present) now idle at .5% based on my testings due to this change in conjunction with the past few performance commits, these are zones that have 600-800 NPC's in them - These values normally are overidden by the spells table (npc_spells), fields (idle_no_sp_recast_min, idle_no_sp_recast_max) From 67c7254fd15e08cdca0eae9ec32b052c6559de49 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 2 Nov 2015 22:48:17 -0600 Subject: [PATCH 18/35] Copy paste fail [skip ci] --- changelog.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0b93e015c..5a1c346de 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,8 +2,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 11/2/2015 == Akkadius: Performance boost (exponential) - Adjusted default idle cast check timers in rules - - NPC:NPCToNPCAggroTimerMin 500 (Now 6000) 6 seconds - - NPC:NPCToNPCAggroTimerMax 2000 (Now 60000) 60 seconds + - Spells:AI_IdleNoSpellMinRecast 500 (Now 6000) 6 seconds + - Spells:AI_IdleNoSpellMaxRecast 2000 (Now 60000) 60 seconds - Database version 9089 will take care of this update automatically only if you used the default values - The CPU cost of NPC's checking the entire entity list to cast beneficial spells (Heals/Buffs) becomes extremely high when higher NPC count zones exist (Based off of process profiling) - Distance checks for every single NPC to every single other NPC who are casting beneficial spells occur every .5 - 2 seconds unless npc_spells dictates other values, which most of the time it does not From 27c8a85f6149a51984ba6054505ffc7b2b639a20 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 2 Nov 2015 23:23:04 -0600 Subject: [PATCH 19/35] Change AI_scan_area_timer to have a little variability in renewing a new timer time versus deciding one on spawn and sticking with it --- zone/mob_ai.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 6bde54d0a..25ed72441 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1364,9 +1364,14 @@ void Mob::AI_Process() { * */ - Mob* tmptar = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); - if (tmptar) - AddToHateList(tmptar); + Mob* temp_target = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); + if (temp_target){ + AddToHateList(temp_target); + } + + AI_scan_area_timer->Disable(); + AI_scan_area_timer->Start(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)), false); + } else if (AI_movement_timer->Check() && !IsRooted()) { From 835fbb81cbf349e102320154b0e7e1deddbea5c6 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 3 Nov 2015 14:09:22 -0500 Subject: [PATCH 20/35] Expand Casting Restrictions Mostly to nerf HT, not fully implemented --- zone/spell_effects.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 4b92fc688..f7e794334 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -6224,16 +6224,17 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama Range 410 - 411 : UNKOWN Range 500 - 599 : Heal if HP less than a specified value Range 600 - 699 : Limit to Body Type [base2 - 600 = Body] - Range 700 : UNKNOWN + Range 700 : UNKNOWN -- Was added to higher HTs in Oct 21 2015 live patch Range 701 : NOT PET Range 800 : UKNOWN Range 818 - 819 : If Undead/If Not Undead Range 820 - 822 : UKNOWN Range 835 : Unknown *not implemented - Range 836 - 837 : Progression Server / Live Server *not implemented - Range 839 : Unknown *not implemented + Range 836 - 837 : Progression Server / Live Server *not fully implemented + Range 839 : Progression Server and GoD released -- broken until Oct 21 2015 on live *not fully implemented Range 842 - 844 : Humaniod lv MAX ((842 - 800) * 2) Range 845 - 847 : UNKNOWN + Range 860 - 871 : Humanoid lv MAX 860 = 90, 871 = 104 *not implemented Range 10000 - 11000 : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement) THIS IS A WORK IN PROGRESS */ @@ -6402,6 +6403,15 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama return true; break; + case 836: + return true; // todo implement progression flag assume not progression for now + + case 837: + return false; // todo implement progression flag assume not progression for now + + case 839: + return true; // todo implement progression flag assume not progression for now, this one is a check if GoD is live + case 842: if (GetBodyType() == BT_Humanoid && GetLevel() <= 84) return true; @@ -6789,4 +6799,4 @@ void Client::BreakFeignDeathWhenCastOn(bool IsResisted) SetFeigned(false); Message_StringID(MT_SpellFailure,FD_CAST_ON); } -} \ No newline at end of file +} From e7184f402d66dbca0a3a80c612fb3333cee08ca0 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 3 Nov 2015 14:13:56 -0500 Subject: [PATCH 21/35] Add Casting Restrictions to SE_CurrentHPOnce --- zone/spell_effects.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f7e794334..a0f2aa8ee 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -283,9 +283,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove //do any AAs apply to these spells? if(dmg < 0) { + if (!PassCastRestriction(false, spells[spell_id].base2[i], true)) + break; dmg = -dmg; Damage(caster, dmg, spell_id, spell.skill, false, buffslot, false); } else { + if (!PassCastRestriction(false, spells[spell_id].base2[i], true)) + break; HealDamage(dmg, caster); } break; From 63ae7ac3157e316f679c972d349912de588f84c7 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 3 Nov 2015 14:15:55 -0500 Subject: [PATCH 22/35] Add Casting Restrictions to SE_CurrentHP (DoTs) buff processing --- zone/spell_effects.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index a0f2aa8ee..f96ac88fd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3433,6 +3433,8 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) switch (effect) { case SE_CurrentHP: { + if (!PassCastRestriction(false, spells[buff.spellid].base2[i], true)) + break; effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod, caster, buff.ticsremaining); // Handle client cast DOTs here. From 8d80f39ead7bc5872287a10498b771815dcbc9d3 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 3 Nov 2015 14:17:55 -0500 Subject: [PATCH 23/35] Fix copy paste error --- zone/spell_effects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f96ac88fd..a2e769320 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -288,7 +288,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove dmg = -dmg; Damage(caster, dmg, spell_id, spell.skill, false, buffslot, false); } else { - if (!PassCastRestriction(false, spells[spell_id].base2[i], true)) + if (!PassCastRestriction(false, spells[spell_id].base2[i], false)) break; HealDamage(dmg, caster); } From a6f6e18969c0067f7cfb59fc91ff9c4cff8a2922 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 3 Nov 2015 18:43:47 -0500 Subject: [PATCH 24/35] Implement cast restriction 700 (NPC only) --- zone/spell_effects.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index a2e769320..e866d1e0f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -6230,7 +6230,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama Range 410 - 411 : UNKOWN Range 500 - 599 : Heal if HP less than a specified value Range 600 - 699 : Limit to Body Type [base2 - 600 = Body] - Range 700 : UNKNOWN -- Was added to higher HTs in Oct 21 2015 live patch + Range 700 : NPC only -- from patch notes "Wizard - Arcane Fusion no longer deals damage to non-NPC targets. This should ensure that wizards who fail their Bucolic Gambit are slightly less likely to annihilate themselves." Range 701 : NOT PET Range 800 : UKNOWN Range 818 - 819 : If Undead/If Not Undead @@ -6394,6 +6394,11 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama return true; break; + case 700: + if (IsNPC()) + return true; + break; + case 701: if (!IsPet()) return true; From 86f35e45d322401edddeaf9686f4c42c840db44f Mon Sep 17 00:00:00 2001 From: Uleat Date: Wed, 4 Nov 2015 23:30:46 -0500 Subject: [PATCH 25/35] Fix for LoadBot() hp issue --- zone/bot.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index 6a684aeac..477581eba 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3737,9 +3737,9 @@ Bot* Bot::LoadBot(uint32 botID, std::string* errorMessage) " `drakkin_tattoo`," " `drakkin_details`," " `ac`," /*not in-use[26]*/ - " `atk`," + " `atk`," /*not in-use[27]*/ " `hp`," - " `mana`," /*not in-use[29]*/ + " `mana`," " `str`," /*not in-use[30]*/ " `sta`," /*not in-use[31]*/ " `cha`," /*not in-use[32]*/ @@ -3753,8 +3753,8 @@ Bot* Bot::LoadBot(uint32 botID, std::string* errorMessage) " `poison`," /*not in-use[40]*/ " `disease`," /*not in-use[41]*/ " `corruption`," /*not in-use[42]*/ - " `show_helm`," - " `follow_distance`" + " `show_helm`,"//43 + " `follow_distance`"//44 " FROM `bot_data`" " WHERE `bot_id` = '%u'", botID @@ -3791,8 +3791,8 @@ Bot* Bot::LoadBot(uint32 botID, std::string* errorMessage) atoi(row[23]), atoi(row[24]), atoi(row[25]), - atoi(row[27]), atoi(row[28]), + atoi(row[29]), defaultNPCTypeStruct.MR, defaultNPCTypeStruct.CR, defaultNPCTypeStruct.DR, From d64205124f97bf97c342e030d50dcc5567f79c7a Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 7 Nov 2015 13:20:24 -0600 Subject: [PATCH 26/35] Implemented #repopclose [distance in units] - Used for development purposes, defaults to 500 units - Real case use: Large zones with 700 NPC's and you are making fast quick tweaks to nearby NPC's you can refresh just the NPC's around you instead of all in the zone - This can be quite the time saver - This command will depop all NPC's and only respawn the NPC's that are 500 units around you or unless you specify otherwise --- changelog.txt | 6 +++ zone/command.cpp | 36 ++++++++++++++-- zone/command.h | 1 + zone/spawn2.cpp | 106 +++++++++++++++++++++++++++++++++++++++++++++++ zone/zone.cpp | 23 ++++++++++ zone/zone.h | 1 + zone/zonedb.h | 1 + 7 files changed, 171 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5a1c346de..742edb5a5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 11/7/2015 == +Akkadius: Implemented #repopclose [distance in units] - Used for development purposes, defaults to 500 units + - Real case use: Large zones with 700 NPC's and you are making fast quick tweaks to nearby NPC's you can refresh just the NPC's around you instead of all in the zone + - This can be quite the time saver + - This command will depop all NPC's and only respawn the NPC's that are 500 units around you or unless you specify otherwise + == 11/2/2015 == Akkadius: Performance boost (exponential) - Adjusted default idle cast check timers in rules - Spells:AI_IdleNoSpellMinRecast 500 (Now 6000) 6 seconds diff --git a/zone/command.cpp b/zone/command.cpp index db41619f4..1aaf159b0 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -344,6 +344,7 @@ int command_init(void) { command_add("reloadzonepoints", "- Reload zone points from database", 150, command_reloadzps) || command_add("reloadzps", nullptr,0, command_reloadzps) || command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) || + command_add("repopclose", "[distance in units] Repops only NPC's nearby for fast development purposes", 100, command_repopclose) || command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", 200, command_resetaa) || command_add("resetaa_timer", "Command to reset AA cooldown timers.", 200, command_resetaa_timer) || command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) || @@ -3921,9 +3922,11 @@ void command_repop(Client *c, const Seperator *sep) LinkedListIterator iterator(zone->spawn2_list); iterator.Reset(); while (iterator.MoreElements()) { - std::string query = StringFormat("DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", - (unsigned long)iterator.GetData()->GetID(), - (unsigned long)zone->GetInstanceID()); + std::string query = StringFormat( + "DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", + (unsigned long)iterator.GetData()->GetID(), + (unsigned long)zone->GetInstanceID() + ); auto results = database.QueryDatabase(query); iterator.Advance(); } @@ -3940,6 +3943,33 @@ void command_repop(Client *c, const Seperator *sep) zone->Repop(atoi(sep->arg[timearg])*1000); } +void command_repopclose(Client *c, const Seperator *sep) +{ + int repop_distance = 500; + + if (sep->arg[1] && strcasecmp(sep->arg[1], "force") == 0) { + + LinkedListIterator iterator(zone->spawn2_list); + iterator.Reset(); + while (iterator.MoreElements()) { + std::string query = StringFormat( + "DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", + (unsigned long)iterator.GetData()->GetID(), + (unsigned long)zone->GetInstanceID() + ); + auto results = database.QueryDatabase(query); + iterator.Advance(); + } + c->Message(0, "Zone depop: Force resetting spawn timers."); + } + if (sep->IsNumber(1)) { + repop_distance = atoi(sep->arg[1]); + } + + c->Message(0, "Zone depoped. Repopping NPC's within %i distance units", repop_distance); + zone->RepopClose(c->GetPosition(), repop_distance); +} + void command_spawnstatus(Client *c, const Seperator *sep) { if((sep->arg[1][0] == 'e') | (sep->arg[1][0] == 'E')) diff --git a/zone/command.h b/zone/command.h index e4130cfff..ac6107a20 100644 --- a/zone/command.h +++ b/zone/command.h @@ -187,6 +187,7 @@ void command_myskills(Client *c, const Seperator *sep); void command_depop(Client *c, const Seperator *sep); void command_depopzone(Client *c, const Seperator *sep); void command_repop(Client *c, const Seperator *sep); +void command_repopclose(Client *c, const Seperator *sep); void command_spawnstatus(Client *c, const Seperator *sep); void command_nukebuffs(Client *c, const Seperator *sep); void command_zuwcoords(Client *c, const Seperator *sep); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index c42356ea9..f2461ed4b 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -351,6 +351,112 @@ void Spawn2::DeathReset(bool realdeath) } } +bool ZoneDatabase::PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance) +{ + std::unordered_map spawn_times; + + float mob_distance = 0; + + timeval tv; + gettimeofday(&tv, nullptr); + + /* Bulk Load NPC Types Data into the cache */ + database.LoadNPCTypesData(0, true); + + std::string spawn_query = StringFormat( + "SELECT " + "respawn_times.id, " + "respawn_times.`start`, " + "respawn_times.duration " + "FROM " + "respawn_times " + "WHERE instance_id = %u", + zone->GetInstanceID() + ); + auto results = QueryDatabase(spawn_query); + for (auto row = results.begin(); row != results.end(); ++row) { + uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0; + uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0; + + /* Our current time was expired */ + if ((start_duration + end_duration) <= tv.tv_sec) { + spawn_times[atoi(row[0])] = 0; + } + /* We still have time left on this timer */ + else { + spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000; + } + } + + const char *zone_name = database.GetZoneName(zoneid); + std::string query = StringFormat( + "SELECT " + "id, " + "spawngroupID, " + "x, " + "y, " + "z, " + "heading, " + "respawntime, " + "variance, " + "pathgrid, " + "_condition, " + "cond_value, " + "enabled, " + "animation " + "FROM " + "spawn2 " + "WHERE zone = '%s' AND version = %u", + zone_name, + version + ); + results = QueryDatabase(query); + + if (!results.Success()) { + return false; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + + uint32 spawn_time_left = 0; + Spawn2* new_spawn = 0; + bool perl_enabled = atoi(row[11]) == 1 ? true : false; + + if (spawn_times.count(atoi(row[0])) != 0) + spawn_time_left = spawn_times[atoi(row[0])]; + + glm::vec4 point; + point.x = atof(row[2]); + point.y = atof(row[3]); + + mob_distance = DistanceNoZ(client_position, point); + + if (mob_distance > repop_distance) + continue; + + new_spawn = new Spawn2( // + atoi(row[0]), // uint32 in_spawn2_id + atoi(row[1]), // uint32 spawngroup_id + atof(row[2]), // float in_x + atof(row[3]), // float in_y + atof(row[4]), // float in_z + atof(row[5]), // float in_heading + atoi(row[6]), // uint32 respawn + atoi(row[7]), // uint32 variance + spawn_time_left, // uint32 timeleft + atoi(row[8]), // uint32 grid + atoi(row[9]), // uint16 in_cond_id + atoi(row[10]), // int16 in_min_value + perl_enabled, // bool in_enabled + (EmuAppearance)atoi(row[12]) // EmuAppearance anim + ); + + spawn2_list.Insert(new_spawn); + } + + return true; +} + bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay) { std::unordered_map spawn_times; diff --git a/zone/zone.cpp b/zone/zone.cpp index 14c0674c6..b3a6fc1ca 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1445,6 +1445,29 @@ void Zone::ClearNPCTypeCache(int id) { } } +void Zone::RepopClose(const glm::vec4& client_position, uint32 repop_distance) +{ + + if (!Depop()) + return; + + LinkedListIterator iterator(spawn2_list); + + iterator.Reset(); + while (iterator.MoreElements()) { + iterator.RemoveCurrent(); + } + + quest_manager.ClearAllTimers(); + + if (!database.PopulateZoneSpawnListClose(zoneid, spawn2_list, GetInstanceVersion(), client_position, repop_distance)) + Log.Out(Logs::General, Logs::None, "Error in Zone::Repop: database.PopulateZoneSpawnList failed"); + + initgrids_timer.Start(); + + mod_repop(); +} + void Zone::Repop(uint32 delay) { if(!Depop()) diff --git a/zone/zone.h b/zone/zone.h index 94bba72e4..cbac77da9 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -140,6 +140,7 @@ public: bool Depop(bool StartSpawnTimer = false); void Repop(uint32 delay = 0); + void RepopClose(const glm::vec4& client_position, uint32 repop_distance); void ClearNPCTypeCache(int id); void SpawnStatus(Mob* client); void ShowEnabledSpawnStatus(Mob* client); diff --git a/zone/zonedb.h b/zone/zonedb.h index f49a9bf0d..66bb13e9e 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -359,6 +359,7 @@ public: bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list); bool LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list); bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay = 0); + bool PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance); Spawn2* LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft); bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value); void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft); From 18c97ca63779b5805d780976a8798a766b6ab1e6 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 7 Nov 2015 13:23:15 -0600 Subject: [PATCH 27/35] Fix some indents, not sure how they got messed up [skip ci] --- zone/zone.h | 2 +- zone/zonedb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/zone.h b/zone/zone.h index cbac77da9..d7ecc6237 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -140,7 +140,7 @@ public: bool Depop(bool StartSpawnTimer = false); void Repop(uint32 delay = 0); - void RepopClose(const glm::vec4& client_position, uint32 repop_distance); + void RepopClose(const glm::vec4& client_position, uint32 repop_distance); void ClearNPCTypeCache(int id); void SpawnStatus(Mob* client); void ShowEnabledSpawnStatus(Mob* client); diff --git a/zone/zonedb.h b/zone/zonedb.h index 66bb13e9e..c4d26792d 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -359,7 +359,7 @@ public: bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list); bool LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list); bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay = 0); - bool PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance); + bool PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance); Spawn2* LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft); bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value); void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft); From ad04b308c06bcb2453e52da9f4821f7f12a618b5 Mon Sep 17 00:00:00 2001 From: Shendare Date: Sun, 8 Nov 2015 22:18:51 -0800 Subject: [PATCH 28/35] Quick query logging addition Reports records affected by inserts, updates, and deletes as well as the records returned by selects. --- common/dbcore.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index d256f7b42..33c691afc 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -128,7 +128,12 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo MySQLRequestResult requestResult(res, (uint32)mysql_affected_rows(&mysql), rowCount, (uint32)mysql_field_count(&mysql), (uint32)mysql_insert_id(&mysql)); if (Log.log_settings[Logs::MySQLQuery].is_category_enabled == 1) - Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u rows returned)", query, rowCount, requestResult.RowCount()); + { + if ((strlen(query) > 6) && (_memicmp(query, "select", 6) == 0)) + Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s returned)", query, requestResult.RowCount(), requestResult.RowCount() == 1 ? "" : "s"); + else + Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s affected)", query, requestResult.RowsAffected(), requestResult.RowsAffected() == 1 ? "" : "s"); + } return requestResult; } From 992797f6108c0aa47a11602bf512a00e7d61d74c Mon Sep 17 00:00:00 2001 From: Shendare Date: Sun, 8 Nov 2015 22:41:39 -0800 Subject: [PATCH 29/35] Fixed query logging addition Resolved platform specific function use. --- common/dbcore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index 33c691afc..76e87cde1 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -129,7 +129,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo if (Log.log_settings[Logs::MySQLQuery].is_category_enabled == 1) { - if ((strlen(query) > 6) && (_memicmp(query, "select", 6) == 0)) + if ((strncasecmp(query, "select", 6) == 0)) Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s returned)", query, requestResult.RowCount(), requestResult.RowCount() == 1 ? "" : "s"); else Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s affected)", query, requestResult.RowsAffected(), requestResult.RowsAffected() == 1 ? "" : "s"); From 78c75501f7040804e412c9d2de2ca909f9643969 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 10 Nov 2015 03:27:30 -0500 Subject: [PATCH 30/35] Reply to the request made on opening XTarget window This allows the Extended Targets option in the EQ Menu to open the window --- common/emu_oplist.h | 2 ++ utils/patches/patch_RoF.conf | 2 ++ utils/patches/patch_RoF2.conf | 2 ++ utils/patches/patch_UF.conf | 2 ++ zone/client_packet.cpp | 13 +++++++++++++ zone/client_packet.h | 1 + 6 files changed, 22 insertions(+) diff --git a/common/emu_oplist.h b/common/emu_oplist.h index 4ef1761bd..28ec9af0f 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -535,6 +535,8 @@ N(OP_WorldLogout), N(OP_WorldObjectsSent), N(OP_WorldUnknown001), N(OP_XTargetAutoAddHaters), +N(OP_XTargetOpen), +N(OP_XTargetOpenResponse), N(OP_XTargetRequest), N(OP_XTargetResponse), N(OP_YellForHelp), diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index 6e3f0ab1a..dfd8f0e84 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -235,6 +235,8 @@ OP_TargetHoTT=0x3af5 OP_XTargetResponse=0x7f64 OP_XTargetRequest=0x6753 OP_XTargetAutoAddHaters=0x5f51 +OP_XTargetOpen=0x7423 +OP_XTargetOpenResponse=0x27e8 OP_TargetBuffs=0x1c71 OP_BuffCreate=0x71f5 OP_BuffRemoveRequest=0x7efd diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 5e67f4c11..0d1cb20ec 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -235,6 +235,8 @@ OP_TargetBuffs=0x4f4b OP_XTargetResponse=0x4d59 OP_XTargetRequest=0x3763 OP_XTargetAutoAddHaters=0x672f +OP_XTargetOpen=0x61df +OP_XTargetOpenResponse=0x3ef8 OP_BuffCreate=0x3377 OP_BuffRemoveRequest=0x64f2 OP_DeleteSpawn=0x7280 diff --git a/utils/patches/patch_UF.conf b/utils/patches/patch_UF.conf index 6f94c92db..e3af9aa7d 100644 --- a/utils/patches/patch_UF.conf +++ b/utils/patches/patch_UF.conf @@ -239,6 +239,8 @@ OP_TargetHoTT=0x790c # C OP_XTargetResponse=0x6eb5 # OP_XTargetRequest=0x4750 # OP_XTargetAutoAddHaters=0x1a28 # +OP_XTargetOpen=0x11ae +OP_XTargetOpenResponse=0x45d3 OP_TargetBuffs=0x3f24 # C OP_BuffCreate=0x2121 # V OP_BuffRemoveRequest=0x4065 diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 2ee01fe25..c955399b8 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -386,6 +386,7 @@ void MapOpcodes() ConnectedOpcodes[OP_WhoAllRequest] = &Client::Handle_OP_WhoAllRequest; ConnectedOpcodes[OP_WorldUnknown001] = &Client::Handle_OP_Ignore; ConnectedOpcodes[OP_XTargetAutoAddHaters] = &Client::Handle_OP_XTargetAutoAddHaters; + ConnectedOpcodes[OP_XTargetOpen] = &Client::Handle_OP_XTargetOpen; ConnectedOpcodes[OP_XTargetRequest] = &Client::Handle_OP_XTargetRequest; ConnectedOpcodes[OP_YellForHelp] = &Client::Handle_OP_YellForHelp; ConnectedOpcodes[OP_ZoneChange] = &Client::Handle_OP_ZoneChange; @@ -13925,6 +13926,18 @@ void Client::Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app) XTargetAutoAddHaters = app->ReadUInt8(0); } +void Client::Handle_OP_XTargetOpen(const EQApplicationPacket *app) +{ + if (app->size != 4) { + Log.Out(Logs::General, Logs::None, "Size mismatch in OP_XTargetOpen, expected 1, got %i", app->size); + DumpPacket(app); + return; + } + + auto outapp = new EQApplicationPacket(OP_XTargetOpenResponse, 0); + FastQueuePacket(&outapp); +} + void Client::Handle_OP_XTargetRequest(const EQApplicationPacket *app) { if (app->size < 12) diff --git a/zone/client_packet.h b/zone/client_packet.h index a39e3fb74..2635724dd 100644 --- a/zone/client_packet.h +++ b/zone/client_packet.h @@ -292,6 +292,7 @@ void Handle_OP_WearChange(const EQApplicationPacket *app); void Handle_OP_WhoAllRequest(const EQApplicationPacket *app); void Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app); + void Handle_OP_XTargetOpen(const EQApplicationPacket *app); void Handle_OP_XTargetRequest(const EQApplicationPacket *app); void Handle_OP_YellForHelp(const EQApplicationPacket *app); void Handle_OP_ZoneChange(const EQApplicationPacket *app); From ee2d8a3d6d04766a4417bfee449b9406276e7d60 Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 11 Nov 2015 13:49:10 -0800 Subject: [PATCH 31/35] Fix for FindMySQL not preferring mysql_root hint. --- cmake/FindMySQL.cmake | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake index 0578c8b0c..8a8673f35 100644 --- a/cmake/FindMySQL.cmake +++ b/cmake/FindMySQL.cmake @@ -21,6 +21,12 @@ IF(MYSQL_ROOT) NAMES mysql.h PATHS ${MYSQL_ROOT}/include PATH_SUFFIXES mysql + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + ) + FIND_PATH(MySQL_INCLUDE_DIR + NAMES mysql.h + PATH_SUFFIXES mysql ) ELSE(MYSQL_ROOT) FIND_PATH(MySQL_INCLUDE_DIR @@ -30,49 +36,46 @@ ELSE(MYSQL_ROOT) ENDIF(MYSQL_ROOT) # Library -SET(MySQL_NAMES libmysql mysqlclient_r mysqlclient) +SET(MySQL_NAMES libmysql) IF(MYSQL_ROOT) - FIND_LIBRARY(MySQL_LIBRARY_DEBUG + FIND_LIBRARY(MySQL_LIBRARY NAMES ${MySQL_NAMES} - PATHS ${MYSQL_ROOT}/lib/debug /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 + PATHS ${MYSQL_ROOT}/lib PATH_SUFFIXES mysql + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH ) - - FIND_LIBRARY(MySQL_LIBRARY_RELEASE + + FIND_LIBRARY(MySQL_LIBRARY NAMES ${MySQL_NAMES} - PATHS ${MYSQL_ROOT}/lib /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 PATH_SUFFIXES mysql ) ELSE(MYSQL_ROOT) - FIND_LIBRARY(MySQL_LIBRARY_DEBUG - NAMES ${MySQL_NAMES} - PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 - PATH_SUFFIXES mysql - ) - - FIND_LIBRARY(MySQL_LIBRARY_RELEASE + FIND_LIBRARY(MySQL_LIBRARY NAMES ${MySQL_NAMES} PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 PATH_SUFFIXES mysql ) ENDIF(MYSQL_ROOT) -IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) +IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) SET(MySQL_FOUND TRUE) - SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} ) -ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) + SET( MySQL_LIBRARIES ${MySQL_LIBRARY} ) +ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) SET(MySQL_FOUND FALSE) SET( MySQL_LIBRARIES ) -ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) +ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) # handle the QUIETLY and REQUIRED arguments and set MySQL_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY_DEBUG MySQL_LIBRARY_RELEASE MySQL_INCLUDE_DIR) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY MySQL_INCLUDE_DIR) IF(MySQL_FOUND) - SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} ) + SET( MySQL_LIBRARY_RELEASE ${MySQL_LIBRARY} ) + SET( MySQL_LIBRARY_DEBUG ${MySQL_LIBRARY} ) + SET( MySQL_LIBRARIES ${MySQL_LIBRARY_RELEASE} ${MySQL_LIBRARY_DEBUG} ) ELSE(MySQL_FOUND) SET( MySQL_LIBRARIES ) ENDIF(MySQL_FOUND) From f188851bfb8fe3f1ab649816a9f57456f35c597c Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 11 Nov 2015 13:52:52 -0800 Subject: [PATCH 32/35] Wont look for mysql .so on non-root systems --- cmake/FindMySQL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake index 8a8673f35..5a7927552 100644 --- a/cmake/FindMySQL.cmake +++ b/cmake/FindMySQL.cmake @@ -52,7 +52,7 @@ IF(MYSQL_ROOT) ) ELSE(MYSQL_ROOT) FIND_LIBRARY(MySQL_LIBRARY - NAMES ${MySQL_NAMES} + NAMES ${MySQL_NAMES} mysqlclient_r mysqlclient PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 PATH_SUFFIXES mysql ) From 7c4abcc68d22754a344691a95cadb1bfb262382e Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 14 Nov 2015 14:37:24 -0500 Subject: [PATCH 33/35] Fix int16 spell ID limit with items (click, procs, etc) See issue #7 (Did we resolve it yet?) --- common/item_struct.h | 2 +- common/patches/rof2_structs.h | 4 ++-- common/patches/rof_structs.h | 4 ++-- common/patches/sod_structs.h | 4 ++-- common/patches/sof_structs.h | 4 ++-- common/patches/uf_structs.h | 4 ++-- common/shareddb.cpp | 10 +++++----- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/common/item_struct.h b/common/item_struct.h index 1fcb49f51..64292f490 100644 --- a/common/item_struct.h +++ b/common/item_struct.h @@ -51,7 +51,7 @@ ** */ struct ItemEffect_Struct { - int16 Effect; + int32 Effect; uint8 Type; uint8 Level; uint8 Level2; diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 22748af8d..81fc48eaa 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4624,7 +4624,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4639,7 +4639,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index adbfbb7fa..beb550cbc 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4623,7 +4623,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4638,7 +4638,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 4e537221c..d9abef4c6 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -4111,7 +4111,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4126,7 +4126,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index d15f20999..db7cfe028 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -3965,7 +3965,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -3980,7 +3980,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index 046eb5138..3631edea3 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -4206,7 +4206,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4221,7 +4221,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; diff --git a/common/shareddb.cpp b/common/shareddb.cpp index ed4106598..0c8fae730 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -997,23 +997,23 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ strcpy(item.CharmFile,row[ItemField::charmfile]); - item.Proc.Effect = (uint16)atoul(row[ItemField::proceffect]); + item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]); item.Proc.Type = (uint8)atoul(row[ItemField::proctype]); item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]); item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]); - item.Worn.Effect = (uint16)atoul(row[ItemField::worneffect]); + item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]); item.Worn.Type = (uint8)atoul(row[ItemField::worntype]); item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]); item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]); - item.Focus.Effect = (uint16)atoul(row[ItemField::focuseffect]); + item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]); item.Focus.Type = (uint8)atoul(row[ItemField::focustype]); item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]); item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]); - item.Scroll.Effect = (uint16)atoul(row[ItemField::scrolleffect]); + item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]); item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]); item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]); item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]); - item.Bard.Effect = (uint16)atoul(row[ItemField::bardeffect]); + item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]); item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]); item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]); item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]); From 525a39912fa149197230692633faceb1813d1375 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 15 Nov 2015 16:35:11 -0500 Subject: [PATCH 34/35] Override Mob::GetEndurancePercent() for Merc This allows their endurance to show in group! --- zone/merc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/zone/merc.h b/zone/merc.h index 4f52d7367..1e409e0ce 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -192,6 +192,7 @@ public: virtual void ScaleStats(int scalepercent, bool setmax = false); virtual void CalcBonuses(); int32 GetEndurance() const {return cur_end;} //This gets our current endurance + inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); } inline virtual int32 GetAC() const { return AC; } inline virtual int32 GetATK() const { return ATK; } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } From 8464a0e3b51805edda1877e3f006e46e31f05c0e Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 17 Nov 2015 18:15:46 -0500 Subject: [PATCH 35/35] Implement Guild Banks for RoF/RoF2 Everything appears to work, but please test! --- common/base_packet.h | 2 + common/emu_oplist.h | 1 + common/eq_packet_structs.h | 16 ++++ common/patches/rof.cpp | 134 ++++++++++++++++++++++++++++++++++ common/patches/rof2.cpp | 134 ++++++++++++++++++++++++++++++++++ common/patches/rof2_ops.h | 2 + common/patches/rof2_structs.h | 108 +++++++++++++++++++++++++++ common/patches/rof_ops.h | 2 + common/patches/rof_structs.h | 108 +++++++++++++++++++++++++++ utils/patches/patch_RoF.conf | 1 + utils/patches/patch_RoF2.conf | 1 + zone/client_packet.cpp | 14 ---- zone/guild.cpp | 4 +- zone/guild_mgr.cpp | 89 ++++++++++++++++++---- 14 files changed, 585 insertions(+), 31 deletions(-) diff --git a/common/base_packet.h b/common/base_packet.h index 027b8d2fb..16a527ade 100644 --- a/common/base_packet.h +++ b/common/base_packet.h @@ -67,6 +67,8 @@ public: uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; } uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; } + uint16 ReadUInt16() { uint16 value = *(uint16 *)(pBuffer + _rpos); _rpos += sizeof(uint16); return value; } + uint16 ReadUInt16(uint32 Offset) const { uint16 value = *(uint16 *)(pBuffer + Offset); return value; } uint32 ReadUInt32() { uint32 value = *(uint32 *)(pBuffer + _rpos); _rpos += sizeof(uint32); return value; } uint32 ReadUInt32(uint32 Offset) const { uint32 value = *(uint32 *)(pBuffer + Offset); return value; } void ReadString(char *str) { uint32 len = static_cast(strlen((char *)(pBuffer + _rpos))) + 1; memcpy(str, pBuffer + _rpos, len); _rpos += len; } diff --git a/common/emu_oplist.h b/common/emu_oplist.h index 28ec9af0f..223491ecd 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -215,6 +215,7 @@ N(OP_GroupUpdate), N(OP_GroupUpdateB), N(OP_GroupUpdateLeaderAA), N(OP_GuildBank), +N(OP_GuildBankItemList), N(OP_GuildCreate), N(OP_GuildDelete), N(OP_GuildDemote), diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 3f6476ba9..74eb9536e 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -4724,6 +4724,22 @@ struct GuildBankItemUpdate_Struct /*226*/ uint16 Unknown226; }; +// newer clients (RoF+) send a list that contains 240 entries +// The packets don't actually use all 64 chars in the strings, but we'll just overallocate for these +struct GuildBankItemListEntry_Struct +{ + uint8 vaild; + uint32 permissions; + char whofor[64]; + char donator[64]; + uint32 item_id; + uint32 item_icon; + uint32 quantity; + uint8 allow_merge; // 1 here for non-full stacks + uint8 usable; + char item_name[64]; +}; + struct GuildBankClear_Struct { /*00*/ uint32 Action; diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 4ee6d4ec0..79c7271fd 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -1179,6 +1179,54 @@ namespace RoF dest->FastQueuePacket(&outapp); } + ENCODE(OP_GuildBank) + { + auto in = *p; + *p = nullptr; + auto outapp = new EQApplicationPacket(OP_GuildBank, in->size + 4); // all of them are 4 bytes bigger + + // The first action in the enum was removed, everything 1 less + // Normally we cast them to their structs, but there are so many here! will only do when it's easier + switch (in->ReadUInt32()) { + case 10: // GuildBankAcknowledge + outapp->WriteUInt32(9); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + break; + case 5: // GuildBankDeposit (ack) + outapp->WriteUInt32(4); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + outapp->WriteUInt32(in->ReadUInt32()); + break; + case 1: { // GuildBankItemUpdate + auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; + auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; + eq->Action = 0; + OUT(Unknown004); + eq->Unknown08 = 0; + OUT(SlotID); + OUT(Area); + OUT(Unknown012); + OUT(ItemID); + OUT(Icon); + OUT(Quantity); + OUT(Permissions); + OUT(AllowMerge); + OUT(Useable); + OUT_str(ItemName); + OUT_str(Donator); + OUT_str(WhoFor); + OUT(Unknown226); + break; + } + default: + break; + } + delete in; + dest->FastQueuePacket(&outapp); + } + ENCODE(OP_GuildMemberList) { //consume the packet @@ -4590,6 +4638,92 @@ namespace RoF DECODE_FORWARD(OP_GroupInvite); } + DECODE(OP_GuildBank) + { + // all actions are 1 off due to the removal of one of enums + switch (__packet->ReadUInt32()) { + case 2: {// GuildBankPromote + DECODE_LENGTH_EXACT(structs::GuildBankPromote_Struct); + SETUP_DIRECT_DECODE(GuildBankPromote_Struct, structs::GuildBankPromote_Struct); + emu->Action = 3; + IN(Unknown04); + IN(Slot); + IN(Slot2); + FINISH_DIRECT_DECODE(); + return; + } + case 3: { // GuildBankViewItem + DECODE_LENGTH_EXACT(structs::GuildBankViewItem_Struct); + SETUP_DIRECT_DECODE(GuildBankViewItem_Struct, structs::GuildBankViewItem_Struct); + emu->Action = 4; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Unknown16); + FINISH_DIRECT_DECODE(); + return; + } + case 4: { // GuildBankDeposit + __packet->WriteUInt32(5); + return; + } + case 5: { // GuildBankPermissions + DECODE_LENGTH_EXACT(structs::GuildBankPermissions_Struct); + SETUP_DIRECT_DECODE(GuildBankPermissions_Struct, structs::GuildBankPermissions_Struct); + emu->Action = 6; + IN(Unknown04); + IN(SlotID); + IN(Unknown10); + IN(ItemID); + IN(Permissions); + strn0cpy(emu->MemberName, eq->MemberName, 64); + FINISH_DIRECT_DECODE(); + return; + } + case 6: { // GuildBankWithdraw + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 7; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 7: { // GuildBankSplitStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 8; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 8: { // GuildBankMergeStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 9; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + default: + Log.Out(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action"); + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ + return; + } + } + DECODE(OP_GuildDemote) { DECODE_LENGTH_EXACT(structs::GuildDemoteStruct); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 7319dc98b..e5cc77791 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -1250,6 +1250,54 @@ namespace RoF2 dest->FastQueuePacket(&outapp); } + ENCODE(OP_GuildBank) + { + auto in = *p; + *p = nullptr; + auto outapp = new EQApplicationPacket(OP_GuildBank, in->size + 4); // all of them are 4 bytes bigger + + // The first action in the enum was removed, everything 1 less + // Normally we cast them to their structs, but there are so many here! will only do when it's easier + switch (in->ReadUInt32()) { + case 10: // GuildBankAcknowledge + outapp->WriteUInt32(9); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + break; + case 5: // GuildBankDeposit (ack) + outapp->WriteUInt32(4); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + outapp->WriteUInt32(in->ReadUInt32()); + break; + case 1: { // GuildBankItemUpdate + auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; + auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; + eq->Action = 0; + OUT(Unknown004); + eq->Unknown08 = 0; + OUT(SlotID); + OUT(Area); + OUT(Unknown012); + OUT(ItemID); + OUT(Icon); + OUT(Quantity); + OUT(Permissions); + OUT(AllowMerge); + OUT(Useable); + OUT_str(ItemName); + OUT_str(Donator); + OUT_str(WhoFor); + OUT(Unknown226); + break; + } + default: + break; + } + delete in; + dest->FastQueuePacket(&outapp); + } + ENCODE(OP_GuildMemberList) { //consume the packet @@ -4739,6 +4787,92 @@ namespace RoF2 DECODE_FORWARD(OP_GroupInvite); } + DECODE(OP_GuildBank) + { + // all actions are 1 off due to the removal of one of enums + switch (__packet->ReadUInt32()) { + case 2: {// GuildBankPromote + DECODE_LENGTH_EXACT(structs::GuildBankPromote_Struct); + SETUP_DIRECT_DECODE(GuildBankPromote_Struct, structs::GuildBankPromote_Struct); + emu->Action = 3; + IN(Unknown04); + IN(Slot); + IN(Slot2); + FINISH_DIRECT_DECODE(); + return; + } + case 3: { // GuildBankViewItem + DECODE_LENGTH_EXACT(structs::GuildBankViewItem_Struct); + SETUP_DIRECT_DECODE(GuildBankViewItem_Struct, structs::GuildBankViewItem_Struct); + emu->Action = 4; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Unknown16); + FINISH_DIRECT_DECODE(); + return; + } + case 4: { // GuildBankDeposit + __packet->WriteUInt32(5); + return; + } + case 5: { // GuildBankPermissions + DECODE_LENGTH_EXACT(structs::GuildBankPermissions_Struct); + SETUP_DIRECT_DECODE(GuildBankPermissions_Struct, structs::GuildBankPermissions_Struct); + emu->Action = 6; + IN(Unknown04); + IN(SlotID); + IN(Unknown10); + IN(ItemID); + IN(Permissions); + strn0cpy(emu->MemberName, eq->MemberName, 64); + FINISH_DIRECT_DECODE(); + return; + } + case 6: { // GuildBankWithdraw + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 7; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 7: { // GuildBankSplitStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 8; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 8: { // GuildBankMergeStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 9; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + default: + Log.Out(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action"); + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ + return; + } + } + DECODE(OP_GuildDemote) { DECODE_LENGTH_EXACT(structs::GuildDemoteStruct); diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 3bb69af5e..9fe76e33c 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -57,6 +57,7 @@ E(OP_GroupFollow) E(OP_GroupFollow2) E(OP_GroupInvite) E(OP_GroupUpdate) +E(OP_GuildBank) E(OP_GuildMemberList) E(OP_GuildMemberUpdate) E(OP_GuildsList) @@ -152,6 +153,7 @@ D(OP_GroupFollow) D(OP_GroupFollow2) D(OP_GroupInvite) D(OP_GroupInvite2) +D(OP_GuildBank) D(OP_GuildDemote) D(OP_GuildRemove) D(OP_GuildStatus) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 81fc48eaa..1e93b7434 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -1859,6 +1859,114 @@ struct GuildUpdate_Struct { GuildsListEntry_Struct entry; }; +struct GuildBankAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +}; + +struct GuildBankDepositAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint32 Fail; //1 = Fail, 0 = Success +}; + +struct GuildBankPromote_Struct +{ +/*00*/ uint32 Action; // 3 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 Slot; +/*16*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3 +/*20*/ uint32 unknown20; +}; + +struct GuildBankPermissions_Struct +{ +/*00*/ uint32 Action; // 6 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Unknown10; // Saw 1, probably indicating it is the main area rather than deposits +/*12*/ uint32 ItemID; +/*16*/ uint32 Permissions; +/*20*/ char MemberName[64]; +}; + +struct GuildBankViewItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; // 0 = Deposit area, 1 = Main area +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Unknown16; +}; + +struct GuildBankWithdrawItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Quantity; +/*20*/ +}; + +struct GuildBankItemUpdate_Struct +{ + void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, + uint32 inPermissions, uint32 inAllowMerge, bool inUseable) + { + Action = inAction; + Unknown004 = inUnknown004; + SlotID = inSlotID; + Area = inArea; + Unknown012 = inUnknown012; + ItemID = inItemID; + Icon = inIcon; + Quantity = inQuantity; + Permissions = inPermissions; + AllowMerge = inAllowMerge; + Useable = inUseable; + ItemName[0] = '\0'; + Donator[0] = '\0'; + WhoFor[0] = '\0'; + }; + +/*000*/ uint32 Action; +/*004*/ uint32 Unknown004; +/*008*/ uint32 Unknown08; +/*012*/ uint16 SlotID; +/*014*/ uint16 Area; +/*016*/ uint32 Unknown012; +/*020*/ uint32 ItemID; +/*024*/ uint32 Icon; +/*028*/ uint32 Quantity; +/*032*/ uint32 Permissions; +/*036*/ uint8 AllowMerge; +/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char ItemName[64]; +/*102*/ char Donator[64]; +/*166*/ char WhoFor[64]; +/*230*/ uint16 Unknown226; +}; + +struct GuildBankClear_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 DepositAreaCount; +/*16*/ uint32 MainAreaCount; +}; + /* ** Money Loot ** Length: 22 Bytes diff --git a/common/patches/rof_ops.h b/common/patches/rof_ops.h index 8e9adfdc9..606c51c62 100644 --- a/common/patches/rof_ops.h +++ b/common/patches/rof_ops.h @@ -42,6 +42,7 @@ E(OP_GroupFollow) E(OP_GroupFollow2) E(OP_GroupInvite) E(OP_GroupUpdate) +E(OP_GuildBank) E(OP_GuildMemberList) E(OP_GuildMemberUpdate) E(OP_GuildsList) @@ -137,6 +138,7 @@ D(OP_GroupFollow) D(OP_GroupFollow2) D(OP_GroupInvite) D(OP_GroupInvite2) +D(OP_GuildBank) D(OP_GuildDemote) D(OP_GuildRemove) D(OP_GuildStatus) diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index beb550cbc..e24935d35 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -1889,6 +1889,114 @@ struct GuildUpdate_Struct { GuildsListEntry_Struct entry; }; +struct GuildBankAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +}; + +struct GuildBankDepositAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint32 Fail; //1 = Fail, 0 = Success +}; + +struct GuildBankPromote_Struct +{ +/*00*/ uint32 Action; // 3 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 Slot; +/*16*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3 +/*20*/ uint32 unknown20; +}; + +struct GuildBankPermissions_Struct +{ +/*00*/ uint32 Action; // 6 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Unknown10; // Saw 1, probably indicating it is the main area rather than deposits +/*12*/ uint32 ItemID; +/*16*/ uint32 Permissions; +/*20*/ char MemberName[64]; +}; + +struct GuildBankViewItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; // 0 = Deposit area, 1 = Main area +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Unknown16; +}; + +struct GuildBankWithdrawItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Quantity; +/*20*/ +}; + +struct GuildBankItemUpdate_Struct +{ + void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, + uint32 inPermissions, uint32 inAllowMerge, bool inUseable) + { + Action = inAction; + Unknown004 = inUnknown004; + SlotID = inSlotID; + Area = inArea; + Unknown012 = inUnknown012; + ItemID = inItemID; + Icon = inIcon; + Quantity = inQuantity; + Permissions = inPermissions; + AllowMerge = inAllowMerge; + Useable = inUseable; + ItemName[0] = '\0'; + Donator[0] = '\0'; + WhoFor[0] = '\0'; + }; + +/*000*/ uint32 Action; +/*004*/ uint32 Unknown004; +/*008*/ uint32 Unknown08; +/*012*/ uint16 SlotID; +/*014*/ uint16 Area; +/*016*/ uint32 Unknown012; +/*020*/ uint32 ItemID; +/*024*/ uint32 Icon; +/*028*/ uint32 Quantity; +/*032*/ uint32 Permissions; +/*036*/ uint8 AllowMerge; +/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char ItemName[64]; +/*102*/ char Donator[64]; +/*166*/ char WhoFor[64]; +/*230*/ uint16 Unknown226; +}; + +struct GuildBankClear_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 DepositAreaCount; +/*16*/ uint32 MainAreaCount; +}; + /* ** Money Loot ** Length: 22 Bytes diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index dfd8f0e84..7a33eb459 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -131,6 +131,7 @@ OP_GuildPromote=0x2945 OP_GuildPublicNote=0x3c2c OP_GuildManageBanker=0x389c # Was 0x096d OP_GuildBank=0x2ab0 # Was 0x10c3 +OP_GuildBankItemList=0x1cbf OP_SetGuildRank=0x3599 OP_GuildUpdateURLAndChannel=0x7851 OP_GuildStatus=0x25a5 diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 0d1cb20ec..6afb7209e 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -130,6 +130,7 @@ OP_GuildPromote=0x6a98 OP_GuildPublicNote=0x5053 OP_GuildManageBanker=0x3f35 OP_GuildBank=0x5134 +OP_GuildBankItemList=0x7850 OP_SetGuildRank=0x0b9c OP_GuildUpdateURLAndChannel=0x2958 OP_GuildStatus=0x7326 diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c955399b8..a766f0470 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -6683,20 +6683,6 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buffer); uint32 sentAction = Action; - if (GetClientVersion() >= ClientVersion::RoF) - { - Action += 1; - /* - // Need to find all of the action types for RoF and switch case here - switch(Action) - { - case 4: - Action = 5; - break; - } - */ - } - if (!IsInAGuild()) { Message(13, "You must be in a Guild to use the Guild Bank."); diff --git a/zone/guild.cpp b/zone/guild.cpp index 12f785b02..7b3c104f8 100644 --- a/zone/guild.cpp +++ b/zone/guild.cpp @@ -248,7 +248,9 @@ void Client::RefreshGuildInfo() if((guild_id != OldGuildID) && GuildBanks) { - ClearGuildBank(); + // Unsure about this for RoF+ ... But they don't have that action anymore so fuck it + if (GetClientVersion() < ClientVersion::RoF) + ClearGuildBank(); if(guild_id != GUILD_NONE) GuildBanks->SendGuildBank(this); diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index 8754a60e8..ed9957908 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -688,11 +688,68 @@ void GuildBankManager::SendGuildBank(Client *c) return; } + auto &guild_bank = *Iterator; + + // RoF+ uses a bulk list packet -- This is also how the Action 0 of older clients basically works + if (c->GetClientVersionBit() & BIT_RoFAndLater) { + auto outapp = new EQApplicationPacket(OP_GuildBankItemList, sizeof(GuildBankItemListEntry_Struct) * 240); + for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) { + const Item_Struct *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); + if (Item) { + outapp->WriteUInt8(1); + outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Permissions); + outapp->WriteString(guild_bank->Items.DepositArea[i].WhoFor); + outapp->WriteString(guild_bank->Items.DepositArea[i].Donator); + outapp->WriteUInt32(Item->ID); + outapp->WriteUInt32(Item->Icon); + if (Item->Stackable) { + outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Quantity); + outapp->WriteUInt8(Item->StackSize == guild_bank->Items.DepositArea[i].Quantity ? 0 : 1); + } else { + outapp->WriteUInt32(1); + outapp->WriteUInt8(0); + } + outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); + outapp->WriteString(Item->Name); + } else { + outapp->WriteUInt8(0); // empty + } + } + outapp->SetWritePosition(outapp->GetWritePosition() + 20); // newer clients have 40 deposit slots, keep them 0 for now + + for (int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) { + const Item_Struct *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); + if (Item) { + outapp->WriteUInt8(1); + outapp->WriteUInt32(guild_bank->Items.MainArea[i].Permissions); + outapp->WriteString(guild_bank->Items.MainArea[i].WhoFor); + outapp->WriteString(guild_bank->Items.MainArea[i].Donator); + outapp->WriteUInt32(Item->ID); + outapp->WriteUInt32(Item->Icon); + if (Item->Stackable) { + outapp->WriteUInt32(guild_bank->Items.MainArea[i].Quantity); + outapp->WriteUInt8(Item->StackSize == guild_bank->Items.MainArea[i].Quantity ? 0 : 1); + } else { + outapp->WriteUInt32(1); + outapp->WriteUInt8(0); + } + outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); + outapp->WriteString(Item->Name); + } else { + outapp->WriteUInt8(0); // empty + } + } + + outapp->size = outapp->GetWritePosition(); // truncate to used size + c->FastQueuePacket(&outapp); + return; + } + for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) { - if((*Iterator)->Items.DepositArea[i].ItemID > 0) + if(guild_bank->Items.DepositArea[i].ItemID > 0) { - const Item_Struct *Item = database.GetItem((*Iterator)->Items.DepositArea[i].ItemID); + const Item_Struct *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); if(!Item) continue; @@ -703,22 +760,22 @@ void GuildBankManager::SendGuildBank(Client *c) if(!Item->Stackable) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, 1, - (*Iterator)->Items.DepositArea[i].Permissions, 0, 0); + guild_bank->Items.DepositArea[i].Permissions, 0, 0); else { - if((*Iterator)->Items.DepositArea[i].Quantity == Item->StackSize) + if(guild_bank->Items.DepositArea[i].Quantity == Item->StackSize) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 0, 0); + guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 0, 0); else gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 1, 0); + guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 1, 0); } strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); - strn0cpy(gbius->Donator, (*Iterator)->Items.DepositArea[i].Donator, sizeof(gbius->Donator)); + strn0cpy(gbius->Donator, guild_bank->Items.DepositArea[i].Donator, sizeof(gbius->Donator)); - strn0cpy(gbius->WhoFor, (*Iterator)->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->WhoFor, guild_bank->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor)); c->FastQueuePacket(&outapp); } @@ -726,9 +783,9 @@ void GuildBankManager::SendGuildBank(Client *c) for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) { - if((*Iterator)->Items.MainArea[i].ItemID > 0) + if(guild_bank->Items.MainArea[i].ItemID > 0) { - const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[i].ItemID); + const Item_Struct *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); if(!Item) continue; @@ -741,22 +798,22 @@ void GuildBankManager::SendGuildBank(Client *c) if(!Item->Stackable) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, - (*Iterator)->Items.MainArea[i].Permissions, 0, Useable); + guild_bank->Items.MainArea[i].Permissions, 0, Useable); else { - if((*Iterator)->Items.MainArea[i].Quantity == Item->StackSize) + if(guild_bank->Items.MainArea[i].Quantity == Item->StackSize) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 0, Useable); + guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 0, Useable); else gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 1, Useable); + guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 1, Useable); } strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); - strn0cpy(gbius->Donator, (*Iterator)->Items.MainArea[i].Donator, sizeof(gbius->Donator)); + strn0cpy(gbius->Donator, guild_bank->Items.MainArea[i].Donator, sizeof(gbius->Donator)); - strn0cpy(gbius->WhoFor, (*Iterator)->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->WhoFor, guild_bank->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor)); c->FastQueuePacket(&outapp); }