From 51fb7d8b77066dcc1f9c1f075403b6cef99528b9 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Mon, 20 Jan 2020 15:38:07 -0500 Subject: [PATCH 01/26] _GetRunSpeed did not correctly report aa mods for Clients. I actually believe this was some old cut-n-paste error. aa_mod was being set to a total of all (3) caps - like the previous line. --- zone/mob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/mob.cpp b/zone/mob.cpp index 71e876938..ea0cf761b 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -684,7 +684,7 @@ int Mob::_GetRunSpeed() const { int runspeedcap = RuleI(Character,BaseRunSpeedCap); runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; - aa_mod = itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; + aa_mod += aabonuses.BaseMovementSpeed + aabonuses.movementspeed; int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed; int movemod = 0; From 63b8df72b2c9b4ac0cc50d755c3eda571bf37d1c Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Sun, 26 Jan 2020 20:53:59 -0500 Subject: [PATCH 02/26] Implement consent for group/raid/guild and add Auto Consent support Refactors consent to be more live accurate Message sent to owner and receiver for each zone a corpse is in Corpses now store consent list instead of clients holding corpse list Consent throttling added Message strings and colors updated Removed reporting invalid consent targets --- common/emu_constants.h | 9 ++++ common/servertalk.h | 3 ++ world/zoneserver.cpp | 119 ++++++++--------------------------------- zone/client.cpp | 46 ++++++++++++++++ zone/client.h | 6 ++- zone/client_packet.cpp | 46 ++++++---------- zone/corpse.cpp | 67 ++++++++++++++++++----- zone/corpse.h | 9 ++++ zone/string_ids.h | 4 ++ zone/worldserver.cpp | 89 +++++++++++++++++------------- 10 files changed, 222 insertions(+), 176 deletions(-) diff --git a/common/emu_constants.h b/common/emu_constants.h index c6491b3b3..945f513b5 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -317,6 +317,15 @@ namespace EQEmu QuestControlGrid = -1 }; + namespace consent { + enum eConsentType : uint8 { + Normal = 0, + Group, + Raid, + Guild + }; + }; // namespace consent + } /*EQEmu*/ #endif /*COMMON_EMU_CONSTANTS_H*/ diff --git a/common/servertalk.h b/common/servertalk.h index b9cb6202e..2557941e7 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -866,10 +866,13 @@ struct SpawnPlayerCorpse_Struct { struct ServerOP_Consent_Struct { char grantname[64]; char ownername[64]; + char zonename[32]; uint8 permission; uint32 zone_id; uint16 instance_id; uint32 message_string_id; + uint8 consent_type; // 0 = normal, 1 = group, 2 = raid, 3 = guild + uint32 consent_id; }; struct ReloadTasks_Struct { diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index dd55fac39..1bbc7f1fc 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1057,110 +1057,37 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { break; } case ServerOP_Consent: { - // Message string id's likely to be used here are: - // CONSENT_YOURSELF = 399 - // CONSENT_INVALID_NAME = 397 - // TARGET_NOT_FOUND = 101 - ZoneServer* zs; - ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - ClientListEntry* cle = client_list.FindCharacter(s->grantname); - if (cle) { - if (cle->instance() != 0) - { - zs = zoneserver_list.FindByInstanceID(cle->instance()); - if (zs) { - zs->SendPacket(pack); - } - else - { - auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->instance_id = s->instance_id; - scs->message_string_id = 101; - zs = zoneserver_list.FindByInstanceID(s->instance_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->instance_id); - } - safe_delete(pack); - } - } - else - { - zs = zoneserver_list.FindByZoneID(cle->zone()); - if (zs) { - zs->SendPacket(pack); - } - else { - // send target not found back to requester - auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->message_string_id = 101; - zs = zoneserver_list.FindByZoneID(s->zone_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id); - } - safe_delete(pack); - } - } - } - else { - // send target not found back to requester - auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->message_string_id = 397; - zs = zoneserver_list.FindByZoneID(s->zone_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id); - } - safe_delete(pack); - } + zoneserver_list.SendPacket(pack); // update corpses in all zones break; } case ServerOP_Consent_Response: { - // Message string id's likely to be used here are: - // CONSENT_YOURSELF = 399 - // CONSENT_INVALID_NAME = 397 - // TARGET_NOT_FOUND = 101 ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - if (s->instance_id != 0) + + ZoneServer* owner_zs = nullptr; + if ((s->instance_id != 0 && (owner_zs = zoneserver_list.FindByInstanceID(s->instance_id))) || + (s->instance_id == 0 && (owner_zs = zoneserver_list.FindByZoneID(s->zone_id)))) { - ZoneServer* zs = zoneserver_list.FindByInstanceID(s->instance_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->instance_id); - } + owner_zs->SendPacket(pack); } else { - ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id); - if (zs) { - zs->SendPacket(pack); - } - else { - LogInfo("Unable to locate zone record for zone id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id); + LogInfo("Unable to locate zone record for zone id [{}] or instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id, s->instance_id); + } + + if (s->consent_type == EQEmu::consent::Normal) + { + // send the message to the client being granted or denied permission + if (ClientListEntry* cle = client_list.FindCharacter(s->grantname)) + { + ZoneServer* granted_zs = nullptr; + if ((cle->instance() != 0 && (granted_zs = zoneserver_list.FindByInstanceID(cle->instance()))) || + (cle->instance() == 0 && (granted_zs = zoneserver_list.FindByZoneID(cle->zone())))) + { + // avoid sending twice if owner and granted are in same zone + if (granted_zs != owner_zs) { + granted_zs->SendPacket(pack); + } + } } } break; diff --git a/zone/client.cpp b/zone/client.cpp index 9ea27869a..f43b4a48e 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -165,6 +165,7 @@ Client::Client(EQStreamInterface* ieqs) hp_self_update_throttle_timer(300), hp_other_update_throttle_timer(500), position_update_timer(10000), + consent_throttle_timer(2000), tmSitting(0) { @@ -6254,6 +6255,51 @@ void Client::DragCorpses() } } +void Client::ConsentCorpses(const char* consent_name, bool deny) +{ + if (strcasecmp(consent_name, GetName()) == 0) { + MessageString(Chat::Red, CONSENT_YOURSELF); + } + else if (!consent_throttle_timer.Check()) { + MessageString(Chat::Red, CONSENT_WAIT); + } + else { + auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); + ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; + strcpy(scs->grantname, consent_name); + strcpy(scs->ownername, GetName()); + strcpy(scs->zonename, "Unknown"); + scs->message_string_id = 0; + scs->permission = deny ? 0 : 1; + scs->zone_id = zone->GetZoneID(); + scs->instance_id = zone->GetInstanceID(); + scs->consent_type = EQEmu::consent::Normal; + scs->consent_id = 0; + if (strcasecmp(scs->grantname, "group") == 0) { + if (!deny) { + Group* grp = GetGroup(); + scs->consent_id = grp ? grp->GetID() : 0; + } + scs->consent_type = EQEmu::consent::Group; + } + else if (strcasecmp(scs->grantname, "raid") == 0) { + if (!deny) { + Raid* raid = GetRaid(); + scs->consent_id = raid ? raid->GetID() : 0; + } + scs->consent_type = EQEmu::consent::Raid; + } + else if (strcasecmp(scs->grantname, "guild") == 0) { + if (!deny) { + scs->consent_id = GuildID(); + } + scs->consent_type = EQEmu::consent::Guild; + } + worldserver.SendPacket(pack); + safe_delete(pack); + } +} + void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_override, int pet_count, int pet_duration) { if(!target || !IsValidSpell(spell_id) || this->GetID() == target->GetID()) diff --git a/zone/client.h b/zone/client.h index 4ff431520..7f6a9bd9e 100644 --- a/zone/client.h +++ b/zone/client.h @@ -793,6 +793,9 @@ public: virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } inline bool AutoSplitEnabled() { return m_pp.autosplit != 0; } + inline bool AutoConsentGroupEnabled() const { return m_pp.groupAutoconsent != 0; } + inline bool AutoConsentRaidEnabled() const { return m_pp.raidAutoconsent != 0; } + inline bool AutoConsentGuildEnabled() const { return m_pp.guildAutoconsent != 0; } void SummonHorse(uint16 spell_id); void SetHorseId(uint16 horseid_in); @@ -957,7 +960,6 @@ public: void EnteringMessages(Client* client); void SendRules(Client* client); - std::list consent_list; const bool GetGMSpeed() const { return (gmspeed > 0); } bool CanUseReport; @@ -1137,6 +1139,7 @@ public: inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); } void DragCorpses(); inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } + void ConsentCorpses(const char* consent_name, bool deny = false); void SendAltCurrencies(); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0); @@ -1527,6 +1530,7 @@ private: Timer hp_self_update_throttle_timer; /* This is to prevent excessive packet sending under trains/fast combat */ Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */ Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */ + Timer consent_throttle_timer; glm::vec3 m_Proximity; glm::vec4 last_position_before_bulk_update; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index ebc6bd38a..09dae201a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4643,43 +4643,16 @@ void Client::Handle_OP_Consent(const EQApplicationPacket *app) { if (app->size<64) { Consent_Struct* c = (Consent_Struct*)app->pBuffer; - if (strcmp(c->name, GetName()) != 0) { - auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, c->name); - strcpy(scs->ownername, GetName()); - scs->message_string_id = 0; - scs->permission = 1; - scs->zone_id = zone->GetZoneID(); - scs->instance_id = zone->GetInstanceID(); - //consent_list.push_back(scs->grantname); - worldserver.SendPacket(pack); - safe_delete(pack); - } - else { - MessageString(Chat::White, CONSENT_YOURSELF); - } + ConsentCorpses(c->name, false); } - return; } void Client::Handle_OP_ConsentDeny(const EQApplicationPacket *app) { if (app->size<64) { Consent_Struct* c = (Consent_Struct*)app->pBuffer; - auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, c->name); - strcpy(scs->ownername, GetName()); - scs->message_string_id = 0; - scs->permission = 0; - scs->zone_id = zone->GetZoneID(); - scs->instance_id = zone->GetInstanceID(); - //consent_list.remove(scs->grantname); - worldserver.SendPacket(pack); - safe_delete(pack); + ConsentCorpses(c->name, true); } - return; } void Client::Handle_OP_Consider(const EQApplicationPacket *app) @@ -13315,6 +13288,21 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) entity_list.QueueClients(this, app, true); } } + else if (sa->type == AT_GroupConsent) + { + m_pp.groupAutoconsent = (sa->parameter == 1); + ConsentCorpses("Group", (sa->parameter != 1)); + } + else if (sa->type == AT_RaidConsent) + { + m_pp.raidAutoconsent = (sa->parameter == 1); + ConsentCorpses("Raid", (sa->parameter != 1)); + } + else if (sa->type == AT_GuildConsent) + { + m_pp.guildAutoconsent = (sa->parameter == 1); + ConsentCorpses("Guild", (sa->parameter != 1)); + } else { std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec << " value: 0x" << std::hex << std::setw(8) << std::setfill('0') << sa->parameter << std::dec << std::endl; diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 09661826d..6b52a0c63 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -282,6 +282,12 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( allowed_looters[i] = 0; } + Group* grp = nullptr; + Raid* raid = nullptr; + consent_group_id = (client->AutoConsentGroupEnabled() && (grp = client->GetGroup())) ? grp->GetID() : 0; + consent_raid_id = (client->AutoConsentRaidEnabled() && (raid = client->GetRaid())) ? raid->GetID() : 0; + consent_guild_id = client->AutoConsentGuildEnabled() ? client->GuildID() : 0; + is_corpse_changed = true; rez_experience = in_rezexp; can_corpse_be_rezzed = true; @@ -647,6 +653,25 @@ void Corpse::DepopPlayerCorpse() { player_corpse_depop = true; } +void Corpse::AddConsentName(const char* add_name) +{ + for (const auto& n : consent_names) { + if (strcasecmp(n.c_str(), add_name) == 0) { + return; + } + } + consent_names.emplace_back(add_name); +} + +void Corpse::RemoveConsentName(const char* rem_name) +{ + consent_names.erase(std::remove_if(consent_names.begin(), consent_names.end(), + [rem_name](const std::string& n) { + return strcasecmp(n.c_str(), rem_name) == 0; + } + ), consent_names.end()); +} + uint32 Corpse::CountItems() { return itemlist.size(); } @@ -1434,29 +1459,43 @@ bool Corpse::Summon(Client* client, bool spell, bool CheckDistance) { is_corpse_changed = true; } else { - client->Message(Chat::White, "Corpse is too far away."); + client->MessageString(Chat::Red, CORPSE_TOO_FAR); return false; } } else { bool consented = false; - std::list::iterator itr; - for(itr = client->consent_list.begin(); itr != client->consent_list.end(); ++itr) { - if(strcmp(this->GetOwnerName(), itr->c_str()) == 0) { - if (!CheckDistance || (DistanceSquaredNoZ(m_Position, client->GetPosition()) <= dist2)) { - GMMove(client->GetX(), client->GetY(), client->GetZ()); - is_corpse_changed = true; - } - else { - client->Message(Chat::White, "Corpse is too far away."); - return false; - } + for (const auto& n : consent_names) { + if (strcasecmp(client->GetName(), n.c_str()) == 0) { + consented = true; + break; + } + } + + if (!consented) { + Group* grp = nullptr; + Raid* raid = nullptr; + if ((consent_guild_id && consent_guild_id != GUILD_NONE && client->GuildID() == consent_guild_id) || + (consent_group_id && (grp = client->GetGroup()) && grp->GetID() == consent_group_id) || + (consent_raid_id && (raid = client->GetRaid()) && raid->GetID() == consent_raid_id)) + { consented = true; } } - if(!consented) { - client->Message(Chat::White, "You do not have permission to move this corpse."); + + if (consented) { + if (!CheckDistance || (DistanceSquaredNoZ(m_Position, client->GetPosition()) <= dist2)) { + GMMove(client->GetX(), client->GetY(), client->GetZ()); + is_corpse_changed = true; + } + else { + client->MessageString(Chat::Red, CORPSE_TOO_FAR); + return false; + } + } + else { + client->MessageString(Chat::Red, CONSENT_DENIED); return false; } } diff --git a/zone/corpse.h b/zone/corpse.h index e7a7c5805..ae365abef 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -74,6 +74,11 @@ class Corpse : public Mob { uint32 GetDecayTime() { if (!corpse_decay_timer.Enabled()) return 0xFFFFFFFF; else return corpse_decay_timer.GetRemainingTime(); } uint32 GetRezTime() { if (!corpse_rez_timer.Enabled()) return 0; else return corpse_rez_timer.GetRemainingTime(); } void SetDecayTimer(uint32 decay_time); + void SetConsentGroupID(uint32 id) { if (IsPlayerCorpse()) { consent_group_id = id; } } + void SetConsentRaidID(uint32 id) { if (IsPlayerCorpse()) { consent_raid_id = id; } } + void SetConsentGuildID(uint32 id) { if (IsPlayerCorpse()) { consent_guild_id = id; } } + void AddConsentName(const char* name); + void RemoveConsentName(const char* name); void Delete(); void Bury(); @@ -142,6 +147,9 @@ private: int32 player_kill_item; /* Determines if Player Kill Item */ uint32 corpse_db_id; /* Corpse Database ID (Player Corpse) */ uint32 char_id; /* Character ID */ + uint32 consent_group_id = 0; /* consented group id */ + uint32 consent_raid_id = 0; /* consented raid id */ + uint32 consent_guild_id = 0; /* consented guild id */ ItemList itemlist; /* Internal Item list used for corpses */ uint32 copper; uint32 silver; @@ -160,6 +168,7 @@ private: Timer corpse_graveyard_timer; Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */ EQEmu::TintProfile item_tint; + std::vector consent_names; LootRequestType loot_request_type; }; diff --git a/zone/string_ids.h b/zone/string_ids.h index 0948d13a8..7c4066b55 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -122,11 +122,13 @@ #define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one. #define PICK_LORE 379 //You cannot pick up a lore item you already possess. #define POISON_TOO_HIGH 382 // This poison is too high level for you to apply. +#define CORPSE_TOO_FAR 389 //The corpse is too far away to summon. #define CONSENT_DENIED 390 //You do not have consent to summon that corpse. #define DISCIPLINE_RDY 393 //You are ready to use a new discipline now. #define CONSENT_INVALID_NAME 397 //Not a valid consent name. #define CONSENT_NPC 398 //You cannot consent NPC\'s. #define CONSENT_YOURSELF 399 //You cannot consent yourself. +#define CONSENT_WAIT 400 //You must wait 2 seconds between consents. #define SONG_NEEDS_DRUM 405 //You need to play a percussion instrument for this song #define SONG_NEEDS_WIND 406 //You need to play a wind instrument for this song #define SONG_NEEDS_STRINGS 407 //You need to play a stringed instrument for this song @@ -266,6 +268,8 @@ #define REZZ_ALREADY_PENDING 1379 //You were unable to restore the corpse to life, but you may have success with a later attempt. #define IN_USE 1406 //Someone else is using that. Try again later. #define DUEL_FLED 1408 //%1 has defeated %2 in a duel to the death! %3 has fled like a cowardly dog! +#define GIVE_CONSENT 1427 //You have given %1 permission to drag your corpse in %2. +#define DENY_CONSENT 1428 //You have denied %1 permission to drag your corpse in %2. #define MEMBER_OF_YOUR_GUILD 1429 #define OFFICER_OF_YOUR_GUILD 1430 #define LEADER_OF_YOUR_GUILD 1431 diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index a5180963d..4d01f792a 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1442,50 +1442,67 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_Consent: { ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - Client* client = entity_list.GetClientByName(s->grantname); - if (client) { - if (s->permission == 1) - client->consent_list.push_back(s->ownername); - else - client->consent_list.remove(s->ownername); - auto outapp = - new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); - ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; - strcpy(crs->grantname, s->grantname); - strcpy(crs->ownername, s->ownername); - crs->permission = s->permission; - strcpy(crs->zonename, "all zones"); - client->QueuePacket(outapp); - safe_delete(outapp); + bool found_corpse = false; + for (auto const& it : entity_list.GetCorpseList()) { + if (it.second->IsPlayerCorpse() && strcmp(it.second->GetOwnerName(), s->ownername) == 0) { + if (s->consent_type == EQEmu::consent::Normal) { + if (s->permission == 1) { + it.second->AddConsentName(s->grantname); + } + else { + it.second->RemoveConsentName(s->grantname); + } + } + else if (s->consent_type == EQEmu::consent::Group) { + it.second->SetConsentGroupID(s->consent_id); + } + else if (s->consent_type == EQEmu::consent::Raid) { + it.second->SetConsentRaidID(s->consent_id); + } + else if (s->consent_type == EQEmu::consent::Guild) { + it.second->SetConsentGuildID(s->consent_id); + } + found_corpse = true; + } } - else { - // target not found - // Message string id's likely to be used here are: - // CONSENT_YOURSELF = 399 - // CONSENT_INVALID_NAME = 397 - // TARGET_NOT_FOUND = 101 - - auto scs_pack = - new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)scs_pack->pBuffer; - strcpy(scs->grantname, s->grantname); - strcpy(scs->ownername, s->ownername); - scs->permission = s->permission; - scs->zone_id = s->zone_id; - scs->instance_id = s->instance_id; - scs->message_string_id = TARGET_NOT_FOUND; - worldserver.SendPacket(scs_pack); - safe_delete(scs_pack); + if (found_corpse) + { + // forward the grant/deny message for this zone to both owner and granted + auto outapp = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); + ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)outapp->pBuffer; + memcpy(outapp->pBuffer, s, sizeof(ServerOP_Consent_Struct)); + if (zone) { + strn0cpy(scs->zonename, zone->GetLongName(), sizeof(scs->zonename)); + } + scs->message_string_id = s->permission ? GIVE_CONSENT : DENY_CONSENT; + worldserver.SendPacket(outapp); + safe_delete(outapp); } break; } case ServerOP_Consent_Response: { ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - Client* client = entity_list.GetClientByName(s->ownername); - if (client) { - client->MessageString(Chat::White, s->message_string_id); + if (s->consent_type == EQEmu::consent::Normal) + { + if (Client* client = entity_list.GetClientByName(s->grantname)) + { + // send the message to the client being granted or denied permission + auto outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); + ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; + strcpy(crs->grantname, s->grantname); + strcpy(crs->ownername, s->ownername); + crs->permission = s->permission; + strn0cpy(crs->zonename, s->zonename, sizeof(crs->zonename)); + client->QueuePacket(outapp); + safe_delete(outapp); + } + } + if (Client* client = entity_list.GetClientByName(s->ownername)) + { + // send owner consent/deny confirmation message + client->MessageString(Chat::White, s->message_string_id, s->grantname, s->zonename); } break; } From 371265d143e58aa88ecbddacb4584f68f675ef61 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Tue, 28 Jan 2020 18:12:24 -0500 Subject: [PATCH 03/26] Make guild consent persistent for summoned corpses Live drops group/raid consent but not guild when moving corpse to another zone Store guild consent id in db for character corpses and keep it updated --- utils/sql/db_update_manifest.txt | 1 + .../2020_01_28_corpse_guild_consent_id.sql | 1 + zone/client.cpp | 2 + zone/corpse.cpp | 7 ++-- zone/corpse.h | 2 +- zone/zonedb.cpp | 39 ++++++++++++------- zone/zonedb.h | 5 ++- 7 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 utils/sql/git/required/2020_01_28_corpse_guild_consent_id.sql diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 53a71e109..8e3172b87 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -401,6 +401,7 @@ 9145|2019_12_24_banned_ips_update.sql|SHOW TABLES LIKE 'Banned_IPs'|not_empty| 9146|2020_01_10_character_soft_deletes.sql|SHOW COLUMNS FROM `character_data` LIKE 'deleted_at'|empty| 9147|2020_01_24_grid_centerpoint_wp.sql|SHOW COLUMNS FROM `grid_entries` LIKE 'centerpoint'|empty| +9148|2020_01_28_corpse_guild_consent_id.sql|SHOW COLUMNS FROM `character_corpses` LIKE 'guild_consent_id'|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/2020_01_28_corpse_guild_consent_id.sql b/utils/sql/git/required/2020_01_28_corpse_guild_consent_id.sql new file mode 100644 index 000000000..b42f257ea --- /dev/null +++ b/utils/sql/git/required/2020_01_28_corpse_guild_consent_id.sql @@ -0,0 +1 @@ +ALTER TABLE `character_corpses` ADD COLUMN `guild_consent_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `time_of_death`; diff --git a/zone/client.cpp b/zone/client.cpp index f43b4a48e..b6d91602c 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6294,6 +6294,8 @@ void Client::ConsentCorpses(const char* consent_name, bool deny) scs->consent_id = GuildID(); } scs->consent_type = EQEmu::consent::Guild; + // update all corpses in db so buried/unloaded corpses see new consent id + database.UpdateCharacterCorpseConsent(CharacterID(), scs->consent_id); } worldserver.SendPacket(pack); safe_delete(pack); diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 6b52a0c63..b24a335d2 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -73,7 +73,7 @@ void Corpse::SendLootReqErrorPacket(Client* client, LootResponse response) { safe_delete(outapp); } -Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard) { +Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard, uint32 guild_consent_id) { uint32 item_count = database.GetCharacterCorpseItemCount(in_dbid); auto buffer = new char[sizeof(PlayerCorpse_Struct) + (item_count * sizeof(player_lootitem::ServerLootItem_Struct))]; @@ -138,6 +138,7 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std: pc->drakkin_details = pcs->drakkin_details; pc->IsRezzed(rezzed); pc->become_npc = false; + pc->consent_guild_id = guild_consent_id; pc->UpdateEquipmentLight(); // itemlist populated above..need to determine actual values @@ -617,11 +618,11 @@ bool Corpse::Save() { /* Create New Corpse*/ if (corpse_db_id == 0) { - corpse_db_id = database.SaveCharacterCorpse(char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position); + corpse_db_id = database.SaveCharacterCorpse(char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consent_guild_id); } /* Update Corpse Data */ else{ - corpse_db_id = database.UpdateCharacterCorpse(corpse_db_id, char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, IsRezzed()); + corpse_db_id = database.UpdateCharacterCorpse(corpse_db_id, char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consent_guild_id, IsRezzed()); } safe_delete_array(dbpc); diff --git a/zone/corpse.h b/zone/corpse.h index ae365abef..02eb707a4 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -48,7 +48,7 @@ class Corpse : public Mob { Corpse(uint32 in_corpseid, uint32 in_charid, const char* in_charname, ItemList* in_itemlist, uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_plat, const glm::vec4& position, float in_size, uint8 in_gender, uint16 in_race, uint8 in_class, uint8 in_deity, uint8 in_level, uint8 in_texture, uint8 in_helmtexture, uint32 in_rezexp, bool wasAtGraveyard = false); ~Corpse(); - static Corpse* LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard); + static Corpse* LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard, uint32 guild_consent_id); /* Corpse: General */ virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index d5346877d..899861c3d 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -4288,10 +4288,10 @@ uint32 ZoneDatabase::GetCharacterCorpseDecayTimer(uint32 corpse_db_id){ return 0; } -uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const char* char_name, uint32 zone_id, uint16 instance_id, PlayerCorpse_Struct* dbpc, const glm::vec4& position, bool is_rezzed) { +uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const char* char_name, uint32 zone_id, uint16 instance_id, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guild_id, bool is_rezzed) { std::string query = StringFormat("UPDATE `character_corpses` " "SET `charname` = '%s', `zone_id` = %u, `instance_id` = %u, `charid` = %d, " - "`x` = %1.1f,`y` = %1.1f,`z` = %1.1f, `heading` = %1.1f, " + "`x` = %1.1f,`y` = %1.1f,`z` = %1.1f, `heading` = %1.1f, `guild_consent_id` = %u, " "`is_locked` = %d, `exp` = %u, `size` = %f, `level` = %u, " "`race` = %u, `gender` = %u, `class` = %u, `deity` = %u, " "`texture` = %u, `helm_texture` = %u, `copper` = %u, " @@ -4303,7 +4303,7 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c "`wc_7` = %u, `wc_8` = %u, `wc_9` = %u " "WHERE `id` = %u", EscapeString(char_name).c_str(), zone_id, instance_id, char_id, - position.x, position.y, position.z, position.w, + position.x, position.y, position.z, position.w, guild_id, dbpc->locked, dbpc->exp, dbpc->size, dbpc->level, dbpc->race, dbpc->gender, dbpc->class_, dbpc->deity, dbpc->texture, dbpc->helmtexture, dbpc->copper, dbpc->silver, dbpc->gold, @@ -4319,12 +4319,19 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c return db_id; } +uint32 ZoneDatabase::UpdateCharacterCorpseConsent(uint32 charid, uint32 guildid) +{ + std::string query = StringFormat("UPDATE `character_corpses` SET `guild_consent_id` = %u WHERE `charid` = %u", guildid, charid); + auto results = QueryDatabase(query); + return results.RowsAffected(); +} + void ZoneDatabase::MarkCorpseAsRezzed(uint32 db_id) { std::string query = StringFormat("UPDATE `character_corpses` SET `is_rezzed` = 1 WHERE `id` = %i", db_id); auto results = QueryDatabase(query); } -uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position) { +uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guildid) { /* Dump Basic Corpse Data */ std::string query = StringFormat( "INSERT INTO `character_corpses` " @@ -4336,6 +4343,7 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui "`y` = %1.1f, " "`z` = %1.1f, " "`heading` = %1.1f, " + "`guild_consent_id` = %u, " "`time_of_death` = NOW(), " "`is_buried` = 0, " "`is_locked` = %d, " @@ -4379,6 +4387,7 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui position.y, position.z, position.w, + guildid, dbpc->locked, dbpc->exp, dbpc->size, @@ -4637,7 +4646,7 @@ bool ZoneDatabase::LoadCharacterCorpseData(uint32 corpse_id, PlayerCorpse_Struct Corpse* ZoneDatabase::SummonBuriedCharacterCorpses(uint32 char_id, uint32 dest_zone_id, uint16 dest_instance_id, const glm::vec4& position) { Corpse* corpse = nullptr; - std::string query = StringFormat("SELECT `id`, `charname`, `time_of_death`, `is_rezzed` " + std::string query = StringFormat("SELECT `id`, `charname`, `time_of_death`, `is_rezzed`, `guild_consent_id` " "FROM `character_corpses` " "WHERE `charid` = '%u' AND `is_buried` = 1 " "ORDER BY `time_of_death` LIMIT 1", @@ -4652,7 +4661,8 @@ Corpse* ZoneDatabase::SummonBuriedCharacterCorpses(uint32 char_id, uint32 dest_z position, row[2], // char* time_of_death atoi(row[3]) == 1, // bool rezzed - false // bool was_at_graveyard + false, // bool was_at_graveyard + atoul(row[4]) // uint32 guild_consent_id ); if (!corpse) continue; @@ -4678,7 +4688,7 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id auto results = QueryDatabase(query); query = StringFormat( - "SELECT `id`, `charname`, `time_of_death`, `is_rezzed` FROM `character_corpses` WHERE `charid` = '%u'" + "SELECT `id`, `charname`, `time_of_death`, `is_rezzed`, `guild_consent_id` FROM `character_corpses` WHERE `charid` = '%u'" "ORDER BY time_of_death", char_id); results = QueryDatabase(query); @@ -4691,7 +4701,8 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id position, row[2], atoi(row[3]) == 1, - false); + false, + atoul(row[4])); if (corpse) { entity_list.AddCorpse(corpse); @@ -4766,7 +4777,7 @@ bool ZoneDatabase::UnburyCharacterCorpse(uint32 db_id, uint32 new_zone_id, uint1 Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) { Corpse* NewCorpse = 0; std::string query = StringFormat( - "SELECT `id`, `charid`, `charname`, `x`, `y`, `z`, `heading`, `time_of_death`, `is_rezzed`, `was_at_graveyard` FROM `character_corpses` WHERE `id` = '%u' LIMIT 1", + "SELECT `id`, `charid`, `charname`, `x`, `y`, `z`, `heading`, `time_of_death`, `is_rezzed`, `was_at_graveyard`, `guild_consent_id` FROM `character_corpses` WHERE `id` = '%u' LIMIT 1", player_corpse_id ); auto results = QueryDatabase(query); @@ -4779,7 +4790,8 @@ Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) { position, row[7], // time_of_death char* time_of_death atoi(row[8]) == 1, // is_rezzed bool rezzed - atoi(row[9]) // was_at_graveyard bool was_at_graveyard + atoi(row[9]), // was_at_graveyard bool was_at_graveyard + atoul(row[10]) // guild_consent_id uint32 guild_consent_id ); entity_list.AddCorpse(NewCorpse); } @@ -4789,10 +4801,10 @@ Corpse* ZoneDatabase::LoadCharacterCorpse(uint32 player_corpse_id) { bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) { std::string query; if (!RuleB(Zone, EnableShadowrest)){ - query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, was_at_graveyard FROM character_corpses WHERE zone_id='%u' AND instance_id='%u'", zone_id, instance_id); + query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, was_at_graveyard, guild_consent_id FROM character_corpses WHERE zone_id='%u' AND instance_id='%u'", zone_id, instance_id); } else{ - query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, 0 as was_at_graveyard FROM character_corpses WHERE zone_id='%u' AND instance_id='%u' AND is_buried=0", zone_id, instance_id); + query = StringFormat("SELECT id, charid, charname, x, y, z, heading, time_of_death, is_rezzed, 0 as was_at_graveyard, guild_consent_id FROM character_corpses WHERE zone_id='%u' AND instance_id='%u' AND is_buried=0", zone_id, instance_id); } auto results = QueryDatabase(query); @@ -4806,7 +4818,8 @@ bool ZoneDatabase::LoadCharacterCorpses(uint32 zone_id, uint16 instance_id) { position, row[7], // time_of_death char* time_of_death atoi(row[8]) == 1, // is_rezzed bool rezzed - atoi(row[9])) + atoi(row[9]), + atoul(row[10])) // guild_consent_id uint32 guild_consent_id ); } diff --git a/zone/zonedb.h b/zone/zonedb.h index d5c02c693..b1d88539d 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -367,8 +367,9 @@ public: uint32 SendCharacterCorpseToGraveyard(uint32 dbid, uint32 zoneid, uint16 instanceid, const glm::vec4& position); uint32 CreateGraveyardRecord(uint32 graveyard_zoneid, const glm::vec4& position); uint32 AddGraveyardIDToZone(uint32 zone_id, uint32 graveyard_id); - uint32 SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position); - uint32 UpdateCharacterCorpse(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, bool rezzed = false); + uint32 SaveCharacterCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guildid); + uint32 UpdateCharacterCorpse(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, PlayerCorpse_Struct* dbpc, const glm::vec4& position, uint32 guildid, bool rezzed = false); + uint32 UpdateCharacterCorpseConsent(uint32 charid, uint32 guildid); uint32 GetFirstCorpseID(uint32 char_id); uint32 GetCharacterCorpseCount(uint32 char_id); uint32 GetCharacterCorpseID(uint32 char_id, uint8 corpse); From 9689787e563d2c7ecb2eca8ff58798c08023e8f8 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Wed, 29 Jan 2020 18:34:33 -0500 Subject: [PATCH 04/26] Remove assignments in conditions --- world/zoneserver.cpp | 37 +++++++++++++++++++++---------------- zone/corpse.cpp | 35 ++++++++++++++++++++++++----------- zone/worldserver.cpp | 16 +++++++--------- 3 files changed, 52 insertions(+), 36 deletions(-) diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 1bbc7f1fc..08ccbfaff 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1064,29 +1064,34 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; ZoneServer* owner_zs = nullptr; - if ((s->instance_id != 0 && (owner_zs = zoneserver_list.FindByInstanceID(s->instance_id))) || - (s->instance_id == 0 && (owner_zs = zoneserver_list.FindByZoneID(s->zone_id)))) - { + if (s->instance_id == 0) { + owner_zs = zoneserver_list.FindByZoneID(s->zone_id); + } + else { + owner_zs = zoneserver_list.FindByInstanceID(s->instance_id); + } + + if (owner_zs) { owner_zs->SendPacket(pack); } - else - { + else { LogInfo("Unable to locate zone record for zone id [{}] or instance id [{}] in zoneserver list for ServerOP_Consent_Response operation", s->zone_id, s->instance_id); } - if (s->consent_type == EQEmu::consent::Normal) - { + if (s->consent_type == EQEmu::consent::Normal) { // send the message to the client being granted or denied permission - if (ClientListEntry* cle = client_list.FindCharacter(s->grantname)) - { + ClientListEntry* cle = client_list.FindCharacter(s->grantname); + if (cle) { ZoneServer* granted_zs = nullptr; - if ((cle->instance() != 0 && (granted_zs = zoneserver_list.FindByInstanceID(cle->instance()))) || - (cle->instance() == 0 && (granted_zs = zoneserver_list.FindByZoneID(cle->zone())))) - { - // avoid sending twice if owner and granted are in same zone - if (granted_zs != owner_zs) { - granted_zs->SendPacket(pack); - } + if (cle->instance() == 0) { + granted_zs = zoneserver_list.FindByZoneID(cle->zone()); + } + else { + granted_zs = zoneserver_list.FindByInstanceID(cle->instance()); + } + // avoid sending twice if owner and granted are in same zone + if (granted_zs && granted_zs != owner_zs) { + granted_zs->SendPacket(pack); } } } diff --git a/zone/corpse.cpp b/zone/corpse.cpp index b24a335d2..734bfa937 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -283,10 +283,16 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( allowed_looters[i] = 0; } - Group* grp = nullptr; - Raid* raid = nullptr; - consent_group_id = (client->AutoConsentGroupEnabled() && (grp = client->GetGroup())) ? grp->GetID() : 0; - consent_raid_id = (client->AutoConsentRaidEnabled() && (raid = client->GetRaid())) ? raid->GetID() : 0; + if (client->AutoConsentGroupEnabled()) { + Group* grp = client->GetGroup(); + consent_group_id = grp ? grp->GetID() : 0; + } + + if (client->AutoConsentRaidEnabled()) { + Raid* raid = client->GetRaid(); + consent_raid_id = raid ? raid->GetID() : 0; + } + consent_guild_id = client->AutoConsentGuildEnabled() ? client->GuildID() : 0; is_corpse_changed = true; @@ -1474,13 +1480,20 @@ bool Corpse::Summon(Client* client, bool spell, bool CheckDistance) { } } - if (!consented) { - Group* grp = nullptr; - Raid* raid = nullptr; - if ((consent_guild_id && consent_guild_id != GUILD_NONE && client->GuildID() == consent_guild_id) || - (consent_group_id && (grp = client->GetGroup()) && grp->GetID() == consent_group_id) || - (consent_raid_id && (raid = client->GetRaid()) && raid->GetID() == consent_raid_id)) - { + if (!consented && consent_guild_id && consent_guild_id != GUILD_NONE) { + if (client->GuildID() == consent_guild_id) { + consented = true; + } + } + if (!consented && consent_group_id) { + Group* grp = client->GetGroup(); + if (grp && grp->GetID() == consent_group_id) { + consented = true; + } + } + if (!consented && consent_raid_id) { + Raid* raid = client->GetRaid(); + if (raid && raid->GetID() == consent_raid_id) { consented = true; } } diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 4d01f792a..e1d90920f 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1467,8 +1467,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } } - if (found_corpse) - { + if (found_corpse) { // forward the grant/deny message for this zone to both owner and granted auto outapp = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)outapp->pBuffer; @@ -1484,10 +1483,9 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_Consent_Response: { ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; - if (s->consent_type == EQEmu::consent::Normal) - { - if (Client* client = entity_list.GetClientByName(s->grantname)) - { + if (s->consent_type == EQEmu::consent::Normal) { + Client* grant_client = entity_list.GetClientByName(s->grantname); + if (grant_client) { // send the message to the client being granted or denied permission auto outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; @@ -1495,12 +1493,12 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) strcpy(crs->ownername, s->ownername); crs->permission = s->permission; strn0cpy(crs->zonename, s->zonename, sizeof(crs->zonename)); - client->QueuePacket(outapp); + grant_client->QueuePacket(outapp); safe_delete(outapp); } } - if (Client* client = entity_list.GetClientByName(s->ownername)) - { + Client* client = entity_list.GetClientByName(s->ownername); + if (client) { // send owner consent/deny confirmation message client->MessageString(Chat::White, s->message_string_id, s->grantname, s->zonename); } From 14c070f845f61581a11b72f9383af321bdc57d9b Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Thu, 30 Jan 2020 20:00:01 -0500 Subject: [PATCH 05/26] Use strn0cpy instead of strcpy when copying consent name buffers Add nullptr checks to consent functions that accept char pointers --- zone/client.cpp | 11 +++++++---- zone/corpse.cpp | 22 +++++++++++++--------- zone/worldserver.cpp | 4 ++-- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index b6d91602c..fd1080797 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6257,7 +6257,10 @@ void Client::DragCorpses() void Client::ConsentCorpses(const char* consent_name, bool deny) { - if (strcasecmp(consent_name, GetName()) == 0) { + if (!consent_name) { + return; + } + else if (strcasecmp(consent_name, GetName()) == 0) { MessageString(Chat::Red, CONSENT_YOURSELF); } else if (!consent_throttle_timer.Check()) { @@ -6266,9 +6269,9 @@ void Client::ConsentCorpses(const char* consent_name, bool deny) else { auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strcpy(scs->grantname, consent_name); - strcpy(scs->ownername, GetName()); - strcpy(scs->zonename, "Unknown"); + strn0cpy(scs->grantname, consent_name, sizeof(scs->grantname)); + strn0cpy(scs->ownername, GetName(), sizeof(scs->ownername)); + strn0cpy(scs->zonename, "Unknown", sizeof(scs->zonename)); scs->message_string_id = 0; scs->permission = deny ? 0 : 1; scs->zone_id = zone->GetZoneID(); diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 734bfa937..3714ea7f7 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -662,21 +662,25 @@ void Corpse::DepopPlayerCorpse() { void Corpse::AddConsentName(const char* add_name) { - for (const auto& n : consent_names) { - if (strcasecmp(n.c_str(), add_name) == 0) { - return; + if (add_name) { + for (const auto& n : consent_names) { + if (strcasecmp(n.c_str(), add_name) == 0) { + return; + } } + consent_names.emplace_back(add_name); } - consent_names.emplace_back(add_name); } void Corpse::RemoveConsentName(const char* rem_name) { - consent_names.erase(std::remove_if(consent_names.begin(), consent_names.end(), - [rem_name](const std::string& n) { - return strcasecmp(n.c_str(), rem_name) == 0; - } - ), consent_names.end()); + if (rem_name) { + consent_names.erase(std::remove_if(consent_names.begin(), consent_names.end(), + [rem_name](const std::string& n) { + return strcasecmp(n.c_str(), rem_name) == 0; + } + ), consent_names.end()); + } } uint32 Corpse::CountItems() { diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index e1d90920f..2787d3c88 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1489,8 +1489,8 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) // send the message to the client being granted or denied permission auto outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; - strcpy(crs->grantname, s->grantname); - strcpy(crs->ownername, s->ownername); + strn0cpy(crs->grantname, s->grantname, sizeof(crs->grantname)); + strn0cpy(crs->ownername, s->ownername, sizeof(crs->ownername)); crs->permission = s->permission; strn0cpy(crs->zonename, s->zonename, sizeof(crs->zonename)); grant_client->QueuePacket(outapp); From c2300d514cecc32547679b4fdcebac5d26d3d662 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 1 Feb 2020 20:49:04 -0800 Subject: [PATCH 06/26] Packet warnings --- common/net/packet.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/net/packet.h b/common/net/packet.h index 1ce173a10..4ff5f8510 100644 --- a/common/net/packet.h +++ b/common/net/packet.h @@ -89,9 +89,9 @@ namespace EQ { public: StaticPacket(void *data, size_t size) { m_data = data; m_data_length = size; m_max_data_length = size; } virtual ~StaticPacket() { } - StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; } + StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; m_max_data_length = o.m_max_data_length; } StaticPacket& operator=(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; return *this; } - StaticPacket(StaticPacket &&o) { m_data = o.m_data; m_data_length = o.m_data_length; } + StaticPacket(StaticPacket &&o) noexcept { m_data = o.m_data; m_data_length = o.m_data_length; } virtual const void *Data() const { return m_data; } virtual void *Data() { return m_data; } @@ -112,7 +112,7 @@ namespace EQ { public: DynamicPacket() { } virtual ~DynamicPacket() { } - DynamicPacket(DynamicPacket &&o) { m_data = std::move(o.m_data); } + DynamicPacket(DynamicPacket &&o) noexcept { m_data = std::move(o.m_data); } DynamicPacket(const DynamicPacket &o) { m_data = o.m_data; } DynamicPacket& operator=(const DynamicPacket &o) { m_data = o.m_data; return *this; } @@ -127,4 +127,4 @@ namespace EQ { std::vector m_data; }; } -} \ No newline at end of file +} From e09b0ae1e9ca8573a1e213654765c690a216af46 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Sun, 2 Feb 2020 14:12:13 -0500 Subject: [PATCH 07/26] Let client handle consent confirmation messages to corpse owner --- common/servertalk.h | 1 - zone/client.cpp | 1 - zone/string_ids.h | 2 -- zone/worldserver.cpp | 34 +++++++++++++++++----------------- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/common/servertalk.h b/common/servertalk.h index 2557941e7..aa3529756 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -870,7 +870,6 @@ struct ServerOP_Consent_Struct { uint8 permission; uint32 zone_id; uint16 instance_id; - uint32 message_string_id; uint8 consent_type; // 0 = normal, 1 = group, 2 = raid, 3 = guild uint32 consent_id; }; diff --git a/zone/client.cpp b/zone/client.cpp index fd1080797..31333dc57 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6272,7 +6272,6 @@ void Client::ConsentCorpses(const char* consent_name, bool deny) strn0cpy(scs->grantname, consent_name, sizeof(scs->grantname)); strn0cpy(scs->ownername, GetName(), sizeof(scs->ownername)); strn0cpy(scs->zonename, "Unknown", sizeof(scs->zonename)); - scs->message_string_id = 0; scs->permission = deny ? 0 : 1; scs->zone_id = zone->GetZoneID(); scs->instance_id = zone->GetInstanceID(); diff --git a/zone/string_ids.h b/zone/string_ids.h index 7c4066b55..3b17b6d5b 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -268,8 +268,6 @@ #define REZZ_ALREADY_PENDING 1379 //You were unable to restore the corpse to life, but you may have success with a later attempt. #define IN_USE 1406 //Someone else is using that. Try again later. #define DUEL_FLED 1408 //%1 has defeated %2 in a duel to the death! %3 has fled like a cowardly dog! -#define GIVE_CONSENT 1427 //You have given %1 permission to drag your corpse in %2. -#define DENY_CONSENT 1428 //You have denied %1 permission to drag your corpse in %2. #define MEMBER_OF_YOUR_GUILD 1429 #define OFFICER_OF_YOUR_GUILD 1430 #define LEADER_OF_YOUR_GUILD 1431 diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 2787d3c88..56f99067c 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1475,7 +1475,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) if (zone) { strn0cpy(scs->zonename, zone->GetLongName(), sizeof(scs->zonename)); } - scs->message_string_id = s->permission ? GIVE_CONSENT : DENY_CONSENT; worldserver.SendPacket(outapp); safe_delete(outapp); } @@ -1483,24 +1482,25 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_Consent_Response: { ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer; + Client* owner_client = entity_list.GetClientByName(s->ownername); + Client* grant_client = nullptr; if (s->consent_type == EQEmu::consent::Normal) { - Client* grant_client = entity_list.GetClientByName(s->grantname); - if (grant_client) { - // send the message to the client being granted or denied permission - auto outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); - ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; - strn0cpy(crs->grantname, s->grantname, sizeof(crs->grantname)); - strn0cpy(crs->ownername, s->ownername, sizeof(crs->ownername)); - crs->permission = s->permission; - strn0cpy(crs->zonename, s->zonename, sizeof(crs->zonename)); - grant_client->QueuePacket(outapp); - safe_delete(outapp); - } + grant_client = entity_list.GetClientByName(s->grantname); } - Client* client = entity_list.GetClientByName(s->ownername); - if (client) { - // send owner consent/deny confirmation message - client->MessageString(Chat::White, s->message_string_id, s->grantname, s->zonename); + if (owner_client || grant_client) { + auto outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); + ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; + strn0cpy(crs->grantname, s->grantname, sizeof(crs->grantname)); + strn0cpy(crs->ownername, s->ownername, sizeof(crs->ownername)); + crs->permission = s->permission; + strn0cpy(crs->zonename, s->zonename, sizeof(crs->zonename)); + if (owner_client) { + owner_client->QueuePacket(outapp); // confirmation message to the owner + } + if (grant_client) { + grant_client->QueuePacket(outapp); // message to the client being granted/denied + } + safe_delete(outapp); } break; } From b8229c84591fbf8235f0dfa9ae4757d443526187 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Sun, 2 Feb 2020 22:57:59 -0500 Subject: [PATCH 08/26] Update CURRENT_BINARY_DATABASE_VERSION for consent sql update --- common/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version.h b/common/version.h index 5d00daaf4..ca37150ec 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9147 +#define CURRENT_BINARY_DATABASE_VERSION 9148 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 From d65a97e556a39e4edb0f4734773311961b3c754c Mon Sep 17 00:00:00 2001 From: KimLS Date: Sun, 2 Feb 2020 20:19:37 -0800 Subject: [PATCH 09/26] Rule for setting max navmesh nodes, default set higher than current to improve accuracy --- common/ruletypes.h | 1 + zone/mob_movement_manager.cpp | 9 +-- zone/pathfinder_nav_mesh.cpp | 109 ++++++++++++++++------------------ 3 files changed, 57 insertions(+), 62 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index c6e99e5f4..8acbb2c14 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -293,6 +293,7 @@ RULE_BOOL(Pathing, Find, true, "Enable pathing for FindPerson requests from the RULE_BOOL(Pathing, Fear, true, "Enable pathing for fear") RULE_REAL(Pathing, NavmeshStepSize, 100.0f, "") RULE_REAL(Pathing, ShortMovementUpdateRange, 130.0f, "") +RULE_INT(Pathing, MaxNavmeshNodes, 4092) RULE_CATEGORY_END() RULE_CATEGORY(Watermap) diff --git a/zone/mob_movement_manager.cpp b/zone/mob_movement_manager.cpp index 5e40dfeee..4ac0c7f23 100644 --- a/zone/mob_movement_manager.cpp +++ b/zone/mob_movement_manager.cpp @@ -1300,7 +1300,9 @@ void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry) */ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode) { - auto sb = who->GetStuckBehavior(); + LogDebug("Handle stuck behavior for {0} at ({1}, {2}, {3}) with movement_mode {4}", who->GetName(), x, y, z, mob_movement_mode); + + auto sb = who->GetStuckBehavior(); MobStuckBehavior behavior = RunToTarget; if (sb >= 0 && sb < MaxStuckBehavior) { @@ -1308,7 +1310,7 @@ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z } auto eiter = _impl->Entries.find(who); - auto &ent = (*eiter); + auto &ent = (*eiter); switch (sb) { case RunToTarget: @@ -1323,8 +1325,7 @@ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z PushStopMoving(ent.second); break; case EvadeCombat: - //PushEvadeCombat(ent.second); - PushStopMoving(ent.second); + PushEvadeCombat(ent.second); break; } } diff --git a/zone/pathfinder_nav_mesh.cpp b/zone/pathfinder_nav_mesh.cpp index 5be10b64f..63e76f486 100644 --- a/zone/pathfinder_nav_mesh.cpp +++ b/zone/pathfinder_nav_mesh.cpp @@ -12,8 +12,6 @@ extern Zone *zone; -const int MaxNavmeshNodes = 1024; - struct PathfinderNavmesh::Implementation { dtNavMesh *nav_mesh; @@ -36,19 +34,19 @@ PathfinderNavmesh::~PathfinderNavmesh() IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags) { partial = false; - + if (!m_impl->nav_mesh) { return IPath(); } - + if (!m_impl->query) { m_impl->query = dtAllocNavMeshQuery(); } - - m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); + + m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes)); glm::vec3 current_location(start.x, start.z, start.y); glm::vec3 dest_location(end.x, end.z, end.y); - + dtQueryFilter filter; filter.setIncludeFlags(flags); filter.setAreaCost(0, 1.0f); //Normal @@ -61,48 +59,48 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl filter.setAreaCost(8, 1.0f); //General Area filter.setAreaCost(9, 0.1f); //Portal filter.setAreaCost(10, 0.1f); //Prefer - + dtPolyRef start_ref; dtPolyRef end_ref; glm::vec3 ext(5.0f, 100.0f, 5.0f); - + m_impl->query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0); m_impl->query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0); - + if (!start_ref || !end_ref) { return IPath(); } - + int npoly = 0; dtPolyRef path[1024] = { 0 }; auto status = m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, 1024); - + if (npoly) { glm::vec3 epos = dest_location; if (path[npoly - 1] != end_ref) { m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0); partial = true; - + auto dist = DistanceSquared(epos, current_location); if (dist < 10000.0f) { stuck = true; } } - + float straight_path[2048 * 3]; unsigned char straight_path_flags[2048]; - + int n_straight_polys; dtPolyRef straight_path_polys[2048]; - + status = m_impl->query->findStraightPath(¤t_location[0], &epos[0], path, npoly, straight_path, straight_path_flags, straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_AREA_CROSSINGS); - + if (dtStatusFailed(status)) { return IPath(); } - + if (n_straight_polys) { IPath Route; for (int i = 0; i < n_straight_polys; ++i) @@ -111,9 +109,9 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl node.x = straight_path[i * 3]; node.z = straight_path[i * 3 + 1]; node.y = straight_path[i * 3 + 2]; - + Route.push_back(node); - + unsigned short flag = 0; if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) { if (flag & 512) { @@ -121,11 +119,11 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl } } } - + return Route; } } - + IPath Route; Route.push_back(end); return Route; @@ -134,19 +132,19 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions &opts) { partial = false; - + if (!m_impl->nav_mesh) { return IPath(); } - + if (!m_impl->query) { m_impl->query = dtAllocNavMeshQuery(); } - - m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); + + m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes)); glm::vec3 current_location(start.x, start.z, start.y); glm::vec3 dest_location(end.x, end.z, end.y); - + dtQueryFilter filter; filter.setIncludeFlags(opts.flags); filter.setAreaCost(0, opts.flag_cost[0]); //Normal @@ -159,83 +157,78 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm filter.setAreaCost(8, opts.flag_cost[7]); //General Area filter.setAreaCost(9, opts.flag_cost[8]); //Portal filter.setAreaCost(10, opts.flag_cost[9]); //Prefer - + static const int max_polys = 256; dtPolyRef start_ref; dtPolyRef end_ref; glm::vec3 ext(10.0f, 200.0f, 10.0f); - + m_impl->query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0); m_impl->query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0); - + if (!start_ref || !end_ref) { return IPath(); } - + int npoly = 0; dtPolyRef path[max_polys] = { 0 }; - m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, max_polys); - + auto status = m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, max_polys); + if (npoly) { glm::vec3 epos = dest_location; if (path[npoly - 1] != end_ref) { m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0); partial = true; - - auto dist = DistanceSquared(epos, current_location); - if (dist < 10000.0f) { - stuck = true; - } } - + int n_straight_polys; glm::vec3 straight_path[max_polys]; unsigned char straight_path_flags[max_polys]; dtPolyRef straight_path_polys[max_polys]; - + auto status = m_impl->query->findStraightPath(¤t_location[0], &epos[0], path, npoly, (float*)&straight_path[0], straight_path_flags, straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS); - + if (dtStatusFailed(status)) { return IPath(); } - + if (n_straight_polys) { if (opts.smooth_path) { IPath Route; - + //Add the first point { auto &flag = straight_path_flags[0]; if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) { auto &p = straight_path[0]; - + Route.push_back(glm::vec3(p.x, p.z, p.y)); } else { auto &p = straight_path[0]; - + float h = 0.0f; if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, p, &h))) { p.y = h + opts.offset; } - + Route.push_back(glm::vec3(p.x, p.z, p.y)); } } - + for (int i = 0; i < n_straight_polys - 1; ++i) { auto &flag = straight_path_flags[i]; - + if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) { auto &poly = straight_path_polys[i]; - + auto &p2 = straight_path[i + 1]; glm::vec3 node(p2.x, p2.z, p2.y); Route.push_back(node); - + unsigned short pflag = 0; if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &pflag))) { if (pflag & 512) { @@ -250,12 +243,12 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm auto dir = glm::normalize(p2 - p1); float total = 0.0f; glm::vec3 previous_pt = p1; - + while (total < dist) { glm::vec3 current_pt; float dist_to_move = opts.step_size; float ff = opts.step_size / 2.0f; - + if (total + dist_to_move + ff >= dist) { current_pt = p2; total = dist; @@ -264,18 +257,18 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm total += dist_to_move; current_pt = p1 + dir * total; } - + float h = 0.0f; if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, current_pt, &h))) { current_pt.y = h + opts.offset; } - + Route.push_back(glm::vec3(current_pt.x, current_pt.z, current_pt.y)); previous_pt = current_pt; } } } - + return Route; } else { @@ -285,7 +278,7 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm auto ¤t = straight_path[i]; glm::vec3 node(current.x, current.z, current.y); Route.push_back(node); - + unsigned short flag = 0; if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) { if (flag & 512) { @@ -293,7 +286,7 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm } } } - + return Route; } } @@ -313,7 +306,7 @@ glm::vec3 PathfinderNavmesh::GetRandomLocation(const glm::vec3 &start) if (!m_impl->query) { m_impl->query = dtAllocNavMeshQuery(); - m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); + m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes)); } dtQueryFilter filter; From 5fefdfcc170a9f42beee3381c7bb000e4e9f36a0 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Mon, 3 Feb 2020 12:50:05 -0500 Subject: [PATCH 10/26] Added new DefaultGuild rule to Character --- common/ruletypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/ruletypes.h b/common/ruletypes.h index dab1d02e1..a7b70bee6 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -159,6 +159,7 @@ RULE_BOOL(Character, PetsUseReagents, true, "Pets use reagent on spells") RULE_BOOL(Character, DismountWater, true, "Dismount horses when entering water") RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing") RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted") +RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated") RULE_CATEGORY_END() RULE_CATEGORY(Mercs) From f9b3b7aecf8c111cd7f87eb166075036c6973294 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Mon, 3 Feb 2020 12:54:26 -0500 Subject: [PATCH 11/26] Implement DefaultGuild rule --- common/database.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/common/database.cpp b/common/database.cpp index ac5ae16bf..581f4c082 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -338,6 +338,27 @@ bool Database::ReserveName(uint32 account_id, char* name) { query = StringFormat("INSERT INTO `character_data` SET `account_id` = %i, `name` = '%s'", account_id, name); results = QueryDatabase(query); if (!results.Success() || results.ErrorMessage() != ""){ return false; } + + // Put character into the default guild if rule is being used. + int guild_id = RuleI(Character, DefaultGuild); + + if (guild_id != 0) { + int char_id=-1; + query = StringFormat("select `id` FROM `character_data` WHERE `name` = '%s'", name); + results = QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + char_id = atoi(row[0]); + } + + if (char_id > -1) { + query = StringFormat("INSERT INTO `guild_members` SET `char_id` = %i, `guild_id` = '%i'", char_id, guild_id); + results = QueryDatabase(query); + if (!results.Success() || results.ErrorMessage() != ""){ + LogInfo("Could not put character [{}] into default Guild", name); + } + } + } + return true; } From ad1f18306b99a802b7c8751e1875dafda1df4a7b Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Mon, 3 Feb 2020 13:47:16 -0500 Subject: [PATCH 12/26] Update command.cpp Fix #size command to be useful for anyone using the model field in npc_types. All will remain the same for everyone else. --- zone/command.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/command.cpp b/zone/command.cpp index 877529c2b..757e2d522 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -2543,7 +2543,7 @@ void command_size(Client *c, const Seperator *sep) else if (!target) c->Message(Chat::White,"Error: this command requires a target"); else { - uint16 Race = target->GetRace(); + uint16 Race = target->GetModel(); uint8 Gender = target->GetGender(); uint8 Texture = 0xFF; uint8 HelmTexture = 0xFF; From 342012c4f4e61d09b3f03f5e9fd061b60830a2bb Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 4 Feb 2020 00:24:43 -0600 Subject: [PATCH 13/26] Fix compile issue --- common/ruletypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 8d3b85d3e..897f249f4 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -294,7 +294,7 @@ RULE_BOOL(Pathing, Find, true, "Enable pathing for FindPerson requests from the RULE_BOOL(Pathing, Fear, true, "Enable pathing for fear") RULE_REAL(Pathing, NavmeshStepSize, 100.0f, "") RULE_REAL(Pathing, ShortMovementUpdateRange, 130.0f, "") -RULE_INT(Pathing, MaxNavmeshNodes, 4092) +RULE_INT(Pathing, MaxNavmeshNodes, 4092, "Max navmesh nodes in a traversable path") RULE_CATEGORY_END() RULE_CATEGORY(Watermap) From d7138e84c011c684d3d0ab798c646f6763dc17c8 Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Tue, 4 Feb 2020 18:27:59 -0500 Subject: [PATCH 14/26] Make consent variable names more descriptive and replace char pointer parameters with std::string Use fmt::format for SQL statement when updating corpse guild id --- zone/client.cpp | 9 +++------ zone/client.h | 2 +- zone/corpse.cpp | 54 +++++++++++++++++++++++-------------------------- zone/corpse.h | 18 ++++++++--------- zone/zonedb.cpp | 2 +- 5 files changed, 39 insertions(+), 46 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 31333dc57..003fe3c1a 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6255,12 +6255,9 @@ void Client::DragCorpses() } } -void Client::ConsentCorpses(const char* consent_name, bool deny) +void Client::ConsentCorpses(std::string consent_name, bool deny) { - if (!consent_name) { - return; - } - else if (strcasecmp(consent_name, GetName()) == 0) { + if (strcasecmp(consent_name.c_str(), GetName()) == 0) { MessageString(Chat::Red, CONSENT_YOURSELF); } else if (!consent_throttle_timer.Check()) { @@ -6269,7 +6266,7 @@ void Client::ConsentCorpses(const char* consent_name, bool deny) else { auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; - strn0cpy(scs->grantname, consent_name, sizeof(scs->grantname)); + strn0cpy(scs->grantname, consent_name.c_str(), sizeof(scs->grantname)); strn0cpy(scs->ownername, GetName(), sizeof(scs->ownername)); strn0cpy(scs->zonename, "Unknown", sizeof(scs->zonename)); scs->permission = deny ? 0 : 1; diff --git a/zone/client.h b/zone/client.h index 7f6a9bd9e..ecbc67b04 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1139,7 +1139,7 @@ public: inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); } void DragCorpses(); inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } - void ConsentCorpses(const char* consent_name, bool deny = false); + void ConsentCorpses(std::string consent_name, bool deny = false); void SendAltCurrencies(); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0); diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 3714ea7f7..0ac100997 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -138,7 +138,7 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std: pc->drakkin_details = pcs->drakkin_details; pc->IsRezzed(rezzed); pc->become_npc = false; - pc->consent_guild_id = guild_consent_id; + pc->consented_guild_id = guild_consent_id; pc->UpdateEquipmentLight(); // itemlist populated above..need to determine actual values @@ -285,15 +285,15 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( if (client->AutoConsentGroupEnabled()) { Group* grp = client->GetGroup(); - consent_group_id = grp ? grp->GetID() : 0; + consented_group_id = grp ? grp->GetID() : 0; } if (client->AutoConsentRaidEnabled()) { Raid* raid = client->GetRaid(); - consent_raid_id = raid ? raid->GetID() : 0; + consented_raid_id = raid ? raid->GetID() : 0; } - consent_guild_id = client->AutoConsentGuildEnabled() ? client->GuildID() : 0; + consented_guild_id = client->AutoConsentGuildEnabled() ? client->GuildID() : 0; is_corpse_changed = true; rez_experience = in_rezexp; @@ -624,11 +624,11 @@ bool Corpse::Save() { /* Create New Corpse*/ if (corpse_db_id == 0) { - corpse_db_id = database.SaveCharacterCorpse(char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consent_guild_id); + corpse_db_id = database.SaveCharacterCorpse(char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consented_guild_id); } /* Update Corpse Data */ else{ - corpse_db_id = database.UpdateCharacterCorpse(corpse_db_id, char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consent_guild_id, IsRezzed()); + corpse_db_id = database.UpdateCharacterCorpse(corpse_db_id, char_id, corpse_name, zone->GetZoneID(), zone->GetInstanceID(), dbpc, m_Position, consented_guild_id, IsRezzed()); } safe_delete_array(dbpc); @@ -660,27 +660,23 @@ void Corpse::DepopPlayerCorpse() { player_corpse_depop = true; } -void Corpse::AddConsentName(const char* add_name) +void Corpse::AddConsentName(std::string consent_player_name) { - if (add_name) { - for (const auto& n : consent_names) { - if (strcasecmp(n.c_str(), add_name) == 0) { - return; - } + for (const auto& consented_player_name : consented_player_names) { + if (strcasecmp(consented_player_name.c_str(), consent_player_name.c_str()) == 0) { + return; } - consent_names.emplace_back(add_name); } + consented_player_names.emplace_back(consent_player_name); } -void Corpse::RemoveConsentName(const char* rem_name) +void Corpse::RemoveConsentName(std::string consent_player_name) { - if (rem_name) { - consent_names.erase(std::remove_if(consent_names.begin(), consent_names.end(), - [rem_name](const std::string& n) { - return strcasecmp(n.c_str(), rem_name) == 0; - } - ), consent_names.end()); - } + consented_player_names.erase(std::remove_if(consented_player_names.begin(), consented_player_names.end(), + [consent_player_name](const std::string& consented_player_name) { + return strcasecmp(consented_player_name.c_str(), consent_player_name.c_str()) == 0; + } + ), consented_player_names.end()); } uint32 Corpse::CountItems() { @@ -1477,27 +1473,27 @@ bool Corpse::Summon(Client* client, bool spell, bool CheckDistance) { else { bool consented = false; - for (const auto& n : consent_names) { - if (strcasecmp(client->GetName(), n.c_str()) == 0) { + for (const auto& consented_player_name : consented_player_names) { + if (strcasecmp(client->GetName(), consented_player_name.c_str()) == 0) { consented = true; break; } } - if (!consented && consent_guild_id && consent_guild_id != GUILD_NONE) { - if (client->GuildID() == consent_guild_id) { + if (!consented && consented_guild_id && consented_guild_id != GUILD_NONE) { + if (client->GuildID() == consented_guild_id) { consented = true; } } - if (!consented && consent_group_id) { + if (!consented && consented_group_id) { Group* grp = client->GetGroup(); - if (grp && grp->GetID() == consent_group_id) { + if (grp && grp->GetID() == consented_group_id) { consented = true; } } - if (!consented && consent_raid_id) { + if (!consented && consented_raid_id) { Raid* raid = client->GetRaid(); - if (raid && raid->GetID() == consent_raid_id) { + if (raid && raid->GetID() == consented_raid_id) { consented = true; } } diff --git a/zone/corpse.h b/zone/corpse.h index 02eb707a4..d453c7e9e 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -74,11 +74,11 @@ class Corpse : public Mob { uint32 GetDecayTime() { if (!corpse_decay_timer.Enabled()) return 0xFFFFFFFF; else return corpse_decay_timer.GetRemainingTime(); } uint32 GetRezTime() { if (!corpse_rez_timer.Enabled()) return 0; else return corpse_rez_timer.GetRemainingTime(); } void SetDecayTimer(uint32 decay_time); - void SetConsentGroupID(uint32 id) { if (IsPlayerCorpse()) { consent_group_id = id; } } - void SetConsentRaidID(uint32 id) { if (IsPlayerCorpse()) { consent_raid_id = id; } } - void SetConsentGuildID(uint32 id) { if (IsPlayerCorpse()) { consent_guild_id = id; } } - void AddConsentName(const char* name); - void RemoveConsentName(const char* name); + void SetConsentGroupID(uint32 group_id) { if (IsPlayerCorpse()) { consented_group_id = group_id; } } + void SetConsentRaidID(uint32 raid_id) { if (IsPlayerCorpse()) { consented_raid_id = raid_id; } } + void SetConsentGuildID(uint32 guild_id) { if (IsPlayerCorpse()) { consented_guild_id = guild_id; } } + void AddConsentName(std::string consent_player_name); + void RemoveConsentName(std::string consent_player_name); void Delete(); void Bury(); @@ -147,9 +147,9 @@ private: int32 player_kill_item; /* Determines if Player Kill Item */ uint32 corpse_db_id; /* Corpse Database ID (Player Corpse) */ uint32 char_id; /* Character ID */ - uint32 consent_group_id = 0; /* consented group id */ - uint32 consent_raid_id = 0; /* consented raid id */ - uint32 consent_guild_id = 0; /* consented guild id */ + uint32 consented_group_id = 0; + uint32 consented_raid_id = 0; + uint32 consented_guild_id = 0; ItemList itemlist; /* Internal Item list used for corpses */ uint32 copper; uint32 silver; @@ -168,7 +168,7 @@ private: Timer corpse_graveyard_timer; Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */ EQEmu::TintProfile item_tint; - std::vector consent_names; + std::vector consented_player_names; LootRequestType loot_request_type; }; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 899861c3d..ea4287f9d 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -4321,7 +4321,7 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c uint32 ZoneDatabase::UpdateCharacterCorpseConsent(uint32 charid, uint32 guildid) { - std::string query = StringFormat("UPDATE `character_corpses` SET `guild_consent_id` = %u WHERE `charid` = %u", guildid, charid); + std::string query = fmt::format("UPDATE `character_corpses` SET `guild_consent_id` = '{}' WHERE charid = '{}'", guildid, charid); auto results = QueryDatabase(query); return results.RowsAffected(); } From 861b879a948f281027c1b259c96982f446c19824 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Wed, 5 Feb 2020 01:34:29 -0600 Subject: [PATCH 15/26] Add GetCharacterTables() with table - key pair. Use in character hard deletes https://gist.github.com/Akkadius/f10e3757a0b52b971076643eccf9c5d0 --- common/database.cpp | 47 +++++----------------- common/database_schema.h | 85 +++++++++++++++++++++++++++++++--------- 2 files changed, 76 insertions(+), 56 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index ac5ae16bf..7e62d7935 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -45,6 +45,7 @@ #include "eq_packet_structs.h" #include "extprofile.h" #include "string_util.h" +#include "database_schema.h" extern Client client; @@ -386,46 +387,18 @@ bool Database::DeleteCharacter(char *character_name) { LogInfo("DeleteCharacter | Character [{}] ({}) is being [{}]", character_name, character_id, delete_type); - query = StringFormat("DELETE FROM `quest_globals` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_activities` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_enabledtasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `completed_tasks` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `friends` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `mail` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `timers` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `inventory` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `char_recipe_list` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `adventure_stats` WHERE `player_id` ='%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `zone_flags` WHERE `charID` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `titles` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `player_titlesets` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `keyring` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `faction_values` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `instance_list_player` WHERE `charid` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_data` WHERE `id` = '%d'", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_skills` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_languages` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_bind` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_currency` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_data` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_spells` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_memmed_spells` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_disciplines` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_material` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_tribute` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_bandolier` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_potionbelt` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_inspect_messages` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_leadership_abilities` WHERE `id` = %u", character_id); QueryDatabase(query); - query = StringFormat("DELETE FROM `character_alt_currency` WHERE `char_id` = '%d'", character_id); QueryDatabase(query); + for (const auto& iter : DatabaseSchema::GetCharacterTables()) { + std::string table_name = iter.first; + std::string character_id_column_name = iter.second; + + QueryDatabase(fmt::format("DELETE FROM {} WHERE {} = {}", table_name, character_id_column_name, character_id)); + } + #ifdef BOTS query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById() -#else - query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d'", character_id); -#endif QueryDatabase(query); +#endif + return true; } diff --git a/common/database_schema.h b/common/database_schema.h index 73637c877..b497ad474 100644 --- a/common/database_schema.h +++ b/common/database_schema.h @@ -22,17 +22,76 @@ #define EQEMU_DATABASE_SCHEMA_H #include +#include namespace DatabaseSchema { /** - * Gets player tables + * Character-specific tables + * + * Does not included related meta-data tables such as 'guilds', 'accounts' + * @return + */ + static std::map GetCharacterTables() + { + return { + {"adventure_stats", "player_id"}, + {"buyer", "charid"}, + {"char_recipe_list", "char_id"}, + {"character_activities", "charid"}, + {"character_alt_currency", "char_id"}, + {"character_alternate_abilities", "id"}, + {"character_auras", "id"}, + {"character_bandolier", "id"}, + {"character_bind", "id"}, + {"character_buffs", "character_id"}, + {"character_corpses", "id"}, + {"character_currency", "id"}, + {"character_data", "id"}, + {"character_disciplines", "id"}, + {"character_enabledtasks", "charid"}, + {"character_inspect_messages", "id"}, + {"character_item_recast", "id"}, + {"character_languages", "id"}, + {"character_leadership_abilities", "id"}, + {"character_material", "id"}, + {"character_memmed_spells", "id"}, + {"character_pet_buffs", "char_id"}, + {"character_pet_info", "char_id"}, + {"character_pet_inventory", "char_id"}, + {"character_potionbelt", "id"}, + {"character_skills", "id"}, + {"character_spells", "id"}, + {"character_tasks", "charid"}, + {"character_tribute", "id"}, + {"completed_tasks", "charid"}, + {"data_buckets", "id"}, + {"faction_values", "char_id"}, + {"friends", "charid"}, + {"guild_members", "char_id"}, + {"guilds", "id"}, + {"instance_list_player", "id"}, + {"inventory", "charid"}, + {"inventory_snapshots", "charid"}, + {"keyring", "char_id"}, + {"mail", "charid"}, + {"player_titlesets", "char_id"}, + {"quest_globals", "charid"}, + {"timers", "char_id"}, + {"titles", "char_id"}, + {"trader", "char_id"}, + {"zone_flags", "charID"} + }; + } + + /** + * Gets all player and meta-data tables * * @return */ static std::vector GetPlayerTables() { - std::vector tables = { + return { "account", "account_ip", "account_flags", @@ -91,8 +150,6 @@ namespace DatabaseSchema { "trader_audit", "zone_flags" }; - - return tables; } /** @@ -102,7 +159,7 @@ namespace DatabaseSchema { */ static std::vector GetContentTables() { - std::vector tables = { + return { "aa_ability", "aa_actions", "aa_effects", @@ -188,8 +245,6 @@ namespace DatabaseSchema { "zone_server", "zoneserver_auth", }; - - return tables; } /** @@ -199,7 +254,7 @@ namespace DatabaseSchema { */ static std::vector GetServerTables() { - std::vector tables = { + return { "banned_ips", "bugs", "bug_reports", @@ -225,8 +280,6 @@ namespace DatabaseSchema { "saylink", "variables", }; - - return tables; } /** @@ -237,7 +290,7 @@ namespace DatabaseSchema { */ static std::vector GetStateTables() { - std::vector tables = { + return { "adventure_members", "chatchannels", "group_id", @@ -253,8 +306,6 @@ namespace DatabaseSchema { "spell_buckets", "spell_globals", }; - - return tables; } /** @@ -264,15 +315,13 @@ namespace DatabaseSchema { */ static std::vector GetLoginTables() { - std::vector tables = { + return { "login_accounts", "login_api_tokens", "login_server_admins", "login_server_list_types", "login_world_servers", }; - - return tables; } /** @@ -282,12 +331,10 @@ namespace DatabaseSchema { */ static std::vector GetVersionTables() { - std::vector tables = { + return { "db_version", "inventory_versions", }; - - return tables; } } From 49134644bc067734d011c0905a41181f0b7f79c8 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Wed, 5 Feb 2020 01:56:39 -0600 Subject: [PATCH 16/26] Update dbcore logging to use aliases --- common/dbcore.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index 46c7fbe12..638fab4ae 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -115,14 +115,14 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql)); - /* Implement Logging at the Root */ + /** + * Error logging + */ if (mysql_errno(&mysql) > 0 && strlen(query) > 0) { - if (LogSys.log_settings[Logs::MySQLError].is_category_enabled == 1) - Log(Logs::General, Logs::MySQLError, "%i: %s \n %s", mysql_errno(&mysql), mysql_error(&mysql), query); + LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query); } return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer); - } // successful query. get results. @@ -143,9 +143,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) { if ((strncasecmp(query, "select", 6) == 0)) { - LogF( - Logs::General, - Logs::MySQLQuery, + LogMySQLQuery( "{0} ({1} row{2} returned) ({3}s)", query, requestResult.RowCount(), @@ -154,9 +152,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo ); } else { - LogF( - Logs::General, - Logs::MySQLQuery, + LogMySQLQuery( "{0} ({1} row{2} affected) ({3}s)", query, requestResult.RowsAffected(), From b4f42c150f2135c499fd7aaba741980e91a0f757 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 5 Feb 2020 12:31:29 -0500 Subject: [PATCH 17/26] Update database.cpp Change variable_name and use LastInsertedID() to remove unneeded call. --- common/database.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index 581f4c082..2dca2ba20 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -343,15 +343,9 @@ bool Database::ReserveName(uint32 account_id, char* name) { int guild_id = RuleI(Character, DefaultGuild); if (guild_id != 0) { - int char_id=-1; - query = StringFormat("select `id` FROM `character_data` WHERE `name` = '%s'", name); - results = QueryDatabase(query); - for (auto row = results.begin(); row != results.end(); ++row) { - char_id = atoi(row[0]); - } - - if (char_id > -1) { - query = StringFormat("INSERT INTO `guild_members` SET `char_id` = %i, `guild_id` = '%i'", char_id, guild_id); + int character_id=results.LastInsertedID(); + if (character_id > -1) { + query = StringFormat("INSERT INTO `guild_members` SET `char_id` = %i, `guild_id` = '%i'", character_id, guild_id); results = QueryDatabase(query); if (!results.Success() || results.ErrorMessage() != ""){ LogInfo("Could not put character [{}] into default Guild", name); From 4accb4ea2ab361916019c3c93cccfdf9319a96c5 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 5 Feb 2020 14:41:36 -0500 Subject: [PATCH 18/26] Update ruletypes.h --- common/ruletypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/ruletypes.h b/common/ruletypes.h index 5797d614a..28231c32e 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -494,6 +494,7 @@ RULE_INT(Combat, NPCAssistCapTimer, 6000, "Time in milliseconds a NPC will take RULE_BOOL(Combat, UseRevampHandToHand, false, "use h2h revamped dmg/delays I believe this was implemented during SoF") RULE_BOOL(Combat, ClassicMasterWu, false, "classic master wu uses a random special, modern doesn't") RULE_INT(Combat, LevelToStopDamageCaps, 0, "1 will effectively disable them, 20 should give basically same results as old incorrect system") +RULE_INT(Combat, LevelToStopACTwinkControl, 50, "1 will effectively disable it, 50 should give basically same results as current system") RULE_BOOL(Combat, ClassicNPCBackstab, false, "true disables npc facestab - npcs get normal attack if not behind") RULE_BOOL(Combat, UseNPCDamageClassLevelMods, true, "Uses GetClassLevelDamageMod calc in npc_scale_manager") RULE_BOOL(Combat, UseExtendedPoisonProcs, false, "Allow old school poisons to last until characrer zones, at a lower proc rate") From 6b27e8831557cefdd24172f5f64725cccf83135d Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 5 Feb 2020 14:42:37 -0500 Subject: [PATCH 19/26] Update attack.cpp --- zone/attack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 308592041..083176e39 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -799,7 +799,7 @@ int Mob::ACSum() // EQ math ac = (ac * 4) / 3; // anti-twink - if (IsClient() && GetLevel() < 50) + if (IsClient() && GetLevel() < RuleI(Combat, LevelToStopACTwinkControl)) ac = std::min(ac, 25 + 6 * GetLevel()); ac = std::max(0, ac + GetClassRaceACBonus()); if (IsNPC()) { From e1adffc4befb0bfb2d68ff62370f1310498119be Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 5 Feb 2020 15:32:07 -0500 Subject: [PATCH 20/26] Update npc.cpp --- zone/npc.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index ed5f37bb5..e88ce4b89 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -778,7 +778,15 @@ bool NPC::Process() } if (GetMana() < GetMaxMana()) { - SetMana(GetMana() + mana_regen + npc_sitting_regen_bonus); + int32 npc_idle_mana_regen_bonus = 2; + uint16 meditate_skill = GetSkill(EQEmu::skills::SkillMeditate); + if (!IsEngaged() && meditate_skill > 0) { + uint8 clevel = GetLevel(); + npc_idle_mana_regen_bonus = + (((meditate_skill / 10) + + (clevel - (clevel / 4))) / 4) + 4; + } + SetMana(GetMana() + mana_regen + npc_idle_mana_regen_bonus); } SendHPUpdate(); @@ -3195,4 +3203,4 @@ void NPC::AIYellForHelp(Mob *sender, Mob *attacker) } } -} \ No newline at end of file +} From e19db3b7f4af69ee3ce39a193401fcca63b72ca2 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 5 Feb 2020 16:25:24 -0500 Subject: [PATCH 21/26] Update npc.cpp --- zone/npc.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index e88ce4b89..006302126 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -778,17 +778,22 @@ bool NPC::Process() } if (GetMana() < GetMaxMana()) { - int32 npc_idle_mana_regen_bonus = 2; - uint16 meditate_skill = GetSkill(EQEmu::skills::SkillMeditate); - if (!IsEngaged() && meditate_skill > 0) { - uint8 clevel = GetLevel(); - npc_idle_mana_regen_bonus = - (((meditate_skill / 10) + - (clevel - (clevel / 4))) / 4) + 4; + if (RuleB(NPC, UseMeditateBasedManaRegen)) { + int32 npc_idle_mana_regen_bonus = 2; + uint16 meditate_skill = GetSkill(EQEmu::skills::SkillMeditate); + if (!IsEngaged() && meditate_skill > 0) { + uint8 clevel = GetLevel(); + npc_idle_mana_regen_bonus = + (((meditate_skill / 10) + + (clevel - (clevel / 4))) / 4) + 4; + } + SetMana(GetMana() + mana_regen + npc_idle_mana_regen_bonus); + } + else { + SetMana(GetMana() + mana_regen + npc_sitting_regen_bonus); } - SetMana(GetMana() + mana_regen + npc_idle_mana_regen_bonus); } - + SendHPUpdate(); if (zone->adv_data && !p_depop) { From 8dacadb4f9de2928c32b9bf882458a0d9a72d414 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 5 Feb 2020 16:26:46 -0500 Subject: [PATCH 22/26] Update ruletypes.h --- common/ruletypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/ruletypes.h b/common/ruletypes.h index 28231c32e..8e5793bc3 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -526,6 +526,7 @@ RULE_INT(NPC, NPCGatePercent, 20, "% at which the NPC Will attempt to gate at") RULE_BOOL(NPC, NPCGateNearBind, false, "Will NPC attempt to gate when near bind location?") RULE_INT(NPC, NPCGateDistanceBind, 75, "Distance from bind before NPC will attempt to gate") RULE_BOOL(NPC, NPCHealOnGate, true, "Will the NPC Heal on Gate") +RULE_BOOL(NPC, UseMeditateBasedManaRegen, false, "Based NPC ooc regen on Meditate skill") RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the npc will heal on gate if enabled") RULE_CATEGORY_END() From 1528e7cb09e8635603b4f3441334b85cf8531033 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 5 Feb 2020 16:28:07 -0500 Subject: [PATCH 23/26] Update npc.cpp --- zone/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index 006302126..96efc83a8 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -793,7 +793,7 @@ bool NPC::Process() SetMana(GetMana() + mana_regen + npc_sitting_regen_bonus); } } - + SendHPUpdate(); if (zone->adv_data && !p_depop) { From 8bcef6c2e72d8e7b25c2f8302e88029907a6515b Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 6 Feb 2020 01:08:53 -0500 Subject: [PATCH 24/26] Fix BodyType bug in GlobalLoot --- zone/loottables.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 3b5ae520f..500af9d70 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -518,7 +518,7 @@ void ZoneDatabase::LoadGlobalLoot() auto bodytypes = SplitString(row[9], '|'); for (auto &b : bodytypes) - e.AddRule(GlobalLoot::RuleTypes::Class, std::stoi(b)); + e.AddRule(GlobalLoot::RuleTypes::BodyType, std::stoi(b)); } zone->AddGlobalLootEntry(e); From 501204a4d2e843433d35956868c6b0cfb918879d Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 6 Feb 2020 01:52:35 -0500 Subject: [PATCH 25/26] Add hot_zone filtering for global loot We do this in GlobalLootEntry::PassesRules since we want to check if the hot zone status changes during run time Value can be null, if null it's not checked. If the value is 0 the zone must not be a hot zone (I guess one might want that) and if it's not 0, the zone must be a hot zone --- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + utils/sql/git/required/2020_02_06_globalloot.sql | 2 ++ zone/global_loot_manager.cpp | 9 +++++++++ zone/global_loot_manager.h | 1 + zone/loottables.cpp | 7 ++++++- 6 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 utils/sql/git/required/2020_02_06_globalloot.sql diff --git a/common/version.h b/common/version.h index ca37150ec..13579c3d2 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9148 +#define CURRENT_BINARY_DATABASE_VERSION 9149 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 8e3172b87..fdaa4a946 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -402,6 +402,7 @@ 9146|2020_01_10_character_soft_deletes.sql|SHOW COLUMNS FROM `character_data` LIKE 'deleted_at'|empty| 9147|2020_01_24_grid_centerpoint_wp.sql|SHOW COLUMNS FROM `grid_entries` LIKE 'centerpoint'|empty| 9148|2020_01_28_corpse_guild_consent_id.sql|SHOW COLUMNS FROM `character_corpses` LIKE 'guild_consent_id'|empty| +9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|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/2020_02_06_globalloot.sql b/utils/sql/git/required/2020_02_06_globalloot.sql new file mode 100644 index 000000000..83144bbb8 --- /dev/null +++ b/utils/sql/git/required/2020_02_06_globalloot.sql @@ -0,0 +1,2 @@ +ALTER TABLE `global_loot` ADD `hot_zone` TINYINT NULL; + diff --git a/zone/global_loot_manager.cpp b/zone/global_loot_manager.cpp index ccdf88840..706769f77 100644 --- a/zone/global_loot_manager.cpp +++ b/zone/global_loot_manager.cpp @@ -1,6 +1,9 @@ #include "global_loot_manager.h" #include "npc.h" #include "client.h" +#include "zone.h" + +extern Zone *zone; std::vector GlobalLootManager::GetGlobalLootTables(NPC *mob) const { @@ -78,6 +81,12 @@ bool GlobalLootEntry::PassesRules(NPC *mob) const if (mob->GetBodyType() == r.value) bPassesBodyType = true; break; + case GlobalLoot::RuleTypes::HotZone: // value == 0 must not be hot_zone, value != must be hot_zone + if (zone->IsHotzone() && !r.value) + return false; + if (!zone->IsHotzone() && r.value) + return false; + break; default: break; } diff --git a/zone/global_loot_manager.h b/zone/global_loot_manager.h index fec5a7215..1de6e7831 100644 --- a/zone/global_loot_manager.h +++ b/zone/global_loot_manager.h @@ -17,6 +17,7 @@ enum class RuleTypes { BodyType = 4, Rare = 5, Raid = 6, + HotZone = 7, Max }; diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 500af9d70..794883c1f 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -464,7 +464,7 @@ void NPC::CheckGlobalLootTables() void ZoneDatabase::LoadGlobalLoot() { auto query = StringFormat("SELECT id, loottable_id, description, min_level, max_level, rare, raid, race, " - "class, bodytype, zone FROM global_loot WHERE enabled = 1"); + "class, bodytype, zone, hot_zone FROM global_loot WHERE enabled = 1"); auto results = QueryDatabase(query); if (!results.Success() || results.RowCount() == 0) @@ -482,6 +482,7 @@ void ZoneDatabase::LoadGlobalLoot() continue; } + GlobalLootEntry e(atoi(row[0]), atoi(row[1]), row[2] ? row[2] : ""); auto min_level = atoi(row[3]); @@ -521,6 +522,10 @@ void ZoneDatabase::LoadGlobalLoot() e.AddRule(GlobalLoot::RuleTypes::BodyType, std::stoi(b)); } + // null is not used + if (row[11]) + e.AddRule(GlobalLoot::RuleTypes::HotZone, atoi(row[11])); + zone->AddGlobalLootEntry(e); } } From 16ac6f624bcec91f8e3aeb2e75c2f7a60305f5b3 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 6 Feb 2020 01:59:18 -0500 Subject: [PATCH 26/26] Remove extra whitespace --- zone/loottables.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 794883c1f..0e5ba8d60 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -482,7 +482,6 @@ void ZoneDatabase::LoadGlobalLoot() continue; } - GlobalLootEntry e(atoi(row[0]), atoi(row[1]), row[2] ? row[2] : ""); auto min_level = atoi(row[3]);