From a3eb74b855b02cb6ade8c8b3b4dc455f73f98795 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 5 Mar 2020 14:37:43 -0500 Subject: [PATCH 01/84] Fix /split while in a raid This still doesn't add support for /autosplit in a raid, how should that work? This changes the Raid::SplitMoney to take a group ID and fails when provided with RAID_GROUPLESS. This does change behavior, but I'm not sure if it was ever used so ... --- zone/client_packet.cpp | 24 ++++++++++++++++-------- zone/lua_raid.cpp | 12 ++++++------ zone/lua_raid.h | 4 ++-- zone/perl_raids.cpp | 15 ++++++++------- zone/raids.cpp | 17 +++++++++++------ zone/raids.h | 2 +- 6 files changed, 44 insertions(+), 30 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 7173dd342..1848a926c 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13327,13 +13327,17 @@ void Client::Handle_OP_Split(const EQApplicationPacket *app) Split_Struct *split = (Split_Struct *)app->pBuffer; //Per the note above, Im not exactly sure what to do on error //to notify the client of the error... - if (!isgrouped) { - Message(Chat::Red, "You can not split money if you're not in a group."); - return; - } - Group *cgroup = GetGroup(); - if (cgroup == nullptr) { - //invalid group, not sure if we should say more... + + Group *group = nullptr; + Raid *raid = nullptr; + + if (IsRaidGrouped()) + raid = GetRaid(); + else if (IsGrouped()) + group = GetGroup(); + + // is there an actual error message for this? + if (raid == nullptr && group == nullptr) { Message(Chat::Red, "You can not split money if you're not in a group."); return; } @@ -13345,7 +13349,11 @@ void Client::Handle_OP_Split(const EQApplicationPacket *app) Message(Chat::Red, "You do not have enough money to do that split."); return; } - cgroup->SplitMoney(split->copper, split->silver, split->gold, split->platinum); + + if (raid) + raid->SplitMoney(raid->GetGroup(this), split->copper, split->silver, split->gold, split->platinum); + else if (group) + group->SplitMoney(split->copper, split->silver, split->gold, split->platinum); return; diff --git a/zone/lua_raid.cpp b/zone/lua_raid.cpp index 93c1f4c28..c181b8bd2 100644 --- a/zone/lua_raid.cpp +++ b/zone/lua_raid.cpp @@ -52,14 +52,14 @@ uint32 Lua_Raid::GetTotalRaidDamage(Lua_Mob other) { return self->GetTotalRaidDamage(other); } -void Lua_Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum) { +void Lua_Raid::SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum) { Lua_Safe_Call_Void(); - self->SplitMoney(copper, silver, gold, platinum); + self->SplitMoney(gid, copper, silver, gold, platinum); } -void Lua_Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter) { +void Lua_Raid::SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter) { Lua_Safe_Call_Void(); - self->SplitMoney(copper, silver, gold, platinum, splitter); + self->SplitMoney(gid, copper, silver, gold, platinum, splitter); } void Lua_Raid::BalanceHP(int penalty, uint32 group_id) { @@ -146,8 +146,8 @@ luabind::scope lua_register_raid() { .def("GetGroup", (int(Lua_Raid::*)(Lua_Client))&Lua_Raid::GetGroup) .def("SplitExp", (void(Lua_Raid::*)(uint32,Lua_Mob))&Lua_Raid::SplitExp) .def("GetTotalRaidDamage", (uint32(Lua_Raid::*)(Lua_Mob))&Lua_Raid::GetTotalRaidDamage) - .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32))&Lua_Raid::SplitMoney) - .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32,Lua_Client))&Lua_Raid::SplitMoney) + .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32,uint32))&Lua_Raid::SplitMoney) + .def("SplitMoney", (void(Lua_Raid::*)(uint32,uint32,uint32,uint32,uint32,Lua_Client))&Lua_Raid::SplitMoney) .def("BalanceHP", (void(Lua_Raid::*)(int,uint32))&Lua_Raid::BalanceHP) .def("IsLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsLeader) .def("IsGroupLeader", (bool(Lua_Raid::*)(const char*))&Lua_Raid::IsGroupLeader) diff --git a/zone/lua_raid.h b/zone/lua_raid.h index 626b98bb2..bc10a729c 100644 --- a/zone/lua_raid.h +++ b/zone/lua_raid.h @@ -34,8 +34,8 @@ public: int GetGroup(Lua_Client c); void SplitExp(uint32 exp, Lua_Mob other); uint32 GetTotalRaidDamage(Lua_Mob other); - void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum); - void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter); + void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum); + void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Lua_Client splitter); void BalanceHP(int penalty, uint32 group_id); bool IsLeader(const char *c); bool IsLeader(Lua_Client c); diff --git a/zone/perl_raids.cpp b/zone/perl_raids.cpp index 72672de4e..670d445e5 100644 --- a/zone/perl_raids.cpp +++ b/zone/perl_raids.cpp @@ -247,13 +247,14 @@ XS(XS_Raid_SplitMoney); /* prototype to pass -Wmissing-prototypes */ XS(XS_Raid_SplitMoney) { dXSARGS; if (items != 5) - Perl_croak(aTHX_ "Usage: Raid::SplitMoney(THIS, uint32 copper, uint32 silver, uint32 gold, uint32 platinum)"); + Perl_croak(aTHX_ "Usage: Raid::SplitMoney(THIS, uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum)"); { Raid *THIS; - uint32 copper = (uint32) SvUV(ST(1)); - uint32 silver = (uint32) SvUV(ST(2)); - uint32 gold = (uint32) SvUV(ST(3)); - uint32 platinum = (uint32) SvUV(ST(4)); + uint32 gid = (uint32) SvUV(ST(1)); + uint32 copper = (uint32) SvUV(ST(2)); + uint32 silver = (uint32) SvUV(ST(3)); + uint32 gold = (uint32) SvUV(ST(4)); + uint32 platinum = (uint32) SvUV(ST(5)); if (sv_derived_from(ST(0), "Raid")) { IV tmp = SvIV((SV *) SvRV(ST(0))); @@ -263,7 +264,7 @@ XS(XS_Raid_SplitMoney) { if (THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->SplitMoney(copper, silver, gold, platinum); + THIS->SplitMoney(gid, copper, silver, gold, platinum); } XSRETURN_EMPTY; } @@ -569,7 +570,7 @@ XS(boot_Raid) { newXSproto(strcpy(buf, "GetGroup"), XS_Raid_GetGroup, file, "$$"); newXSproto(strcpy(buf, "SplitExp"), XS_Raid_SplitExp, file, "$$$"); newXSproto(strcpy(buf, "GetTotalRaidDamage"), XS_Raid_GetTotalRaidDamage, file, "$$"); - newXSproto(strcpy(buf, "SplitMoney"), XS_Raid_SplitMoney, file, "$$$$$"); + newXSproto(strcpy(buf, "SplitMoney"), XS_Raid_SplitMoney, file, "$$$$$$"); newXSproto(strcpy(buf, "BalanceHP"), XS_Raid_BalanceHP, file, "$$$"); newXSproto(strcpy(buf, "IsLeader"), XS_Raid_IsLeader, file, "$$"); newXSproto(strcpy(buf, "IsGroupLeader"), XS_Raid_IsGroupLeader, file, "$$"); diff --git a/zone/raids.cpp b/zone/raids.cpp index 7a153864d..a4e1535d3 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -728,15 +728,20 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, float range, Mob* caster, int3 } //basically the same as Group's version just with more people like a lot of non group specific raid stuff -void Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter){ +//this only functions if the member has a group in the raid. This does not support /autosplit? +void Raid::SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter) +{ //avoid unneeded work + if (gid == RAID_GROUPLESS) + return; + if(copper == 0 && silver == 0 && gold == 0 && platinum == 0) return; uint32 i; uint8 membercount = 0; for (i = 0; i < MAX_RAID_MEMBERS; i++) { - if (members[i].member != nullptr) { + if (members[i].member != nullptr && members[i].GroupNumber == gid) { membercount++; } } @@ -809,11 +814,11 @@ void Raid::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum msg += " as your split"; for (i = 0; i < MAX_RAID_MEMBERS; i++) { - if (members[i].member != nullptr) { // If Group Member is Client - //I could not get MoneyOnCorpse to work, so we use this - members[i].member->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true); + if (members[i].member != nullptr && members[i].GroupNumber == gid) { // If Group Member is Client + //I could not get MoneyOnCorpse to work, so we use this + members[i].member->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true); - members[i].member->Message(Chat::Green, msg.c_str()); + members[i].member->Message(Chat::Green, msg.c_str()); } } } diff --git a/zone/raids.h b/zone/raids.h index 260ae6c71..26ba90a02 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -159,7 +159,7 @@ public: void BalanceHP(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0); void BalanceMana(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0); void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range = 0); - void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); + void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid); void TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid); From 581d5b1289962960946a62caae4759325ac85d8e Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 7 Mar 2020 18:58:12 -0500 Subject: [PATCH 02/84] Deleted characters will no longer show in the guild window. --- common/guild_base.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/guild_base.cpp b/common/guild_base.cpp index 642db7cbc..b7ac8515c 100644 --- a/common/guild_base.cpp +++ b/common/guild_base.cpp @@ -912,7 +912,7 @@ bool BaseGuildManager::GetEntireGuild(uint32 guild_id, std::vectorQueryDatabase(query); if (!results.Success()) { return false; @@ -941,7 +941,7 @@ bool BaseGuildManager::GetCharInfo(const char *char_name, CharGuildInfo &into) { m_db->DoEscapeString(esc, char_name, nl); //load up the rank info for each guild. - std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.name='%s'", esc); + std::string query = StringFormat(GuildMemberBaseQuery " WHERE c.name='%s' AND c.deleted_at IS NULL", esc); safe_delete_array(esc); auto results = m_db->QueryDatabase(query); if (!results.Success()) { @@ -969,9 +969,9 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) { //load up the rank info for each guild. std::string query; #ifdef BOTS - query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C'", char_id); + query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C' AND c.deleted_at IS NULL", char_id); #else - query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d", char_id); + query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.deleted_at IS NULL", char_id); #endif auto results = m_db->QueryDatabase(query); if (!results.Success()) { From 2a9248697ef1eeefcc7b1647d2c51612e1fa7a8d Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 8 Mar 2020 10:38:28 -0400 Subject: [PATCH 03/84] Add GetGroupIDByCharID and GetGuildIDByCharID to Perl/Lua. --- common/database.cpp | 22 ++++++++++++++++++++++ common/database.h | 1 + zone/embparser_api.cpp | 37 +++++++++++++++++++++++++++++++++++++ zone/lua_general.cpp | 10 ++++++++++ zone/questmgr.cpp | 14 ++++++++++++++ zone/questmgr.h | 2 ++ 6 files changed, 86 insertions(+) diff --git a/common/database.cpp b/common/database.cpp index 352ecbbc1..9c846b260 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2158,6 +2158,28 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id) return atoi(row[0]); } +uint32 Database::GetGroupIDByCharID(uint32 character_id) +{ + std::string query = fmt::format( + SQL( + SELECT groupid + FROM group_id + WHERE charid = '{}' + ), + character_id + ); + auto results = QueryDatabase(query); + + if (!results.Success()) + return 0; + + if (results.RowCount() == 0) + return 0; + + auto row = results.begin(); + return atoi(row[0]); +} + /** * @param log_settings */ diff --git a/common/database.h b/common/database.h index f569da20b..4b9391d31 100644 --- a/common/database.h +++ b/common/database.h @@ -133,6 +133,7 @@ public: uint32 GetCharacterID(const char *name); uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0); uint32 GetGuildIDByCharID(uint32 char_id); + uint32 GetGroupIDByCharID(uint32 char_id); void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0); void GetCharName(uint32 char_id, char* name); diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 871cc0ced..8a68b0fe3 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3169,6 +3169,41 @@ XS(XS__getguildnamebyid) { XSRETURN(1); } +XS(XS__getguildidbycharid); +XS(XS__getguildidbycharid) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getguildidbycharid(uint32 char_id)"); + dXSTARG; + + int RETVAL; + uint32 char_id = (int) SvUV(ST(0)); + + RETVAL = quest_manager.getguildidbycharid(char_id); + + XSprePUSH; + PUSHi((IV)RETVAL); + + XSRETURN(1); +} + +XS(XS__getgroupidbycharid); +XS(XS__getgroupidbycharid) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getgroupidbycharid(uint32 char_id)"); + dXSTARG; + + int RETVAL; + uint32 char_id = (int) SvUV(ST(0)); + + RETVAL = quest_manager.getgroupidbycharid(char_id); + XSprePUSH; + PUSHi((IV)RETVAL); + + XSRETURN(1); +} + XS(XS__SetRunning); XS(XS__SetRunning) { dXSARGS; @@ -3942,6 +3977,8 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file); newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); + newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file); + newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 0d1086ad1..cc60664b5 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -858,6 +858,14 @@ const char *lua_get_guild_name_by_id(uint32 guild_id) { return quest_manager.getguildnamebyid(guild_id); } +int lua_get_guild_id_by_char_id(uint32 char_id) { + return database.GetGuildIDByCharID(char_id); +} + +int lua_get_group_id_by_char_id(uint32 char_id) { + return database.GetGroupIDByCharID(char_id); +} + uint32 lua_create_instance(const char *zone, uint32 version, uint32 duration) { return quest_manager.CreateInstance(zone, version, duration); } @@ -1728,6 +1736,8 @@ luabind::scope lua_register_general() { luabind::def("set_data", (void(*)(std::string, std::string, std::string))&lua_set_data), luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), + luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), + luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), luabind::def("create_instance", &lua_create_instance), luabind::def("destroy_instance", &lua_destroy_instance), luabind::def("update_instance_timer", &lua_update_instance_timer), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index bea136e28..4b2eb432f 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2876,6 +2876,20 @@ const char* QuestManager::getguildnamebyid(int guild_id) { return(""); } +int QuestManager::getguildidbycharid(uint32 char_id) { + if (char_id > 0) { + return database.GetGuildIDByCharID(char_id); + } + return 0; +} + +int QuestManager::getgroupidbycharid(uint32 char_id) { + if (char_id > 0) { + return database.GetGroupIDByCharID(char_id); + } + return 0; +} + void QuestManager::SetRunning(bool val) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index 5ad551c43..53b425bd0 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -251,6 +251,8 @@ public: const char* varlink(char* perltext, int item_id); std::string saylink(char *saylink_text, bool silent, const char *link_name); const char* getguildnamebyid(int guild_id); + int getguildidbycharid(uint32 char_id); + int getgroupidbycharid(uint32 char_id); void SetRunning(bool val); bool IsRunning(); void FlyMode(GravityBehavior flymode); From cede38f5624a8409f4382af8027b8f34b179f1c4 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 8 Mar 2020 21:11:56 -0400 Subject: [PATCH 04/84] Add GetRaidIDByCharID to Perl/Lua. --- common/database.cpp | 16 ++++++++++++++++ common/database.h | 1 + zone/embparser_api.cpp | 18 ++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 7 +++++++ zone/questmgr.h | 1 + 6 files changed, 48 insertions(+) diff --git a/common/database.cpp b/common/database.cpp index 9c846b260..3f64a21f9 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2180,6 +2180,22 @@ uint32 Database::GetGroupIDByCharID(uint32 character_id) return atoi(row[0]); } +uint32 Database::GetRaidIDByCharID(uint32 character_id) { + std::string query = fmt::format( + SQL( + SELECT raidid + FROM raid_members + WHERE charid = '{}' + ), + character_id + ); + auto results = QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + return atoi(row[0]); + } + return 0; +} + /** * @param log_settings */ diff --git a/common/database.h b/common/database.h index 4b9391d31..95458c1c1 100644 --- a/common/database.h +++ b/common/database.h @@ -134,6 +134,7 @@ public: uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0); uint32 GetGuildIDByCharID(uint32 char_id); uint32 GetGroupIDByCharID(uint32 char_id); + uint32 GetRaidIDByCharID(uint32 char_id); void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0); void GetCharName(uint32 char_id, char* name); diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 8a68b0fe3..efdc09803 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3204,6 +3204,23 @@ XS(XS__getgroupidbycharid) { XSRETURN(1); } +XS(XS__getraididbycharid); +XS(XS__getraididbycharid) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getraididbycharid(uint32 char_id)"); + dXSTARG; + + int RETVAL; + uint32 char_id = (int) SvUV(ST(0)); + + RETVAL = quest_manager.getraididbycharid(char_id); + XSprePUSH; + PUSHi((IV)RETVAL); + + XSRETURN(1); +} + XS(XS__SetRunning); XS(XS__SetRunning) { dXSARGS; @@ -3979,6 +3996,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file); newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file); + newXS(strcpy(buf, "getraididbycharid"), XS__getraididbycharid, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index cc60664b5..69e262199 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -866,6 +866,10 @@ int lua_get_group_id_by_char_id(uint32 char_id) { return database.GetGroupIDByCharID(char_id); } +int lua_get_raid_id_by_char_id(uint32 char_id) { + return database.GetRaidIDByCharID(char_id); +} + uint32 lua_create_instance(const char *zone, uint32 version, uint32 duration) { return quest_manager.CreateInstance(zone, version, duration); } @@ -1738,6 +1742,7 @@ luabind::scope lua_register_general() { luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), + luabind::def("get_raid_id_by_char_id", &lua_get_raid_id_by_char_id), luabind::def("create_instance", &lua_create_instance), luabind::def("destroy_instance", &lua_destroy_instance), luabind::def("update_instance_timer", &lua_update_instance_timer), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 4b2eb432f..033b42f1a 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2890,6 +2890,13 @@ int QuestManager::getgroupidbycharid(uint32 char_id) { return 0; } +int QuestManager::getraididbycharid(uint32 char_id) { + if (char_id > 0) { + return database.GetRaidIDByCharID(char_id); + } + return 0; +} + void QuestManager::SetRunning(bool val) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index 53b425bd0..2aa1df109 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -253,6 +253,7 @@ public: const char* getguildnamebyid(int guild_id); int getguildidbycharid(uint32 char_id); int getgroupidbycharid(uint32 char_id); + int getraididbycharid(uint32 char_id); void SetRunning(bool val); bool IsRunning(); void FlyMode(GravityBehavior flymode); From 8d252dfd9aac41699177b776e7f1636ec43b867f Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Mon, 9 Mar 2020 03:00:07 -0500 Subject: [PATCH 05/84] Implement database dump service --- common/CMakeLists.txt | 4 + common/cli/eqemu_command_handler.cpp | 2 +- common/database/database_dump_service.h | 77 ++++++++++++++++ common/file_util.cpp | 67 ++++++++++++++ common/file_util.h | 32 +++++++ utils/sql/character_table_list.txt | 57 ------------ utils/sql/data_tables.txt | 6 -- utils/sql/system_tables.txt | 113 ------------------------ utils/sql/user_tables.txt | 94 -------------------- world/world_server_command_handler.cpp | 62 ++++++++++++- world/world_server_command_handler.h | 1 + 11 files changed, 243 insertions(+), 272 deletions(-) create mode 100644 common/database/database_dump_service.h create mode 100644 common/file_util.cpp create mode 100644 common/file_util.h delete mode 100644 utils/sql/character_table_list.txt delete mode 100644 utils/sql/data_tables.txt delete mode 100644 utils/sql/system_tables.txt delete mode 100644 utils/sql/user_tables.txt diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index a959d9093..e312c202d 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -9,6 +9,7 @@ SET(common_sources crash.cpp crc16.cpp crc32.cpp + database/database_dump_service.cpp database.cpp database_conversions.cpp database_instances.cpp @@ -31,6 +32,7 @@ SET(common_sources event_sub.cpp extprofile.cpp faction.cpp + file_util.cpp guild_base.cpp guilds.cpp inventory_profile.cpp @@ -120,6 +122,7 @@ SET(common_headers cli/argh.h cli/eqemu_command_handler.h cli/terminal_color.hpp + database/database_dump_service.h data_verification.h database.h database_schema.h @@ -150,6 +153,7 @@ SET(common_headers event_sub.h extprofile.h faction.h + file_util.h features.h fixed_memory_hash_set.h fixed_memory_variable_hash_set.h diff --git a/common/cli/eqemu_command_handler.cpp b/common/cli/eqemu_command_handler.cpp index bbcdb4612..96ed5a155 100644 --- a/common/cli/eqemu_command_handler.cpp +++ b/common/cli/eqemu_command_handler.cpp @@ -96,7 +96,7 @@ namespace EQEmuCommand { "\nCommand" << termcolor::reset << "\n\n" << termcolor::green << argv[1] << arguments_string << termcolor::reset << "\n" << - termcolor::yellow << (!options_string.empty() ? "\nOptions\n" : "") << + termcolor::yellow << (!options_string.empty() ? "\nOptions\n\n" : "") << termcolor::reset << termcolor::cyan << options_string << termcolor::reset; std::cout << command_string.str() << std::endl; diff --git a/common/database/database_dump_service.h b/common/database/database_dump_service.h new file mode 100644 index 000000000..096d4c5d3 --- /dev/null +++ b/common/database/database_dump_service.h @@ -0,0 +1,77 @@ +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +*/ + +#ifndef EQEMU_DATABASE_DUMP_SERVICE_H +#define EQEMU_DATABASE_DUMP_SERVICE_H + + +class DatabaseDumpService { +public: + void Dump(); + bool IsDumpAllTables() const; + void SetDumpAllTables(bool dump_all_tables); + bool IsDumpWithNoData() const; + void SetDumpWithNoData(bool dump_with_no_data); + bool IsDumpSystemTables() const; + void SetDumpSystemTables(bool dump_system_tables); + bool IsDumpContentTables() const; + void SetDumpContentTables(bool dump_content_tables); + bool IsDumpPlayerTables() const; + void SetDumpPlayerTables(bool dump_player_tables); + bool IsDumpLoginServerTables() const; + void SetDumpLoginServerTables(bool dump_login_server_tables); + bool IsDumpNoTableLock() const; + void SetDumpNoTableLock(bool dump_no_table_lock); + bool IsDumpWithCompression() const; + void SetDumpWithCompression(bool dump_with_compression); + const std::string &GetDumpPath() const; + void SetDumpPath(const std::string &dump_path); + const std::string &GetDumpFileName() const; + void SetDumpFileName(const std::string &dump_file_name); + +private: + bool dump_all_tables; + bool dump_system_tables; + bool dump_content_tables; + bool dump_player_tables; + bool dump_login_server_tables; + bool dump_with_no_data; + bool dump_no_table_lock; + bool dump_with_compression; + std::string dump_path; + std::string dump_file_name; + + std::string execute(const std::string &cmd, bool return_result); + bool IsMySQLInstalled(); + std::string GetMySQLVersion(); + std::string GetBaseMySQLDumpCommand(); + std::string GetPlayerTablesList(); + std::string GetSystemTablesList(); + std::string GetContentTablesList(); + std::string GetLoginTableList(); + bool IsTarAvailable(); + bool IsRarAvailable(); + bool HasCompressionBinary(); + std::string GetDumpFileNameWithPath(); + std::string GetSetDumpPath(); +}; + + +#endif //EQEMU_DATABASE_DUMP_SERVICE_H diff --git a/common/file_util.cpp b/common/file_util.cpp new file mode 100644 index 000000000..8c9aca9a4 --- /dev/null +++ b/common/file_util.cpp @@ -0,0 +1,67 @@ +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +*/ + +#include +#include "file_util.h" + +#ifdef _WINDOWS +#include +#include +#include +#include +#include +#include +#else + +#include +#include + +#endif + +/** + * @param name + * @return + */ +bool FileUtil::exists(const std::string &name) +{ + std::ifstream f(name.c_str()); + + return f.good(); +} + +/** + * @param directory_name + */ +void FileUtil::mkdir(const std::string& directory_name) +{ + +#ifdef _WINDOWS + struct _stat st; + if (_stat(directory_name.c_str(), &st) == 0) // exists + return; + _mkdir(directory_name.c_str()); +#else + struct stat st{}; + if (stat(directory_name.c_str(), &st) == 0) { // exists + return; + } + ::mkdir(directory_name.c_str(), 0755); +#endif +} \ No newline at end of file diff --git a/common/file_util.h b/common/file_util.h new file mode 100644 index 000000000..05869d303 --- /dev/null +++ b/common/file_util.h @@ -0,0 +1,32 @@ +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +*/ + +#ifndef EQEMU_FILE_UTIL_H +#define EQEMU_FILE_UTIL_H + + +class FileUtil { +public: + static bool exists(const std::string &name); + static void mkdir(const std::string& directory_name); +}; + + +#endif //EQEMU_FILE_UTIL_H diff --git a/utils/sql/character_table_list.txt b/utils/sql/character_table_list.txt deleted file mode 100644 index ab6610dab..000000000 --- a/utils/sql/character_table_list.txt +++ /dev/null @@ -1,57 +0,0 @@ -account -account_ip -account_flags -account_rewards -adventure_details -adventure_stats -buyer -char_recipe_list -character_activities -character_alt_currency -character_alternate_abilities -character_auras -character_bandolier -character_bind -character_buffs -character_corpse_items -character_corpses -character_currency -character_data -character_disciplines -character_enabledtasks -character_inspect_messages -character_item_recast -character_languages -character_leadership_abilities -character_material -character_memmed_spells -character_pet_buffs -character_pet_info -character_pet_inventory -character_potionbelt -character_skills -character_spells -character_tasks -character_tribute -completed_tasks -data_buckets -faction_values -friends -guild_bank -guild_members -guild_ranks -guild_relations -guilds -instance_list_player -inventory -inventory_snapshots -keyring -mail -player_titlesets -quest_globals -sharedbank -timers -titles -trader -trader_audit -zone_flags" \ No newline at end of file diff --git a/utils/sql/data_tables.txt b/utils/sql/data_tables.txt deleted file mode 100644 index 8738c716b..000000000 --- a/utils/sql/data_tables.txt +++ /dev/null @@ -1,6 +0,0 @@ -command_settings -inventory_versions -launcher -rule_sets -rule_values -variables \ No newline at end of file diff --git a/utils/sql/system_tables.txt b/utils/sql/system_tables.txt deleted file mode 100644 index a33605130..000000000 --- a/utils/sql/system_tables.txt +++ /dev/null @@ -1,113 +0,0 @@ -aa_ability -aa_actions -aa_effects -aa_rank_effects -aa_rank_prereqs -aa_ranks -aa_required_level_cost -adventure_template -adventure_template_entry -adventure_template_entry_flavor -altadv_vars -alternate_currency -auras -base_data -blocked_spells -books -bug_reports -char_create_combinations -char_create_point_allocations -class_skill -damageshieldtypes -data_buckets -db_str -doors -eqtime -faction_base_data -faction_list -faction_list_mod -fear_hints -fishing -forage -global_loot -goallists -graveyard -grid -grid_entries -ground_spawns -horses -instance_list -items -ip_exemptions -ldon_trap_entries -ldon_trap_templates -level_exp_mods -logsys_categories -lootdrop -lootdrop_entries -loottable -loottable_entries -merc_armorinfo -merc_buffs -merc_inventory -merc_merchant_entries -merc_merchant_template_entries -merc_merchant_templates -merc_name_types -merc_npc_types -merc_spell_list_entries -merc_spell_lists -merc_stance_entries -merc_stats -merc_subtypes -merc_templates -merc_types -merc_weaponinfo -merchantlist -mercs -name_filter -npc_emotes -npc_faction -npc_faction_entries -npc_scale_global_base -npc_spells -npc_spells_effects -npc_spells_effects_entries -npc_spells_entries -npc_types -npc_types_metadata -npc_types_tint -object -perl_event_export_settings -pets -pets_equipmentset -pets_equipmentset_entries -profanity_list -proximities -races -saylink -skill_caps -spawn2 -spawn_condition_values -spawn_conditions -spawn_events -spawnentry -spawngroup -spells_new -start_zones -starting_items -task_activities -tasks -tasksets -titles -tradeskill_recipe -tradeskill_recipe_entries -traps -tribute_levels -tributes -veteran_reward_templates -zone -zone_points -zone_server -zone_state_dump -zoneserver_auth diff --git a/utils/sql/user_tables.txt b/utils/sql/user_tables.txt deleted file mode 100644 index ee19fe472..000000000 --- a/utils/sql/user_tables.txt +++ /dev/null @@ -1,94 +0,0 @@ -aa_timers -account -account_flags -account_ip -account_rewards -adventure_details -adventure_members -adventure_stats -banned_ips -bugs -buyer -char_recipe_list -character_activities -character_alt_currency -character_alternate_abilities -character_auras -character_bandolier -character_bind -character_buffs -character_corpse_items -character_corpses -character_currency -character_data -character_disciplines -character_enabledtasks -character_inspect_messages -character_item_recast -character_languages -character_leadership_abilities -character_material -character_memmed_spells -character_pet_buffs -character_pet_info -character_pet_inventory -character_potionbelt -character_skills -character_spells -character_tasks -character_tribute -chatchannels -completed_tasks -discovered_items -eventlog -faction_values -friends -gm_ips -group_id -group_leaders -guild_bank -guild_members -guild_ranks -guild_relations -guilds -hackers -instance_list_player -inventory -inventory_snapshots -item_tick -keyring -launcher_zones -lfguild -mail -merchantlist_temp -object_contents -petitions -player_titlesets -qs_merchant_transaction_record -qs_merchant_transaction_record_entries -qs_player_aa_rate_hourly -qs_player_delete_record -qs_player_delete_record_entries -qs_player_events -qs_player_handin_record -qs_player_handin_record_entries -qs_player_move_record -qs_player_move_record_entries -qs_player_npc_kill_record -qs_player_npc_kill_record_entries -qs_player_speech -qs_player_trade_record -qs_player_trade_record_entries -quest_globals -raid_details -raid_leaders -raid_members -reports -respawn_times -sharedbank -spell_buckets -spell_globals -timers -trader -trader_audit -zone_flags diff --git a/world/world_server_command_handler.cpp b/world/world_server_command_handler.cpp index 3a929d89f..565277f97 100644 --- a/world/world_server_command_handler.cpp +++ b/world/world_server_command_handler.cpp @@ -24,6 +24,7 @@ #include "../common/version.h" #include "worlddb.h" #include "../common/database_schema.h" +#include "../common/database/database_dump_service.h" namespace WorldserverCommandHandler { @@ -51,6 +52,7 @@ namespace WorldserverCommandHandler { function_map["database:version"] = &WorldserverCommandHandler::DatabaseVersion; function_map["database:set-account-status"] = &WorldserverCommandHandler::DatabaseSetAccountStatus; function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema; + function_map["database:dump"] = &WorldserverCommandHandler::DatabaseDump; EQEmuCommand::HandleMenu(function_map, cmd, argc, argv); } @@ -145,7 +147,7 @@ namespace WorldserverCommandHandler { */ void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description) { - description = "Displays server database schema"; + description = "Displays server database schema"; if (cmd[{"-h", "--help"}]) { return; @@ -202,4 +204,62 @@ namespace WorldserverCommandHandler { std::cout << payload.str() << std::endl; } + /** + * @param argc + * @param argv + * @param cmd + * @param description + */ + void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description) + { + description = "Dumps server database tables"; + + if (cmd[{"-h", "--help"}]) { + return; + } + + std::vector arguments = {}; + std::vector options = { + "--all", + "--content-tables", + "--login-tables", + "--player-tables", + "--system-tables", + "--table-structure-only", + "--no-table-lock", + "--dump-path=", + "--compress" + }; + + + if (argc < 3) { + EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv); + return; + } + + auto database_dump_service = new DatabaseDumpService(); + bool dump_all = cmd[{"-a", "--all"}]; + + if (!cmd("--dump-path").str().empty()) { + database_dump_service->SetDumpPath(cmd("--dump-path").str()); + } + + /** + * Set Option + */ + database_dump_service->SetDumpContentTables(cmd[{"-c", "--content-tables"}] || dump_all); + database_dump_service->SetDumpLoginServerTables(cmd[{"-c", "--login-tables"}] || dump_all); + database_dump_service->SetDumpPlayerTables(cmd[{"-c", "--player-tables"}] || dump_all); + database_dump_service->SetDumpSystemTables(cmd[{"-c", "--system-tables"}] || dump_all); + database_dump_service->SetDumpWithNoData(cmd[{"-c", "--table-structure-only"}]); + database_dump_service->SetDumpAllTables(dump_all); + database_dump_service->SetDumpNoTableLock(cmd[{"--no-table-lock"}]); + database_dump_service->SetDumpWithCompression(cmd[{"--compress"}]); + + /** + * Dump + */ + database_dump_service->Dump(); + } + } \ No newline at end of file diff --git a/world/world_server_command_handler.h b/world/world_server_command_handler.h index f3d4317f2..a32a78f0f 100644 --- a/world/world_server_command_handler.h +++ b/world/world_server_command_handler.h @@ -30,6 +30,7 @@ namespace WorldserverCommandHandler { void DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description); void DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description); void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description); + void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description); }; From d4a1ea82dce70d3006c7c25c41d3001ffb0a263c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 03:01:59 -0500 Subject: [PATCH 06/84] Create database_dump_service.cpp --- common/database/database_dump_service.cpp | 434 ++++++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 common/database/database_dump_service.cpp diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp new file mode 100644 index 000000000..68608bd67 --- /dev/null +++ b/common/database/database_dump_service.cpp @@ -0,0 +1,434 @@ +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +*/ + +#include +#include +#include +#include "database_dump_service.h" +#include "../eqemu_logsys.h" +#include "../string_util.h" +#include "../eqemu_config.h" +#include "../database_schema.h" +#include "../file_util.h" + +#define DATABASE_DUMP_PATH "backups/" + +/** + * @param cmd + * @param return_result + * @return + */ +std::string DatabaseDumpService::execute(const std::string &cmd, bool return_result = true) +{ + const char *file_name = "db-exec-result.txt"; + + if (return_result) { + std::system((cmd + " > " + file_name).c_str()); + } + else { + std::system((cmd).c_str()); + } + + std::string result; + + if (return_result) { + std::ifstream file(file_name); + result = {std::istreambuf_iterator(file), std::istreambuf_iterator()}; + std::remove(file_name); + + } + + return result; +} + +/** + * @return bool + */ +bool DatabaseDumpService::IsMySQLInstalled() +{ + std::string version_output = GetMySQLVersion(); + + return version_output.find("mysql") != std::string::npos && version_output.find("Ver") != std::string::npos; +} + +/** + * Linux + * @return bool + */ +bool DatabaseDumpService::IsTarAvailable() +{ + std::string version_output = execute("tar --version"); + + return version_output.find("GNU tar") != std::string::npos; +} + +/** + * Windows TODO + * @return bool + */ +bool DatabaseDumpService::IsRarAvailable() +{ + std::string version_output = execute("winrar --version"); + + return version_output.find("todo") != std::string::npos; +} + +/** + * @return + */ +bool DatabaseDumpService::HasCompressionBinary() +{ + return IsTarAvailable() || IsRarAvailable(); +} + +/** + * @return + */ +std::string DatabaseDumpService::GetMySQLVersion() +{ + std::string version_output = execute("mysql --version"); + + return trim(version_output); +} + +/** + * @return + */ +std::string DatabaseDumpService::GetBaseMySQLDumpCommand() +{ + auto config = EQEmuConfig::get(); + + return fmt::format( + "mysqldump -u {} -p{} -h {} {}", + config->DatabaseUsername, + config->DatabasePassword, + config->DatabaseHost, + config->DatabaseDB + ); +} + +/** + * @return + */ +std::string DatabaseDumpService::GetPlayerTablesList() +{ + std::string tables_list; + std::vector tables = DatabaseSchema::GetPlayerTables(); + for (const auto &table : tables) { + tables_list += table + " "; + } + + return trim(tables_list); +} + +/** + * @return + */ +std::string DatabaseDumpService::GetLoginTableList() +{ + std::string tables_list; + std::vector tables = DatabaseSchema::GetLoginTables(); + for (const auto &table : tables) { + tables_list += table + " "; + } + + return trim(tables_list); +} + +/** + * @return + */ +std::string DatabaseDumpService::GetSystemTablesList() +{ + std::string tables_list; + + std::vector tables = DatabaseSchema::GetServerTables(); + for (const auto &table : tables) { + tables_list += table + " "; + } + + tables = DatabaseSchema::GetStateTables(); + for (const auto &table : tables) { + tables_list += table + " "; + } + + tables = DatabaseSchema::GetVersionTables(); + for (const auto &table : tables) { + tables_list += table + " "; + } + + return trim(tables_list); +} + +/** + * @return + */ +std::string DatabaseDumpService::GetContentTablesList() +{ + std::string tables_list; + + std::vector tables = DatabaseSchema::GetContentTables(); + for (const auto &table : tables) { + tables_list += table + " "; + } + + return trim(tables_list); +} + +/** + * @return + */ +std::string GetDumpDate() +{ + + time_t now = time(nullptr); + struct tm time_struct{}; + char buf[80]; + time_struct = *localtime(&now); + strftime(buf, sizeof(buf), "%Y-%m-%d", &time_struct); + + std::string time = buf; + + return time; +} + +/** + * @return + */ +std::string DatabaseDumpService::GetSetDumpPath() +{ + return !GetDumpPath().empty() ? GetDumpPath() : DATABASE_DUMP_PATH; +} +/** + * @return + */ +std::string DatabaseDumpService::GetDumpFileNameWithPath() +{ + return GetSetDumpPath() + GetDumpFileName(); +} + +void DatabaseDumpService::Dump() +{ + if (!IsMySQLInstalled()) { + LogError("MySQL is not installed; Please check your PATH for a valid MySQL installation"); + return; + } + + LogInfo("MySQL installed [{}]", GetMySQLVersion()); + + SetDumpFileName(EQEmuConfig::get()->DatabaseDB + '-' + GetDumpDate()); + + auto config = EQEmuConfig::get(); + + LogInfo( + "Database [{}] Host [{}] Username [{}]", + config->DatabaseDB, + config->DatabaseHost, + config->DatabaseUsername + ); + + std::string options = "--compact --allow-keywords --extended-insert"; + + if (IsDumpWithNoData()) { + options += " --no-data"; + } + + if (IsDumpNoTableLock()) { + options += " --skip-lock-tables"; + } + + std::string tables_to_dump; + std::string dump_descriptor; + + if (!IsDumpAllTables()) { + if (IsDumpPlayerTables()) { + tables_to_dump += GetPlayerTablesList(); + dump_descriptor += "-player"; + } + + if (IsDumpSystemTables()) { + tables_to_dump += GetSystemTablesList(); + dump_descriptor += "-system"; + } + + if (IsDumpContentTables()) { + tables_to_dump += GetContentTablesList(); + dump_descriptor += "-content"; + } + + if (IsDumpLoginServerTables()) { + tables_to_dump += GetLoginTableList(); + dump_descriptor += "-login"; + } + } + + if (!dump_descriptor.empty()) { + SetDumpFileName(GetDumpFileName() + dump_descriptor); + } + + std::string execute_command = fmt::format( + "{} {} {} > {}.sql", + GetBaseMySQLDumpCommand(), + options, + tables_to_dump, + GetDumpFileNameWithPath() + ); + + if (!FileUtil::exists(GetSetDumpPath())) { + FileUtil::mkdir(GetSetDumpPath()); + } + + execute(execute_command, false); + + if (!tables_to_dump.empty()) { + LogInfo("Dumping Tables [{}]", tables_to_dump); + } + + LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath()); + + if (IsDumpWithCompression()) { + if (HasCompressionBinary()) { + LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath()); + + if (IsTarAvailable()) { + execute( + fmt::format( + "tar -zcvf {}.tar.gz -C {} {}.sql", + GetDumpFileNameWithPath(), + GetSetDumpPath(), + GetDumpFileName() + ) + ); + LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath()); + } + } + else { + LogWarning("Compression requested but binary not found... Skipping..."); + } + } + +// LogDebug("[{}] dump-path", GetSetDumpPath()); +// LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false")); +// LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false")); +// LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false")); +// LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false")); +// LogDebug("[{}] login", (IsDumpLoginServerTables() ? "true" : "false")); +// LogDebug("[{}] player", (IsDumpPlayerTables() ? "true" : "false")); +// LogDebug("[{}] system", (IsDumpSystemTables() ? "true" : "false")); +} + +bool DatabaseDumpService::IsDumpSystemTables() const +{ + return dump_system_tables; +} + +void DatabaseDumpService::SetDumpSystemTables(bool dump_system_tables) +{ + DatabaseDumpService::dump_system_tables = dump_system_tables; +} + +bool DatabaseDumpService::IsDumpContentTables() const +{ + return dump_content_tables; +} + +void DatabaseDumpService::SetDumpContentTables(bool dump_content_tables) +{ + DatabaseDumpService::dump_content_tables = dump_content_tables; +} + +bool DatabaseDumpService::IsDumpPlayerTables() const +{ + return dump_player_tables; +} + +void DatabaseDumpService::SetDumpPlayerTables(bool dump_player_tables) +{ + DatabaseDumpService::dump_player_tables = dump_player_tables; +} + +bool DatabaseDumpService::IsDumpLoginServerTables() const +{ + return dump_login_server_tables; +} + +void DatabaseDumpService::SetDumpLoginServerTables(bool dump_login_server_tables) +{ + DatabaseDumpService::dump_login_server_tables = dump_login_server_tables; +} + +bool DatabaseDumpService::IsDumpWithNoData() const +{ + return dump_with_no_data; +} + +void DatabaseDumpService::SetDumpWithNoData(bool dump_with_no_data) +{ + DatabaseDumpService::dump_with_no_data = dump_with_no_data; +} + +bool DatabaseDumpService::IsDumpAllTables() const +{ + return dump_all_tables; +} + +void DatabaseDumpService::SetDumpAllTables(bool dump_all_tables) +{ + DatabaseDumpService::dump_all_tables = dump_all_tables; +} +bool DatabaseDumpService::IsDumpNoTableLock() const +{ + return dump_no_table_lock; +} + +void DatabaseDumpService::SetDumpNoTableLock(bool dump_no_table_lock) +{ + DatabaseDumpService::dump_no_table_lock = dump_no_table_lock; +} + +bool DatabaseDumpService::IsDumpWithCompression() const +{ + return dump_with_compression; +} + +void DatabaseDumpService::SetDumpWithCompression(bool dump_with_compression) +{ + DatabaseDumpService::dump_with_compression = dump_with_compression; +} + +const std::string &DatabaseDumpService::GetDumpPath() const +{ + return dump_path; +} + +void DatabaseDumpService::SetDumpPath(const std::string &dump_path) +{ + DatabaseDumpService::dump_path = dump_path; +} + +void DatabaseDumpService::SetDumpFileName(const std::string &dump_file_name) +{ + DatabaseDumpService::dump_file_name = dump_file_name; +} + +const std::string &DatabaseDumpService::GetDumpFileName() const +{ + return dump_file_name; +} From dd1470892dc3eb6448852803b06bb2b6b50a1902 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 03:20:43 -0500 Subject: [PATCH 07/84] Update database_dump_service.cpp --- common/database/database_dump_service.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index 68608bd67..4d0273bf6 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -28,6 +28,13 @@ #include "../database_schema.h" #include "../file_util.h" +#include +#if _WIN32 +#include +#else +#include +#endif + #define DATABASE_DUMP_PATH "backups/" /** From bfecd6ad14a8991e30292fe4a837242e1be341cf Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 14:08:17 -0500 Subject: [PATCH 08/84] Add query-serv table dump option, add option to dump directly to console, add initializers for dump settings --- common/database/database_dump_service.cpp | 77 ++++++++++++++++++++--- common/database/database_dump_service.h | 23 ++++--- common/database_schema.h | 27 +++++++- world/world_server_command_handler.cpp | 4 ++ 4 files changed, 113 insertions(+), 18 deletions(-) diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index 4d0273bf6..f7a339c84 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -29,10 +29,13 @@ #include "../file_util.h" #include + #if _WIN32 #include #else + #include + #endif #define DATABASE_DUMP_PATH "backups/" @@ -159,6 +162,20 @@ std::string DatabaseDumpService::GetLoginTableList() return trim(tables_list); } +/** + * @return + */ +std::string DatabaseDumpService::GetQueryServTables() +{ + std::string tables_list; + std::vector tables = DatabaseSchema::GetQueryServerTables(); + for (const auto &table : tables) { + tables_list += table + " "; + } + + return trim(tables_list); +} + /** * @return */ @@ -238,6 +255,10 @@ void DatabaseDumpService::Dump() return; } + if (IsDumpOutputToConsole()) { + LogSys.SilenceConsoleLogging(); + } + LogInfo("MySQL installed [{}]", GetMySQLVersion()); SetDumpFileName(EQEmuConfig::get()->DatabaseDB + '-' + GetDumpDate()); @@ -266,43 +287,59 @@ void DatabaseDumpService::Dump() if (!IsDumpAllTables()) { if (IsDumpPlayerTables()) { - tables_to_dump += GetPlayerTablesList(); + tables_to_dump += GetPlayerTablesList() + " "; dump_descriptor += "-player"; } if (IsDumpSystemTables()) { - tables_to_dump += GetSystemTablesList(); + tables_to_dump += GetSystemTablesList() + " "; dump_descriptor += "-system"; } if (IsDumpContentTables()) { - tables_to_dump += GetContentTablesList(); + tables_to_dump += GetContentTablesList() + " "; dump_descriptor += "-content"; } if (IsDumpLoginServerTables()) { - tables_to_dump += GetLoginTableList(); + tables_to_dump += GetLoginTableList() + " "; dump_descriptor += "-login"; } + + if (IsDumpQueryServerTables()) { + tables_to_dump += GetQueryServTables(); + dump_descriptor += "-queryserv"; + } } if (!dump_descriptor.empty()) { SetDumpFileName(GetDumpFileName() + dump_descriptor); } + /** + * If we are dumping to stdout then we don't generate a file + */ + std::string pipe_file; + if (!IsDumpOutputToConsole()) { + pipe_file = fmt::format(" > {}.sql", GetDumpFileNameWithPath()); + } + std::string execute_command = fmt::format( - "{} {} {} > {}.sql", + "{} {} {} {}", GetBaseMySQLDumpCommand(), options, tables_to_dump, - GetDumpFileNameWithPath() + pipe_file ); - if (!FileUtil::exists(GetSetDumpPath())) { + if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) { FileUtil::mkdir(GetSetDumpPath()); } - execute(execute_command, false); + std::string execution_result = execute(execute_command, IsDumpOutputToConsole()); + if (!execution_result.empty()) { + std::cout << execution_result; + } if (!tables_to_dump.empty()) { LogInfo("Dumping Tables [{}]", tables_to_dump); @@ -310,7 +347,7 @@ void DatabaseDumpService::Dump() LogInfo("Database dump created at [{}.sql]", GetDumpFileNameWithPath()); - if (IsDumpWithCompression()) { + if (IsDumpWithCompression() && !IsDumpOutputToConsole()) { if (HasCompressionBinary()) { LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath()); @@ -331,8 +368,10 @@ void DatabaseDumpService::Dump() } } +// LogDebug("[{}] dump-to-console", IsDumpOutputToConsole()); // LogDebug("[{}] dump-path", GetSetDumpPath()); // LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false")); +// LogDebug("[{}] query-serv", (IsDumpQueryServerTables() ? "true" : "false")); // LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false")); // LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false")); // LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false")); @@ -439,3 +478,23 @@ const std::string &DatabaseDumpService::GetDumpFileName() const { return dump_file_name; } + +bool DatabaseDumpService::IsDumpQueryServerTables() const +{ + return dump_query_server_tables; +} + +void DatabaseDumpService::SetDumpQueryServerTables(bool dump_query_server_tables) +{ + DatabaseDumpService::dump_query_server_tables = dump_query_server_tables; +} + +bool DatabaseDumpService::IsDumpOutputToConsole() const +{ + return dump_output_to_console; +} + +void DatabaseDumpService::SetDumpOutputToConsole(bool dump_output_to_console) +{ + DatabaseDumpService::dump_output_to_console = dump_output_to_console; +} \ No newline at end of file diff --git a/common/database/database_dump_service.h b/common/database/database_dump_service.h index 096d4c5d3..eb87520da 100644 --- a/common/database/database_dump_service.h +++ b/common/database/database_dump_service.h @@ -45,16 +45,22 @@ public: void SetDumpPath(const std::string &dump_path); const std::string &GetDumpFileName() const; void SetDumpFileName(const std::string &dump_file_name); + bool IsDumpQueryServerTables() const; + void SetDumpQueryServerTables(bool dump_query_server_tables); + bool IsDumpOutputToConsole() const; + void SetDumpOutputToConsole(bool dump_output_to_console); private: - bool dump_all_tables; - bool dump_system_tables; - bool dump_content_tables; - bool dump_player_tables; - bool dump_login_server_tables; - bool dump_with_no_data; - bool dump_no_table_lock; - bool dump_with_compression; + bool dump_all_tables = false; + bool dump_system_tables = false; + bool dump_content_tables = false; + bool dump_player_tables = false; + bool dump_query_server_tables = false; + bool dump_login_server_tables = false; + bool dump_with_no_data = false; + bool dump_no_table_lock = false; + bool dump_with_compression = false; + bool dump_output_to_console = false; std::string dump_path; std::string dump_file_name; @@ -71,6 +77,7 @@ private: bool HasCompressionBinary(); std::string GetDumpFileNameWithPath(); std::string GetSetDumpPath(); + std::string GetQueryServTables(); }; diff --git a/common/database_schema.h b/common/database_schema.h index b497ad474..5502441d0 100644 --- a/common/database_schema.h +++ b/common/database_schema.h @@ -233,7 +233,6 @@ namespace DatabaseSchema { "task_activities", "tasks", "tasksets", - "titles", "tradeskill_recipe", "tradeskill_recipe_entries", "traps", @@ -282,6 +281,32 @@ namespace DatabaseSchema { }; } + /** + * Gets QueryServer tables + * + * @return + */ + static std::vector GetQueryServerTables() + { + return { + "qs_merchant_transaction_record", + "qs_merchant_transaction_record_entries", + "qs_player_aa_rate_hourly", + "qs_player_delete_record", + "qs_player_delete_record_entries", + "qs_player_events", + "qs_player_handin_record", + "qs_player_handin_record_entries", + "qs_player_move_record", + "qs_player_move_record_entries", + "qs_player_npc_kill_record", + "qs_player_npc_kill_record_entries", + "qs_player_speech", + "qs_player_trade_record", + "qs_player_trade_record_entries", + }; + } + /** * Gets state tables * Tables that keep track of server state diff --git a/world/world_server_command_handler.cpp b/world/world_server_command_handler.cpp index 565277f97..32e794800 100644 --- a/world/world_server_command_handler.cpp +++ b/world/world_server_command_handler.cpp @@ -225,9 +225,11 @@ namespace WorldserverCommandHandler { "--login-tables", "--player-tables", "--system-tables", + "--query-serv-tables", "--table-structure-only", "--no-table-lock", "--dump-path=", + "--dump-output-to-console", "--compress" }; @@ -252,9 +254,11 @@ namespace WorldserverCommandHandler { database_dump_service->SetDumpPlayerTables(cmd[{"-c", "--player-tables"}] || dump_all); database_dump_service->SetDumpSystemTables(cmd[{"-c", "--system-tables"}] || dump_all); database_dump_service->SetDumpWithNoData(cmd[{"-c", "--table-structure-only"}]); + database_dump_service->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}]); database_dump_service->SetDumpAllTables(dump_all); database_dump_service->SetDumpNoTableLock(cmd[{"--no-table-lock"}]); database_dump_service->SetDumpWithCompression(cmd[{"--compress"}]); + database_dump_service->SetDumpOutputToConsole(cmd[{"--dump-output-to-console"}]); /** * Dump From 53be04c39c54ea3aa481dceaa63d410e208e5a61 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 15:51:11 -0500 Subject: [PATCH 09/84] Don't lock tables by default; move tables around in schema; add peq-dump.sh script --- common/database/database_dump_service.cpp | 46 +++++++++++++++++----- common/database/database_dump_service.h | 27 +++++++------ common/database_schema.h | 17 ++++---- utils/sql/peq-dump/peq-dump.sh | 47 +++++++++++++++++++++++ world/world_server_command_handler.cpp | 6 ++- 5 files changed, 112 insertions(+), 31 deletions(-) create mode 100755 utils/sql/peq-dump/peq-dump.sh diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index f7a339c84..7610f3759 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -255,6 +255,10 @@ void DatabaseDumpService::Dump() return; } + if (IsDumpDropTableSyntaxOnly()) { + SetDumpOutputToConsole(true); + } + if (IsDumpOutputToConsole()) { LogSys.SilenceConsoleLogging(); } @@ -278,7 +282,7 @@ void DatabaseDumpService::Dump() options += " --no-data"; } - if (IsDumpNoTableLock()) { + if (!IsDumpTableLock()) { options += " --skip-lock-tables"; } @@ -336,9 +340,22 @@ void DatabaseDumpService::Dump() FileUtil::mkdir(GetSetDumpPath()); } - std::string execution_result = execute(execute_command, IsDumpOutputToConsole()); - if (!execution_result.empty()) { - std::cout << execution_result; + if (IsDumpDropTableSyntaxOnly()) { + std::vector tables = SplitString(tables_to_dump, ' '); + + for (auto &table : tables) { + std::cout << "DROP TABLE `" << table << "`;" << std::endl; + } + + if (tables_to_dump.empty()) { + std::cerr << "No tables were specified" << std::endl; + } + } + else { + std::string execution_result = execute(execute_command, IsDumpOutputToConsole()); + if (!execution_result.empty()) { + std::cout << execution_result; + } } if (!tables_to_dump.empty()) { @@ -439,14 +456,15 @@ void DatabaseDumpService::SetDumpAllTables(bool dump_all_tables) { DatabaseDumpService::dump_all_tables = dump_all_tables; } -bool DatabaseDumpService::IsDumpNoTableLock() const + +bool DatabaseDumpService::IsDumpTableLock() const { - return dump_no_table_lock; + return dump_table_lock; } -void DatabaseDumpService::SetDumpNoTableLock(bool dump_no_table_lock) +void DatabaseDumpService::SetDumpTableLock(bool dump_table_lock) { - DatabaseDumpService::dump_no_table_lock = dump_no_table_lock; + DatabaseDumpService::dump_table_lock = dump_table_lock; } bool DatabaseDumpService::IsDumpWithCompression() const @@ -497,4 +515,14 @@ bool DatabaseDumpService::IsDumpOutputToConsole() const void DatabaseDumpService::SetDumpOutputToConsole(bool dump_output_to_console) { DatabaseDumpService::dump_output_to_console = dump_output_to_console; -} \ No newline at end of file +} + +bool DatabaseDumpService::IsDumpDropTableSyntaxOnly() const +{ + return dump_drop_table_syntax_only; +} + +void DatabaseDumpService::SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only) +{ + DatabaseDumpService::dump_drop_table_syntax_only = dump_drop_table_syntax_only; +} diff --git a/common/database/database_dump_service.h b/common/database/database_dump_service.h index eb87520da..20f57e85c 100644 --- a/common/database/database_dump_service.h +++ b/common/database/database_dump_service.h @@ -37,8 +37,8 @@ public: void SetDumpPlayerTables(bool dump_player_tables); bool IsDumpLoginServerTables() const; void SetDumpLoginServerTables(bool dump_login_server_tables); - bool IsDumpNoTableLock() const; - void SetDumpNoTableLock(bool dump_no_table_lock); + bool IsDumpTableLock() const; + void SetDumpTableLock(bool dump_table_lock); bool IsDumpWithCompression() const; void SetDumpWithCompression(bool dump_with_compression); const std::string &GetDumpPath() const; @@ -49,18 +49,21 @@ public: void SetDumpQueryServerTables(bool dump_query_server_tables); bool IsDumpOutputToConsole() const; void SetDumpOutputToConsole(bool dump_output_to_console); + bool IsDumpDropTableSyntaxOnly() const; + void SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only); private: - bool dump_all_tables = false; - bool dump_system_tables = false; - bool dump_content_tables = false; - bool dump_player_tables = false; - bool dump_query_server_tables = false; - bool dump_login_server_tables = false; - bool dump_with_no_data = false; - bool dump_no_table_lock = false; - bool dump_with_compression = false; - bool dump_output_to_console = false; + bool dump_all_tables = false; + bool dump_system_tables = false; + bool dump_content_tables = false; + bool dump_player_tables = false; + bool dump_query_server_tables = false; + bool dump_login_server_tables = false; + bool dump_with_no_data = false; + bool dump_table_lock = false; + bool dump_with_compression = false; + bool dump_output_to_console = false; + bool dump_drop_table_syntax_only = false; std::string dump_path; std::string dump_file_name; diff --git a/common/database_schema.h b/common/database_schema.h index 5502441d0..40c9c39f1 100644 --- a/common/database_schema.h +++ b/common/database_schema.h @@ -85,7 +85,8 @@ namespace DatabaseSchema { } /** - * Gets all player and meta-data tables + * @description Gets all player and meta-data tables + * @note These tables have no content in the PEQ daily dump * * @return */ @@ -98,6 +99,8 @@ namespace DatabaseSchema { "account_rewards", "adventure_details", "adventure_stats", + "bugs", + "bug_reports", "buyer", "char_recipe_list", "character_activities", @@ -129,6 +132,8 @@ namespace DatabaseSchema { "character_tribute", "completed_tasks", "data_buckets", + "discovered_items", + "eventlog", "faction_values", "friends", "guild_bank", @@ -141,9 +146,12 @@ namespace DatabaseSchema { "inventory_snapshots", "keyring", "mail", + "petitions", "player_titlesets", "quest_globals", + "saylink", "sharedbank", + "reports", "timers", "titles", "trader", @@ -255,13 +263,9 @@ namespace DatabaseSchema { { return { "banned_ips", - "bugs", - "bug_reports", "command_settings", "db_str", - "discovered_items", "eqtime", - "eventlog", "gm_ips", "hackers", "ip_exemptions", @@ -271,12 +275,9 @@ namespace DatabaseSchema { "logsys_categories", "name_filter", "perl_event_export_settings", - "petitions", "profanity_list", - "reports", "rule_sets", "rule_values", - "saylink", "variables", }; } diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh new file mode 100755 index 000000000..afcb63212 --- /dev/null +++ b/utils/sql/peq-dump/peq-dump.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +world_path="" + +if [ -d "bin" ] +then + world_path="bin/" +fi + +world_bin="${world_path}world" + +echo "World path is [$world_path] bin is [$world_bin]" + +# Run from the context of server directory +# +# --content-tables +# --login-tables +# --player-tables +# --system-tables +# --query-serv-tables + +############################################# +# dump +############################################# + +dump_path=/tmp/peq-dump/ + +mkdir -p ${dump_path} + +############################################# +# generate "drop_" table files +############################################# +bash -c "${world_bin} database:dump --content-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_content.sql" +bash -c "${world_bin} database:dump --login-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_login.sql" +bash -c "${world_bin} database:dump --player-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_player.sql" +bash -c "${world_bin} database:dump --system-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_system.sql" +bash -c "${world_bin} database:dump --query-serv-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_queryserv.sql" + +############################################# +# generate "create_" table files +############################################# +bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql" +bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console > ${dump_path}create_tables_login.sql" +bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console > ${dump_path}create_tables_player.sql" +bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql" +bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console > ${dump_path}create_tables_queryserv.sql" + diff --git a/world/world_server_command_handler.cpp b/world/world_server_command_handler.cpp index 32e794800..5ccbf167c 100644 --- a/world/world_server_command_handler.cpp +++ b/world/world_server_command_handler.cpp @@ -227,9 +227,10 @@ namespace WorldserverCommandHandler { "--system-tables", "--query-serv-tables", "--table-structure-only", - "--no-table-lock", + "--table-lock", "--dump-path=", "--dump-output-to-console", + "--drop-table-syntax-only", "--compress" }; @@ -256,9 +257,10 @@ namespace WorldserverCommandHandler { database_dump_service->SetDumpWithNoData(cmd[{"-c", "--table-structure-only"}]); database_dump_service->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}]); database_dump_service->SetDumpAllTables(dump_all); - database_dump_service->SetDumpNoTableLock(cmd[{"--no-table-lock"}]); + database_dump_service->SetDumpTableLock(cmd[{"--table-lock"}]); database_dump_service->SetDumpWithCompression(cmd[{"--compress"}]); database_dump_service->SetDumpOutputToConsole(cmd[{"--dump-output-to-console"}]); + database_dump_service->SetDumpDropTableSyntaxOnly(cmd[{"--drop-table-syntax-only"}]); /** * Dump From 899e2d339793dad50107c30e695728cbd874cace Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 16:31:30 -0500 Subject: [PATCH 10/84] Add innodb conversion script; will hook up in manifest later --- .../2020_03_09_convert_myisam_to_innodb.sql | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql diff --git a/utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql b/utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql new file mode 100644 index 000000000..ec9f6607b --- /dev/null +++ b/utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql @@ -0,0 +1,99 @@ +ALTER TABLE `aa_actions` ENGINE=InnoDB; +ALTER TABLE `aa_effects` ENGINE=InnoDB; +ALTER TABLE `aa_required_level_cost` ENGINE=InnoDB; +ALTER TABLE `aa_timers` ENGINE=InnoDB; +ALTER TABLE `account_flags` ENGINE=InnoDB; +ALTER TABLE `account_ip` ENGINE=InnoDB; +ALTER TABLE `account` ENGINE=InnoDB; +ALTER TABLE `adventure_template_entry_flavor` ENGINE=InnoDB; +ALTER TABLE `adventure_template_entry` ENGINE=InnoDB; +ALTER TABLE `altadv_vars` ENGINE=InnoDB; +ALTER TABLE `alternate_currency` ENGINE=InnoDB; +ALTER TABLE `banned_ips` ENGINE=InnoDB; +ALTER TABLE `base_data` ENGINE=InnoDB; +ALTER TABLE `blocked_spells` ENGINE=InnoDB; +ALTER TABLE `buyer` ENGINE=InnoDB; +ALTER TABLE `char_create_combinations` ENGINE=InnoDB; +ALTER TABLE `char_create_point_allocations` ENGINE=InnoDB; +ALTER TABLE `character_activities` ENGINE=InnoDB; +ALTER TABLE `character_enabledtasks` ENGINE=InnoDB; +ALTER TABLE `character_tasks` ENGINE=InnoDB; +ALTER TABLE `chatchannels` ENGINE=InnoDB; +ALTER TABLE `completed_tasks` ENGINE=InnoDB; +ALTER TABLE `damageshieldtypes` ENGINE=InnoDB; +ALTER TABLE `discovered_items` ENGINE=InnoDB; +ALTER TABLE `eqtime` ENGINE=InnoDB; +ALTER TABLE `eventlog` ENGINE=InnoDB; +ALTER TABLE `faction_list_mod` ENGINE=InnoDB; +ALTER TABLE `faction_list` ENGINE=InnoDB; +ALTER TABLE `faction_values` ENGINE=InnoDB; +ALTER TABLE `friends` ENGINE=InnoDB; +ALTER TABLE `goallists` ENGINE=InnoDB; +ALTER TABLE `guild_bank` ENGINE=InnoDB; +ALTER TABLE `guild_members` ENGINE=InnoDB; +ALTER TABLE `guild_ranks` ENGINE=InnoDB; +ALTER TABLE `guild_relations` ENGINE=InnoDB; +ALTER TABLE `guilds` ENGINE=InnoDB; +ALTER TABLE `hackers` ENGINE=InnoDB; +ALTER TABLE `horses` ENGINE=InnoDB; +ALTER TABLE `inventory_versions` ENGINE=InnoDB; +ALTER TABLE `item_tick` ENGINE=InnoDB; +ALTER TABLE `items` ENGINE=InnoDB; +ALTER TABLE `keyring` ENGINE=InnoDB; +ALTER TABLE `launcher_zones` ENGINE=InnoDB; +ALTER TABLE `launcher` ENGINE=InnoDB; +ALTER TABLE `ldon_trap_entries` ENGINE=InnoDB; +ALTER TABLE `ldon_trap_templates` ENGINE=InnoDB; +ALTER TABLE `lfguild` ENGINE=InnoDB; +ALTER TABLE `lootdrop_entries` ENGINE=InnoDB; +ALTER TABLE `lootdrop` ENGINE=InnoDB; +ALTER TABLE `loottable_entries` ENGINE=InnoDB; +ALTER TABLE `loottable` ENGINE=InnoDB; +ALTER TABLE `mail` ENGINE=InnoDB; +ALTER TABLE `merc_armorinfo` ENGINE=InnoDB; +ALTER TABLE `merc_buffs` ENGINE=InnoDB; +ALTER TABLE `merc_inventory` ENGINE=InnoDB; +ALTER TABLE `merc_merchant_entries` ENGINE=InnoDB; +ALTER TABLE `merc_merchant_template_entries` ENGINE=InnoDB; +ALTER TABLE `merc_merchant_templates` ENGINE=InnoDB; +ALTER TABLE `merc_name_types` ENGINE=InnoDB; +ALTER TABLE `merc_npc_types` ENGINE=InnoDB; +ALTER TABLE `merc_spell_list_entries` ENGINE=InnoDB; +ALTER TABLE `merc_spell_lists` ENGINE=InnoDB; +ALTER TABLE `merc_stance_entries` ENGINE=InnoDB; +ALTER TABLE `merc_stats` ENGINE=InnoDB; +ALTER TABLE `merc_subtypes` ENGINE=InnoDB; +ALTER TABLE `merc_templates` ENGINE=InnoDB; +ALTER TABLE `merc_types` ENGINE=InnoDB; +ALTER TABLE `merc_weaponinfo` ENGINE=InnoDB; +ALTER TABLE `mercs` ENGINE=InnoDB; +ALTER TABLE `name_filter` ENGINE=InnoDB; +ALTER TABLE `npc_types` ENGINE=InnoDB; +ALTER TABLE `object_contents` ENGINE=InnoDB; +ALTER TABLE `petitions` ENGINE=InnoDB; +ALTER TABLE `pets_equipmentset_entries` ENGINE=InnoDB; +ALTER TABLE `pets_equipmentset` ENGINE=InnoDB; +ALTER TABLE `player_titlesets` ENGINE=InnoDB; +ALTER TABLE `proximities` ENGINE=InnoDB; +ALTER TABLE `races` ENGINE=InnoDB; +ALTER TABLE `raid_details` ENGINE=InnoDB; +ALTER TABLE `raid_leaders` ENGINE=InnoDB; +ALTER TABLE `raid_members` ENGINE=InnoDB; +ALTER TABLE `rule_sets` ENGINE=InnoDB; +ALTER TABLE `rule_values` ENGINE=InnoDB; +ALTER TABLE `saylink` ENGINE=InnoDB; +ALTER TABLE `sharedbank` ENGINE=InnoDB; +ALTER TABLE `skill_caps` ENGINE=InnoDB; +ALTER TABLE `spell_globals` ENGINE=InnoDB; +ALTER TABLE `spells_new` ENGINE=InnoDB; +ALTER TABLE `task_activities` ENGINE=InnoDB; +ALTER TABLE `tasks` ENGINE=InnoDB; +ALTER TABLE `tasksets` ENGINE=InnoDB; +ALTER TABLE `timers` ENGINE=InnoDB; +ALTER TABLE `titles` ENGINE=InnoDB; +ALTER TABLE `trader_audit` ENGINE=InnoDB; +ALTER TABLE `trader` ENGINE=InnoDB; +ALTER TABLE `tradeskill_recipe_entries` ENGINE=InnoDB; +ALTER TABLE `tradeskill_recipe` ENGINE=InnoDB; +ALTER TABLE `variables` ENGINE=InnoDB; +ALTER TABLE `veteran_reward_templates` ENGINE=InnoDB; \ No newline at end of file From 6438a37fb5869c362d08d4404da3b1f8dd2d983a Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 16:31:43 -0500 Subject: [PATCH 11/84] Split up state table dump --- common/database/database_dump_service.cpp | 28 +++++++++++++++++++++-- common/database/database_dump_service.h | 26 ++++++++++++--------- common/database_schema.h | 17 +++++++------- utils/sql/peq-dump/peq-dump.sh | 12 ++++++---- world/world_server_command_handler.cpp | 15 +++++++----- 5 files changed, 66 insertions(+), 32 deletions(-) diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index 7610f3759..5d6da79e9 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -188,12 +188,21 @@ std::string DatabaseDumpService::GetSystemTablesList() tables_list += table + " "; } - tables = DatabaseSchema::GetStateTables(); + tables = DatabaseSchema::GetVersionTables(); for (const auto &table : tables) { tables_list += table + " "; } - tables = DatabaseSchema::GetVersionTables(); + return trim(tables_list); +} +/** + * @return + */ +std::string DatabaseDumpService::GetStateTablesList() +{ + std::string tables_list; + + std::vector tables = DatabaseSchema::GetStateTables(); for (const auto &table : tables) { tables_list += table + " "; } @@ -300,6 +309,11 @@ void DatabaseDumpService::Dump() dump_descriptor += "-system"; } + if (IsDumpStateTables()) { + tables_to_dump += GetStateTablesList() + " "; + dump_descriptor += "-state"; + } + if (IsDumpContentTables()) { tables_to_dump += GetContentTablesList() + " "; dump_descriptor += "-content"; @@ -526,3 +540,13 @@ void DatabaseDumpService::SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax { DatabaseDumpService::dump_drop_table_syntax_only = dump_drop_table_syntax_only; } + +bool DatabaseDumpService::IsDumpStateTables() const +{ + return dump_state_tables; +} + +void DatabaseDumpService::SetDumpStateTables(bool dump_state_tables) +{ + DatabaseDumpService::dump_state_tables = dump_state_tables; +} diff --git a/common/database/database_dump_service.h b/common/database/database_dump_service.h index 20f57e85c..439a380ba 100644 --- a/common/database/database_dump_service.h +++ b/common/database/database_dump_service.h @@ -51,19 +51,22 @@ public: void SetDumpOutputToConsole(bool dump_output_to_console); bool IsDumpDropTableSyntaxOnly() const; void SetDumpDropTableSyntaxOnly(bool dump_drop_table_syntax_only); + bool IsDumpStateTables() const; + void SetDumpStateTables(bool dump_state_tables); private: - bool dump_all_tables = false; - bool dump_system_tables = false; - bool dump_content_tables = false; - bool dump_player_tables = false; - bool dump_query_server_tables = false; - bool dump_login_server_tables = false; - bool dump_with_no_data = false; - bool dump_table_lock = false; - bool dump_with_compression = false; - bool dump_output_to_console = false; - bool dump_drop_table_syntax_only = false; + bool dump_all_tables = false; + bool dump_state_tables = false; + bool dump_system_tables = false; + bool dump_content_tables = false; + bool dump_player_tables = false; + bool dump_query_server_tables = false; + bool dump_login_server_tables = false; + bool dump_with_no_data = false; + bool dump_table_lock = false; + bool dump_with_compression = false; + bool dump_output_to_console = false; + bool dump_drop_table_syntax_only = false; std::string dump_path; std::string dump_file_name; @@ -73,6 +76,7 @@ private: std::string GetBaseMySQLDumpCommand(); std::string GetPlayerTablesList(); std::string GetSystemTablesList(); + std::string GetStateTablesList(); std::string GetContentTablesList(); std::string GetLoginTableList(); bool IsTarAvailable(); diff --git a/common/database_schema.h b/common/database_schema.h index 40c9c39f1..75856eb9f 100644 --- a/common/database_schema.h +++ b/common/database_schema.h @@ -99,8 +99,6 @@ namespace DatabaseSchema { "account_rewards", "adventure_details", "adventure_stats", - "bugs", - "bug_reports", "buyer", "char_recipe_list", "character_activities", @@ -133,7 +131,6 @@ namespace DatabaseSchema { "completed_tasks", "data_buckets", "discovered_items", - "eventlog", "faction_values", "friends", "guild_bank", @@ -149,9 +146,9 @@ namespace DatabaseSchema { "petitions", "player_titlesets", "quest_globals", - "saylink", "sharedbank", - "reports", + "spell_buckets", + "spell_globals", "timers", "titles", "trader", @@ -263,6 +260,7 @@ namespace DatabaseSchema { { return { "banned_ips", + "chatchannels", "command_settings", "db_str", "eqtime", @@ -318,7 +316,9 @@ namespace DatabaseSchema { { return { "adventure_members", - "chatchannels", + "bugs", + "bug_reports", + "eventlog", "group_id", "group_leaders", "item_tick", @@ -329,8 +329,9 @@ namespace DatabaseSchema { "raid_leaders", "raid_members", "respawn_times", - "spell_buckets", - "spell_globals", + "reports", + "saylink", + }; } diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index afcb63212..06300fbd7 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -34,14 +34,16 @@ bash -c "${world_bin} database:dump --content-tables --drop-table-syntax-only -- bash -c "${world_bin} database:dump --login-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_login.sql" bash -c "${world_bin} database:dump --player-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_player.sql" bash -c "${world_bin} database:dump --system-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_system.sql" +bash -c "${world_bin} database:dump --state-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_state.sql" bash -c "${world_bin} database:dump --query-serv-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_queryserv.sql" ############################################# # generate "create_" table files ############################################# -bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql" -bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console > ${dump_path}create_tables_login.sql" -bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console > ${dump_path}create_tables_player.sql" -bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql" -bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console > ${dump_path}create_tables_queryserv.sql" +bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_login.sql" +bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_player.sql" +bash -c "${world_bin} database:dump --state-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_state.sql" +bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql" +bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql" +bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql" \ No newline at end of file diff --git a/world/world_server_command_handler.cpp b/world/world_server_command_handler.cpp index 5ccbf167c..9bad28541 100644 --- a/world/world_server_command_handler.cpp +++ b/world/world_server_command_handler.cpp @@ -224,6 +224,7 @@ namespace WorldserverCommandHandler { "--content-tables", "--login-tables", "--player-tables", + "--state-tables", "--system-tables", "--query-serv-tables", "--table-structure-only", @@ -250,13 +251,15 @@ namespace WorldserverCommandHandler { /** * Set Option */ - database_dump_service->SetDumpContentTables(cmd[{"-c", "--content-tables"}] || dump_all); - database_dump_service->SetDumpLoginServerTables(cmd[{"-c", "--login-tables"}] || dump_all); - database_dump_service->SetDumpPlayerTables(cmd[{"-c", "--player-tables"}] || dump_all); - database_dump_service->SetDumpSystemTables(cmd[{"-c", "--system-tables"}] || dump_all); - database_dump_service->SetDumpWithNoData(cmd[{"-c", "--table-structure-only"}]); - database_dump_service->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}]); + database_dump_service->SetDumpContentTables(cmd[{"--content-tables"}] || dump_all); + database_dump_service->SetDumpLoginServerTables(cmd[{"--login-tables"}] || dump_all); + database_dump_service->SetDumpPlayerTables(cmd[{"--player-tables"}] || dump_all); + database_dump_service->SetDumpStateTables(cmd[{"--state-tables"}] || dump_all); + database_dump_service->SetDumpSystemTables(cmd[{"--system-tables"}] || dump_all); + database_dump_service->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}] || dump_all); database_dump_service->SetDumpAllTables(dump_all); + + database_dump_service->SetDumpWithNoData(cmd[{"--table-structure-only"}]); database_dump_service->SetDumpTableLock(cmd[{"--table-lock"}]); database_dump_service->SetDumpWithCompression(cmd[{"--compress"}]); database_dump_service->SetDumpOutputToConsole(cmd[{"--dump-output-to-console"}]); From e7fab67d8ab0ab69a9be45a10e0000e341633ecb Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 22:57:27 -0500 Subject: [PATCH 12/84] Finalize peq-dump.sh script [skip ci] --- utils/sql/peq-dump/peq-dump.sh | 36 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index 06300fbd7..f60ed02d0 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -1,7 +1,11 @@ #!/usr/bin/env bash +# Run from the context of server directory world_path="" +############################################# +# world path +############################################# if [ -d "bin" ] then world_path="bin/" @@ -11,25 +15,18 @@ world_bin="${world_path}world" echo "World path is [$world_path] bin is [$world_bin]" -# Run from the context of server directory -# -# --content-tables -# --login-tables -# --player-tables -# --system-tables -# --query-serv-tables - ############################################# # dump ############################################# dump_path=/tmp/peq-dump/ - -mkdir -p ${dump_path} +echo "Generating dump path [${dump_path}]" +rm -rf ${dump_path} && mkdir -p ${dump_path} ############################################# # generate "drop_" table files ############################################# +echo "Generating [drop_*] table exports..." bash -c "${world_bin} database:dump --content-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_content.sql" bash -c "${world_bin} database:dump --login-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_login.sql" bash -c "${world_bin} database:dump --player-tables --drop-table-syntax-only --dump-output-to-console > ${dump_path}drop_tables_player.sql" @@ -40,10 +37,27 @@ bash -c "${world_bin} database:dump --query-serv-tables --drop-table-syntax-only ############################################# # generate "create_" table files ############################################# +echo "Generating [create_*] table exports..." + +# structure only bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_login.sql" bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_player.sql" bash -c "${world_bin} database:dump --state-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_state.sql" bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql" +# with content bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql" -bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql" \ No newline at end of file +bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql" + +############################################# +# zip +############################################# +human_date=$(date +"%B-%d-%Y" | tr '[:upper:]' '[:lower:]') + +echo "Compressing..." +bash -c "cd ${dump_path} && zip peq-latest.zip * && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip" + +echo "Cleaning up..." +rm -rf ${dump_path} + +echo "Dump located [/tmp/peq-latest.zip]" \ No newline at end of file From fa12b146a3e13fdbe11d09b7717bd57f57fc9156 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 9 Mar 2020 23:05:01 -0500 Subject: [PATCH 13/84] Add "all" .sql files [skip ci] --- utils/sql/peq-dump/peq-dump.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index f60ed02d0..7fd9bf278 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -49,6 +49,13 @@ bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only - bash -c "${world_bin} database:dump --content-tables --dump-output-to-console > ${dump_path}create_tables_content.sql" bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > ${dump_path}create_tables_system.sql" +############################################# +# "all" exports +############################################# + +bash -c "cd ${dump_path} && ls * | grep create | sed 's/.*/source &;/' > create_all_tables.sql" +bash -c "cd ${dump_path} && ls * | grep drop | sed 's/.*/source &;/' > drop_all_tables.sql" + ############################################# # zip ############################################# From c42d6dcd1b0833fb8cf6fb57f6facb5b583b2dc7 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 10 Mar 2020 00:14:28 -0500 Subject: [PATCH 14/84] Add 7zip compression; tweak dump settings --- common/database/database_dump_service.cpp | 26 +++++++++++++++++------ common/database/database_dump_service.h | 2 +- utils/sql/peq-dump/peq-dump.sh | 3 +-- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index 5d6da79e9..e98a8d830 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -90,14 +90,14 @@ bool DatabaseDumpService::IsTarAvailable() } /** - * Windows TODO + * Windows * @return bool */ -bool DatabaseDumpService::IsRarAvailable() +bool DatabaseDumpService::Is7ZipAvailable() { std::string version_output = execute("winrar --version"); - return version_output.find("todo") != std::string::npos; + return version_output.find("7-Zip") != std::string::npos; } /** @@ -105,7 +105,7 @@ bool DatabaseDumpService::IsRarAvailable() */ bool DatabaseDumpService::HasCompressionBinary() { - return IsTarAvailable() || IsRarAvailable(); + return IsTarAvailable() || Is7ZipAvailable(); } /** @@ -285,7 +285,7 @@ void DatabaseDumpService::Dump() config->DatabaseUsername ); - std::string options = "--compact --allow-keywords --extended-insert"; + std::string options = "--allow-keywords --extended-insert"; if (IsDumpWithNoData()) { options += " --no-data"; @@ -358,7 +358,7 @@ void DatabaseDumpService::Dump() std::vector tables = SplitString(tables_to_dump, ' '); for (auto &table : tables) { - std::cout << "DROP TABLE `" << table << "`;" << std::endl; + std::cout << "DROP TABLE IF EXISTS `" << table << "`;" << std::endl; } if (tables_to_dump.empty()) { @@ -393,6 +393,20 @@ void DatabaseDumpService::Dump() ); LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath()); } + else if (Is7ZipAvailable()) { + execute( + fmt::format( + "7z a -t7z {}.zip -C {} {}.sql", + GetDumpFileNameWithPath(), + GetSetDumpPath(), + GetDumpFileNameWithPath() + ) + ); + LogInfo("Compressed dump created at [{}.zip]", GetDumpFileNameWithPath()); + } + else { + LogInfo("Compression requested, but no available compression binary was found"); + } } else { LogWarning("Compression requested but binary not found... Skipping..."); diff --git a/common/database/database_dump_service.h b/common/database/database_dump_service.h index 439a380ba..f0614e85b 100644 --- a/common/database/database_dump_service.h +++ b/common/database/database_dump_service.h @@ -80,7 +80,7 @@ private: std::string GetContentTablesList(); std::string GetLoginTableList(); bool IsTarAvailable(); - bool IsRarAvailable(); + bool Is7ZipAvailable(); bool HasCompressionBinary(); std::string GetDumpFileNameWithPath(); std::string GetSetDumpPath(); diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index 7fd9bf278..911439c8f 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -52,7 +52,6 @@ bash -c "${world_bin} database:dump --system-tables --dump-output-to-console > $ ############################################# # "all" exports ############################################# - bash -c "cd ${dump_path} && ls * | grep create | sed 's/.*/source &;/' > create_all_tables.sql" bash -c "cd ${dump_path} && ls * | grep drop | sed 's/.*/source &;/' > drop_all_tables.sql" @@ -62,7 +61,7 @@ bash -c "cd ${dump_path} && ls * | grep drop | sed 's/.*/source &;/' > drop_all_ human_date=$(date +"%B-%d-%Y" | tr '[:upper:]' '[:lower:]') echo "Compressing..." -bash -c "cd ${dump_path} && zip peq-latest.zip * && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip" +bash -c "cd /tmp/ && rm peq-latest.zip && zip peq-latest.zip peq-dump/* && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip" echo "Cleaning up..." rm -rf ${dump_path} From 431a325414dc4702bc1d8c5eec0e97f60ebfce6d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 10 Mar 2020 00:22:39 -0500 Subject: [PATCH 15/84] Update manifest [skip ci] --- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/common/version.h b/common/version.h index 359c27576..99261fe83 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 9151 +#define CURRENT_BINARY_DATABASE_VERSION 9152 #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 9be222856..4113a838a 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -405,6 +405,7 @@ 9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|empty| 9150|2020_02_06_aa_reset_on_death.sql|SHOW COLUMNS FROM `aa_ability` LIKE 'reset_on_death'|empty| 9151|2020_03_05_npc_always_aggro.sql|SHOW COLUMNS FROM `npc_types` LIKE 'always_aggro'|empty| +9152|2020_03_09_convert_myisam_to_innodb.sql|SELECT * FROM db_version WHERE version >= 9151|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not From f3d82710669896e5360deb5216fb7c6c2b958db7 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 10 Mar 2020 13:41:53 -0500 Subject: [PATCH 16/84] Slightly adjust manifest criteria [skip ci] --- utils/sql/db_update_manifest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 4113a838a..28b22028e 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -405,7 +405,7 @@ 9149|2020_02_06_globalloot.sql|SHOW COLUMNS FROM `global_loot` LIKE 'hot_zone'|empty| 9150|2020_02_06_aa_reset_on_death.sql|SHOW COLUMNS FROM `aa_ability` LIKE 'reset_on_death'|empty| 9151|2020_03_05_npc_always_aggro.sql|SHOW COLUMNS FROM `npc_types` LIKE 'always_aggro'|empty| -9152|2020_03_09_convert_myisam_to_innodb.sql|SELECT * FROM db_version WHERE version >= 9151|empty| +9152|2020_03_09_convert_myisam_to_innodb.sql|SELECT * FROM db_version WHERE version >= 9152|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not From 08414bda55ce234a1888f6571b91fa59cbf511b2 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 10 Mar 2020 19:18:18 -0500 Subject: [PATCH 17/84] Fix 7zip availability check [skip ci] --- common/database/database_dump_service.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index e98a8d830..c4aa971d6 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -95,7 +95,7 @@ bool DatabaseDumpService::IsTarAvailable() */ bool DatabaseDumpService::Is7ZipAvailable() { - std::string version_output = execute("winrar --version"); + std::string version_output = execute("7z -help"); return version_output.find("7-Zip") != std::string::npos; } From e451dad94e9db50c23395ebf5162fce0fde46e13 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 10 Mar 2020 19:42:52 -0500 Subject: [PATCH 18/84] Dump tweaks [skip ci] --- utils/sql/peq-dump/peq-dump.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index 911439c8f..ccb7b8949 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -21,7 +21,8 @@ echo "World path is [$world_path] bin is [$world_bin]" dump_path=/tmp/peq-dump/ echo "Generating dump path [${dump_path}]" -rm -rf ${dump_path} && mkdir -p ${dump_path} +rm -rf ${dump_path} +mkdir -p ${dump_path} ############################################# # generate "drop_" table files @@ -61,7 +62,7 @@ bash -c "cd ${dump_path} && ls * | grep drop | sed 's/.*/source &;/' > drop_all_ human_date=$(date +"%B-%d-%Y" | tr '[:upper:]' '[:lower:]') echo "Compressing..." -bash -c "cd /tmp/ && rm peq-latest.zip && zip peq-latest.zip peq-dump/* && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip" +bash -c "cd /tmp/ && rm -rf peq-latest.zip && zip peq-latest.zip peq-dump/* && mv ${dump_path}peq-latest.zip /tmp/peq-latest.zip" echo "Cleaning up..." rm -rf ${dump_path} From 785804a9365f34a4a03ac734fdb9d52d1b6cd0ff Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 10 Mar 2020 19:54:26 -0500 Subject: [PATCH 19/84] Move tables around in schema [skip ci] --- common/database_schema.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/database_schema.h b/common/database_schema.h index 75856eb9f..7f883aa9f 100644 --- a/common/database_schema.h +++ b/common/database_schema.h @@ -259,14 +259,10 @@ namespace DatabaseSchema { static std::vector GetServerTables() { return { - "banned_ips", "chatchannels", "command_settings", "db_str", "eqtime", - "gm_ips", - "hackers", - "ip_exemptions", "launcher", "launcher_zones", "level_exp_mods", @@ -316,11 +312,15 @@ namespace DatabaseSchema { { return { "adventure_members", - "bugs", + "banned_ips", "bug_reports", + "bugs", "eventlog", + "gm_ips", "group_id", "group_leaders", + "hackers", + "ip_exemptions", "item_tick", "lfguild", "merchantlist_temp", @@ -328,8 +328,8 @@ namespace DatabaseSchema { "raid_details", "raid_leaders", "raid_members", - "respawn_times", "reports", + "respawn_times", "saylink", }; From 240d5c2a66b7f4d482ec7164192f177624789b85 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Wed, 11 Mar 2020 01:39:08 -0500 Subject: [PATCH 20/84] Add LOS check with NPC::AICheckCloseBeneficialSpells [skip ci] --- zone/npc.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index 6df237d5d..0cc2580fe 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -3093,6 +3093,14 @@ bool NPC::AICheckCloseBeneficialSpells( continue; } + if (!mob->CheckLosFN(caster)) { + continue; + } + + if (mob->GetReverseFactionCon(caster) >= FACTION_KINDLY) { + continue; + } + LogAICastBeneficialClose( "NPC [{}] Distance [{}] Cast Range [{}] Caster [{}]", mob->GetCleanName(), @@ -3101,10 +3109,6 @@ bool NPC::AICheckCloseBeneficialSpells( caster->GetCleanName() ); - if (mob->GetReverseFactionCon(caster) >= FACTION_KINDLY) { - continue; - } - if ((spell_types & SpellType_Buff) && !RuleB(NPC, BuffFriends)) { if (mob != caster) { spell_types = SpellType_Heal; From 7f25f8a235bf6b040592e3f3c37774d7e2783869 Mon Sep 17 00:00:00 2001 From: Ali Date: Wed, 11 Mar 2020 17:28:56 +0300 Subject: [PATCH 21/84] Modified eqemu_server.pl to pull latest PEQ * Also added an escape to skip pulling Maps (tighter feedback loop if developing) --- utils/scripts/eqemu_server.pl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index a5ae9e7b8..3c8663273 100755 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -52,6 +52,10 @@ if (-e "eqemu_server_skip_update.txt") { $skip_self_update_check = 1; } +if (-e "eqemu_server_skip_maps_update.txt") { + $skip_self_maps_update_check = 1; +} + #::: Check for script self update check_xml_to_json_conversion() if $ARGV[0] eq "convert_xml"; do_self_update_check_routine() if !$skip_self_update_check; @@ -460,7 +464,7 @@ sub do_installer_routines { get_remote_file($install_repository_request_url . "libmysql.dll", "libmysql.dll", 1); } - map_files_fetch_bulk(); + map_files_fetch_bulk() if !$skip_self_maps_update_check; opcodes_fetch(); plugins_fetch(); quest_files_fetch(); @@ -1705,26 +1709,22 @@ sub fetch_server_dlls { sub fetch_peq_db_full { print "[Install] Downloading latest PEQ Database... Please wait...\n"; - get_remote_file("http://edit.projecteq.net/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1); + get_remote_file("http://db.projecteq.net/api/v1/dump/latest", "updates_staged/peq-latest.zip", 1); print "[Install] Downloaded latest PEQ Database... Extracting...\n"; - unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/'); - my $start_dir = "updates_staged/peq_db"; + unzip('updates_staged/peq-latest.zip', 'updates_staged/peq_db/'); + my $start_dir = "updates_staged/peq_db/peq-dump"; find( sub { push @files, $File::Find::name unless -d; }, $start_dir ); for my $file (@files) { $destination_file = $file; - $destination_file =~ s/updates_staged\/peq_db\///g; - if ($file =~ /peqbeta|player_tables/i) { + $destination_file =~ s/updates_staged\/peq_db\/peq-dump\///g; + if ($file =~ /create_tables_content|create_tables_login|create_tables_player|create_tables_queryserv|create_tables_state|create_tables_system/i) { print "[Install] DB :: Installing :: " . $destination_file . "\n"; get_mysql_result_from_file($file); } } - - #::: PEQ DB baseline version - print get_mysql_result("DELETE FROM db_version"); - print get_mysql_result("INSERT INTO `db_version` (`version`) VALUES (9130);"); } sub map_files_fetch_bulk { From dac7541d891757950d3722bbb5aae497f332bfd2 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 11 Mar 2020 20:43:53 -0700 Subject: [PATCH 22/84] Update README.md Change the badges to the updated builds we have for appveyor. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f3b829732..31f88be38 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # EQEmulator Core Server -|Travis CI (Linux)|Appveyor w/ Bots (Windows) |Appveyor w/o Bots (Windows) | +|Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) | |:---:|:---:|:---:| -|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp/branch/master) |[![Build status](https://ci.appveyor.com/api/projects/status/mdwbr4o9l6mxqofj/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server-w0pq2/branch/master) | +|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/v3utuu0dttm2cqd0?svg=true)](https://ci.appveyor.com/project/KimLS/server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp) | *** From 6a61fd5df9aa2d1b975ea9c532e57d32fe0baa38 Mon Sep 17 00:00:00 2001 From: Uleat Date: Thu, 12 Mar 2020 23:12:44 -0400 Subject: [PATCH 23/84] Tweaked compression arguments for 7-Zip cli command invocation --- common/database/database_dump_service.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index c4aa971d6..d505a1a24 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -50,7 +50,11 @@ std::string DatabaseDumpService::execute(const std::string &cmd, bool return_res const char *file_name = "db-exec-result.txt"; if (return_result) { +#ifdef _WINDOWS + std::system((cmd + " > " + file_name + " 2>&1").c_str()); +#else std::system((cmd + " > " + file_name).c_str()); +#endif } else { std::system((cmd).c_str()); @@ -95,7 +99,7 @@ bool DatabaseDumpService::IsTarAvailable() */ bool DatabaseDumpService::Is7ZipAvailable() { - std::string version_output = execute("7z -help"); + std::string version_output = execute("7z --help"); return version_output.find("7-Zip") != std::string::npos; } @@ -396,9 +400,8 @@ void DatabaseDumpService::Dump() else if (Is7ZipAvailable()) { execute( fmt::format( - "7z a -t7z {}.zip -C {} {}.sql", + "7z a -t7z {}.zip {}.sql", GetDumpFileNameWithPath(), - GetSetDumpPath(), GetDumpFileNameWithPath() ) ); From 463c0d9e0e7d28665e0d8456c49e63f02b8b79a5 Mon Sep 17 00:00:00 2001 From: Uleat Date: Wed, 18 Mar 2020 16:12:25 -0400 Subject: [PATCH 24/84] Added proximity check for feared clients --- common/ruletypes.h | 1 + zone/mob_ai.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/common/ruletypes.h b/common/ruletypes.h index f1d00529f..20e26e315 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -161,6 +161,7 @@ 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_BOOL(Character, ProcessFearedProximity, true, "Processes proximity checks when feared") RULE_CATEGORY_END() RULE_CATEGORY(Mercs) diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 43d85c450..b687c0c8a 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -747,6 +747,13 @@ void Client::AI_Process() RunTo(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z); } } + if (RuleB(Character, ProcessFearedProximity) && proximity_timer.Check()) { + entity_list.ProcessMove(this, glm::vec3(GetX(), GetY(), GetZ())); + if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity)) + ProcessTaskProximities(GetX(), GetY(), GetZ()); + + m_Proximity = glm::vec3(GetX(), GetY(), GetZ()); + } return; } From e384cf6149eeaf7d2c1df5c5cf5a0fc50cc8af98 Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 18 Mar 2020 20:42:27 -0700 Subject: [PATCH 25/84] Replace hard coded 12 with EFFECT_COUNT in the two spots I see it used. --- zone/npc.cpp | 2 +- zone/zonedb.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index 0cc2580fe..b7dc3272a 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -962,7 +962,7 @@ void NPC::Depop(bool StartSpawnTimer) { } bool NPC::DatabaseCastAccepted(int spell_id) { - for (int i=0; i < 12; i++) { + for (int i=0; i < EFFECT_COUNT; i++) { switch(spells[spell_id].effectid[i]) { case SE_Stamina: { if(IsEngaged() && GetHPRatio() < 100) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index cad4e1df8..1dfbeb4a2 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3703,7 +3703,7 @@ void ZoneDatabase::LoadBuffs(Client *client) if (!IsValidSpell(buffs[index].spellid)) continue; - for (int effectIndex = 0; effectIndex < 12; ++effectIndex) { + for (int effectIndex = 0; effectIndex < EFFECT_COUNT; ++effectIndex) { if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Charm) { buffs[index].spellid = SPELL_UNKNOWN; From 0ab729162594d03841a4b5ea6c3d2e6fc8b2dc10 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 19 Mar 2020 16:43:16 -0400 Subject: [PATCH 26/84] Add countitem(item_id) to Perl/Lua. --- zone/embparser_api.cpp | 14 ++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 26 ++++++++++++++++++++++++++ zone/questmgr.h | 1 + 4 files changed, 46 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index efdc09803..cf55925b8 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2797,6 +2797,19 @@ XS(XS__collectitems) { XSRETURN_IV(quantity); } +XS(XS__countitem); +XS(XS__countitem) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::countitem(int item_id)"); + + uint32 item_id = (int) SvIV(ST(0)); + + int quantity = quest_manager.countitem(item_id); + + XSRETURN_IV(quantity); +} + XS(XS__UpdateSpawnTimer); XS(XS__UpdateSpawnTimer) { dXSARGS; @@ -3951,6 +3964,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "clearspawntimers"), XS__clearspawntimers, file); newXS(strcpy(buf, "collectitems"), XS__collectitems, file); newXS(strcpy(buf, "completedtasksinset"), XS__completedtasksinset, file); + newXS(strcpy(buf, "countitem"), XS__countitem, file); newXS(strcpy(buf, "createdoor"), XS__CreateDoor, file); newXS(strcpy(buf, "creategroundobject"), XS__CreateGroundObject, file); newXS(strcpy(buf, "creategroundobjectfrommodel"), XS__CreateGroundObjectFromModel, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 69e262199..9367cef21 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -781,6 +781,10 @@ int lua_collect_items(uint32 item_id, bool remove) { return quest_manager.collectitems(item_id, remove); } +int lua_count_item(uint32 item_id) { + return quest_manager.countitem(item_id); +} + void lua_update_spawn_timer(uint32 id, uint32 new_time) { quest_manager.UpdateSpawnTimer(id, new_time); } @@ -1724,6 +1728,7 @@ luabind::scope lua_register_general() { luabind::def("create_door", &lua_create_door), luabind::def("modify_npc_stat", &lua_modify_npc_stat), luabind::def("collect_items", &lua_collect_items), + luabind::def("count_item", &lua_count_item), luabind::def("update_spawn_timer", &lua_update_spawn_timer), luabind::def("merchant_set_item", (void(*)(uint32,uint32))&lua_merchant_set_item), luabind::def("merchant_set_item", (void(*)(uint32,uint32,uint32))&lua_merchant_set_item), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 033b42f1a..0c36b876a 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2580,6 +2580,32 @@ int QuestManager::collectitems(uint32 item_id, bool remove) return quantity; } +int QuestManager::countitem(uint32 item_id) { + QuestManagerCurrentQuestVars(); + int quantity = 0; + EQEmu::ItemInstance *item = nullptr; + static const int16 slots[][2] = { + { EQEmu::invslot::POSSESSIONS_BEGIN, EQEmu::invslot::POSSESSIONS_END }, + { EQEmu::invbag::GENERAL_BAGS_BEGIN, EQEmu::invbag::GENERAL_BAGS_END }, + { EQEmu::invbag::CURSOR_BAG_BEGIN, EQEmu::invbag::CURSOR_BAG_END}, + { EQEmu::invslot::BANK_BEGIN, EQEmu::invslot::BANK_END }, + { EQEmu::invbag::BANK_BAGS_BEGIN, EQEmu::invbag::BANK_BAGS_END }, + { EQEmu::invslot::SHARED_BANK_BEGIN, EQEmu::invslot::SHARED_BANK_END }, + { EQEmu::invbag::SHARED_BANK_BAGS_BEGIN, EQEmu::invbag::SHARED_BANK_BAGS_END }, + }; + const size_t size = sizeof(slots) / sizeof(slots[0]); + for (int slot_index = 0; slot_index < size; ++slot_index) { + for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) { + item = initiator->GetInv().GetItem(slot_id); + if (item && item->GetID() == item_id) { + quantity += item->IsStackable() ? item->GetCharges() : 1; + } + } + } + + return quantity; +} + void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime) { bool found = false; diff --git a/zone/questmgr.h b/zone/questmgr.h index 2aa1df109..21d5b5db1 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -219,6 +219,7 @@ public: int getlevel(uint8 type); int collectitems(uint32 item_id, bool remove); int collectitems_processSlot(int16 slot_id, uint32 item_id, bool remove); + int countitem(uint32 item_id); void enabletitle(int titleset); bool checktitle(int titlecheck); void removetitle(int titlecheck); From e431c56f7c432a0171cfc847ce40ec904066804d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 21 Mar 2020 18:41:36 -0500 Subject: [PATCH 27/84] Remove tables that no longer exist --- .../sql/git/required/2020_03_09_convert_myisam_to_innodb.sql | 4 ---- 1 file changed, 4 deletions(-) diff --git a/utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql b/utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql index ec9f6607b..31ccf1094 100644 --- a/utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql +++ b/utils/sql/git/required/2020_03_09_convert_myisam_to_innodb.sql @@ -1,7 +1,3 @@ -ALTER TABLE `aa_actions` ENGINE=InnoDB; -ALTER TABLE `aa_effects` ENGINE=InnoDB; -ALTER TABLE `aa_required_level_cost` ENGINE=InnoDB; -ALTER TABLE `aa_timers` ENGINE=InnoDB; ALTER TABLE `account_flags` ENGINE=InnoDB; ALTER TABLE `account_ip` ENGINE=InnoDB; ALTER TABLE `account` ENGINE=InnoDB; From 52d2469da291184039beaf0923358765312d2068 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 21 Mar 2020 17:05:28 -0700 Subject: [PATCH 28/84] Rewrite how zone finds ports --- common/event/event_loop.h | 4 ++++ world/main.cpp | 1 + world/zonelist.cpp | 41 ++++++++++++++++++--------------------- world/zonelist.h | 5 +++-- zone/main.cpp | 19 +++++++++--------- zone/worldserver.cpp | 15 ++++++++++---- 6 files changed, 47 insertions(+), 38 deletions(-) diff --git a/common/event/event_loop.h b/common/event/event_loop.h index 295c0532d..537c3280a 100644 --- a/common/event/event_loop.h +++ b/common/event/event_loop.h @@ -25,6 +25,10 @@ namespace EQ uv_run(&m_loop, UV_RUN_DEFAULT); } + void Shutdown() { + uv_stop(&m_loop); + } + uv_loop_t* Handle() { return &m_loop; } private: diff --git a/world/main.cpp b/world/main.cpp index 72cc6d391..9aac1a903 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -415,6 +415,7 @@ int main(int argc, char** argv) { RegisterConsoleFunctions(console); } + zoneserver_list.Init(); std::unique_ptr server_connection; server_connection.reset(new EQ::Net::ServertalkServer()); diff --git a/world/zonelist.cpp b/world/zonelist.cpp index abb2a5f6f..7f898f89c 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -39,7 +39,6 @@ ZSList::ZSList() { NextID = 1; CurGroupID = 1; - LastAllocatedPort = 0; memset(pLockedZones, 0, sizeof(pLockedZones)); m_tick.reset(new EQ::Timer(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1))); @@ -76,7 +75,12 @@ void ZSList::Remove(const std::string &uuid) auto iter = zone_server_list.begin(); while (iter != zone_server_list.end()) { if ((*iter)->GetUUID().compare(uuid) == 0) { + auto port = (*iter)->GetCPort(); zone_server_list.erase(iter); + + if (port != 0) { + m_ports_free.push_back(port); + } return; } iter++; @@ -239,6 +243,14 @@ bool ZSList::SetLockedZone(uint16 iZoneID, bool iLock) { return false; } +void ZSList::Init() +{ + const WorldConfig* Config = WorldConfig::get(); + for (uint16 i = Config->ZonePortLow; i <= Config->ZonePortHigh; ++i) { + m_ports_free.push_back(i); + } +} + bool ZSList::IsZoneLocked(uint16 iZoneID) { for (auto &zone : pLockedZones) { if (zone == iZoneID) @@ -577,30 +589,15 @@ void ZSList::RebootZone(const char* ip1, uint16 port, const char* ip2, uint32 sk safe_delete_array(tmp); } -uint16 ZSList::GetAvailableZonePort() +uint16 ZSList::GetAvailableZonePort() { - const WorldConfig *Config = WorldConfig::get(); - int i; - uint16 port = 0; - - if (LastAllocatedPort == 0) - i = Config->ZonePortLow; - else - i = LastAllocatedPort + 1; - - while (i != LastAllocatedPort && port == 0) { - if (i>Config->ZonePortHigh) - i = Config->ZonePortLow; - - if (!FindByPort(i)) { - port = i; - break; - } - i++; + if (m_ports_free.empty()) { + return 0; } - LastAllocatedPort = port; - return port; + auto first = m_ports_free.front(); + m_ports_free.pop_front(); + return first; } uint32 ZSList::TriggerBootup(uint32 iZoneID, uint32 iInstanceID) { diff --git a/world/zonelist.h b/world/zonelist.h index 8b8525f57..5066d4e6d 100644 --- a/world/zonelist.h +++ b/world/zonelist.h @@ -7,6 +7,7 @@ #include "../common/event/timer.h" #include #include +#include class WorldTCPConnection; class ServerPacket; @@ -22,6 +23,7 @@ public: ZSList(); ~ZSList(); + void Init(); bool IsZoneLocked(uint16 iZoneID); bool SendPacket(ServerPacket *pack); bool SendPacket(uint32 zoneid, ServerPacket *pack); @@ -73,8 +75,7 @@ private: uint32 NextID; uint16 pLockedZones[MaxLockedZones]; uint32 CurGroupID; - uint16 LastAllocatedPort; - + std::deque m_ports_free; std::unique_ptr m_tick; std::unique_ptr m_keepalive; diff --git a/zone/main.cpp b/zone/main.cpp index 6d3eee96c..0445534d4 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -92,7 +92,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../common/unix.h" #endif -volatile bool RunLoops = true; extern volatile bool is_zone_loaded; EntityList entity_list; @@ -577,19 +576,19 @@ int main(int argc, char** argv) { return 0; } +void Shutdown() +{ + Zone::Shutdown(true); + LogInfo("Shutting down..."); + LogSys.CloseFileLogs(); + EQ::EventLoop::Get().Shutdown(); +} + void CatchSignal(int sig_num) { #ifdef _WINDOWS LogInfo("Recieved signal: [{}]", sig_num); #endif - RunLoops = false; -} - -void Shutdown() -{ - Zone::Shutdown(true); - RunLoops = false; - LogInfo("Shutting down..."); - LogSys.CloseFileLogs(); + Shutdown(); } /* Update Window Title with relevant information */ diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 60f770c92..87cfb13ef 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -57,7 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA extern EntityList entity_list; extern Zone* zone; extern volatile bool is_zone_loaded; -extern void CatchSignal(int); +extern void Shutdown(); extern WorldServer worldserver; extern PetitionList petition_list; extern uint32 numclients; @@ -192,8 +192,15 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) if (pack->size != sizeof(ServerConnectInfo)) break; ServerConnectInfo* sci = (ServerConnectInfo*)pack->pBuffer; - LogInfo("World assigned Port: [{}] for this zone", sci->port); - ZoneConfig::SetZonePort(sci->port); + + if (sci->port == 0) { + LogCritical("World did not have a port to assign from this server, the port range was not large enough."); + Shutdown(); + } + else { + LogInfo("World assigned Port: [{}] for this zone", sci->port); + ZoneConfig::SetZonePort(sci->port); + } break; } case ServerOP_ChannelMessage: { @@ -482,7 +489,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_ShutdownAll: { entity_list.Save(); - CatchSignal(2); + Shutdown(); break; } case ServerOP_ZoneShutdown: { From 1cdf507b9fd475c13a9910bfb20dbfe7640c5f1a Mon Sep 17 00:00:00 2001 From: Ali Date: Tue, 24 Mar 2020 12:44:45 +0300 Subject: [PATCH 29/84] [ci skip] Enhanced .gitignore * Removes the generated files from both CMake and VS --- .gitignore | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 287c07412..b8ec6881f 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,19 @@ perl/ submodules/* cmake-build-debug/ -.nfs.* \ No newline at end of file +.nfs.* + +# Visual Studio and CMAKE Generated Files +/.vs/ +*.vcxproj +*.vcxproj.filters +*.vcxproj.user +*.cmake +*.ilk +*.pdb +*.sln +*.dir/ +libs/ +bin/ +/Win32 +/client_files/**/CMakeFiles/ From 60e194e32bb5af2049ff1900c408fa663e60ffef Mon Sep 17 00:00:00 2001 From: Ali Date: Tue, 24 Mar 2020 10:06:49 +0300 Subject: [PATCH 30/84] Fix double damaging spell messages to non-attacked and non-attacker With handling for client attacker and pets thanks to @noudess --- zone/spells.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 5b8ee33f8..2a129fb6b 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3426,6 +3426,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r bool isproc, int level_override) { + bool isDamageOrLifetapSpell = IsDamageSpell(spell_id) || IsLifetapSpell(spell_id); + // well we can't cast a spell on target without a target if(!spelltar) { @@ -3967,9 +3969,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r // send to people in the area, ignoring caster and target //live dosent send this to anybody but the caster //entity_list.QueueCloseClients(spelltar, action_packet, true, 200, this, true, spelltar->IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS); - - // TEMPORARY - this is the message for the spell. - // double message on effects that use ChangeHP - working on this message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer; cd->target = action->target; @@ -3980,7 +3979,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r cd->hit_heading = action->hit_heading; cd->hit_pitch = action->hit_pitch; cd->damage = 0; - if(!IsEffectInSpell(spell_id, SE_BindAffinity)){ + if(!IsEffectInSpell(spell_id, SE_BindAffinity) && !isDamageOrLifetapSpell){ entity_list.QueueCloseClients( spelltar, /* Sender */ message_packet, /* Packet */ @@ -3990,6 +3989,19 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r true, /* Packet ACK */ (spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) /* Message Filter Type: (8 or 9) */ ); + } else if (isDamageOrLifetapSpell && + (IsClient() || + (HasOwner() && + GetOwner()->IsClient() + ) + ) + ) { + (HasOwner() ? GetOwner() : this)->CastToClient()->QueuePacket( + message_packet, + true, + Mob::CLIENT_CONNECTINGALL, + (spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) + ); } safe_delete(action_packet); safe_delete(message_packet); From a2b381bc9edf5886f536ba5e055544248bcc71ab Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 29 Mar 2020 16:34:07 -0400 Subject: [PATCH 31/84] Added command 'editmassrespawn' for mass editing of respawn times --- zone/command.cpp | 143 ++++++++++++++++++++++++++++++++++++++++++++++- zone/command.h | 1 + 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/zone/command.cpp b/zone/command.cpp index 757e2d522..23b269395 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -196,6 +196,7 @@ int command_init(void) command_add("disarmtrap", "Analog for ldon disarm trap for the newer clients since we still don't have it working.", 80, command_disarmtrap) || command_add("distance", "- Reports the distance between you and your target.", 80, command_distance) || command_add("doanim", "[animnum] [type] - Send an EmoteAnim for you or your target", 50, command_doanim) || + command_add("editmassrespawn", "[name-search] [second-value] - Mass (Zone wide) NPC respawn timer editing command", 100, command_editmassrespawn) || command_add("emote", "['name'/'world'/'zone'] [type] [message] - Send an emote message", 80, command_emote) || command_add("emotesearch", "Searches NPC Emotes", 80, command_emotesearch) || command_add("emoteview", "Lists all NPC Emotes", 80, command_emoteview) || @@ -6525,6 +6526,144 @@ void command_doanim(Client *c, const Seperator *sep) c->DoAnim(atoi(sep->arg[1]),atoi(sep->arg[2])); } +void command_editmassrespawn(Client* c, const Seperator* sep) +{ + if (strcasecmp(sep->arg[1], "usage") == 0) { + c->Message(Chat::White, "#editmassrespawn [exact_match: =]npc_type_name new_respawn_seconds (apply)"); + return; + } + + std::string search_npc_type; + if (sep->arg[1]) { + search_npc_type = sep->arg[1]; + } + + int change_respawn_seconds = 0; + if (sep->arg[2] && sep->IsNumber(2)) { + change_respawn_seconds = atoi(sep->arg[2]); + } + + bool change_apply = false; + if (sep->arg[3] && strcasecmp(sep->arg[3], "apply") == 0) { + change_apply = true; + } + + std::string search_encapsulator = "%"; + if (search_npc_type[0] == '=') { + + search_npc_type = search_npc_type.substr(1); + search_encapsulator = ""; + } + + std::string query = fmt::format( + SQL( + SELECT tc.id, ta.spawngroupID, ta.id, tc.name, ta.respawntime + FROM spawn2 ta + INNER JOIN spawnentry tb ON ta.spawngroupID = tb.spawngroupID + INNER JOIN npc_types tc ON tb.npcID = tc.id + WHERE ta.zone LIKE '{}' + AND ta.version = '{}' + AND tc.name LIKE '{}{}{}' + ORDER BY tc.id, ta.spawngroupID, ta.id + ), + zone->GetShortName(), + zone->GetInstanceVersion(), + search_encapsulator, + search_npc_type, + search_encapsulator + ); + + std::string status = "(Searching)"; + if (change_apply) { + status = "(Applying)"; + } + + int results_count = 0; + + auto results = database.QueryDatabase(query); + if (results.Success() && results.RowCount()) { + + results_count = results.RowCount(); + + for (auto row : results) { + c->Message( + Chat::Yellow, + fmt::format( + "NPC (npcid:{}) (sgid:{}) (s2id:{}) [{}] Respawn: Current [{}] New [{}] {}", + row[0], + row[1], + row[2], + row[3], + row[4], + change_respawn_seconds, + status + ).c_str() + ); + } + + c->Message(Chat::Yellow, "Found (%i) NPC's that match this search...", results_count); + + if (change_respawn_seconds > 0) { + + if (change_apply) { + + results = database.QueryDatabase( + fmt::format( + SQL( + UPDATE spawn2 + SET respawntime = '{}' + WHERE id IN ( + SELECT ta.id + FROM spawn2 ta + INNER JOIN spawnentry tb ON ta.spawngroupID = tb.spawngroupID + INNER JOIN npc_types tc ON tb.npcID = tc.id + WHERE ta.zone LIKE '{}' + AND ta.version = '{}' + AND tc.name LIKE '{}{}{}' + ) + ), + change_respawn_seconds, + zone->GetShortName(), + zone->GetInstanceVersion(), + search_encapsulator, + search_npc_type, + search_encapsulator + ) + ); + + if (results.Success()) { + + c->Message(Chat::Yellow, "Changes applied to (%i) NPC 'Spawn2' entries", results_count); + zone->Repop(); + } + else { + + c->Message(Chat::Yellow, "Found (0) NPC's that match this search..."); + } + } + else { + + std::string saylink = fmt::format( + "#editmassrespawn {}{} {} apply", + (search_encapsulator.empty() ? "=" : ""), + search_npc_type, + change_respawn_seconds + ); + + c->Message( + Chat::Yellow, "To apply these changes, click <%s> or type [%s]", + EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink, false, "Apply").c_str(), + saylink.c_str() + ); + } + } + } + else { + + c->Message(Chat::Yellow, "Found (0) NPC's that match this search..."); + } +} + void command_randomfeatures(Client *c, const Seperator *sep) { Mob *target=c->GetTarget(); @@ -7782,7 +7921,7 @@ void command_npcemote(Client *c, const Seperator *sep) void command_npceditmass(Client *c, const Seperator *sep) { if (strcasecmp(sep->arg[1], "usage") == 0) { - c->Message(Chat::White, "#npceditmass search_column [exact_match: =]search_value change_column change_value"); + c->Message(Chat::White, "#npceditmass search_column [exact_match: =]search_value change_column change_value (apply)"); return; } @@ -7930,7 +8069,7 @@ void command_npceditmass(Client *c, const Seperator *sep) std::string saylink = fmt::format( "#npceditmass {} {}{} {} {} apply", search_column, - (exact_match ? '=' : '\0'), + (exact_match ? "=" : ""), search_value, change_column, change_value diff --git a/zone/command.h b/zone/command.h index d64950f9c..7c1af0edf 100644 --- a/zone/command.h +++ b/zone/command.h @@ -91,6 +91,7 @@ void command_disablerecipe(Client *c, const Seperator *sep); void command_disarmtrap(Client *c, const Seperator *sep); void command_distance(Client *c, const Seperator *sep); void command_doanim(Client *c, const Seperator *sep); +void command_editmassrespawn(Client* c, const Seperator* sep); void command_emote(Client *c, const Seperator *sep); void command_emotesearch(Client* c, const Seperator *sep); void command_emoteview(Client* c, const Seperator *sep); From a48153baa1ec458d91642aec6cc0061698efb0f1 Mon Sep 17 00:00:00 2001 From: Ali Al-Khalifa Date: Mon, 30 Mar 2020 00:26:56 +0300 Subject: [PATCH 32/84] Fix errant formatting Mistakenly had a variable in camelCase --- zone/spells.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 2a129fb6b..be1419caa 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3426,7 +3426,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r bool isproc, int level_override) { - bool isDamageOrLifetapSpell = IsDamageSpell(spell_id) || IsLifetapSpell(spell_id); + bool is_damage_or_lifetap_spell = IsDamageSpell(spell_id) || IsLifetapSpell(spell_id); // well we can't cast a spell on target without a target if(!spelltar) @@ -3979,7 +3979,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r cd->hit_heading = action->hit_heading; cd->hit_pitch = action->hit_pitch; cd->damage = 0; - if(!IsEffectInSpell(spell_id, SE_BindAffinity) && !isDamageOrLifetapSpell){ + if(!IsEffectInSpell(spell_id, SE_BindAffinity) && !is_damage_or_lifetap_spell){ entity_list.QueueCloseClients( spelltar, /* Sender */ message_packet, /* Packet */ @@ -3989,7 +3989,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r true, /* Packet ACK */ (spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) /* Message Filter Type: (8 or 9) */ ); - } else if (isDamageOrLifetapSpell && + } else if (is_damage_or_lifetap_spell && (IsClient() || (HasOwner() && GetOwner()->IsClient() From b94fdda429de46d133560ef993d764af26ebec6b Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 29 Mar 2020 18:02:27 -0400 Subject: [PATCH 33/84] Updated command 'editmassrespawn' queries to use resolved names over aliases --- zone/command.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/zone/command.cpp b/zone/command.cpp index 23b269395..42453faab 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -6557,14 +6557,14 @@ void command_editmassrespawn(Client* c, const Seperator* sep) std::string query = fmt::format( SQL( - SELECT tc.id, ta.spawngroupID, ta.id, tc.name, ta.respawntime - FROM spawn2 ta - INNER JOIN spawnentry tb ON ta.spawngroupID = tb.spawngroupID - INNER JOIN npc_types tc ON tb.npcID = tc.id - WHERE ta.zone LIKE '{}' - AND ta.version = '{}' - AND tc.name LIKE '{}{}{}' - ORDER BY tc.id, ta.spawngroupID, ta.id + SELECT npc_types.id, spawn2.spawngroupID, spawn2.id, npc_types.name, spawn2.respawntime + FROM spawn2 + INNER JOIN spawnentry ON spawn2.spawngroupID = spawnentry.spawngroupID + INNER JOIN npc_types ON spawnentry.npcID = npc_types.id + WHERE spawn2.zone LIKE '{}' + AND spawn2.version = '{}' + AND npc_types.name LIKE '{}{}{}' + ORDER BY npc_types.id, spawn2.spawngroupID, spawn2.id ), zone->GetShortName(), zone->GetInstanceVersion(), @@ -6613,13 +6613,13 @@ void command_editmassrespawn(Client* c, const Seperator* sep) UPDATE spawn2 SET respawntime = '{}' WHERE id IN ( - SELECT ta.id - FROM spawn2 ta - INNER JOIN spawnentry tb ON ta.spawngroupID = tb.spawngroupID - INNER JOIN npc_types tc ON tb.npcID = tc.id - WHERE ta.zone LIKE '{}' - AND ta.version = '{}' - AND tc.name LIKE '{}{}{}' + SELECT spawn2.id + FROM spawn2 + INNER JOIN spawnentry ON spawn2.spawngroupID = spawnentry.spawngroupID + INNER JOIN npc_types ON spawnentry.npcID = npc_types.id + WHERE spawn2.zone LIKE '{}' + AND spawn2.version = '{}' + AND npc_types.name LIKE '{}{}{}' ) ), change_respawn_seconds, From 99c1c826a8acbe7d4820632257ef7d5a357642fa Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 30 Mar 2020 08:02:45 -0400 Subject: [PATCH 34/84] Fix for bots guild-related view query issue --- common/version.h | 2 +- .../sql/git/bots/bots_db_update_manifest.txt | 1 + .../required/2020_03_30_bots_view_update.sql | 24 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 utils/sql/git/bots/required/2020_03_30_bots_view_update.sql diff --git a/common/version.h b/common/version.h index 99261fe83..7c378e763 100644 --- a/common/version.h +++ b/common/version.h @@ -37,7 +37,7 @@ #define CURRENT_BINARY_DATABASE_VERSION 9152 #ifdef BOTS - #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9026 + #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027 #else #define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0 #endif diff --git a/utils/sql/git/bots/bots_db_update_manifest.txt b/utils/sql/git/bots/bots_db_update_manifest.txt index 1e18516b7..86e7c49dd 100644 --- a/utils/sql/git/bots/bots_db_update_manifest.txt +++ b/utils/sql/git/bots/bots_db_update_manifest.txt @@ -25,6 +25,7 @@ 9024|2019_06_27_bots_pet_get_lost.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'petgetlost'|empty| 9025|2019_08_26_bots_owner_option_spawn_message.sql|SELECT * FROM db_version WHERE bots_version >= 9025|empty| 9026|2019_09_09_bots_owner_options_rework.sql|SHOW COLUMNS FROM `bot_owner_options` LIKE 'option_type'|empty| +9027|2020_03_30_bots_view_update.sql|SELECT * FROM db_version WHERE bots_version >= 9027|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/bots/required/2020_03_30_bots_view_update.sql b/utils/sql/git/bots/required/2020_03_30_bots_view_update.sql new file mode 100644 index 000000000..d4948efed --- /dev/null +++ b/utils/sql/git/bots/required/2020_03_30_bots_view_update.sql @@ -0,0 +1,24 @@ +DROP VIEW IF EXISTS `vw_bot_character_mobs`; + +-- Views +CREATE VIEW `vw_bot_character_mobs` AS +SELECT +_utf8'C' AS mob_type, +c.`id`, +c.`name`, +c.`class`, +c.`level`, +c.`last_login`, +c.`zone_id`, +c.`deleted_at` +FROM `character_data` AS c +UNION ALL +SELECT _utf8'B' AS mob_type, +b.`bot_id` AS id, +b.`name`, +b.`class`, +b.`level`, +b.`last_spawn` AS last_login, +b.`zone_id`, +NULL AS `deleted_at` +FROM `bot_data` AS b; From 3a7908b1de0da73f3a844c3a81f7525d04808aaa Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 30 Mar 2020 16:45:50 -0400 Subject: [PATCH 35/84] Fix for bots database updates not running when invoked from world.exe [skip ci] --- utils/scripts/eqemu_server.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl index 3c8663273..6618b021e 100755 --- a/utils/scripts/eqemu_server.pl +++ b/utils/scripts/eqemu_server.pl @@ -537,7 +537,10 @@ sub check_for_world_bootup_database_update { if ($binary_database_version == $local_database_version && $ARGV[0] eq "ran_from_world") { print "[Update] Database up to date...\n"; - exit; + if (trim($db_version[2]) == 0) { + print "[Update] Continuing bootup\n"; + exit; + } } else { #::: We ran world - Database needs to update, lets backup and run updates and continue world bootup From d4ea9bbee06a05cf4a8fbbb3025a721e5357a0bb Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 31 Mar 2020 02:00:09 -0500 Subject: [PATCH 36/84] Use a better name generator --- common/CMakeLists.txt | 2 + common/namegenerator/namegen.cpp | 536 +++++++++++++++++++++++++++++++ common/namegenerator/namegen.h | 269 ++++++++++++++++ world/client.cpp | 81 +---- 4 files changed, 815 insertions(+), 73 deletions(-) create mode 100644 common/namegenerator/namegen.cpp create mode 100644 common/namegenerator/namegen.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e312c202d..57f000ccb 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -77,6 +77,7 @@ SET(common_sources unix.cpp platform.cpp json/jsoncpp.cpp + namegenerator/namegen.cpp net/console_server.cpp net/console_server_connection.cpp net/crc32.cpp @@ -221,6 +222,7 @@ SET(common_headers event/timer.h json/json.h json/json-forwards.h + namegenerator/namegen.h net/console_server.h net/console_server_connection.h net/crc32.h diff --git a/common/namegenerator/namegen.cpp b/common/namegenerator/namegen.cpp new file mode 100644 index 000000000..fa632c844 --- /dev/null +++ b/common/namegenerator/namegen.cpp @@ -0,0 +1,536 @@ +/** + * + * @file A fantasy name generator library. + * @version 1.0.1 + * @license Public Domain + * @author German M. Bravo (Kronuz) + * + */ + +#include "namegen.h" + +#include // for move, reverse +#include // for rng seed +#include // for size_t, mbsrtowcs, wcsrtombs +#include // for towupper +#include // for make_unique +#include // for mt19937, uniform_real_distribution +#include // for invalid_argument, out_of_range + + +using namespace NameGen; + + +static std::mt19937 rng(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + + +// https://isocpp.org/wiki/faq/ctors#static-init-order +// Avoid the "static initialization order fiasco" +const std::unordered_map>& Generator::SymbolMap() +{ + static auto* const symbols = new std::unordered_map>({ + { + "s", { + "ach", "ack", "ad", "age", "ald", "ale", "an", "ang", "ar", "ard", + "as", "ash", "at", "ath", "augh", "aw", "ban", "bel", "bur", "cer", + "cha", "che", "dan", "dar", "del", "den", "dra", "dyn", "ech", "eld", + "elm", "em", "en", "end", "eng", "enth", "er", "ess", "est", "et", + "gar", "gha", "hat", "hin", "hon", "ia", "ight", "ild", "im", "ina", + "ine", "ing", "ir", "is", "iss", "it", "kal", "kel", "kim", "kin", + "ler", "lor", "lye", "mor", "mos", "nal", "ny", "nys", "old", "om", + "on", "or", "orm", "os", "ough", "per", "pol", "qua", "que", "rad", + "rak", "ran", "ray", "ril", "ris", "rod", "roth", "ryn", "sam", + "say", "ser", "shy", "skel", "sul", "tai", "tan", "tas", "ther", + "tia", "tin", "ton", "tor", "tur", "um", "und", "unt", "urn", "usk", + "ust", "ver", "ves", "vor", "war", "wor", "yer" + } + }, + { + "v", { + "a", "e", "i", "o", "u", "y" + } + }, + { + "V", { + "a", "e", "i", "o", "u", "y", "ae", "ai", "au", "ay", "ea", "ee", + "ei", "eu", "ey", "ia", "ie", "oe", "oi", "oo", "ou", "ui" + } + }, + { + "c", { + "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", + "s", "t", "v", "w", "x", "y", "z" + } + }, + { + "B", { + "b", "bl", "br", "c", "ch", "chr", "cl", "cr", "d", "dr", "f", "g", + "h", "j", "k", "l", "ll", "m", "n", "p", "ph", "qu", "r", "rh", "s", + "sch", "sh", "sl", "sm", "sn", "st", "str", "sw", "t", "th", "thr", + "tr", "v", "w", "wh", "y", "z", "zh" + } + }, + { + "C", { + "b", "c", "ch", "ck", "d", "f", "g", "gh", "h", "k", "l", "ld", "ll", + "lt", "m", "n", "nd", "nn", "nt", "p", "ph", "q", "r", "rd", "rr", + "rt", "s", "sh", "ss", "st", "t", "th", "v", "w", "y", "z" + } + }, + { + "i", { + "air", "ankle", "ball", "beef", "bone", "bum", "bumble", "bump", + "cheese", "clod", "clot", "clown", "corn", "dip", "dolt", "doof", + "dork", "dumb", "face", "finger", "foot", "fumble", "goof", + "grumble", "head", "knock", "knocker", "knuckle", "loaf", "lump", + "lunk", "meat", "muck", "munch", "nit", "numb", "pin", "puff", + "skull", "snark", "sneeze", "thimble", "twerp", "twit", "wad", + "wimp", "wipe" + } + }, + { + "m", { + "baby", "booble", "bunker", "cuddle", "cuddly", "cutie", "doodle", + "foofie", "gooble", "honey", "kissie", "lover", "lovey", "moofie", + "mooglie", "moopie", "moopsie", "nookum", "poochie", "poof", + "poofie", "pookie", "schmoopie", "schnoogle", "schnookie", + "schnookum", "smooch", "smoochie", "smoosh", "snoogle", "snoogy", + "snookie", "snookum", "snuggy", "sweetie", "woogle", "woogy", + "wookie", "wookum", "wuddle", "wuddly", "wuggy", "wunny" + } + }, + { + "M", { + "boo", "bunch", "bunny", "cake", "cakes", "cute", "darling", + "dumpling", "dumplings", "face", "foof", "goo", "head", "kin", + "kins", "lips", "love", "mush", "pie", "poo", "pooh", "pook", "pums" + } + }, + { + "D", { + "b", "bl", "br", "cl", "d", "f", "fl", "fr", "g", "gh", "gl", "gr", + "h", "j", "k", "kl", "m", "n", "p", "th", "w" + } + }, + { + "d", { + "elch", "idiot", "ob", "og", "ok", "olph", "olt", "omph", "ong", + "onk", "oo", "oob", "oof", "oog", "ook", "ooz", "org", "ork", "orm", + "oron", "ub", "uck", "ug", "ulf", "ult", "um", "umb", "ump", "umph", + "un", "unb", "ung", "unk", "unph", "unt", "uzz" + } + } + }); + + return *symbols; +} + + +#ifdef HAVE_CXX14 +using std::make_unique; +#else +// make_unique is not available in c++11, so we use this template function +// to maintain full c++11 compatibility; std::make_unique is part of C++14. +template +std::unique_ptr make_unique(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} +#endif + + +Generator::Generator() +{ +} + + +Generator::Generator(std::vector>&& generators_) : + generators(std::move(generators_)) +{ +} + + +size_t Generator::combinations() +{ + size_t total = 1; + for (auto& g : generators) { + total *= g->combinations(); + } + return total; +} + + +size_t Generator::min() +{ + size_t final = 0; + for (auto& g : generators) { + final += g->min(); + } + return final; +} + + +size_t Generator::max() +{ + size_t final = 0; + for (auto& g : generators) { + final += g->max(); + } + return final; +} + + +std::string Generator::toString() { + std::string str; + for (auto& g : generators) { + str.append(g->toString()); + } + return str; +} + + +void Generator::add(std::unique_ptr&& g) +{ + generators.push_back(std::move(g)); +} + + +Random::Random() +{ +} + +Random::Random(std::vector>&& generators_) : + Generator(std::move(generators_)) +{ +} + +size_t Random::combinations() +{ + size_t total = 0; + for (auto& g : generators) { + total += g->combinations(); + } + return total ? total : 1; +} + +size_t Random::min() +{ + size_t final = -1; + for (auto& g : generators) { + size_t current = g->min(); + if (current < final) { + final = current; + } + } + return final; +} + +size_t Random::max() +{ + size_t final = 0; + for (auto& g : generators) { + size_t current = g->max(); + if (current > final) { + final = current; + } + } + return final; +} + + +std::string Random::toString() +{ + if (!generators.size()) { + return ""; + } + std::uniform_real_distribution distribution(0, generators.size() - 1); + int rnd = distribution(rng) + 0.5; + return generators[rnd]->toString(); +} + + +Sequence::Sequence() +{ +} + +Sequence::Sequence(std::vector>&& generators_) : + Generator(std::move(generators_)) +{ +} + +Literal::Literal(const std::string &value_) : + value(value_) +{ +} + +size_t Literal::combinations() +{ + return 1; +} + +size_t Literal::min() +{ + return value.size(); +} + +size_t Literal::max() +{ + return value.size(); +} + +std::string Literal::toString() +{ + return value; +} + +Reverser::Reverser(std::unique_ptr&& g) +{ + add(std::move(g)); +} + + +std::string Reverser::toString() +{ + std::wstring str = towstring(Generator::toString()); + std::reverse(str.begin(), str.end()); + return tostring(str); +} + +Capitalizer::Capitalizer(std::unique_ptr&& g) +{ + add(std::move(g)); +} + +std::string Capitalizer::toString() +{ + std::wstring str = towstring(Generator::toString()); + str[0] = std::towupper(str[0]); + return tostring(str); +} + + +Collapser::Collapser(std::unique_ptr&& g) +{ + add(std::move(g)); +} + +std::string Collapser::toString() +{ + std::wstring str = towstring(Generator::toString()); + std::wstring out; + int cnt = 0; + wchar_t pch = L'\0'; + for (auto ch : str) { + if (ch == pch) { + cnt++; + } else { + cnt = 0; + } + int mch = 2; + switch(ch) { + case 'a': + case 'h': + case 'i': + case 'j': + case 'q': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + mch = 1; + } + if (cnt < mch) { + out.push_back(ch); + } + pch = ch; + } + return tostring(out); +} + + +Generator::Generator(const std::string &pattern, bool collapse_triples) { + std::unique_ptr last; + + std::stack> stack; + std::unique_ptr top = make_unique(); + + for (auto c : pattern) { + switch (c) { + case '<': + stack.push(std::move(top)); + top = make_unique(); + break; + case '(': + stack.push(std::move(top)); + top = make_unique(); + break; + case '>': + case ')': + if (stack.size() == 0) { + throw std::invalid_argument("Unbalanced brackets"); + } else if (c == '>' && top->type != group_types::symbol) { + throw std::invalid_argument("Unexpected '>' in pattern"); + } else if (c == ')' && top->type != group_types::literal) { + throw std::invalid_argument("Unexpected ')' in pattern"); + } + last = top->produce(); + top = std::move(stack.top()); + stack.pop(); + top->add(std::move(last)); + break; + case '|': + top->split(); + break; + case '!': + if (top->type == group_types::symbol) { + top->wrap(wrappers::capitalizer); + } else { + top->add(c); + } + break; + case '~': + if (top->type == group_types::symbol) { + top->wrap(wrappers::reverser); + } else { + top->add(c); + } + break; + default: + top->add(c); + break; + } + } + + if (stack.size() != 0) { + throw std::invalid_argument("Missing closing bracket"); + } + + std::unique_ptr g = top->produce(); + if (collapse_triples) { + g = make_unique(std::move(g)); + } + add(std::move(g)); +} + + +Generator::Group::Group(group_types_t type_) : + type(type_) +{ +} + +void Generator::Group::add(std::unique_ptr&& g) +{ + while (!wrappers.empty()) { + switch (wrappers.top()) { + case reverser: + g = make_unique(std::move(g)); + break; + case capitalizer: + g = make_unique(std::move(g)); + break; + } + wrappers.pop(); + } + if (set.size() == 0) { + set.push_back(make_unique()); + } + set.back()->add(std::move(g)); +} + +void Generator::Group::add(char c) +{ + std::string value(1, c); + std::unique_ptr g = make_unique(); + g->add(make_unique(value)); + Group::add(std::move(g)); +} + +std::unique_ptr Generator::Group::produce() +{ + switch (set.size()) { + case 0: + return make_unique(""); + case 1: + return std::move(*set.begin()); + default: + return make_unique(std::move(set)); + } +} + +void Generator::Group::split() +{ + if (set.size() == 0) { + set.push_back(make_unique()); + } + set.push_back(make_unique()); +} + +void Generator::Group::wrap(wrappers_t type) +{ + wrappers.push(type); +} + +Generator::GroupSymbol::GroupSymbol() : + Group(group_types::symbol) +{ +} + +void Generator::GroupSymbol::add(char c) +{ + std::string value(1, c); + std::unique_ptr g = make_unique(); + try { + static const auto& symbols = SymbolMap(); + for (const auto& s : symbols.at(value)) { + g->add(make_unique(s)); + } + } catch (const std::out_of_range&) { + g->add(make_unique(value)); + } + Group::add(std::move(g)); +} + +Generator::GroupLiteral::GroupLiteral() : + Group(group_types::literal) +{ +} + +std::wstring towstring(const std::string & s) +{ + const char *cs = s.c_str(); + const size_t wn = std::mbsrtowcs(nullptr, &cs, 0, nullptr); + + if (wn == static_cast(-1)) { + return L""; + } + + std::vector buf(wn); + cs = s.c_str(); + const size_t wn_again = std::mbsrtowcs(buf.data(), &cs, wn, nullptr); + + if (wn_again == static_cast(-1)) { + return L""; + } + + return std::wstring(buf.data(), wn); +} + +std::string tostring(const std::wstring & s) +{ + const wchar_t *cs = s.c_str(); + const size_t wn = std::wcsrtombs(nullptr, &cs, 0, nullptr); + + if (wn == static_cast(-1)) { + return ""; + } + + std::vector buf(wn); + const size_t wn_again = std::wcsrtombs(buf.data(), &cs, wn, nullptr); + + if (wn_again == static_cast(-1)) { + return ""; + } + + return std::string(buf.data(), wn); +} \ No newline at end of file diff --git a/common/namegenerator/namegen.h b/common/namegenerator/namegen.h new file mode 100644 index 000000000..4ddcf1bf5 --- /dev/null +++ b/common/namegenerator/namegen.h @@ -0,0 +1,269 @@ +/** + * + * @file A fantasy name generator library. + * @version 1.0.1 + * @license Public Domain + * @author German M. Bravo (Kronuz) + * + * This library is designed after the RinkWorks Fantasy Name Generator. + * @see http://www.rinkworks.com/namegen/ + * + * @example + * NameGen::Generator generator("sV'i"); + * generator.toString(); // Returns a new name each call with produce() + * // => "entheu'loaf" + * + * ## Pattern Syntax + * + * The compile() function creates a name generator based on an input + * pattern. The letters s, v, V, c, B, C, i, m, M, D, and d represent + * different types of random replacements. Everything else is produced + * literally. + * + * s - generic syllable + * v - vowel + * V - vowel or vowel combination + * c - consonant + * B - consonant or consonant combination suitable for beginning a word + * C - consonant or consonant combination suitable anywhere in a word + * i - insult + * m - mushy name + * M - mushy name ending + * D - consonant suited for a stupid person's name + * d - syllable suited for a stupid person's name (begins with a vowel) + * + * All characters between parenthesis () are produced literally. For + * example, the pattern "s(dim)", produces a random generic syllable + * followed by "dim". + * + * Characters between angle brackets <> produce patterns from the table + * above. Imagine the entire pattern is wrapped in one of these. + * + * In both types of groupings, a vertical bar | denotes a random + * choice. Empty groups are allowed. For example, "(foo|bar)" produces + * either "foo" or "bar". The pattern "" produces a constant, + * vowel, or nothing at all. + * + * An exclamation point ! means to capitalize the component that + * follows it. For example, "!(foo)" will produce "Foo" and "v!s" will + * produce a lowercase vowel followed by a capitalized syllable, like + * "eRod". + * + * A tilde ~ means to reverse the letters of the component that + * follows it. For example, "~(foo)" will produce "oof". To reverse an + * entire template, wrap it in brackets. For example, to reverse + * "sV'i" as a whole use "~". The template "~sV'i" will only + * reverse the initial syllable. + * + * ## Internals + * + * A name generator is anything with a toString() method, including, + * importantly, strings themselves. The generator constructors + * (Random, Sequence) perform additional optimizations when *not* used + * with the `new` keyword: they may pass through a provided generator, + * combine provided generators, or even return a simple string. + * + * New pattern symbols added to Generator.symbols will automatically + * be used by the compiler. + */ + +#pragma once + +#include // for size_t +#include // for wstring +#include // for unique_ptr +#include // for stack +#include // for string +#include // for unordered_map +#include // for vector + + +namespace NameGen { + +// Middle Earth +#define MIDDLE_EARTH "(bil|bal|ban|hil|ham|hal|hol|hob|wil|me|or|ol|od|gor|for|fos|tol|ar|fin|ere|leo|vi|bi|bren|thor)(|go|orbis|apol|adur|mos|ri|i|na|ole|n)(|tur|axia|and|bo|gil|bin|bras|las|mac|grim|wise|l|lo|fo|co|ra|via|da|ne|ta|y|wen|thiel|phin|dir|dor|tor|rod|on|rdo|dis)" + +// Japanese Names (Constrained) +#define JAPANESE_NAMES_CONSTRAINED "(aka|aki|bashi|gawa|kawa|furu|fuku|fuji|hana|hara|haru|hashi|hira|hon|hoshi|ichi|iwa|kami|kawa|ki|kita|kuchi|kuro|marui|matsu|miya|mori|moto|mura|nabe|naka|nishi|no|da|ta|o|oo|oka|saka|saki|sawa|shita|shima|i|suzu|taka|take|to|toku|toyo|ue|wa|wara|wata|yama|yoshi|kei|ko|zawa|zen|sen|ao|gin|kin|ken|shiro|zaki|yuki|asa)(||||||||||bashi|gawa|kawa|furu|fuku|fuji|hana|hara|haru|hashi|hira|hon|hoshi|chi|wa|ka|kami|kawa|ki|kita|kuchi|kuro|marui|matsu|miya|mori|moto|mura|nabe|naka|nishi|no|da|ta|o|oo|oka|saka|saki|sawa|shita|shima|suzu|taka|take|to|toku|toyo|ue|wa|wara|wata|yama|yoshi|kei|ko|zawa|zen|sen|ao|gin|kin|ken|shiro|zaki|yuki|sa)" + +// Japanese Names (Diverse) +#define JAPANESE_NAMES_DIVERSE "(a|i|u|e|o|||||)(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)))(|||n)" + +// Chinese Names +#define CHINESE_NAMES "(zh|x|q|sh|h)(ao|ian|uo|ou|ia)(|(l|w|c|p|b|m)(ao|ian|uo|ou|ia)(|n)|-(l|w|c|p|b|m)(ao|ian|uo|ou|ia)(|(d|j|q|l)(a|ai|iu|ao|i)))" + +// Greek Names +#define GREEK_NAMES "(tia)|s(os)|Bc(ios)|Bv(ios|os)>" + +// Hawaiian Names (1) +#define HAWAIIAN_NAMES_1 "((h|k|l|m|n|p|w|')|)(a|e|i|o|u)((h|k|l|m|n|p|w|')|)(a|e|i|o|u)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)" + +// Hawaiian Names (2) +#define HAWAIIAN_NAMES_2 "((h|k|l|m|n|p|w|)(a|e|i|o|u|a'|e'|i'|o'|u'|ae|ai|ao|au|oi|ou|eu|ei)(k|l|m|n|p|)|)(h|k|l|m|n|p|w|)(a|e|i|o|u|a'|e'|i'|o'|u'|ae|ai|ao|au|oi|ou|eu|ei)(k|l|m|n|p|)" + +// Old Latin Place Names +#define OLD_LATIN_PLACE_NAMES "sv(nia|lia|cia|sia)" + +// Dragons (Pern) +#define DRAGONS_PERN "<|>>(th)" + +// Dragon Riders +#define DRAGON_RIDERS "c'" + +// Pokemon +#define POKEMON "v(mon|chu|zard|rtle)" + +// Fantasy (Vowels, R, etc.) +#define FANTASY_VOWELS_R "(|(|s|h|ty|ph|r))(i|ae|ya|ae|eu|ia|i|eo|ai|a)(lo|la|sri|da|dai|the|sty|lae|due|li|lly|ri|na|ral|sur|rith)(|(su|nu|sti|llo|ria|))(|(n|ra|p|m|lis|cal|deu|dil|suir|phos|ru|dru|rin|raap|rgue))" + +// Fantasy (S, A, etc.) +#define FANTASY_S_A "(cham|chan|jisk|lis|frich|isk|lass|mind|sond|sund|ass|chad|lirt|und|mar|lis|il|)(jask|ast|ista|adar|irra|im|ossa|assa|osia|ilsa|)(|(an|ya|la|sta|sda|sya|st|nya))" + +// Fantasy (H, L, etc.) +#define FANTASY_H_L "(ch|ch't|sh|cal|val|ell|har|shar|shal|rel|laen|ral|jh't|alr|ch|ch't|av)(|(is|al|ow|ish|ul|el|ar|iel))(aren|aeish|aith|even|adur|ulash|alith|atar|aia|erin|aera|ael|ira|iel|ahur|ishul)" + +// Fantasy (N, L, etc.) +#define FANTASY_N_L "(ethr|qil|mal|er|eal|far|fil|fir|ing|ind|il|lam|quel|quar|quan|qar|pal|mal|yar|um|ard|enn|ey)(|(|on|us|un|ar|as|en|ir|ur|at|ol|al|an))(uard|wen|arn|on|il|ie|on|iel|rion|rian|an|ista|rion|rian|cil|mol|yon)" + +// Fantasy (K, N, etc.) +#define FANTASY_K_N "(taith|kach|chak|kank|kjar|rak|kan|kaj|tach|rskal|kjol|jok|jor|jad|kot|kon|knir|kror|kol|tul|rhaok|rhak|krol|jan|kag|ryr)(|in|or|an|ar|och|un|mar|yk|ja|arn|ir|ros|ror)(|(mund|ard|arn|karr|chim|kos|rir|arl|kni|var|an|in|ir|a|i|as))" + +// Fantasy (J, G, Z, etc.) +#define FANTASY_J_G_Z "(aj|ch|etz|etzl|tz|kal|gahn|kab|aj|izl|ts|jaj|lan|kach|chaj|qaq|jol|ix|az|biq|nam)(|(|aw|al|yes|il|ay|en|tom||oj|im|ol|aj|an|as))(aj|am|al|aqa|ende|elja|ich|ak|ix|in|ak|al|il|ek|ij|os|al|im)" + +// Fantasy (K, J, Y, etc.) +#define FANTASY_K_J_Y "(yi|shu|a|be|na|chi|cha|cho|ksa|yi|shu)(th|dd|jj|sh|rr|mk|n|rk|y|jj|th)(us|ash|eni|akra|nai|ral|ect|are|el|urru|aja|al|uz|ict|arja|ichi|ural|iru|aki|esh)" + +// Fantasy (S, E, etc.) +#define FANTASY_S_E "(syth|sith|srr|sen|yth|ssen|then|fen|ssth|kel|syn|est|bess|inth|nen|tin|cor|sv|iss|ith|sen|slar|ssil|sthen|svis|s|ss|s|ss)(|(tys|eus|yn|of|es|en|ath|elth|al|ell|ka|ith|yrrl|is|isl|yr|ast|iy))(us|yn|en|ens|ra|rg|le|en|ith|ast|zon|in|yn|ys)" + + + class Generator + { + typedef enum wrappers { + capitalizer, + reverser + } wrappers_t; + + typedef enum group_types { + symbol, + literal + } group_types_t; + + + class Group { + std::stack wrappers; + std::vector> set; + + public: + group_types_t type; + + Group(group_types_t type_); + virtual ~Group() { } + + std::unique_ptr produce(); + void split(); + void wrap(wrappers_t type); + void add(std::unique_ptr&& g); + + virtual void add(char c); + }; + + + class GroupSymbol : public Group { + public: + GroupSymbol(); + void add(char c); + }; + + + class GroupLiteral : public Group { + public: + GroupLiteral(); + }; + + protected: + std::vector> generators; + + public: + static const std::unordered_map>& SymbolMap(); + + Generator(); + Generator(const std::string& pattern, bool collapse_triples=true); + Generator(std::vector>&& generators_); + + virtual ~Generator() = default; + + virtual size_t combinations(); + virtual size_t min(); + virtual size_t max(); + virtual std::string toString(); + + void add(std::unique_ptr&& g); + }; + + + class Random : public Generator + { + public: + Random(); + Random(std::vector>&& generators_); + + size_t combinations(); + size_t min(); + size_t max(); + std::string toString(); + }; + + + class Sequence : public Generator + { + public: + Sequence(); + Sequence(std::vector>&& generators_); + }; + + + class Literal : public Generator + { + std::string value; + + public: + Literal(const std::string& value_); + + size_t combinations(); + size_t min(); + size_t max(); + std::string toString(); + }; + + + class Reverser : public Generator { + public: + Reverser(std::unique_ptr&& g); + + std::string toString(); + }; + + + class Capitalizer : public Generator + { + public: + Capitalizer(std::unique_ptr&& g); + + std::string toString(); + }; + + + class Collapser : public Generator + { + public: + Collapser(std::unique_ptr&& g); + + std::string toString(); + }; + +} + +std::wstring towstring(const std::string& s); +std::string tostring(const std::wstring& s); \ No newline at end of file diff --git a/world/client.cpp b/world/client.cpp index 2d4b65e71..c4d1c6c70 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -46,6 +46,7 @@ #include "clientlist.h" #include "wguild_mgr.h" #include "sof_char_create_data.h" +#include "../common/namegenerator/namegen.h" #include #include @@ -533,80 +534,14 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) return true; } -bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) { - // creates up to a 10 char name - char vowels[18]="aeiouyaeiouaeioe"; - char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd"; - char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr"; - int rndnum=emu_random.Int(0, 75),n=1; - bool dlc=false; - bool vwl=false; - bool dbl=false; - if (rndnum>63) - { // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel - rndnum=(rndnum-61)*2; // name can't start with "ng" "nd" or "rk" - rndname[0]=paircons[rndnum]; - rndname[1]=paircons[rndnum+1]; - n=2; - } - else if (rndnum>16) - { - rndnum-=17; - rndname[0]=cons[rndnum]; - } - else - { - rndname[0]=vowels[rndnum]; - vwl=true; - } - int namlen=emu_random.Int(5, 10); - for (int i=n;i46) - { // pick a cons pair - if (i>namlen-3) // last 2 chars in name? - { // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng" - rndnum=emu_random.Int(0, 7)*2; - } - else - { // pick any from the set - rndnum=(rndnum-47)*2; - } - rndname[i]=paircons[rndnum]; - rndname[i+1]=paircons[rndnum+1]; - dlc=true; // flag keeps second letter from being doubled below - i+=1; - } - else - { // select a single cons - rndname[i]=cons[rndnum]; - } - } - else - { // select a vowel - rndname[i]=vowels[emu_random.Int(0, 16)]; - } - vwl=!vwl; - if (!dbl && !dlc) - { // one chance at double letters in name - if (!emu_random.Int(0, i+9)) // chances decrease towards end of name - { - rndname[i+1]=rndname[i]; - dbl=true; - i+=1; - } - } - } +bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) +{ + NameGen::Generator generator("!Bvss"); + std::string random_name = generator.toString(); - rndname[0]=toupper(rndname[0]); - NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer; - memset(ngs->name,0,64); - strcpy(ngs->name,rndname); + auto *ngs = (NameGeneration_Struct *) app->pBuffer; + memset(ngs->name, 0, 64); + strcpy(ngs->name, random_name.c_str()); QueuePacket(app); return true; From 6fb6d8891d8a23ca6c039502b7ae5d573ac78b89 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Tue, 31 Mar 2020 09:22:16 -0400 Subject: [PATCH 37/84] Hack to fix RoF2 perma IVU/IVA bug after zoning. This fixes the problem, but I believe someone with better knowledge of the client than I can find a more "correct" solution. Posted as a PR per @joligario to solve it for now. Was also asked to put SE_Invisibility in there so that this "hack" is a catch all. --- zone/client_packet.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 1848a926c..1caf2b4b3 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4017,6 +4017,14 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) //Message(Chat::Red, "You cant cast right now, you arent in control of yourself!"); return; } + + // Hack for broken RoF2 which allows casting after a zoned IVU/IVA + if (invisible_undead || invisible_animals) { + BuffFadeByEffect(SE_InvisVsAnimals); + BuffFadeByEffect(SE_InvisVsUndead); + BuffFadeByEffect(SE_InvisVsUndead2); + BuffFadeByEffect(SE_Invisibility); // Included per JJ for completeness - client handles this one atm + } CastSpell_Struct* castspell = (CastSpell_Struct*)app->pBuffer; From 51b31b5e531cb6ebb44bc8bad5241ac37e34b40b Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 31 Mar 2020 19:31:04 -0400 Subject: [PATCH 38/84] Add getitemname(item_id) to Perl/Lua. --- zone/embparser_api.cpp | 17 +++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 10 ++++++++++ zone/questmgr.h | 1 + 4 files changed, 33 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index cf55925b8..901d25ce2 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2810,6 +2810,22 @@ XS(XS__countitem) { XSRETURN_IV(quantity); } +XS(XS__getitemname); +XS(XS__getitemname) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getitemname(uint32 item_id)"); + + dXSTARG; + uint32 item_id = (int) SvIV(ST(0)); + std::string item_name = quest_manager.getitemname(item_id); + + sv_setpv(TARG, item_name.c_str()); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__UpdateSpawnTimer); XS(XS__UpdateSpawnTimer) { dXSARGS; @@ -4005,6 +4021,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file); newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file); newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file); + newXS(strcpy(buf, "getitemname"), XS__getitemname, file); newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file); newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 9367cef21..15fc3d3e1 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -807,6 +807,10 @@ std::string lua_item_link(int item_id) { return quest_manager.varlink(text, item_id); } +std::string lua_get_item_name(uint32 item_id) { + return quest_manager.getitemname(item_id); +} + std::string lua_say_link(const char *phrase, bool silent, const char *link_name) { char text[256] = { 0 }; strncpy(text, phrase, 255); @@ -1734,6 +1738,7 @@ luabind::scope lua_register_general() { luabind::def("merchant_set_item", (void(*)(uint32,uint32,uint32))&lua_merchant_set_item), luabind::def("merchant_count_item", &lua_merchant_count_item), luabind::def("item_link", &lua_item_link), + luabind::def("get_item_name", (std::string(*)(uint32))&lua_get_item_name), luabind::def("say_link", (std::string(*)(const char*,bool,const char*))&lua_say_link), luabind::def("say_link", (std::string(*)(const char*,bool))&lua_say_link), luabind::def("say_link", (std::string(*)(const char*))&lua_say_link), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0c36b876a..a1ec7d959 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2696,6 +2696,16 @@ const char* QuestManager::varlink(char* perltext, int item_id) { return perltext; } +std::string QuestManager::getitemname(uint32 item_id) { + const EQEmu::ItemData* item_data = database.GetItem(item_id); + if (!item_data) { + return "INVALID ITEM ID IN GETITEMNAME"; + } + + std::string item_name = item_data->Name; + return item_name; +} + uint16 QuestManager::CreateInstance(const char *zone, int16 version, uint32 duration) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index 21d5b5db1..cde58fc0d 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -220,6 +220,7 @@ public: int collectitems(uint32 item_id, bool remove); int collectitems_processSlot(int16 slot_id, uint32 item_id, bool remove); int countitem(uint32 item_id); + std::string getitemname(uint32 item_id); void enabletitle(int titleset); bool checktitle(int titlecheck); void removetitle(int titlecheck); From ceb8b31bc0570dbb0bc17b50e96fefb0212f8369 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 31 Mar 2020 19:48:44 -0400 Subject: [PATCH 39/84] Add getspellname(spell_id) to Perl/Lua. --- zone/embparser_api.cpp | 17 +++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 9 +++++++++ zone/questmgr.h | 1 + 4 files changed, 32 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index cf55925b8..bb90d77ce 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -822,6 +822,22 @@ XS(XS__isdisctome) { XSRETURN(1); } +XS(XS__getspellname); +XS(XS__getspellname) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getspellname(uint32 spell_id)"); + + dXSTARG; + uint32 spell_id = (int) SvIV(ST(0)); + std::string spell_name = quest_manager.getspellname(spell_id); + + sv_setpv(TARG, spell_name.c_str()); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__safemove); XS(XS__safemove) { dXSARGS; @@ -4011,6 +4027,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file); newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file); newXS(strcpy(buf, "getraididbycharid"), XS__getraididbycharid, file); + newXS(strcpy(buf, "getspellname"), XS__getspellname, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 9367cef21..ef07d3742 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -393,6 +393,10 @@ bool lua_is_disc_tome(int item_id) { return quest_manager.isdisctome(item_id); } +std::string lua_get_spell_name(uint32 spell_id) { + return quest_manager.getspellname(spell_id); +} + void lua_safe_move() { quest_manager.safemove(); } @@ -1648,6 +1652,7 @@ luabind::scope lua_register_general() { luabind::def("depop_zone", &lua_depop_zone), luabind::def("repop_zone", &lua_repop_zone), luabind::def("is_disc_tome", &lua_is_disc_tome), + luabind::def("get_spell_name", (std::string(*)(uint32))&lua_get_spell_name), luabind::def("safe_move", &lua_safe_move), luabind::def("rain", &lua_rain), luabind::def("snow", &lua_snow), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0c36b876a..7fb1474fd 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -906,6 +906,15 @@ bool QuestManager::isdisctome(int item_id) { return(true); } +std::string QuestManager::getspellname(uint32 spell_id) { + if (!IsValidSpell(spell_id)) { + return "INVALID SPELL ID IN GETSPELLNAME"; + } + + std::string spell_name = GetSpellName(spell_id); + return spell_name; +} + void QuestManager::safemove() { QuestManagerCurrentQuestVars(); if (initiator && initiator->IsClient()) diff --git a/zone/questmgr.h b/zone/questmgr.h index 21d5b5db1..6ea7fcf38 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -107,6 +107,7 @@ public: void level(int newlevel); void traindisc(int discipline_tome_item_id); bool isdisctome(int item_id); + std::string getspellname(uint32 spell_id); void safemove(); void rain(int weather); void snow(int weather); From 89740595779c7a3a2b2fe87425166b508e469c3e Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 31 Mar 2020 20:01:12 -0400 Subject: [PATCH 40/84] Remove unused variables in resettaskactivity. --- zone/embparser_api.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 6e07ad9f0..19c3a2b38 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2358,7 +2358,6 @@ XS(XS__updatetaskactivity) { XS(XS__resettaskactivity); XS(XS__resettaskactivity) { dXSARGS; - unsigned int task, activity; if (items == 2) { int task_id = (int) SvIV(ST(0)); int activity_id = (int) SvIV(ST(1)); From 6d3848b2c74989a574cf1f36d2b5afd1c572391d Mon Sep 17 00:00:00 2001 From: KimLS Date: Tue, 31 Mar 2020 19:55:27 -0700 Subject: [PATCH 41/84] Removed make_unique from namegen, was conflicting with real make_unique on windows and we're set to cxx11 still --- common/namegenerator/namegen.cpp | 48 +++++++++++--------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/common/namegenerator/namegen.cpp b/common/namegenerator/namegen.cpp index fa632c844..3ef880ea4 100644 --- a/common/namegenerator/namegen.cpp +++ b/common/namegenerator/namegen.cpp @@ -125,20 +125,6 @@ const std::unordered_map>& Generator return *symbols; } - -#ifdef HAVE_CXX14 -using std::make_unique; -#else -// make_unique is not available in c++11, so we use this template function -// to maintain full c++11 compatibility; std::make_unique is part of C++14. -template -std::unique_ptr make_unique(Args&&... args) -{ - return std::unique_ptr(new T(std::forward(args)...)); -} -#endif - - Generator::Generator() { } @@ -353,17 +339,17 @@ Generator::Generator(const std::string &pattern, bool collapse_triples) { std::unique_ptr last; std::stack> stack; - std::unique_ptr top = make_unique(); + std::unique_ptr top = std::unique_ptr(); for (auto c : pattern) { switch (c) { case '<': stack.push(std::move(top)); - top = make_unique(); + top = std::unique_ptr(); break; case '(': stack.push(std::move(top)); - top = make_unique(); + top = std::unique_ptr(); break; case '>': case ')': @@ -408,7 +394,7 @@ Generator::Generator(const std::string &pattern, bool collapse_triples) { std::unique_ptr g = top->produce(); if (collapse_triples) { - g = make_unique(std::move(g)); + g = std::unique_ptr(new Collapser(std::move(g))); } add(std::move(g)); } @@ -424,16 +410,16 @@ void Generator::Group::add(std::unique_ptr&& g) while (!wrappers.empty()) { switch (wrappers.top()) { case reverser: - g = make_unique(std::move(g)); + g = std::unique_ptr(new Reverser(std::move(g))); break; case capitalizer: - g = make_unique(std::move(g)); + g = std::unique_ptr(new Capitalizer(std::move(g))); break; } wrappers.pop(); } if (set.size() == 0) { - set.push_back(make_unique()); + set.push_back(std::unique_ptr()); } set.back()->add(std::move(g)); } @@ -441,8 +427,8 @@ void Generator::Group::add(std::unique_ptr&& g) void Generator::Group::add(char c) { std::string value(1, c); - std::unique_ptr g = make_unique(); - g->add(make_unique(value)); + std::unique_ptr g = std::unique_ptr(); + g->add(std::unique_ptr(new Literal(value))); Group::add(std::move(g)); } @@ -450,20 +436,20 @@ std::unique_ptr Generator::Group::produce() { switch (set.size()) { case 0: - return make_unique(""); + return std::unique_ptr(new Literal("")); case 1: return std::move(*set.begin()); default: - return make_unique(std::move(set)); + return std::unique_ptr(new Random(std::move(set))); } } void Generator::Group::split() { if (set.size() == 0) { - set.push_back(make_unique()); + set.push_back(std::unique_ptr()); } - set.push_back(make_unique()); + set.push_back(std::unique_ptr()); } void Generator::Group::wrap(wrappers_t type) @@ -479,14 +465,14 @@ Generator::GroupSymbol::GroupSymbol() : void Generator::GroupSymbol::add(char c) { std::string value(1, c); - std::unique_ptr g = make_unique(); + std::unique_ptr g = std::unique_ptr(); try { static const auto& symbols = SymbolMap(); for (const auto& s : symbols.at(value)) { - g->add(make_unique(s)); + g->add(std::unique_ptr(new Literal(s))); } } catch (const std::out_of_range&) { - g->add(make_unique(value)); + g->add(std::unique_ptr(new Literal(value))); } Group::add(std::move(g)); } @@ -533,4 +519,4 @@ std::string tostring(const std::wstring & s) } return std::string(buf.data(), wn); -} \ No newline at end of file +} From 4712b56078266a84c36aba76a598dc9aa24a3a60 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 31 Mar 2020 22:24:09 -0400 Subject: [PATCH 42/84] Add gettaskname(task_id) to Perl/Lua. --- zone/embparser_api.cpp | 18 ++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 10 ++++++++++ zone/questmgr.h | 1 + zone/tasks.cpp | 11 +++++++++++ zone/tasks.h | 1 + 6 files changed, 46 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 6e07ad9f0..b299a42b5 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2629,6 +2629,23 @@ XS(XS__istaskappropriate) { XSRETURN(1); } +XS(XS__gettaskname); +XS(XS__gettaskname) { + dXSARGS; + if (items != 1) { + Perl_croak(aTHX_ "Usage: quest::gettaskname(uint32 task_id)"); + } + + dXSTARG; + uint32 task_id = (int) SvIV(ST(0)); + std::string task_name = quest_manager.gettaskname(task_id); + + sv_setpv(TARG, task_name.c_str()); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__popup); // prototype to pass -Wmissing-prototypes XS(XS__popup) { dXSARGS; @@ -4050,6 +4067,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); newXS(strcpy(buf, "getplayercorpsecountbyzoneid"), XS__getplayercorpsecountbyzoneid, file); newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file); + newXS(strcpy(buf, "gettaskname"), XS__gettaskname, file); newXS(strcpy(buf, "givecash"), XS__givecash, file); newXS(strcpy(buf, "gmmove"), XS__gmmove, file); newXS(strcpy(buf, "gmsay"), XS__gmsay, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 346ad4042..e388a9e1b 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -733,6 +733,10 @@ bool lua_is_task_appropriate(int task) { return quest_manager.istaskappropriate(task); } +std::string lua_get_task_name(uint32 task_id) { + return quest_manager.gettaskname(task_id); +} + void lua_popup(const char *title, const char *text, uint32 id, uint32 buttons, uint32 duration) { quest_manager.popup(title, text, id, buttons, duration); } @@ -1724,6 +1728,7 @@ luabind::scope lua_register_general() { luabind::def("active_tasks_in_set", &lua_active_tasks_in_set), luabind::def("completed_tasks_in_set", &lua_completed_tasks_in_set), luabind::def("is_task_appropriate", &lua_is_task_appropriate), + luabind::def("get_task_name", (std::string(*)(uint32))&lua_get_task_name), luabind::def("popup", &lua_popup), luabind::def("clear_spawn_timers", &lua_clear_spawn_timers), luabind::def("zone_emote", &lua_zone_emote), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 7479767c3..7e0f9eb5f 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2441,6 +2441,16 @@ bool QuestManager::istaskappropriate(int task) { return false; } +std::string QuestManager::gettaskname(uint32 task_id) { + QuestManagerCurrentQuestVars(); + + if (RuleB(TaskSystem, EnableTaskSystem)) { + return taskmanager->GetTaskName(task_id); + } + + return std::string(); +} + void QuestManager::clearspawntimers() { if(!zone) return; diff --git a/zone/questmgr.h b/zone/questmgr.h index b5947b67e..04b16a902 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -214,6 +214,7 @@ public: int activetasksinset(int taskset); int completedtasksinset(int taskset); bool istaskappropriate(int task); + std::string gettaskname(uint32 task_id); void clearspawntimers(); void ze(int type, const char *str); void we(int type, const char *str); diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 778a556e3..afa7b2062 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -955,6 +955,17 @@ bool TaskManager::AppropriateLevel(int TaskID, int PlayerLevel) { } +std::string TaskManager::GetTaskName(uint32 task_id) +{ + if (task_id > 0 && task_id < MAXTASKS) { + if (Tasks[task_id] != nullptr) { + return Tasks[task_id]->Title; + } + } + + return std::string(); +} + int TaskManager::GetTaskMinLevel(int TaskID) { if (Tasks[TaskID]->MinLevel) diff --git a/zone/tasks.h b/zone/tasks.h index 0bc45c146..48fc8e2cc 100644 --- a/zone/tasks.h +++ b/zone/tasks.h @@ -299,6 +299,7 @@ public: bool AppropriateLevel(int TaskID, int PlayerLevel); int GetTaskMinLevel(int TaskID); int GetTaskMaxLevel(int TaskID); + std::string GetTaskName(uint32 task_id); void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID); void TaskQuestSetSelector(Client *c, ClientTaskState *state, Mob *mob, int count, int *tasks); // task list provided by QuestManager (perl/lua) void SendActiveTasksToClient(Client *c, bool TaskComplete=false); From a4bf484c74e68e718c4420ff66eaac489a6aab7a Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 31 Mar 2020 23:09:19 -0400 Subject: [PATCH 43/84] Add CheckInstanceByCharID(instance_id, char_id) to Perl/Lua. --- zone/embparser_api.cpp | 20 ++++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 4 ++++ zone/questmgr.h | 1 + 4 files changed, 30 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 6e07ad9f0..c9ee6ea8a 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3108,6 +3108,25 @@ XS(XS__RemoveFromInstanceByCharID) { XSRETURN_EMPTY; } +XS(XS__CheckInstanceByCharID); +XS(XS__CheckInstanceByCharID) { + dXSARGS; + if (items != 2) { + Perl_croak(aTHX_ "Usage: quest::CheckInstanceByCharID(uint16 instance_id, uint32 char_id)"); + } + + bool RETVAL; + dXSTARG; + + uint16 instance_id = (int) SvUV(ST(0)); + uint32 char_id = (int) SvUV(ST(1)); + RETVAL = quest_manager.CheckInstanceByCharID(instance_id, char_id); + XSprePUSH; + PUSHu((IV) RETVAL); + + XSRETURN(1); +} + XS(XS__RemoveAllFromInstance); XS(XS__RemoveAllFromInstance) { dXSARGS; @@ -3972,6 +3991,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "RemoveAllFromInstance"), XS__RemoveAllFromInstance, file); newXS(strcpy(buf, "RemoveFromInstance"), XS__RemoveFromInstance, file); newXS(strcpy(buf, "RemoveFromInstanceByCharID"), XS__RemoveFromInstanceByCharID, file); + newXS(strcpy(buf, "CheckInstanceByCharID"), XS__CheckInstanceByCharID, file); newXS(strcpy(buf, "SendMail"), XS__SendMail, file); newXS(strcpy(buf, "SetRunning"), XS__SetRunning, file); newXS(strcpy(buf, "activespeakactivity"), XS__activespeakactivity, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 346ad4042..4c2358594 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -934,6 +934,10 @@ void lua_remove_from_instance_by_char_id(uint32 instance_id, uint32 char_id) { quest_manager.RemoveFromInstanceByCharID(instance_id, char_id); } +bool lua_check_instance_by_char_id(uint32 instance_id, uint32 char_id) { + return quest_manager.CheckInstanceByCharID(instance_id, char_id); +} + void lua_remove_all_from_instance(uint32 instance_id) { quest_manager.RemoveAllFromInstance(instance_id); } @@ -1772,6 +1776,7 @@ luabind::scope lua_register_general() { luabind::def("assign_raid_to_instance", &lua_assign_raid_to_instance), luabind::def("remove_from_instance", &lua_remove_from_instance), luabind::def("remove_from_instance_by_char_id", &lua_remove_from_instance_by_char_id), + luabind::def("check_instance_by_char_id", (bool(*)(uint16, uint32))&lua_check_instance_by_char_id), luabind::def("remove_all_from_instance", &lua_remove_all_from_instance), luabind::def("flag_instance_by_group_leader", &lua_flag_instance_by_group_leader), luabind::def("flag_instance_by_raid_leader", &lua_flag_instance_by_raid_leader), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 7479767c3..30511c309 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2856,6 +2856,10 @@ void QuestManager::RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id database.RemoveClientFromInstance(instance_id, char_id); } +bool QuestManager::CheckInstanceByCharID(uint16 instance_id, uint32 char_id) { + return database.CharacterInInstanceGroup(instance_id, char_id); +} + void QuestManager::RemoveAllFromInstance(uint16 instance_id) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index b5947b67e..b81e6fbe9 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -245,6 +245,7 @@ public: void AssignRaidToInstance(uint16 instance_id); void RemoveFromInstance(uint16 instance_id); void RemoveFromInstanceByCharID(uint16 instance_id, uint32 char_id); + bool CheckInstanceByCharID(uint16 instance_id, uint32 char_id); //void RemoveGroupFromInstance(uint16 instance_id); //potentially useful but not implmented at this time. //void RemoveRaidFromInstance(uint16 instance_id); //potentially useful but not implmented at this time. void RemoveAllFromInstance(uint16 instance_id); From 8193b046276bf2a939f0481d0bb38935a515eafe Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 1 Apr 2020 08:41:40 -0400 Subject: [PATCH 44/84] Update ruletypes.h --- common/ruletypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 20e26e315..a4c1ef8a2 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -161,7 +161,7 @@ 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_BOOL(Character, ProcessFearedProximity, true, "Processes proximity checks when feared") +RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared") RULE_CATEGORY_END() RULE_CATEGORY(Mercs) From 15dde4778a1697dd178012120f61743f858bfd70 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 2 Apr 2020 11:52:27 -0400 Subject: [PATCH 45/84] Update aggro.cpp --- zone/aggro.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 87b98d599..dad9aacc4 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -237,6 +237,11 @@ bool Mob::CheckWillAggro(Mob *mob) { if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning) return false; } + + // We don't want to aggro clients outside of water if we're water only. + if (mob->IsClient() && mob->CastToClient()->GetLastRegion() != RegionTypeWater && IsUnderwaterOnly()) { + return false; + } /** * Pets shouldn't scan for aggro From 803c3aabe434ee22aacbffe035aeaf40d4d75871 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 2 Apr 2020 11:54:19 -0400 Subject: [PATCH 46/84] Update client.cpp --- zone/client.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zone/client.cpp b/zone/client.cpp index 8c4b42957..a270d6579 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8756,6 +8756,11 @@ void Client::CheckRegionTypeChanges() // still same region, do nothing if (last_region_type == new_region) return; + + // If we got out of water clear any water aggro for water only npcs + if (last_region_type == RegionTypeWater) { + entity_list.ClearWaterAggro(this); + } // region type changed last_region_type = new_region; From a898a1d07b9833fbe261f2cc9a1eafc48c107d62 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 2 Apr 2020 11:55:05 -0400 Subject: [PATCH 47/84] Update aggro.cpp --- zone/aggro.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index dad9aacc4..b568d11af 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -32,6 +32,7 @@ #endif #include "map.h" +#include "water_map.h" extern Zone* zone; //#define LOSDEBUG 6 From 42f959329d8190cd33070a5001869cc373771364 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 2 Apr 2020 11:56:06 -0400 Subject: [PATCH 48/84] Update client.h --- zone/client.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zone/client.h b/zone/client.h index 58b0d9af8..edc3f18c0 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1293,6 +1293,8 @@ public: void SendHPUpdateMarquee(); void CheckRegionTypeChanges(); + + WaterRegionType GetLastRegion() { return last_region_type; } int32 CalcATK(); From ef0b29dc8e43ce9f98f1385b907df87587dc38bb Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 2 Apr 2020 12:03:45 -0400 Subject: [PATCH 49/84] Update entity.cpp --- zone/entity.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/zone/entity.cpp b/zone/entity.cpp index b13fb5649..0e93be722 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3294,6 +3294,36 @@ void EntityList::ClearAggro(Mob* targ) } } +//removes "targ" from all hate lists of mobs that are water only. +//water only mobs that are fleed from to another region are healed as per live +void EntityList::ClearWaterAggro(Mob* targ) +{ + Client *c = nullptr; + if (targ->IsClient()) + c = targ->CastToClient(); + auto it = npc_list.begin(); + while (it != npc_list.end()) { + if (it->second->IsUnderwaterOnly()) { + if (it->second->CheckAggro(targ)) { + if (c) + c->RemoveXTarget(it->second, false); + it->second->RemoveFromHateList(targ); + } + if (c && it->second->IsOnFeignMemory(c)) { + it->second->RemoveFromFeignMemory(c); //just in case we feigned + c->RemoveXTarget(it->second, false); + } + if (!it->second->GetHateTop()) { + // target fled the water and no other targets. + // Heal NPC as on live + it->second->Heal(); + } + } + ++it; + } +} + + void EntityList::ClearFeignAggro(Mob *targ) { auto it = npc_list.begin(); From abeb93f1e60b802b46c41c98874eda0a16e97532 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 2 Apr 2020 12:04:16 -0400 Subject: [PATCH 50/84] Update entity.h --- zone/entity.h | 1 + 1 file changed, 1 insertion(+) diff --git a/zone/entity.h b/zone/entity.h index 505f34963..3c182be29 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -447,6 +447,7 @@ public: void Process(); void ClearAggro(Mob* targ); + void ClearWaterAggro(Mob* targ); void ClearFeignAggro(Mob* targ); void ClearZoneFeignAggro(Client* targ); void AggroZone(Mob* who, uint32 hate = 0); From 561433902e28a039b3e7d604c4c1049f30d04530 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Thu, 2 Apr 2020 13:08:05 -0400 Subject: [PATCH 51/84] Removed heal per @mackal --- zone/entity.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/zone/entity.cpp b/zone/entity.cpp index 0e93be722..e74136be7 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3295,7 +3295,6 @@ void EntityList::ClearAggro(Mob* targ) } //removes "targ" from all hate lists of mobs that are water only. -//water only mobs that are fleed from to another region are healed as per live void EntityList::ClearWaterAggro(Mob* targ) { Client *c = nullptr; @@ -3313,11 +3312,6 @@ void EntityList::ClearWaterAggro(Mob* targ) it->second->RemoveFromFeignMemory(c); //just in case we feigned c->RemoveXTarget(it->second, false); } - if (!it->second->GetHateTop()) { - // target fled the water and no other targets. - // Heal NPC as on live - it->second->Heal(); - } } ++it; } From 41d0b1a94787a0c036e22e85a1bea5982a50da1b Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 5 Apr 2020 20:41:49 -0400 Subject: [PATCH 52/84] Add getcharidbyname(name) to Perl/Lua. --- zone/embparser_api.cpp | 18 ++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 4 ++++ zone/questmgr.h | 1 + 4 files changed, 28 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 3ca3184d5..3021836a4 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3231,6 +3231,23 @@ XS(XS__saylink) { XSRETURN(1); } +XS(XS__getcharidbyname); +XS(XS__getcharidbyname) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getcharidbyname(string name)"); + dXSTARG; + + uint32 RETVAL; + const char *name = (const char *) SvPV_nolen(ST(0)); + + RETVAL = quest_manager.getcharidbyname(name); + XSprePUSH; + PUSHu((UV)RETVAL); + + XSRETURN(1); +} + XS(XS__getguildnamebyid); XS(XS__getguildnamebyid) { dXSARGS; @@ -4072,6 +4089,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "follow"), XS__follow, file); newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file); newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file); + newXS(strcpy(buf, "getcharidbyname"), XS__getcharidbyname, file); newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file); newXS(strcpy(buf, "getitemname"), XS__getitemname, file); newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index ddae2dd26..af5eea3af 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -870,6 +870,10 @@ bool lua_delete_data(std::string bucket_key) { return DataBucket::DeleteData(bucket_key); } +uint32 lua_get_char_id_by_name(const char* name) { + return quest_manager.getcharidbyname(name); +} + const char *lua_get_guild_name_by_id(uint32 guild_id) { return quest_manager.getguildnamebyid(guild_id); } @@ -1763,6 +1767,7 @@ luabind::scope lua_register_general() { luabind::def("set_data", (void(*)(std::string, std::string))&lua_set_data), luabind::def("set_data", (void(*)(std::string, std::string, std::string))&lua_set_data), luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), + luabind::def("get_char_id_by_name", (uint32(*)(const char*))&lua_get_char_id_by_name), luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 62cd73610..18f290c80 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2928,6 +2928,10 @@ std::string QuestManager::saylink(char *saylink_text, bool silent, const char *l return EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink_text, silent, link_name); } +uint32 QuestManager::getcharidbyname(const char* name) { + return database.GetCharacterID(name); +} + const char* QuestManager::getguildnamebyid(int guild_id) { if (guild_id > 0) return guild_mgr.GetGuildName(guild_id); diff --git a/zone/questmgr.h b/zone/questmgr.h index c47c775e7..a381fa124 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -255,6 +255,7 @@ public: void FlagInstanceByRaidLeader(uint32 zone, int16 version); const char* varlink(char* perltext, int item_id); std::string saylink(char *saylink_text, bool silent, const char *link_name); + uint32 getcharidbyname(const char* name); const char* getguildnamebyid(int guild_id); int getguildidbycharid(uint32 char_id); int getgroupidbycharid(uint32 char_id); From ae959be5ace8035232acb5919b3ee8da3b1e1c1c Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 5 Apr 2020 21:11:21 -0400 Subject: [PATCH 53/84] Added getcharnamebyid(char_id) to Perl/Lua. --- common/database.cpp | 16 ++++++++++++++++ common/database.h | 1 + zone/embparser_api.cpp | 19 +++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 7 +++++++ zone/questmgr.h | 1 + 6 files changed, 49 insertions(+) diff --git a/common/database.cpp b/common/database.cpp index 3f64a21f9..ab9b1ce84 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -925,6 +925,22 @@ void Database::GetCharName(uint32 char_id, char* name) { } } +const char* Database::GetCharNameByID(uint32 char_id) { + std::string query = fmt::format("SELECT `name` FROM `character_data` WHERE id = {}", char_id); + auto results = QueryDatabase(query); + + if (!results.Success()) { + return ""; + } + + if (results.RowCount() == 0) { + return ""; + } + + auto row = results.begin(); + return row[0]; +} + bool Database::LoadVariables() { auto results = QueryDatabase(StringFormat("SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache.last_update)); diff --git a/common/database.h b/common/database.h index 95458c1c1..44c264dfd 100644 --- a/common/database.h +++ b/common/database.h @@ -138,6 +138,7 @@ public: void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0); void GetCharName(uint32 char_id, char* name); + const char *GetCharNameByID(uint32 char_id); void LoginIP(uint32 AccountID, const char* LoginIP); /* Instancing */ diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 3ca3184d5..eac2cdc48 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3231,6 +3231,24 @@ XS(XS__saylink) { XSRETURN(1); } +XS(XS__getcharnamebyid); +XS(XS__getcharnamebyid) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getcharnamebyid(uint32 char_id)"); + dXSTARG; + + Const_char *RETVAL; + uint32 char_id = (int) SvUV(ST(0)); + + RETVAL = quest_manager.getcharnamebyid(char_id); + + sv_setpv(TARG, RETVAL); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__getguildnamebyid); XS(XS__getguildnamebyid) { dXSARGS; @@ -4076,6 +4094,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getitemname"), XS__getitemname, file); newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file); + newXS(strcpy(buf, "getcharnamebyid"), XS__getcharnamebyid, file); newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file); newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index ddae2dd26..72749998d 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -870,6 +870,10 @@ bool lua_delete_data(std::string bucket_key) { return DataBucket::DeleteData(bucket_key); } +const char *lua_get_char_name_by_id(uint32 char_id) { + return database.GetCharNameByID(char_id); +} + const char *lua_get_guild_name_by_id(uint32 guild_id) { return quest_manager.getguildnamebyid(guild_id); } @@ -1763,6 +1767,7 @@ luabind::scope lua_register_general() { luabind::def("set_data", (void(*)(std::string, std::string))&lua_set_data), luabind::def("set_data", (void(*)(std::string, std::string, std::string))&lua_set_data), luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), + luabind::def("get_char_name_by_id", &lua_get_char_name_by_id), luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 62cd73610..5fa96b937 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2928,6 +2928,13 @@ std::string QuestManager::saylink(char *saylink_text, bool silent, const char *l return EQEmu::SayLinkEngine::GenerateQuestSaylink(saylink_text, silent, link_name); } +const char* QuestManager::getcharnamebyid(uint32 char_id) { + if (char_id > 0) { + return database.GetCharNameByID(char_id); + } + return ""; +} + const char* QuestManager::getguildnamebyid(int guild_id) { if (guild_id > 0) return guild_mgr.GetGuildName(guild_id); diff --git a/zone/questmgr.h b/zone/questmgr.h index c47c775e7..519d1b798 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -255,6 +255,7 @@ public: void FlagInstanceByRaidLeader(uint32 zone, int16 version); const char* varlink(char* perltext, int item_id); std::string saylink(char *saylink_text, bool silent, const char *link_name); + const char* getcharnamebyid(uint32 char_id); const char* getguildnamebyid(int guild_id); int getguildidbycharid(uint32 char_id); int getgroupidbycharid(uint32 char_id); From 035bac1044a778143798a8c313a8bff9f2b24203 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 5 Apr 2020 21:22:23 -0400 Subject: [PATCH 54/84] Update embparser_api.cpp --- zone/embparser_api.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 2dc5b70a0..dfb23ddc8 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3231,7 +3231,6 @@ XS(XS__saylink) { XSRETURN(1); } - XS(XS__getcharnamebyid); XS(XS__getcharnamebyid) { dXSARGS; From 02cac686b63ec407193c726181418f0b185e6945 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 00:09:57 -0400 Subject: [PATCH 55/84] Add getnpcnamebyid(npc_id) to Perl/Lua. --- common/database.cpp | 17 +++++++++++++++++ common/database.h | 1 + zone/embparser_api.cpp | 17 +++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 7 +++++++ zone/questmgr.h | 1 + 6 files changed, 48 insertions(+) diff --git a/common/database.cpp b/common/database.cpp index ab9b1ce84..1935406a2 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -941,6 +941,22 @@ const char* Database::GetCharNameByID(uint32 char_id) { return row[0]; } +const char* Database::GetNPCNameByID(uint32 npc_id) { + std::string query = fmt::format("SELECT `name` FROM `npc_types` WHERE id = {}", npc_id); + auto results = QueryDatabase(query); + + if (!results.Success()) { + return ""; + } + + if (results.RowCount() == 0) { + return ""; + } + + auto row = results.begin(); + return row[0]; +} + bool Database::LoadVariables() { auto results = QueryDatabase(StringFormat("SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache.last_update)); @@ -2389,3 +2405,4 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) { return 0; } + diff --git a/common/database.h b/common/database.h index 44c264dfd..cf85acf9c 100644 --- a/common/database.h +++ b/common/database.h @@ -139,6 +139,7 @@ public: void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0); void GetCharName(uint32 char_id, char* name); const char *GetCharNameByID(uint32 char_id); + const char *GetNPCNameByID(uint32 npc_id); void LoginIP(uint32 AccountID, const char* LoginIP); /* Instancing */ diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index dfb23ddc8..d926ffcbb 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2858,6 +2858,22 @@ XS(XS__getitemname) { XSRETURN(1); } +XS(XS__getnpcnamebyid); +XS(XS__getnpcnamebyid) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getnpcnamebyid(uint32 npc_id)"); + + dXSTARG; + uint32 npc_id = (int) SvIV(ST(0)); + const char *npc_name = quest_manager.getnpcnamebyid(npc_id); + + sv_setpv(TARG, npc_name); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__UpdateSpawnTimer); XS(XS__UpdateSpawnTimer) { dXSARGS; @@ -4110,6 +4126,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file); newXS(strcpy(buf, "getitemname"), XS__getitemname, file); newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); + newXS(strcpy(buf, "getnpcnamebyid"), XS__getnpcnamebyid, file); newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file); newXS(strcpy(buf, "getcharnamebyid"), XS__getcharnamebyid, file); newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 848348fbf..07b200315 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -890,6 +890,10 @@ int lua_get_group_id_by_char_id(uint32 char_id) { return database.GetGroupIDByCharID(char_id); } +const char *lua_get_npc_name_by_id(uint32 npc_id) { + return quest_manager.getnpcnamebyid(npc_id); +} + int lua_get_raid_id_by_char_id(uint32 char_id) { return database.GetRaidIDByCharID(char_id); } @@ -1776,6 +1780,7 @@ luabind::scope lua_register_general() { luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), + luabind::def("get_npc_name_by_id", &lua_get_npc_name_by_id), luabind::def("get_raid_id_by_char_id", &lua_get_raid_id_by_char_id), luabind::def("create_instance", &lua_create_instance), luabind::def("destroy_instance", &lua_destroy_instance), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0a61361c6..e2006222c 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2725,6 +2725,13 @@ std::string QuestManager::getitemname(uint32 item_id) { return item_name; } +const char *QuestManager::getnpcnamebyid(uint32 npc_id) { + if (npc_id > 0) { + return database.GetNPCNameByID(npc_id); + } + return ""; +} + uint16 QuestManager::CreateInstance(const char *zone, int16 version, uint32 duration) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index a3c7eab3d..934dd148a 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -260,6 +260,7 @@ public: const char* getguildnamebyid(int guild_id); int getguildidbycharid(uint32 char_id); int getgroupidbycharid(uint32 char_id); + const char* getnpcnamebyid(uint32 npc_id); int getraididbycharid(uint32 char_id); void SetRunning(bool val); bool IsRunning(); From 6ddcc2bb8a5412baa41b402edc9edef792e4adaa Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 00:49:57 -0400 Subject: [PATCH 56/84] Add getcurrencyid(item_id) to Perl/Lua. --- zone/embparser_api.cpp | 18 ++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 11 +++++++++++ zone/questmgr.h | 1 + 4 files changed, 35 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index dfb23ddc8..2c8ebb54b 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3265,6 +3265,23 @@ XS(XS__getcharidbyname) { XSRETURN(1); } +XS(XS__getcurrencyid); +XS(XS__getcurrencyid) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getcurrencyid(uint32 item_id)"); + dXSTARG; + + int RETVAL; + uint32 item_id = (int) SvUV(ST(0));; + + RETVAL = quest_manager.getcurrencyid(item_id); + XSprePUSH; + PUSHi((IV)RETVAL); + + XSRETURN(1); +} + XS(XS__getguildnamebyid); XS(XS__getguildnamebyid) { dXSARGS; @@ -4107,6 +4124,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file); newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file); newXS(strcpy(buf, "getcharidbyname"), XS__getcharidbyname, file); + newXS(strcpy(buf, "getcurrencyid"), XS__getcurrencyid, file); newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file); newXS(strcpy(buf, "getitemname"), XS__getitemname, file); newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 848348fbf..3525a74ad 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -878,6 +878,10 @@ uint32 lua_get_char_id_by_name(const char* name) { return quest_manager.getcharidbyname(name); } +int lua_get_currency_id(uint32 item_id) { + return quest_manager.getcurrencyid(item_id); +} + const char *lua_get_guild_name_by_id(uint32 guild_id) { return quest_manager.getguildnamebyid(guild_id); } @@ -1773,6 +1777,7 @@ luabind::scope lua_register_general() { luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), luabind::def("get_char_name_by_id", &lua_get_char_name_by_id), luabind::def("get_char_id_by_name", (uint32(*)(const char*))&lua_get_char_id_by_name), + luabind::def("get_currency_id", &lua_get_currency_id), luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0a61361c6..c6afdb46e 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2939,6 +2939,17 @@ uint32 QuestManager::getcharidbyname(const char* name) { return database.GetCharacterID(name); } +int QuestManager::getcurrencyid(uint32 item_id) { + auto iter = zone->AlternateCurrencies.begin(); + while (iter != zone->AlternateCurrencies.end()) { + if (item_id == (*iter).item_id) { + return (*iter).id; + } + ++iter; + } + return 0; +} + const char* QuestManager::getguildnamebyid(int guild_id) { if (guild_id > 0) return guild_mgr.GetGuildName(guild_id); diff --git a/zone/questmgr.h b/zone/questmgr.h index a3c7eab3d..f3d95ff8a 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -257,6 +257,7 @@ public: std::string saylink(char *saylink_text, bool silent, const char *link_name); const char* getcharnamebyid(uint32 char_id); uint32 getcharidbyname(const char* name); + int getcurrencyid(uint32 item_id); const char* getguildnamebyid(int guild_id); int getguildidbycharid(uint32 char_id); int getgroupidbycharid(uint32 char_id); From 03ca345b37250692112a8dff8e1113410665343a Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 01:07:59 -0400 Subject: [PATCH 57/84] Add getcurrencyitemid(currency_id) to Perl/Lua. --- zone/embparser_api.cpp | 18 ++++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 13 +++++++++++++ zone/questmgr.h | 1 + 4 files changed, 37 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index dfb23ddc8..0bde28561 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3265,6 +3265,23 @@ XS(XS__getcharidbyname) { XSRETURN(1); } +XS(XS__getcurrencyitemid); +XS(XS__getcurrencyitemid) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getcurrencyitemid(int currency_id)"); + dXSTARG; + + int RETVAL; + int currency_id = (int) SvUV(ST(0)); + + RETVAL = quest_manager.getcurrencyitemid(currency_id); + + XSprePUSH; + PUSHi((IV)RETVAL); + XSRETURN(1); +} + XS(XS__getguildnamebyid); XS(XS__getguildnamebyid) { dXSARGS; @@ -4112,6 +4129,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file); newXS(strcpy(buf, "getcharnamebyid"), XS__getcharnamebyid, file); + newXS(strcpy(buf, "getcurrencyitemid"), XS__getcurrencyitemid, file); newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file); newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 848348fbf..cc320ab63 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -878,6 +878,10 @@ uint32 lua_get_char_id_by_name(const char* name) { return quest_manager.getcharidbyname(name); } +int lua_get_currency_item_id(int currency_id) { + return quest_manager.getcurrencyitemid(currency_id); +} + const char *lua_get_guild_name_by_id(uint32 guild_id) { return quest_manager.getguildnamebyid(guild_id); } @@ -1773,6 +1777,7 @@ luabind::scope lua_register_general() { luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), luabind::def("get_char_name_by_id", &lua_get_char_name_by_id), luabind::def("get_char_id_by_name", (uint32(*)(const char*))&lua_get_char_id_by_name), + luabind::def("get_currency_item_id", &lua_get_currency_item_id), luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0a61361c6..7560678e1 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2939,6 +2939,19 @@ uint32 QuestManager::getcharidbyname(const char* name) { return database.GetCharacterID(name); } +int QuestManager::getcurrencyitemid(int currency_id) { + if (currency_id > 0) { + auto iter = zone->AlternateCurrencies.begin(); + while (iter != zone->AlternateCurrencies.end()) { + if (currency_id == (*iter).id) { + return (*iter).item_id; + } + ++iter; + } + } + return 0; +} + const char* QuestManager::getguildnamebyid(int guild_id) { if (guild_id > 0) return guild_mgr.GetGuildName(guild_id); diff --git a/zone/questmgr.h b/zone/questmgr.h index a3c7eab3d..a4743b2ad 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -257,6 +257,7 @@ public: std::string saylink(char *saylink_text, bool silent, const char *link_name); const char* getcharnamebyid(uint32 char_id); uint32 getcharidbyname(const char* name); + int getcurrencyitemid(int currency_id); const char* getguildnamebyid(int guild_id); int getguildidbycharid(uint32 char_id); int getgroupidbycharid(uint32 char_id); From 358bd60716a152dba6a1d051f14c589fd75fa988 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 01:36:46 -0400 Subject: [PATCH 58/84] Add getskillname(skill_id) to Perl/Lua. --- zone/embparser_api.cpp | 17 +++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 12 ++++++++++++ zone/questmgr.h | 1 + 4 files changed, 35 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index dfb23ddc8..0ddfb289a 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -838,6 +838,22 @@ XS(XS__getspellname) { XSRETURN(1); } +XS(XS__getskillname); +XS(XS__getskillname) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getskillname(int skill_id)"); + + dXSTARG; + int skill_id = (int) SvIV(ST(0)); + std::string skill_name = quest_manager.getskillname(skill_id); + + sv_setpv(TARG, skill_name.c_str()); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__safemove); XS(XS__safemove) { dXSARGS; @@ -4117,6 +4133,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file); newXS(strcpy(buf, "getraididbycharid"), XS__getraididbycharid, file); newXS(strcpy(buf, "getspellname"), XS__getspellname, file); + newXS(strcpy(buf, "getskillname"), XS__getskillname, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 848348fbf..a3ed7b04a 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -397,6 +397,10 @@ std::string lua_get_spell_name(uint32 spell_id) { return quest_manager.getspellname(spell_id); } +std::string lua_get_skill_name(int skill_id) { + return quest_manager.getskillname(skill_id); +} + void lua_safe_move() { quest_manager.safemove(); } @@ -1673,6 +1677,7 @@ luabind::scope lua_register_general() { luabind::def("repop_zone", &lua_repop_zone), luabind::def("is_disc_tome", &lua_is_disc_tome), luabind::def("get_spell_name", (std::string(*)(uint32))&lua_get_spell_name), + luabind::def("get_skill_name", (std::string(*)(int))&lua_get_skill_name), luabind::def("safe_move", &lua_safe_move), luabind::def("rain", &lua_rain), luabind::def("snow", &lua_snow), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0a61361c6..6a568466e 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -915,6 +915,18 @@ std::string QuestManager::getspellname(uint32 spell_id) { return spell_name; } +std::string QuestManager::getskillname(int skill_id) { + if (skill_id >= 0 && skill_id < EQEmu::skills::SkillCount) { + std::map Skills = EQEmu::skills::GetSkillTypeMap(); + for (auto skills_iter : Skills) { + if (skill_id == skills_iter.first) { + return skills_iter.second; + } + } + } + return std::string(); +} + void QuestManager::safemove() { QuestManagerCurrentQuestVars(); if (initiator && initiator->IsClient()) diff --git a/zone/questmgr.h b/zone/questmgr.h index a3c7eab3d..50f077298 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -108,6 +108,7 @@ public: void traindisc(int discipline_tome_item_id); bool isdisctome(int item_id); std::string getspellname(uint32 spell_id); + std::string getskillname(int skill_id); void safemove(); void rain(int weather); void snow(int weather); From fab071d9da4617f9c60f4154394820e4579b0bff Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 02:02:20 -0400 Subject: [PATCH 59/84] Add getracename(race_id) to Perl/Lua. --- zone/embparser_api.cpp | 17 +++++++++++++++++ zone/lua_general.cpp | 5 +++++ zone/questmgr.cpp | 4 ++++ zone/questmgr.h | 1 + 4 files changed, 27 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index dfb23ddc8..9e7b11b52 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -822,6 +822,22 @@ XS(XS__isdisctome) { XSRETURN(1); } +XS(XS__getracename); +XS(XS__getracename) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getracename(uint16 race_id)"); + + dXSTARG; + uint16 race_id = (int) SvIV(ST(0)); + std::string race_name = quest_manager.getracename(race_id); + + sv_setpv(TARG, race_name.c_str()); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__getspellname); XS(XS__getspellname) { dXSARGS; @@ -4116,6 +4132,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getguildidbycharid"), XS__getguildidbycharid, file); newXS(strcpy(buf, "getgroupidbycharid"), XS__getgroupidbycharid, file); newXS(strcpy(buf, "getraididbycharid"), XS__getraididbycharid, file); + newXS(strcpy(buf, "getracename"), XS__getracename, file); newXS(strcpy(buf, "getspellname"), XS__getspellname, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 848348fbf..0659605e3 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -393,6 +393,10 @@ bool lua_is_disc_tome(int item_id) { return quest_manager.isdisctome(item_id); } +std::string lua_get_race_name(uint32 race_id) { + return quest_manager.getracename(race_id); +} + std::string lua_get_spell_name(uint32 spell_id) { return quest_manager.getspellname(spell_id); } @@ -1672,6 +1676,7 @@ luabind::scope lua_register_general() { luabind::def("depop_zone", &lua_depop_zone), luabind::def("repop_zone", &lua_repop_zone), luabind::def("is_disc_tome", &lua_is_disc_tome), + luabind::def("get_race_name", (std::string(*)(uint16))&lua_get_race_name), luabind::def("get_spell_name", (std::string(*)(uint32))&lua_get_spell_name), luabind::def("safe_move", &lua_safe_move), luabind::def("rain", &lua_rain), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0a61361c6..c4de76f14 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -906,6 +906,10 @@ bool QuestManager::isdisctome(int item_id) { return(true); } +std::string QuestManager::getracename(uint16 race_id) { + return GetRaceIDName(race_id); +} + std::string QuestManager::getspellname(uint32 spell_id) { if (!IsValidSpell(spell_id)) { return "INVALID SPELL ID IN GETSPELLNAME"; diff --git a/zone/questmgr.h b/zone/questmgr.h index a3c7eab3d..24cbcc825 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -107,6 +107,7 @@ public: void level(int newlevel); void traindisc(int discipline_tome_item_id); bool isdisctome(int item_id); + std::string getracename(uint16 race_id); std::string getspellname(uint32 spell_id); void safemove(); void rain(int weather); From c2c6282cc77bbe693b0d38f212ac65c94268742d Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 02:26:58 -0400 Subject: [PATCH 60/84] Add getclassname(class_id, level) to Perl/Lua. --- zone/embparser_api.cpp | 21 +++++++++++++++++++++ zone/lua_general.cpp | 10 ++++++++++ zone/questmgr.cpp | 4 ++++ zone/questmgr.h | 1 + 4 files changed, 36 insertions(+) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index dfb23ddc8..839928b89 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3265,6 +3265,26 @@ XS(XS__getcharidbyname) { XSRETURN(1); } +XS(XS__getclassname); +XS(XS__getclassname) { + dXSARGS; + if (items < 1 || items > 2) + Perl_croak(aTHX_ "Usage: quest::getclassname(uint8 class_id, [uint8 level = 0])"); + dXSTARG; + + std::string RETVAL; + uint8 class_id = (int) SvUV(ST(0)); + uint8 level = 0; + if (items > 1) + level = (int) SvUV(ST(1)); + + RETVAL = quest_manager.getclassname(class_id, level); + sv_setpv(TARG, RETVAL.c_str()); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__getguildnamebyid); XS(XS__getguildnamebyid) { dXSARGS; @@ -4107,6 +4127,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file); newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file); newXS(strcpy(buf, "getcharidbyname"), XS__getcharidbyname, file); + newXS(strcpy(buf, "getclassname"), XS__getclassname, file); newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file); newXS(strcpy(buf, "getitemname"), XS__getitemname, file); newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 848348fbf..00dbb1993 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -878,6 +878,14 @@ uint32 lua_get_char_id_by_name(const char* name) { return quest_manager.getcharidbyname(name); } +std::string lua_get_class_name(uint8 class_id) { + return quest_manager.getclassname(class_id); +} + +std::string lua_get_class_name(uint8 class_id, uint8 level) { + return quest_manager.getclassname(class_id, level); +} + const char *lua_get_guild_name_by_id(uint32 guild_id) { return quest_manager.getguildnamebyid(guild_id); } @@ -1773,6 +1781,8 @@ luabind::scope lua_register_general() { luabind::def("delete_data", (bool(*)(std::string))&lua_delete_data), luabind::def("get_char_name_by_id", &lua_get_char_name_by_id), luabind::def("get_char_id_by_name", (uint32(*)(const char*))&lua_get_char_id_by_name), + luabind::def("get_class_name", (std::string(*)(uint8))&lua_get_class_name), + luabind::def("get_class_name", (std::string(*)(uint8,uint8))&lua_get_class_name), luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("get_guild_id_by_char_id", &lua_get_guild_id_by_char_id), luabind::def("get_group_id_by_char_id", &lua_get_group_id_by_char_id), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 0a61361c6..1a00b7f93 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2939,6 +2939,10 @@ uint32 QuestManager::getcharidbyname(const char* name) { return database.GetCharacterID(name); } +std::string QuestManager::getclassname(uint8 class_id, uint8 level) { + return GetClassIDName(class_id, level); +} + const char* QuestManager::getguildnamebyid(int guild_id) { if (guild_id > 0) return guild_mgr.GetGuildName(guild_id); diff --git a/zone/questmgr.h b/zone/questmgr.h index a3c7eab3d..581ee4f0b 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -257,6 +257,7 @@ public: std::string saylink(char *saylink_text, bool silent, const char *link_name); const char* getcharnamebyid(uint32 char_id); uint32 getcharidbyname(const char* name); + std::string getclassname(uint8 class_id, uint8 level = 0); const char* getguildnamebyid(int guild_id); int getguildidbycharid(uint32 char_id); int getgroupidbycharid(uint32 char_id); From b5575133cd08bc0854e3c3d584b248dac773d9d0 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Mon, 6 Apr 2020 08:10:15 -0400 Subject: [PATCH 61/84] Put in braces in my new function as well as the source function. The entire file has implied braces... I'd change them all but fear making a mistake. --- zone/entity.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/zone/entity.cpp b/zone/entity.cpp index e74136be7..b3805ad63 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3277,13 +3277,15 @@ void EntityList::Evade(Mob *who) void EntityList::ClearAggro(Mob* targ) { Client *c = nullptr; - if (targ->IsClient()) + if (targ->IsClient()) { c = targ->CastToClient(); + } auto it = npc_list.begin(); while (it != npc_list.end()) { if (it->second->CheckAggro(targ)) { - if (c) + if (c) { c->RemoveXTarget(it->second, false); + } it->second->RemoveFromHateList(targ); } if (c && it->second->IsOnFeignMemory(c)) { @@ -3298,14 +3300,16 @@ void EntityList::ClearAggro(Mob* targ) void EntityList::ClearWaterAggro(Mob* targ) { Client *c = nullptr; - if (targ->IsClient()) + if (targ->IsClient()) { c = targ->CastToClient(); + } auto it = npc_list.begin(); while (it != npc_list.end()) { if (it->second->IsUnderwaterOnly()) { if (it->second->CheckAggro(targ)) { - if (c) + if (c) { c->RemoveXTarget(it->second, false); + } it->second->RemoveFromHateList(targ); } if (c && it->second->IsOnFeignMemory(c)) { From 973fd376e58eae48c8c2532038ad91b0f081906a Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Mon, 6 Apr 2020 08:23:57 -0400 Subject: [PATCH 62/84] Propose change in location of Stun check as possible resolution to crash --- zone/npc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index b7dc3272a..39b1b046b 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -694,11 +694,6 @@ void NPC::RemoveCash() { bool NPC::Process() { - if (IsStunned() && stunned_timer.Check()) { - Mob::UnStun(); - this->spun_timer.Disable(); - } - if (p_depop) { Mob* owner = entity_list.GetMob(this->ownerid); @@ -711,6 +706,11 @@ bool NPC::Process() } return false; } + + if (IsStunned() && stunned_timer.Check()) { + Mob::UnStun(); + this->spun_timer.Disable(); + } SpellProcess(); From 40ef4c799b61e3b608823982b7076fce7f9efed1 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 16:22:08 -0400 Subject: [PATCH 63/84] Update embparser_api.cpp --- zone/embparser_api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 4daebd009..bad973bfe 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3327,7 +3327,7 @@ XS(XS__getcurrencyitemid) { XSprePUSH; PUSHi((IV)RETVAL); - XSRETURN(1); + XSRETURN(1); } XS(XS__getcurrencyid); From f8735cf9ba19b4d90a04384886fd1c35a7381525 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 18:06:18 -0400 Subject: [PATCH 64/84] Update lua_general.cpp --- zone/lua_general.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index a45bffb90..d047238de 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -895,7 +895,7 @@ std::string lua_get_class_name(uint8 class_id, uint8 level) { } int lua_get_currency_id(uint32 item_id) { - return quest_manager.getcurrencyid(item_id) + return quest_manager.getcurrencyid(item_id); } int lua_get_currency_item_id(int currency_id) { From cbd1f42a085220b2b729d69a7f9f9212cda89e48 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Apr 2020 18:57:13 -0400 Subject: [PATCH 65/84] Merge conflict fixes... --- zone/embparser_api.cpp | 2 +- zone/questmgr.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index e3e5a5664..c65cd204c 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3358,7 +3358,7 @@ XS(XS__getcurrencyid) { dXSTARG; int RETVAL; - uint32 item_id = (int) SvUV(ST(0));; + uint32 item_id = (int) SvUV(ST(0)); RETVAL = quest_manager.getcurrencyid(item_id); XSprePUSH; diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 52ef22621..ba6a5340c 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2986,6 +2986,7 @@ int QuestManager::getcurrencyitemid(int currency_id) { } ++iter; } + } return 0; } From 1728923bbb6a1af1f1c8104983225f73226a0c7e Mon Sep 17 00:00:00 2001 From: Akkadius Date: Wed, 8 Apr 2020 16:00:27 -0500 Subject: [PATCH 66/84] Revert "Merge pull request #1007 from EQEmu/feature/improved-name-generator" This reverts commit 3c71e2c91df68421ab32d7f14094f067014cb70b, reversing changes made to 80d160175450a7e74500f5c773f9e1d72ecb907d. --- common/CMakeLists.txt | 2 - common/namegenerator/namegen.cpp | 522 ------------------------------- common/namegenerator/namegen.h | 269 ---------------- world/client.cpp | 81 ++++- 4 files changed, 73 insertions(+), 801 deletions(-) delete mode 100644 common/namegenerator/namegen.cpp delete mode 100644 common/namegenerator/namegen.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 57f000ccb..e312c202d 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -77,7 +77,6 @@ SET(common_sources unix.cpp platform.cpp json/jsoncpp.cpp - namegenerator/namegen.cpp net/console_server.cpp net/console_server_connection.cpp net/crc32.cpp @@ -222,7 +221,6 @@ SET(common_headers event/timer.h json/json.h json/json-forwards.h - namegenerator/namegen.h net/console_server.h net/console_server_connection.h net/crc32.h diff --git a/common/namegenerator/namegen.cpp b/common/namegenerator/namegen.cpp deleted file mode 100644 index 3ef880ea4..000000000 --- a/common/namegenerator/namegen.cpp +++ /dev/null @@ -1,522 +0,0 @@ -/** - * - * @file A fantasy name generator library. - * @version 1.0.1 - * @license Public Domain - * @author German M. Bravo (Kronuz) - * - */ - -#include "namegen.h" - -#include // for move, reverse -#include // for rng seed -#include // for size_t, mbsrtowcs, wcsrtombs -#include // for towupper -#include // for make_unique -#include // for mt19937, uniform_real_distribution -#include // for invalid_argument, out_of_range - - -using namespace NameGen; - - -static std::mt19937 rng(std::chrono::high_resolution_clock::now().time_since_epoch().count()); - - -// https://isocpp.org/wiki/faq/ctors#static-init-order -// Avoid the "static initialization order fiasco" -const std::unordered_map>& Generator::SymbolMap() -{ - static auto* const symbols = new std::unordered_map>({ - { - "s", { - "ach", "ack", "ad", "age", "ald", "ale", "an", "ang", "ar", "ard", - "as", "ash", "at", "ath", "augh", "aw", "ban", "bel", "bur", "cer", - "cha", "che", "dan", "dar", "del", "den", "dra", "dyn", "ech", "eld", - "elm", "em", "en", "end", "eng", "enth", "er", "ess", "est", "et", - "gar", "gha", "hat", "hin", "hon", "ia", "ight", "ild", "im", "ina", - "ine", "ing", "ir", "is", "iss", "it", "kal", "kel", "kim", "kin", - "ler", "lor", "lye", "mor", "mos", "nal", "ny", "nys", "old", "om", - "on", "or", "orm", "os", "ough", "per", "pol", "qua", "que", "rad", - "rak", "ran", "ray", "ril", "ris", "rod", "roth", "ryn", "sam", - "say", "ser", "shy", "skel", "sul", "tai", "tan", "tas", "ther", - "tia", "tin", "ton", "tor", "tur", "um", "und", "unt", "urn", "usk", - "ust", "ver", "ves", "vor", "war", "wor", "yer" - } - }, - { - "v", { - "a", "e", "i", "o", "u", "y" - } - }, - { - "V", { - "a", "e", "i", "o", "u", "y", "ae", "ai", "au", "ay", "ea", "ee", - "ei", "eu", "ey", "ia", "ie", "oe", "oi", "oo", "ou", "ui" - } - }, - { - "c", { - "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", - "s", "t", "v", "w", "x", "y", "z" - } - }, - { - "B", { - "b", "bl", "br", "c", "ch", "chr", "cl", "cr", "d", "dr", "f", "g", - "h", "j", "k", "l", "ll", "m", "n", "p", "ph", "qu", "r", "rh", "s", - "sch", "sh", "sl", "sm", "sn", "st", "str", "sw", "t", "th", "thr", - "tr", "v", "w", "wh", "y", "z", "zh" - } - }, - { - "C", { - "b", "c", "ch", "ck", "d", "f", "g", "gh", "h", "k", "l", "ld", "ll", - "lt", "m", "n", "nd", "nn", "nt", "p", "ph", "q", "r", "rd", "rr", - "rt", "s", "sh", "ss", "st", "t", "th", "v", "w", "y", "z" - } - }, - { - "i", { - "air", "ankle", "ball", "beef", "bone", "bum", "bumble", "bump", - "cheese", "clod", "clot", "clown", "corn", "dip", "dolt", "doof", - "dork", "dumb", "face", "finger", "foot", "fumble", "goof", - "grumble", "head", "knock", "knocker", "knuckle", "loaf", "lump", - "lunk", "meat", "muck", "munch", "nit", "numb", "pin", "puff", - "skull", "snark", "sneeze", "thimble", "twerp", "twit", "wad", - "wimp", "wipe" - } - }, - { - "m", { - "baby", "booble", "bunker", "cuddle", "cuddly", "cutie", "doodle", - "foofie", "gooble", "honey", "kissie", "lover", "lovey", "moofie", - "mooglie", "moopie", "moopsie", "nookum", "poochie", "poof", - "poofie", "pookie", "schmoopie", "schnoogle", "schnookie", - "schnookum", "smooch", "smoochie", "smoosh", "snoogle", "snoogy", - "snookie", "snookum", "snuggy", "sweetie", "woogle", "woogy", - "wookie", "wookum", "wuddle", "wuddly", "wuggy", "wunny" - } - }, - { - "M", { - "boo", "bunch", "bunny", "cake", "cakes", "cute", "darling", - "dumpling", "dumplings", "face", "foof", "goo", "head", "kin", - "kins", "lips", "love", "mush", "pie", "poo", "pooh", "pook", "pums" - } - }, - { - "D", { - "b", "bl", "br", "cl", "d", "f", "fl", "fr", "g", "gh", "gl", "gr", - "h", "j", "k", "kl", "m", "n", "p", "th", "w" - } - }, - { - "d", { - "elch", "idiot", "ob", "og", "ok", "olph", "olt", "omph", "ong", - "onk", "oo", "oob", "oof", "oog", "ook", "ooz", "org", "ork", "orm", - "oron", "ub", "uck", "ug", "ulf", "ult", "um", "umb", "ump", "umph", - "un", "unb", "ung", "unk", "unph", "unt", "uzz" - } - } - }); - - return *symbols; -} - -Generator::Generator() -{ -} - - -Generator::Generator(std::vector>&& generators_) : - generators(std::move(generators_)) -{ -} - - -size_t Generator::combinations() -{ - size_t total = 1; - for (auto& g : generators) { - total *= g->combinations(); - } - return total; -} - - -size_t Generator::min() -{ - size_t final = 0; - for (auto& g : generators) { - final += g->min(); - } - return final; -} - - -size_t Generator::max() -{ - size_t final = 0; - for (auto& g : generators) { - final += g->max(); - } - return final; -} - - -std::string Generator::toString() { - std::string str; - for (auto& g : generators) { - str.append(g->toString()); - } - return str; -} - - -void Generator::add(std::unique_ptr&& g) -{ - generators.push_back(std::move(g)); -} - - -Random::Random() -{ -} - -Random::Random(std::vector>&& generators_) : - Generator(std::move(generators_)) -{ -} - -size_t Random::combinations() -{ - size_t total = 0; - for (auto& g : generators) { - total += g->combinations(); - } - return total ? total : 1; -} - -size_t Random::min() -{ - size_t final = -1; - for (auto& g : generators) { - size_t current = g->min(); - if (current < final) { - final = current; - } - } - return final; -} - -size_t Random::max() -{ - size_t final = 0; - for (auto& g : generators) { - size_t current = g->max(); - if (current > final) { - final = current; - } - } - return final; -} - - -std::string Random::toString() -{ - if (!generators.size()) { - return ""; - } - std::uniform_real_distribution distribution(0, generators.size() - 1); - int rnd = distribution(rng) + 0.5; - return generators[rnd]->toString(); -} - - -Sequence::Sequence() -{ -} - -Sequence::Sequence(std::vector>&& generators_) : - Generator(std::move(generators_)) -{ -} - -Literal::Literal(const std::string &value_) : - value(value_) -{ -} - -size_t Literal::combinations() -{ - return 1; -} - -size_t Literal::min() -{ - return value.size(); -} - -size_t Literal::max() -{ - return value.size(); -} - -std::string Literal::toString() -{ - return value; -} - -Reverser::Reverser(std::unique_ptr&& g) -{ - add(std::move(g)); -} - - -std::string Reverser::toString() -{ - std::wstring str = towstring(Generator::toString()); - std::reverse(str.begin(), str.end()); - return tostring(str); -} - -Capitalizer::Capitalizer(std::unique_ptr&& g) -{ - add(std::move(g)); -} - -std::string Capitalizer::toString() -{ - std::wstring str = towstring(Generator::toString()); - str[0] = std::towupper(str[0]); - return tostring(str); -} - - -Collapser::Collapser(std::unique_ptr&& g) -{ - add(std::move(g)); -} - -std::string Collapser::toString() -{ - std::wstring str = towstring(Generator::toString()); - std::wstring out; - int cnt = 0; - wchar_t pch = L'\0'; - for (auto ch : str) { - if (ch == pch) { - cnt++; - } else { - cnt = 0; - } - int mch = 2; - switch(ch) { - case 'a': - case 'h': - case 'i': - case 'j': - case 'q': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - mch = 1; - } - if (cnt < mch) { - out.push_back(ch); - } - pch = ch; - } - return tostring(out); -} - - -Generator::Generator(const std::string &pattern, bool collapse_triples) { - std::unique_ptr last; - - std::stack> stack; - std::unique_ptr top = std::unique_ptr(); - - for (auto c : pattern) { - switch (c) { - case '<': - stack.push(std::move(top)); - top = std::unique_ptr(); - break; - case '(': - stack.push(std::move(top)); - top = std::unique_ptr(); - break; - case '>': - case ')': - if (stack.size() == 0) { - throw std::invalid_argument("Unbalanced brackets"); - } else if (c == '>' && top->type != group_types::symbol) { - throw std::invalid_argument("Unexpected '>' in pattern"); - } else if (c == ')' && top->type != group_types::literal) { - throw std::invalid_argument("Unexpected ')' in pattern"); - } - last = top->produce(); - top = std::move(stack.top()); - stack.pop(); - top->add(std::move(last)); - break; - case '|': - top->split(); - break; - case '!': - if (top->type == group_types::symbol) { - top->wrap(wrappers::capitalizer); - } else { - top->add(c); - } - break; - case '~': - if (top->type == group_types::symbol) { - top->wrap(wrappers::reverser); - } else { - top->add(c); - } - break; - default: - top->add(c); - break; - } - } - - if (stack.size() != 0) { - throw std::invalid_argument("Missing closing bracket"); - } - - std::unique_ptr g = top->produce(); - if (collapse_triples) { - g = std::unique_ptr(new Collapser(std::move(g))); - } - add(std::move(g)); -} - - -Generator::Group::Group(group_types_t type_) : - type(type_) -{ -} - -void Generator::Group::add(std::unique_ptr&& g) -{ - while (!wrappers.empty()) { - switch (wrappers.top()) { - case reverser: - g = std::unique_ptr(new Reverser(std::move(g))); - break; - case capitalizer: - g = std::unique_ptr(new Capitalizer(std::move(g))); - break; - } - wrappers.pop(); - } - if (set.size() == 0) { - set.push_back(std::unique_ptr()); - } - set.back()->add(std::move(g)); -} - -void Generator::Group::add(char c) -{ - std::string value(1, c); - std::unique_ptr g = std::unique_ptr(); - g->add(std::unique_ptr(new Literal(value))); - Group::add(std::move(g)); -} - -std::unique_ptr Generator::Group::produce() -{ - switch (set.size()) { - case 0: - return std::unique_ptr(new Literal("")); - case 1: - return std::move(*set.begin()); - default: - return std::unique_ptr(new Random(std::move(set))); - } -} - -void Generator::Group::split() -{ - if (set.size() == 0) { - set.push_back(std::unique_ptr()); - } - set.push_back(std::unique_ptr()); -} - -void Generator::Group::wrap(wrappers_t type) -{ - wrappers.push(type); -} - -Generator::GroupSymbol::GroupSymbol() : - Group(group_types::symbol) -{ -} - -void Generator::GroupSymbol::add(char c) -{ - std::string value(1, c); - std::unique_ptr g = std::unique_ptr(); - try { - static const auto& symbols = SymbolMap(); - for (const auto& s : symbols.at(value)) { - g->add(std::unique_ptr(new Literal(s))); - } - } catch (const std::out_of_range&) { - g->add(std::unique_ptr(new Literal(value))); - } - Group::add(std::move(g)); -} - -Generator::GroupLiteral::GroupLiteral() : - Group(group_types::literal) -{ -} - -std::wstring towstring(const std::string & s) -{ - const char *cs = s.c_str(); - const size_t wn = std::mbsrtowcs(nullptr, &cs, 0, nullptr); - - if (wn == static_cast(-1)) { - return L""; - } - - std::vector buf(wn); - cs = s.c_str(); - const size_t wn_again = std::mbsrtowcs(buf.data(), &cs, wn, nullptr); - - if (wn_again == static_cast(-1)) { - return L""; - } - - return std::wstring(buf.data(), wn); -} - -std::string tostring(const std::wstring & s) -{ - const wchar_t *cs = s.c_str(); - const size_t wn = std::wcsrtombs(nullptr, &cs, 0, nullptr); - - if (wn == static_cast(-1)) { - return ""; - } - - std::vector buf(wn); - const size_t wn_again = std::wcsrtombs(buf.data(), &cs, wn, nullptr); - - if (wn_again == static_cast(-1)) { - return ""; - } - - return std::string(buf.data(), wn); -} diff --git a/common/namegenerator/namegen.h b/common/namegenerator/namegen.h deleted file mode 100644 index 4ddcf1bf5..000000000 --- a/common/namegenerator/namegen.h +++ /dev/null @@ -1,269 +0,0 @@ -/** - * - * @file A fantasy name generator library. - * @version 1.0.1 - * @license Public Domain - * @author German M. Bravo (Kronuz) - * - * This library is designed after the RinkWorks Fantasy Name Generator. - * @see http://www.rinkworks.com/namegen/ - * - * @example - * NameGen::Generator generator("sV'i"); - * generator.toString(); // Returns a new name each call with produce() - * // => "entheu'loaf" - * - * ## Pattern Syntax - * - * The compile() function creates a name generator based on an input - * pattern. The letters s, v, V, c, B, C, i, m, M, D, and d represent - * different types of random replacements. Everything else is produced - * literally. - * - * s - generic syllable - * v - vowel - * V - vowel or vowel combination - * c - consonant - * B - consonant or consonant combination suitable for beginning a word - * C - consonant or consonant combination suitable anywhere in a word - * i - insult - * m - mushy name - * M - mushy name ending - * D - consonant suited for a stupid person's name - * d - syllable suited for a stupid person's name (begins with a vowel) - * - * All characters between parenthesis () are produced literally. For - * example, the pattern "s(dim)", produces a random generic syllable - * followed by "dim". - * - * Characters between angle brackets <> produce patterns from the table - * above. Imagine the entire pattern is wrapped in one of these. - * - * In both types of groupings, a vertical bar | denotes a random - * choice. Empty groups are allowed. For example, "(foo|bar)" produces - * either "foo" or "bar". The pattern "" produces a constant, - * vowel, or nothing at all. - * - * An exclamation point ! means to capitalize the component that - * follows it. For example, "!(foo)" will produce "Foo" and "v!s" will - * produce a lowercase vowel followed by a capitalized syllable, like - * "eRod". - * - * A tilde ~ means to reverse the letters of the component that - * follows it. For example, "~(foo)" will produce "oof". To reverse an - * entire template, wrap it in brackets. For example, to reverse - * "sV'i" as a whole use "~". The template "~sV'i" will only - * reverse the initial syllable. - * - * ## Internals - * - * A name generator is anything with a toString() method, including, - * importantly, strings themselves. The generator constructors - * (Random, Sequence) perform additional optimizations when *not* used - * with the `new` keyword: they may pass through a provided generator, - * combine provided generators, or even return a simple string. - * - * New pattern symbols added to Generator.symbols will automatically - * be used by the compiler. - */ - -#pragma once - -#include // for size_t -#include // for wstring -#include // for unique_ptr -#include // for stack -#include // for string -#include // for unordered_map -#include // for vector - - -namespace NameGen { - -// Middle Earth -#define MIDDLE_EARTH "(bil|bal|ban|hil|ham|hal|hol|hob|wil|me|or|ol|od|gor|for|fos|tol|ar|fin|ere|leo|vi|bi|bren|thor)(|go|orbis|apol|adur|mos|ri|i|na|ole|n)(|tur|axia|and|bo|gil|bin|bras|las|mac|grim|wise|l|lo|fo|co|ra|via|da|ne|ta|y|wen|thiel|phin|dir|dor|tor|rod|on|rdo|dis)" - -// Japanese Names (Constrained) -#define JAPANESE_NAMES_CONSTRAINED "(aka|aki|bashi|gawa|kawa|furu|fuku|fuji|hana|hara|haru|hashi|hira|hon|hoshi|ichi|iwa|kami|kawa|ki|kita|kuchi|kuro|marui|matsu|miya|mori|moto|mura|nabe|naka|nishi|no|da|ta|o|oo|oka|saka|saki|sawa|shita|shima|i|suzu|taka|take|to|toku|toyo|ue|wa|wara|wata|yama|yoshi|kei|ko|zawa|zen|sen|ao|gin|kin|ken|shiro|zaki|yuki|asa)(||||||||||bashi|gawa|kawa|furu|fuku|fuji|hana|hara|haru|hashi|hira|hon|hoshi|chi|wa|ka|kami|kawa|ki|kita|kuchi|kuro|marui|matsu|miya|mori|moto|mura|nabe|naka|nishi|no|da|ta|o|oo|oka|saka|saki|sawa|shita|shima|suzu|taka|take|to|toku|toyo|ue|wa|wara|wata|yama|yoshi|kei|ko|zawa|zen|sen|ao|gin|kin|ken|shiro|zaki|yuki|sa)" - -// Japanese Names (Diverse) -#define JAPANESE_NAMES_DIVERSE "(a|i|u|e|o|||||)(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)))(|||n)" - -// Chinese Names -#define CHINESE_NAMES "(zh|x|q|sh|h)(ao|ian|uo|ou|ia)(|(l|w|c|p|b|m)(ao|ian|uo|ou|ia)(|n)|-(l|w|c|p|b|m)(ao|ian|uo|ou|ia)(|(d|j|q|l)(a|ai|iu|ao|i)))" - -// Greek Names -#define GREEK_NAMES "(tia)|s(os)|Bc(ios)|Bv(ios|os)>" - -// Hawaiian Names (1) -#define HAWAIIAN_NAMES_1 "((h|k|l|m|n|p|w|')|)(a|e|i|o|u)((h|k|l|m|n|p|w|')|)(a|e|i|o|u)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w|')|)(a|e|i|o|u)|)" - -// Hawaiian Names (2) -#define HAWAIIAN_NAMES_2 "((h|k|l|m|n|p|w|)(a|e|i|o|u|a'|e'|i'|o'|u'|ae|ai|ao|au|oi|ou|eu|ei)(k|l|m|n|p|)|)(h|k|l|m|n|p|w|)(a|e|i|o|u|a'|e'|i'|o'|u'|ae|ai|ao|au|oi|ou|eu|ei)(k|l|m|n|p|)" - -// Old Latin Place Names -#define OLD_LATIN_PLACE_NAMES "sv(nia|lia|cia|sia)" - -// Dragons (Pern) -#define DRAGONS_PERN "<|>>(th)" - -// Dragon Riders -#define DRAGON_RIDERS "c'" - -// Pokemon -#define POKEMON "v(mon|chu|zard|rtle)" - -// Fantasy (Vowels, R, etc.) -#define FANTASY_VOWELS_R "(|(|s|h|ty|ph|r))(i|ae|ya|ae|eu|ia|i|eo|ai|a)(lo|la|sri|da|dai|the|sty|lae|due|li|lly|ri|na|ral|sur|rith)(|(su|nu|sti|llo|ria|))(|(n|ra|p|m|lis|cal|deu|dil|suir|phos|ru|dru|rin|raap|rgue))" - -// Fantasy (S, A, etc.) -#define FANTASY_S_A "(cham|chan|jisk|lis|frich|isk|lass|mind|sond|sund|ass|chad|lirt|und|mar|lis|il|)(jask|ast|ista|adar|irra|im|ossa|assa|osia|ilsa|)(|(an|ya|la|sta|sda|sya|st|nya))" - -// Fantasy (H, L, etc.) -#define FANTASY_H_L "(ch|ch't|sh|cal|val|ell|har|shar|shal|rel|laen|ral|jh't|alr|ch|ch't|av)(|(is|al|ow|ish|ul|el|ar|iel))(aren|aeish|aith|even|adur|ulash|alith|atar|aia|erin|aera|ael|ira|iel|ahur|ishul)" - -// Fantasy (N, L, etc.) -#define FANTASY_N_L "(ethr|qil|mal|er|eal|far|fil|fir|ing|ind|il|lam|quel|quar|quan|qar|pal|mal|yar|um|ard|enn|ey)(|(|on|us|un|ar|as|en|ir|ur|at|ol|al|an))(uard|wen|arn|on|il|ie|on|iel|rion|rian|an|ista|rion|rian|cil|mol|yon)" - -// Fantasy (K, N, etc.) -#define FANTASY_K_N "(taith|kach|chak|kank|kjar|rak|kan|kaj|tach|rskal|kjol|jok|jor|jad|kot|kon|knir|kror|kol|tul|rhaok|rhak|krol|jan|kag|ryr)(|in|or|an|ar|och|un|mar|yk|ja|arn|ir|ros|ror)(|(mund|ard|arn|karr|chim|kos|rir|arl|kni|var|an|in|ir|a|i|as))" - -// Fantasy (J, G, Z, etc.) -#define FANTASY_J_G_Z "(aj|ch|etz|etzl|tz|kal|gahn|kab|aj|izl|ts|jaj|lan|kach|chaj|qaq|jol|ix|az|biq|nam)(|(|aw|al|yes|il|ay|en|tom||oj|im|ol|aj|an|as))(aj|am|al|aqa|ende|elja|ich|ak|ix|in|ak|al|il|ek|ij|os|al|im)" - -// Fantasy (K, J, Y, etc.) -#define FANTASY_K_J_Y "(yi|shu|a|be|na|chi|cha|cho|ksa|yi|shu)(th|dd|jj|sh|rr|mk|n|rk|y|jj|th)(us|ash|eni|akra|nai|ral|ect|are|el|urru|aja|al|uz|ict|arja|ichi|ural|iru|aki|esh)" - -// Fantasy (S, E, etc.) -#define FANTASY_S_E "(syth|sith|srr|sen|yth|ssen|then|fen|ssth|kel|syn|est|bess|inth|nen|tin|cor|sv|iss|ith|sen|slar|ssil|sthen|svis|s|ss|s|ss)(|(tys|eus|yn|of|es|en|ath|elth|al|ell|ka|ith|yrrl|is|isl|yr|ast|iy))(us|yn|en|ens|ra|rg|le|en|ith|ast|zon|in|yn|ys)" - - - class Generator - { - typedef enum wrappers { - capitalizer, - reverser - } wrappers_t; - - typedef enum group_types { - symbol, - literal - } group_types_t; - - - class Group { - std::stack wrappers; - std::vector> set; - - public: - group_types_t type; - - Group(group_types_t type_); - virtual ~Group() { } - - std::unique_ptr produce(); - void split(); - void wrap(wrappers_t type); - void add(std::unique_ptr&& g); - - virtual void add(char c); - }; - - - class GroupSymbol : public Group { - public: - GroupSymbol(); - void add(char c); - }; - - - class GroupLiteral : public Group { - public: - GroupLiteral(); - }; - - protected: - std::vector> generators; - - public: - static const std::unordered_map>& SymbolMap(); - - Generator(); - Generator(const std::string& pattern, bool collapse_triples=true); - Generator(std::vector>&& generators_); - - virtual ~Generator() = default; - - virtual size_t combinations(); - virtual size_t min(); - virtual size_t max(); - virtual std::string toString(); - - void add(std::unique_ptr&& g); - }; - - - class Random : public Generator - { - public: - Random(); - Random(std::vector>&& generators_); - - size_t combinations(); - size_t min(); - size_t max(); - std::string toString(); - }; - - - class Sequence : public Generator - { - public: - Sequence(); - Sequence(std::vector>&& generators_); - }; - - - class Literal : public Generator - { - std::string value; - - public: - Literal(const std::string& value_); - - size_t combinations(); - size_t min(); - size_t max(); - std::string toString(); - }; - - - class Reverser : public Generator { - public: - Reverser(std::unique_ptr&& g); - - std::string toString(); - }; - - - class Capitalizer : public Generator - { - public: - Capitalizer(std::unique_ptr&& g); - - std::string toString(); - }; - - - class Collapser : public Generator - { - public: - Collapser(std::unique_ptr&& g); - - std::string toString(); - }; - -} - -std::wstring towstring(const std::string& s); -std::string tostring(const std::wstring& s); \ No newline at end of file diff --git a/world/client.cpp b/world/client.cpp index c4d1c6c70..2d4b65e71 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -46,7 +46,6 @@ #include "clientlist.h" #include "wguild_mgr.h" #include "sof_char_create_data.h" -#include "../common/namegenerator/namegen.h" #include #include @@ -534,14 +533,80 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) return true; } -bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) -{ - NameGen::Generator generator("!Bvss"); - std::string random_name = generator.toString(); +bool Client::HandleGenerateRandomNamePacket(const EQApplicationPacket *app) { + // creates up to a 10 char name + char vowels[18]="aeiouyaeiouaeioe"; + char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd"; + char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr"; + int rndnum=emu_random.Int(0, 75),n=1; + bool dlc=false; + bool vwl=false; + bool dbl=false; + if (rndnum>63) + { // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel + rndnum=(rndnum-61)*2; // name can't start with "ng" "nd" or "rk" + rndname[0]=paircons[rndnum]; + rndname[1]=paircons[rndnum+1]; + n=2; + } + else if (rndnum>16) + { + rndnum-=17; + rndname[0]=cons[rndnum]; + } + else + { + rndname[0]=vowels[rndnum]; + vwl=true; + } + int namlen=emu_random.Int(5, 10); + for (int i=n;i46) + { // pick a cons pair + if (i>namlen-3) // last 2 chars in name? + { // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng" + rndnum=emu_random.Int(0, 7)*2; + } + else + { // pick any from the set + rndnum=(rndnum-47)*2; + } + rndname[i]=paircons[rndnum]; + rndname[i+1]=paircons[rndnum+1]; + dlc=true; // flag keeps second letter from being doubled below + i+=1; + } + else + { // select a single cons + rndname[i]=cons[rndnum]; + } + } + else + { // select a vowel + rndname[i]=vowels[emu_random.Int(0, 16)]; + } + vwl=!vwl; + if (!dbl && !dlc) + { // one chance at double letters in name + if (!emu_random.Int(0, i+9)) // chances decrease towards end of name + { + rndname[i+1]=rndname[i]; + dbl=true; + i+=1; + } + } + } - auto *ngs = (NameGeneration_Struct *) app->pBuffer; - memset(ngs->name, 0, 64); - strcpy(ngs->name, random_name.c_str()); + rndname[0]=toupper(rndname[0]); + NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer; + memset(ngs->name,0,64); + strcpy(ngs->name,rndname); QueuePacket(app); return true; From 88ff56b2f2df92678fe04f1381b7d561a03cec62 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 01:43:00 -0500 Subject: [PATCH 67/84] Add client->SendToGuildHall - have instances properly cycle out IDs --- common/database.h | 10 +- common/database_instances.cpp | 137 ++++++++++++++-------- common/ruletypes.h | 7 +- common/timer.cpp | 12 +- zone/client.cpp | 44 ++++++- zone/client.h | 11 +- zone/client_packet.cpp | 215 ++++++++++++++++++---------------- zone/lua_client.cpp | 6 + zone/lua_client.h | 1 + zone/perl_client.cpp | 26 +++- zone/zone.cpp | 24 +++- zone/zone.h | 4 + 12 files changed, 323 insertions(+), 174 deletions(-) diff --git a/common/database.h b/common/database.h index cf85acf9c..96897e4ea 100644 --- a/common/database.h +++ b/common/database.h @@ -159,7 +159,7 @@ public: uint16 GetInstanceID(const char* zone, uint32 charid, int16 version); uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version); uint16 GetInstanceVersion(uint16 instance_id); - uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma); + uint32 GetTimeRemainingInstance(uint16 instance_id, bool is_perma = false); uint32 VersionFromInstanceID(uint16 instance_id); uint32 ZoneIDFromInstanceID(uint16 instance_id); @@ -196,19 +196,19 @@ public: void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus); void SetAgreementFlag(uint32 acctid); - + int GetIPExemption(std::string account_ip); int GetInstanceID(uint32 char_id, uint32 zone_id); /* Groups */ - + char* GetGroupLeaderForLogin(const char* name,char* leaderbuf); char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr); - + uint32 GetGroupID(const char* name); - + void ClearGroup(uint32 gid = 0); void ClearGroupLeader(uint32 gid = 0); void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false); diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 548a84bdb..3359dc7ce 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -97,42 +97,53 @@ bool Database::CheckInstanceExists(uint16 instance_id) { bool Database::CheckInstanceExpired(uint16 instance_id) { - int32 start_time = 0; - int32 duration = 0; + int32 start_time = 0; + int32 duration = 0; uint32 never_expires = 0; - std::string query = StringFormat("SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id); + std::string query = StringFormat( + "SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", + instance_id + ); + auto results = QueryDatabase(query); - if (!results.Success()) + if (!results.Success()) { return true; + } - if (results.RowCount() == 0) + if (results.RowCount() == 0) { return true; + } auto row = results.begin(); - start_time = atoi(row[0]); - duration = atoi(row[1]); + start_time = atoi(row[0]); + duration = atoi(row[1]); never_expires = atoi(row[2]); - if (never_expires == 1) + if (never_expires == 1) { return false; + } - timeval tv; + timeval tv{}; gettimeofday(&tv, nullptr); - if ((start_time + duration) <= tv.tv_sec) - return true; + return (start_time + duration) <= tv.tv_sec; - return false; } bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration) { - std::string query = StringFormat("INSERT INTO instance_list (id, zone, version, start_time, duration)" - " values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", - (unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration); + std::string query = StringFormat( + "INSERT INTO instance_list (id, zone, version, start_time, duration)" + " values (%u, %u, %u, UNIX_TIMESTAMP(), %u)", + instance_id, + zone_id, + version, + duration + ); + auto results = QueryDatabase(query); return results.Success(); @@ -140,66 +151,79 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version bool Database::GetUnusedInstanceID(uint16 &instance_id) { - uint32 count = RuleI(Zone, ReservedInstances); - uint32 max = 65535; + uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances); + uint32 max = 32000; + + std::string query = StringFormat( + "SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", + max_reserved_instance_id, + max_reserved_instance_id + ); + + if (RuleB(Instances, RecycleInstanceIds)) { + query = ( + SQL( + SELECT i.id + 1 AS next_available + FROM instance_list i + LEFT JOIN instance_list i2 ON i2.id = i.id + 1 + WHERE i2.id IS NULL + ORDER BY i.id + LIMIT 0, 1; + + ) + ); + } - std::string query = StringFormat("SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", count, count); auto results = QueryDatabase(query); - if (!results.Success()) - { + if (!results.Success()) { instance_id = 0; return false; } - if (results.RowCount() == 0) - { - instance_id = 0; - return false; + if (results.RowCount() == 0) { + instance_id = max_reserved_instance_id; + return true; } auto row = results.begin(); - if (atoi(row[0]) <= max) - { + if (atoi(row[0]) <= max) { instance_id = atoi(row[0]); + return true; } - query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", count); + query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id); results = QueryDatabase(query); - if (!results.Success()) - { + if (!results.Success()) { instance_id = 0; return false; } - if (results.RowCount() == 0) - { + if (results.RowCount() == 0) { instance_id = 0; return false; } - count++; - for (auto row = results.begin(); row != results.end(); ++row) - { - if (count < atoi(row[0])) - { - instance_id = count; + max_reserved_instance_id++; + for (auto row = results.begin(); row != results.end(); ++row) { + if (max_reserved_instance_id < atoi(row[0])) { + instance_id = max_reserved_instance_id; return true; } - if (count > max) - { + if (max_reserved_instance_id > max) { instance_id = 0; return false; } - count++; + max_reserved_instance_id++; } - instance_id = count; + instance_id = max_reserved_instance_id; + return true; } @@ -357,7 +381,7 @@ uint16 Database::GetInstanceVersion(uint16 instance_id) { return atoi(row[0]); } -uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma) +uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool is_perma) { uint32 start_time = 0; uint32 duration = 0; @@ -548,17 +572,36 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list &ch void Database::PurgeExpiredInstances() { - std::string query("SELECT id FROM instance_list where (start_time+duration) <= UNIX_TIMESTAMP() and never_expires = 0"); + + /** + * Delay purging by a day so that we can continue using adjacent free instance id's + * from the table without risking the chance we immediately re-allocate a zone that freshly expired but + * has not been fully de-allocated + */ + std::string query = + SQL( + SELECT + id + FROM + instance_list + where + (start_time + duration) <= (UNIX_TIMESTAMP() + 86400) + and never_expires = 0 + ); + auto results = QueryDatabase(query); - if (!results.Success()) + if (!results.Success()) { return; + } - if (results.RowCount() == 0) + if (results.RowCount() == 0) { return; + } - for (auto row = results.begin(); row != results.end(); ++row) + for (auto row = results.begin(); row != results.end(); ++row) { DeleteInstance(atoi(row[0])); + } } void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) @@ -566,4 +609,4 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) std::string query = StringFormat("UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), " "duration=%u WHERE id=%u", new_duration, instance_id); auto results = QueryDatabase(query); -} \ No newline at end of file +} diff --git a/common/ruletypes.h b/common/ruletypes.h index a4c1ef8a2..2f5b9f246 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -270,7 +270,6 @@ RULE_INT(Zone, PEQZoneDebuff1, 4454, "First debuff casted by #peqzone Default is RULE_INT(Zone, PEQZoneDebuff2, 2209, "Second debuff casted by #peqzone Default is Tendrils of Apathy") RULE_BOOL(Zone, UsePEQZoneDebuffs, true, "Will determine if #peqzone will debuff players or not when used") RULE_REAL(Zone, HotZoneBonus, 0.75, "") -RULE_INT(Zone, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running") RULE_INT(Zone, EbonCrystalItemID, 40902, "") RULE_INT(Zone, RadiantCrystalItemID, 40903, "") RULE_BOOL(Zone, LevelBasedEXPMods, false, "Allows you to use the level_exp_mods table in consideration to your players EXP hits") @@ -775,6 +774,12 @@ RULE_BOOL(HotReload, QuestsRepopWhenPlayersNotInCombat, true, "When a hot reload RULE_BOOL(HotReload, QuestsResetTimersWithReload, true, "When a hot reload is triggered, quest timers will be reset") RULE_CATEGORY_END() +RULE_CATEGORY(Instances) +RULE_INT(Instances, ReservedInstances, 30, "Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running") +RULE_BOOL(Instances, RecycleInstanceIds, true, "Will recycle free instance ids instead of gradually running out at 32k") +RULE_INT(Instances, GuildHallExpirationDays, 90, "Amount of days before a Guild Hall instance expires") +RULE_CATEGORY_END() + #undef RULE_CATEGORY #undef RULE_INT #undef RULE_REAL diff --git a/common/timer.cpp b/common/timer.cpp index 120e3dea7..f4d931764 100644 --- a/common/timer.cpp +++ b/common/timer.cpp @@ -129,13 +129,17 @@ void Timer::SetTimer(uint32 set_timer_time) { } } -uint32 Timer::GetRemainingTime() const { +uint32 Timer::GetRemainingTime() const +{ if (enabled) { - if (current_time - start_time > timer_time) + if (current_time - start_time > timer_time) { return 0; - else + } + else { return (start_time + timer_time) - current_time; - } else { + } + } + else { return 0xFFFFFFFF; } } diff --git a/zone/client.cpp b/zone/client.cpp index a270d6579..c75573612 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1918,7 +1918,7 @@ void Client::CheckManaEndUpdate() { else if (group) { group->SendEndurancePacketFrom(this); } - + auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct)); EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer; endurance_update->cur_end = GetEndurance(); @@ -8756,7 +8756,7 @@ void Client::CheckRegionTypeChanges() // still same region, do nothing if (last_region_type == new_region) return; - + // If we got out of water clear any water aggro for water only npcs if (last_region_type == RegionTypeWater) { entity_list.ClearWaterAggro(this); @@ -9203,7 +9203,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id) secondary_item->SetOrnamentationIDFile(model_id); SendItemPacket(EQEmu::invslot::slotSecondary, secondary_item, ItemPacketTrade); WearChange(EQEmu::textures::weaponSecondary, static_cast(model_id), 0); - + Message(Chat::Yellow, "Your secondary weapon appearance has been modified"); } } @@ -9292,3 +9292,41 @@ void Client::SetBotOption(BotOwnerOption boo, bool flag) { } #endif + +void Client::SendToGuildHall() +{ + std::string zone_short_name = "guildhall"; + uint32 zone_id = database.GetZoneID(zone_short_name.c_str()); + if (zone_id == 0) { + return; + } + + uint32 expiration_time = (RuleI(Instances, GuildHallExpirationDays) * 86400); + uint16 instance_id = 0; + std::string guild_hall_instance_key = fmt::format("guild-hall-instance-{}", GuildID()); + std::string instance_data = DataBucket::GetData(guild_hall_instance_key); + if (!instance_data.empty() && std::stoi(instance_data) > 0) { + instance_id = std::stoi(instance_data); + } + + if (instance_id <= 0) { + if (!database.GetUnusedInstanceID(instance_id)) { + Message(Chat::Red, "Server was unable to find a free instance id."); + return; + } + + if (!database.CreateInstance(instance_id, zone_id, 0, expiration_time)) { + Message(Chat::Red, "Server was unable to create a new instance."); + return; + } + + DataBucket::SetData( + guild_hall_instance_key, + std::to_string(instance_id), + std::to_string(expiration_time) + ); + } + + AssignToInstance(instance_id); + MovePC(345, instance_id, -1.00, -1.00, 3.34, 0, 1); +} diff --git a/zone/client.h b/zone/client.h index edc3f18c0..0986a31f5 100644 --- a/zone/client.h +++ b/zone/client.h @@ -633,6 +633,7 @@ public: void MovePC(uint32 zoneID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(uint32 zoneID, uint32 instanceID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); + void SendToGuildHall(); void AssignToInstance(uint16 instance_id); void RemoveFromInstance(uint16 instance_id); void WhoAll(); @@ -691,7 +692,7 @@ public: int GetClientMaxLevel() const { return client_max_level; } void SetClientMaxLevel(int max_level) { client_max_level = max_level; } - + void CheckManaEndUpdate(); void SendManaUpdate(); void SendEnduranceUpdate(); @@ -1293,7 +1294,7 @@ public: void SendHPUpdateMarquee(); void CheckRegionTypeChanges(); - + WaterRegionType GetLastRegion() { return last_region_type; } int32 CalcATK(); @@ -1635,9 +1636,9 @@ private: bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth); int client_max_level; - + #ifdef BOTS - + public: enum BotOwnerOption : size_t { booDeathMarquee, @@ -1654,7 +1655,7 @@ public: bool GetBotOption(BotOwnerOption boo) const; void SetBotOption(BotOwnerOption boo, bool flag = true); - + bool GetBotPulling() { return m_bot_pulling; } void SetBotPulling(bool flag = true) { m_bot_pulling = flag; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 1caf2b4b3..779a4e352 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -599,7 +599,7 @@ void Client::CompleteConnect() if (group) group->SendHPManaEndPacketsTo(this); } - + //bulk raid send in here eventually @@ -818,35 +818,46 @@ void Client::CompleteConnect() database.QueryDatabase( StringFormat( "UPDATE `character_data` SET `last_login` = UNIX_TIMESTAMP() WHERE id = %u", - this->CharacterID() + CharacterID() ) ); } - if (zone) { - if (zone->GetInstanceTimer()) { - uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime(); - uint32 day = (ttime / 86400000); - uint32 hour = (ttime / 3600000) % 24; - uint32 minute = (ttime / 60000) % 60; - uint32 second = (ttime / 1000) % 60; - if (day) { - Message(Chat::Yellow, "%s(%u) will expire in %u days, %u hours, %u minutes, and %u seconds.", - zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second); - } - else if (hour) { - Message(Chat::Yellow, "%s(%u) will expire in %u hours, %u minutes, and %u seconds.", - zone->GetLongName(), zone->GetInstanceID(), hour, minute, second); - } - else if (minute) { - Message(Chat::Yellow, "%s(%u) will expire in %u minutes, and %u seconds.", - zone->GetLongName(), zone->GetInstanceID(), minute, second); - } - else { - Message(Chat::Yellow, "%s(%u) will expire in in %u seconds.", - zone->GetLongName(), zone->GetInstanceID(), second); - } + if (zone && zone->GetInstanceID() > 0) { + + uint32 remaining_time_seconds = zone->GetInstanceTimeRemaining(); + uint32 day = (remaining_time_seconds / 86400); + uint32 hour = (remaining_time_seconds / 3600) % 24; + uint32 minute = (remaining_time_seconds / 60) % 60; + uint32 second = (remaining_time_seconds / 1) % 60; + + LogInfo("Remaining time seconds [{}]", remaining_time_seconds); + + if (day) { + Message( + Chat::Yellow, "%s (%u) will expire in %u days, %u hours, %u minutes, and %u seconds.", + zone->GetLongName(), zone->GetInstanceID(), day, hour, minute, second + ); } + else if (hour) { + Message( + Chat::Yellow, "%s (%u) will expire in %u hours, %u minutes, and %u seconds.", + zone->GetLongName(), zone->GetInstanceID(), hour, minute, second + ); + } + else if (minute) { + Message( + Chat::Yellow, "%s (%u) will expire in %u minutes, and %u seconds.", + zone->GetLongName(), zone->GetInstanceID(), minute, second + ); + } + else { + Message( + Chat::Yellow, "%s (%u) will expire in in %u seconds.", + zone->GetLongName(), zone->GetInstanceID(), second + ); + } + } SendRewards(); @@ -1237,7 +1248,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */ // set to full support in case they're a gm with items in disabled expansion slots..but, have their gm flag off... // item loss will occur when they use the 'empty' slots, if this is not done - m_inv.SetGMInventory(true); + m_inv.SetGMInventory(true); loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */ database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */ database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */ @@ -1341,7 +1352,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) client_max_level = GetCharMaxLevelFromBucket(); } SetClientMaxLevel(client_max_level); - + // we know our class now, so we might have to fix our consume timer! if (class_ == MONK) consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER); @@ -2840,7 +2851,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) // rogue simply won't apply at all, no skill check done. uint16 poison_skill = GetSkill(EQEmu::skills::SkillApplyPoison); - + if (ChanceRoll < (.75 + poison_skill / 1000)) { ApplyPoisonSuccessResult = 1; AddProcToWeapon(poison->Proc.Effect, false, (GetDEX() / 100) + 103, POISON_PROC); @@ -3917,7 +3928,7 @@ void Client::Handle_OP_Bug(const EQApplicationPacket *app) Message(0, "Bug reporting is disabled on this server."); return; } - + if (app->size != sizeof(BugReport_Struct)) { printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct)); } @@ -4017,7 +4028,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) //Message(Chat::Red, "You cant cast right now, you arent in control of yourself!"); return; } - + // Hack for broken RoF2 which allows casting after a zoned IVU/IVA if (invisible_undead || invisible_animals) { BuffFadeByEffect(SE_InvisVsAnimals); @@ -4370,9 +4381,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { sizeof(PlayerPositionUpdateClient_Struct), app->size); return; } - + PlayerPositionUpdateClient_Struct *ppu = (PlayerPositionUpdateClient_Struct *) app->pBuffer; - + /* Boat handling */ if (ppu->spawn_id != GetID()) { /* If player is controlling boat */ @@ -4382,16 +4393,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { controlling_boat_id = 0; return; } - + auto boat_delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); boat->SetDelta(boat_delta); - + auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct *ppus = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer; boat->MakeSpawnUpdate(ppus); entity_list.QueueCloseClients(boat, outapp, true, 300, this, false); safe_delete(outapp); - + /* Update the boat's position on the server, without sending an update */ boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading), false); return; @@ -4406,9 +4417,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { if (cmob != nullptr) { cmob->SetPosition(ppu->x_pos, ppu->y_pos, ppu->z_pos); cmob->SetHeading(EQ12toFloat(ppu->heading)); - mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0, + mMovementManager->SendCommandToClients(cmob, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny, nullptr, this); - cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos, + cmob->CastToNPC()->SaveGuardSpot(glm::vec4(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ12toFloat(ppu->heading))); } } @@ -4426,7 +4437,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { // From this point forward, we need to use a new set of variables for client // position. If the client is in a boat, we need to add the boat pos and // the client offset together. - + float cx = ppu->x_pos; float cy = ppu->y_pos; float cz = ppu->z_pos; @@ -4451,45 +4462,45 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { /* Check to see if PPU should trigger an update to the rewind position. */ float rewind_x_diff = 0; float rewind_y_diff = 0; - + rewind_x_diff = cx - m_RewindLocation.x; rewind_x_diff *= rewind_x_diff; rewind_y_diff = cy - m_RewindLocation.y; rewind_y_diff *= rewind_y_diff; - - /* + + /* We only need to store updated values if the player has moved. If the player has moved more than units for x or y, then we'll store his pre-PPU x and y for /rewind, in case he gets stuck. */ - + if ((rewind_x_diff > 750) || (rewind_y_diff > 750)) m_RewindLocation = glm::vec3(m_Position); - + /* If the PPU was a large jump, such as a cross zone gate or Call of Hero, just update rewind coordinates to the new ppu coordinates. This will prevent exploitation. */ - + if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000)) m_RewindLocation = glm::vec3(cx, cy, cz); - + if (proximity_timer.Check()) { entity_list.ProcessMove(this, glm::vec3(cx, cy, cz)); if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity)) ProcessTaskProximities(cx, cy, cz); - + m_Proximity = glm::vec3(cx, cy, cz); } - + /* Update internal state */ m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); - + if (IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) { if (zone->random.Real(0, 100) < 70)//should be good CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20); } - + /* Break Hide if moving without sneaking and set rewind timer if moved */ if (cy != m_Position.y || cx != m_Position.x) { if ((hidden || improved_hidden) && !sneaking) { @@ -4508,7 +4519,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { } rewind_timer.Start(30000, true); } - + /* Handle client aggro scanning timers NPCs */ is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true; @@ -4572,55 +4583,55 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { } int32 new_animation = ppu->animation; - + /* Update internal server position from what the client has sent */ m_Position.x = cx; m_Position.y = cy; m_Position.z = cz; - + /* Visual Debugging */ if (RuleB(Character, OPClientUpdateVisualDebug)) { LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading); this->SendAppearanceEffect(78, 0, 0, 0, 0); this->SendAppearanceEffect(41, 0, 0, 0, 0); } - + /* Only feed real time updates when client is moving */ if (is_client_moving || new_heading != m_Position.w || new_animation != animation) { - + animation = ppu->animation; m_Position.w = new_heading; - + /* Broadcast update to other clients */ auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp->pBuffer; - + MakeSpawnUpdate(position_update); - + if (gm_hide_me) { entity_list.QueueClientsStatus(this, outapp, true, Admin(), 255); } else { entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true); } - - + + /* Always send position updates to group - send when beyond normal ClientPositionUpdate range */ Group *group = this->GetGroup(); Raid *raid = this->GetRaid(); - + if (raid) { raid->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1)); } else if (group) { group->QueueClients(this, outapp, true, true, (RuleI(Range, ClientPositionUpdates) * -1)); } - + safe_delete(outapp); } - + if (zone->watermap) { if (zone->watermap->InLiquid(glm::vec3(m_Position))) { CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17); - + // Dismount horses when entering water if (GetHorseId() && RuleB(Character, DismountWater)) { SetHorseId(0); @@ -5757,23 +5768,23 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) printf("Error in FindPersonRequest_Struct. Expected size of: %zu, but got: %i\n", sizeof(FindPersonRequest_Struct), app->size); else { FindPersonRequest_Struct* t = (FindPersonRequest_Struct*)app->pBuffer; - + std::vector points; Mob* target = entity_list.GetMob(t->npc_id); - + if (target == nullptr) { //empty length packet == not found. EQApplicationPacket outapp(OP_FindPersonReply, 0); QueuePacket(&outapp); return; } - + if (!RuleB(Pathing, Find) && RuleB(Bazaar, EnableWarpToTrader) && target->IsClient() && (target->CastToClient()->Trader || target->CastToClient()->Buyer)) { Message(Chat::Yellow, "Moving you to Trader %s", target->GetName()); MovePC(zone->GetZoneID(), zone->GetInstanceID(), target->GetX(), target->GetY(), target->GetZ(), 0.0f); } - + if (!RuleB(Pathing, Find) || !zone->pathing) { //fill in the path array... @@ -5796,40 +5807,40 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) { glm::vec3 Start(GetX(), GetY(), GetZ() + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION); glm::vec3 End(target->GetX(), target->GetY(), target->GetZ() + (target->GetSize() < 6.0 ? 6 : target->GetSize()) * HEAD_POSITION); - + bool partial = false; bool stuck = false; auto pathlist = zone->pathing->FindRoute(Start, End, partial, stuck); - + if (pathlist.empty() || partial) { EQApplicationPacket outapp(OP_FindPersonReply, 0); QueuePacket(&outapp); return; } - + // Live appears to send the points in this order: // Final destination. // Current Position. // rest of the points. FindPerson_Point p; - + int PointNumber = 0; - + bool LeadsToTeleporter = false; - + auto v = pathlist.back(); - + p.x = v.pos.x; p.y = v.pos.y; p.z = v.pos.z; points.push_back(p); - + p.x = GetX(); p.y = GetY(); p.z = GetZ(); points.push_back(p); - + for (auto Iterator = pathlist.begin(); Iterator != pathlist.end(); ++Iterator) { if ((*Iterator).teleport) // Teleporter @@ -5837,7 +5848,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) LeadsToTeleporter = true; break; } - + glm::vec3 v = (*Iterator).pos; p.x = v.x; p.y = v.y; @@ -5845,17 +5856,17 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) points.push_back(p); ++PointNumber; } - + if (!LeadsToTeleporter) { p.x = target->GetX(); p.y = target->GetY(); p.z = target->GetZ(); - + points.push_back(p); } } - + SendPathPacket(points); } } @@ -11098,14 +11109,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) { case RaidCommandInviteIntoExisting: case RaidCommandInvite: { - + Client *player_to_invite = entity_list.GetClientByName(raid_command_packet->player_name); if (!player_to_invite) break; Group *player_to_invite_group = player_to_invite->GetGroup(); - + if (player_to_invite->HasRaid()) { Message(Chat::Red, "%s is already in a raid.", player_to_invite->GetName()); break; @@ -11120,7 +11131,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); break; } - + /* Send out invite to the client */ auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *raid_command = (RaidGeneral_Struct*)outapp->pBuffer; @@ -11132,7 +11143,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) raid_command->action = 20; player_to_invite->QueuePacket(outapp); - + safe_delete(outapp); break; @@ -11228,7 +11239,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } if (player_invited_group->IsLeader(player_invited_group->members[x])) { Client *c = nullptr; - + if (player_invited_group->members[x]->IsClient()) c = player_invited_group->members[x]->CastToClient(); else @@ -11238,24 +11249,24 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, true, true, true); raid->SendBulkRaid(c); - + if (raid->IsLocked()) { raid->SendRaidLockTo(c); } } else { Client *c = nullptr; - + if (player_invited_group->members[x]->IsClient()) c = player_invited_group->members[x]->CastToClient(); else continue; - + raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id); raid->SendBulkRaid(c); - + if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -11289,12 +11300,12 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) c = group->members[x]->CastToClient(); else continue; - + raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id, false, true); raid->SendBulkRaid(c); - + if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -11302,17 +11313,17 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) else { Client *c = nullptr; - + if (group->members[x]->IsClient()) c = group->members[x]->CastToClient(); else continue; - + raid->SendRaidCreate(c); raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, raid_free_group_id); raid->SendBulkRaid(c); - + if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -11329,7 +11340,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) if (player_invited_group) { raid = new Raid(player_accepting_invite); - + entity_list.AddRaid(raid); raid->SetRaidDetails(); Client *addClientig = nullptr; @@ -11353,7 +11364,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) raid->SendMakeLeaderPacketTo(raid->leadername, c); raid->AddMember(c, 0, true, true, true); raid->SendBulkRaid(c); - + if (raid->IsLocked()) { raid->SendRaidLockTo(c); } @@ -11478,7 +11489,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) raid->SetGroupLeader(raid_command_packet->leader_name, false); /* We were the leader of our old group */ - if (old_group < 12) { + if (old_group < 12) { /* Assign new group leader if we can */ for (int x = 0; x < MAX_RAID_MEMBERS; x++) { if (raid->members[x].GroupNumber == old_group) { @@ -11507,7 +11518,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) strn0cpy(raid_command_packet->playername, raid->members[x].membername, 64); worldserver.SendPacket(pack); - + safe_delete(pack); } break; @@ -11553,7 +11564,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) raid->SetGroupLeader(raid_command_packet->leader_name, false); for (int x = 0; x < MAX_RAID_MEMBERS; x++) { if (raid->members[x].GroupNumber == oldgrp && strlen(raid->members[x].membername) > 0 && strcmp(raid->members[x].membername, raid_command_packet->leader_name) != 0){ - + raid->SetGroupLeader(raid->members[x].membername); raid->UpdateGroupAAs(oldgrp); @@ -11576,7 +11587,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) strn0cpy(raid_command->playername, raid->members[x].membername, 64); raid_command->zoneid = zone->GetZoneID(); raid_command->instance_id = zone->GetInstanceID(); - + worldserver.SendPacket(pack); safe_delete(pack); } @@ -11591,14 +11602,14 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) else { auto pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* raid_command = (ServerRaidGeneralAction_Struct*)pack->pBuffer; - + raid_command->rid = raid->GetID(); raid_command->zoneid = zone->GetZoneID(); raid_command->instance_id = zone->GetInstanceID(); strn0cpy(raid_command->playername, raid_command_packet->leader_name, 64); worldserver.SendPacket(pack); - + safe_delete(pack); } diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 9d0873360..955130922 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -90,6 +90,11 @@ void Lua_Client::SetPVP(bool v) { self->SetPVP(v); } +void Lua_Client::SendToGuildHall() { + Lua_Safe_Call_Void(); + self->SendToGuildHall(); +} + bool Lua_Client::GetPVP() { Lua_Safe_Call_Bool(); return self->GetPVP(); @@ -1584,6 +1589,7 @@ luabind::scope lua_register_client() { .def("Disconnect", (void(Lua_Client::*)(void))&Lua_Client::Disconnect) .def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD) .def("WorldKick", (void(Lua_Client::*)(void))&Lua_Client::WorldKick) + .def("SendToGuildHall", (void(Lua_Client::*)(void))&Lua_Client::SendToGuildHall) .def("GetAnon", (bool(Lua_Client::*)(void))&Lua_Client::GetAnon) .def("Duck", (void(Lua_Client::*)(void))&Lua_Client::Duck) .def("Stand", (void(Lua_Client::*)(void))&Lua_Client::Stand) diff --git a/zone/lua_client.h b/zone/lua_client.h index aef0378cb..b0eb719e8 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -39,6 +39,7 @@ public: void Disconnect(); bool IsLD(); void WorldKick(); + void SendToGuildHall(); bool GetAnon(); void Duck(); void Stand(); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 2390dea3a..e46b5e8d4 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -245,6 +245,27 @@ XS(XS_Client_WorldKick) { XSRETURN_EMPTY; } +XS(XS_Client_SendToGuildHall); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_SendToGuildHall) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::SendToGuildHall(THIS)"); + { + Client *THIS; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV *) SvRV(ST(0))); + THIS = INT2PTR(Client *, tmp); + } else + Perl_croak(aTHX_ "THIS is not of type Client"); + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + THIS->SendToGuildHall(); + } + XSRETURN_EMPTY; +} + XS(XS_Client_GetAnon); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_GetAnon) { dXSARGS; @@ -2439,7 +2460,7 @@ XS(XS_Client_MemmedCount) { RETVAL = THIS->MemmedCount(); XSprePUSH; - PUSHu((UV) RETVAL); + PUSHu((UV) RETVAL); } XSRETURN(1); } @@ -4786,7 +4807,7 @@ XS(XS_Client_AddLevelBasedExp) { if (items > 2) max_level = (uint8) SvUV(ST(2)); - + if (items > 3) ignore_mods = (bool) SvTRUE(ST(3)); @@ -6564,6 +6585,7 @@ XS(boot_Client) { newXSproto(strcpy(buf, "SendSound"), XS_Client_SendSound, file, "$"); newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$"); newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$"); + newXSproto(strcpy(buf, "SendToGuildHall"), XS_Client_SendToGuildHall, file, "$"); newXSproto(strcpy(buf, "SendWebLink"), XS_Client_SendWebLink, file, "$:$"); newXSproto(strcpy(buf, "SendZoneFlagInfo"), XS_Client_SendZoneFlagInfo, file, "$$"); newXSproto(strcpy(buf, "SetAAPoints"), XS_Client_SetAAPoints, file, "$$"); diff --git a/zone/zone.cpp b/zone/zone.cpp index 16cdc0af8..9e50d0b8c 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -140,7 +140,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { if(iInstanceID != 0) { auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16)); - *((uint16*)pack->pBuffer) = iInstanceID; + *((uint16*)pack->pBuffer) = iInstanceID; worldserver.SendPacket(pack); delete pack; } @@ -491,7 +491,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) { void Zone::GetMerchantDataForZoneLoad() { LogInfo("Loading Merchant Lists"); - std::string query = StringFormat( + std::string query = StringFormat( "SELECT " "DISTINCT ml.merchantid, " "ml.slot, " @@ -816,7 +816,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) { LogDebug("Graveyard ID is [{}]", graveyard_id()); bool GraveYardLoaded = database.GetZoneGraveyard(graveyard_id(), &pgraveyard_zoneid, &m_Graveyard.x, &m_Graveyard.y, &m_Graveyard.z, &m_Graveyard.w); - + if (GraveYardLoaded) { LogDebug("Loaded a graveyard for zone [{}]: graveyard zoneid is [{}] at [{}]", short_name, graveyard_zoneid(), to_string(m_Graveyard).c_str()); } @@ -907,7 +907,7 @@ Zone::~Zone() { //Modified for timezones. bool Zone::Init(bool iStaticZone) { SetStaticZone(iStaticZone); - + //load the zone config file. if (!LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion())) // try loading the zone name... LoadZoneCFG(zone->GetFileName(), zone->GetInstanceVersion()); // if that fails, try the file name, then load defaults @@ -1018,6 +1018,10 @@ bool Zone::Init(bool iStaticZone) { petition_list.ClearPetitions(); petition_list.ReadDatabase(); + if (zone->GetInstanceID() > 0) { + zone->SetInstanceTimeRemaining(database.GetTimeRemainingInstance(zone->GetInstanceID())); + } + LogInfo("Loading timezone data"); zone->zone_time.setEQTimeZone(database.GetZoneTZ(zoneid, GetInstanceVersion())); @@ -1089,7 +1093,7 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id) if (instance_id != 0) { safe_delete_array(map_name); - if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate, + if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind, can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, max_movement_update_range, zone_type, default_ruleset, &map_name)) { LogError("Error loading the Zone Config"); @@ -2455,3 +2459,13 @@ void Zone::SetQuestHotReloadQueued(bool in_quest_hot_reload_queued) { quest_hot_reload_queued = in_quest_hot_reload_queued; } + +uint32 Zone::GetInstanceTimeRemaining() const +{ + return instance_time_remaining; +} + +void Zone::SetInstanceTimeRemaining(uint32 instance_time_remaining) +{ + Zone::instance_time_remaining = instance_time_remaining; +} diff --git a/zone/zone.h b/zone/zone.h index 1243e18c2..fc7fa8bf7 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -278,6 +278,9 @@ public: ZonePoint *GetClosestZonePoint(const glm::vec3 &location, uint32 to, Client *client, float max_distance = 40000.0f); ZonePoint *GetClosestZonePointWithoutZone(float x, float y, float z, Client *client, float max_distance = 40000.0f); + uint32 GetInstanceTimeRemaining() const; + void SetInstanceTimeRemaining(uint32 instance_time_remaining); + /** * GMSay Callback for LogSys * @@ -361,6 +364,7 @@ private: uint8 zone_type; uint16 instanceversion; uint32 instanceid; + uint32 instance_time_remaining; uint32 pgraveyard_id, pgraveyard_zoneid; uint32 pMaxClients; uint32 zoneid; From d89b2f11b5fc334a064f542b4fb0b71a6746ce0d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 02:03:30 -0500 Subject: [PATCH 68/84] Get time remaining directly from database for now, this needs to be cached better at the zone state level, I'll refactor this when repositories are merged in --- zone/client_packet.cpp | 2 +- zone/zone.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 779a4e352..542b52288 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -825,7 +825,7 @@ void Client::CompleteConnect() if (zone && zone->GetInstanceID() > 0) { - uint32 remaining_time_seconds = zone->GetInstanceTimeRemaining(); + uint32 remaining_time_seconds = database.GetTimeRemainingInstance(zone->GetInstanceID()); uint32 day = (remaining_time_seconds / 86400); uint32 hour = (remaining_time_seconds / 3600) % 24; uint32 minute = (remaining_time_seconds / 60) % 60; diff --git a/zone/zone.cpp b/zone/zone.cpp index 9e50d0b8c..55de2b291 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1018,10 +1018,6 @@ bool Zone::Init(bool iStaticZone) { petition_list.ClearPetitions(); petition_list.ReadDatabase(); - if (zone->GetInstanceID() > 0) { - zone->SetInstanceTimeRemaining(database.GetTimeRemainingInstance(zone->GetInstanceID())); - } - LogInfo("Loading timezone data"); zone->zone_time.setEQTimeZone(database.GetZoneTZ(zoneid, GetInstanceVersion())); From bd8e94ff174d9a34c566c10fd249868fdd681a37 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 02:20:56 -0500 Subject: [PATCH 69/84] Use version 1 for GH --- zone/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/client.cpp b/zone/client.cpp index c75573612..4a7a66954 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -9315,7 +9315,7 @@ void Client::SendToGuildHall() return; } - if (!database.CreateInstance(instance_id, zone_id, 0, expiration_time)) { + if (!database.CreateInstance(instance_id, zone_id, 1, expiration_time)) { Message(Chat::Red, "Server was unable to create a new instance."); return; } From d1349e5ac9debf1f9cd5df700f3e28b142fcff56 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 02:30:46 -0500 Subject: [PATCH 70/84] Oops, math --- common/database_instances.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 3359dc7ce..d6a12c750 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -585,7 +585,7 @@ void Database::PurgeExpiredInstances() FROM instance_list where - (start_time + duration) <= (UNIX_TIMESTAMP() + 86400) + (start_time + duration) <= (UNIX_TIMESTAMP() - 86400) and never_expires = 0 ); From 499fe153ab4e38e1534a9bf623f4706442080b75 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 02:56:45 -0500 Subject: [PATCH 71/84] Tweak peq dump [skip ci] --- utils/sql/peq-dump/peq-dump.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index ccb7b8949..1687034fd 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -44,6 +44,7 @@ echo "Generating [create_*] table exports..." bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_login.sql" bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_player.sql" bash -c "${world_bin} database:dump --state-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_state.sql" +echo 'INSERT INTO `instance_list` VALUES (1,25,1,1,0,0,1),(2,25,2,1,0,0,1),(3,151,1,1,0,0,1),(4,114,1,1,0,0,1),(5,344,1,1,0,0,1),(6,202,0,1,0,0,1);' > "${dump_path}create_tables_state.sql" bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql" # with content @@ -67,4 +68,4 @@ bash -c "cd /tmp/ && rm -rf peq-latest.zip && zip peq-latest.zip peq-dump/* && m echo "Cleaning up..." rm -rf ${dump_path} -echo "Dump located [/tmp/peq-latest.zip]" \ No newline at end of file +echo "Dump located [/tmp/peq-latest.zip]" From 0dc3e5ba35f481f66f1d93e4aea5ff5529d47da1 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 03:20:41 -0500 Subject: [PATCH 72/84] Add jank permanent reference pass back in [skip ci] --- common/database.h | 2 +- common/database_instances.cpp | 2 +- zone/client_packet.cpp | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/common/database.h b/common/database.h index 96897e4ea..962349fa9 100644 --- a/common/database.h +++ b/common/database.h @@ -159,7 +159,7 @@ public: uint16 GetInstanceID(const char* zone, uint32 charid, int16 version); uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version); uint16 GetInstanceVersion(uint16 instance_id); - uint32 GetTimeRemainingInstance(uint16 instance_id, bool is_perma = false); + uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma); uint32 VersionFromInstanceID(uint16 instance_id); uint32 ZoneIDFromInstanceID(uint16 instance_id); diff --git a/common/database_instances.cpp b/common/database_instances.cpp index d6a12c750..350c9849f 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -381,7 +381,7 @@ uint16 Database::GetInstanceVersion(uint16 instance_id) { return atoi(row[0]); } -uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool is_perma) +uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma) { uint32 start_time = 0; uint32 duration = 0; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 542b52288..1267386eb 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -823,16 +823,15 @@ void Client::CompleteConnect() ); } - if (zone && zone->GetInstanceID() > 0) { + if (zone && zone->GetInstanceTimer()) { - uint32 remaining_time_seconds = database.GetTimeRemainingInstance(zone->GetInstanceID()); + bool is_permanent = false; + uint32 remaining_time_seconds = database.GetTimeRemainingInstance(zone->GetInstanceID(), is_permanent); uint32 day = (remaining_time_seconds / 86400); uint32 hour = (remaining_time_seconds / 3600) % 24; uint32 minute = (remaining_time_seconds / 60) % 60; uint32 second = (remaining_time_seconds / 1) % 60; - LogInfo("Remaining time seconds [{}]", remaining_time_seconds); - if (day) { Message( Chat::Yellow, "%s (%u) will expire in %u days, %u hours, %u minutes, and %u seconds.", From b5b473f25d5fa00642710122ab351258b310ed47 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 03:21:33 -0500 Subject: [PATCH 73/84] Update peq dump [skip ci] --- utils/sql/peq-dump/peq-dump.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index 1687034fd..086cd3357 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -44,7 +44,7 @@ echo "Generating [create_*] table exports..." bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_login.sql" bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_player.sql" bash -c "${world_bin} database:dump --state-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_state.sql" -echo 'INSERT INTO `instance_list` VALUES (1,25,1,1,0,0,1),(2,25,2,1,0,0,1),(3,151,1,1,0,0,1),(4,114,1,1,0,0,1),(5,344,1,1,0,0,1),(6,202,0,1,0,0,1);' > "${dump_path}create_tables_state.sql" +echo 'REPLACE INTO `instance_list` VALUES (1,25,1,1,0,0,1),(2,25,2,1,0,0,1),(3,151,1,1,0,0,1),(4,114,1,1,0,0,1),(5,344,1,1,0,0,1),(6,202,0,1,0,0,1);' > "${dump_path}create_tables_state.sql" bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql" # with content From b41f2dac663e42fa25bbe78aa945d46738db4028 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 10 Apr 2020 03:26:09 -0500 Subject: [PATCH 74/84] Clamp value for max reserved instance id [skip ci] --- common/database_instances.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 350c9849f..10a2ce032 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -194,6 +194,11 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id) return true; } + if (instance_id < max_reserved_instance_id) { + instance_id = max_reserved_instance_id; + return true; + } + query = StringFormat("SELECT id FROM instance_list where id > %u ORDER BY id", max_reserved_instance_id); results = QueryDatabase(query); From a031c20e7ec865a96aa6f31e6aeefe0ab733cc00 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Sat, 11 Apr 2020 16:44:19 -0500 Subject: [PATCH 75/84] Update peq-dump.sh [skip ci] --- utils/sql/peq-dump/peq-dump.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/peq-dump/peq-dump.sh b/utils/sql/peq-dump/peq-dump.sh index 086cd3357..7eaffdc6a 100755 --- a/utils/sql/peq-dump/peq-dump.sh +++ b/utils/sql/peq-dump/peq-dump.sh @@ -44,7 +44,7 @@ echo "Generating [create_*] table exports..." bash -c "${world_bin} database:dump --login-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_login.sql" bash -c "${world_bin} database:dump --player-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_player.sql" bash -c "${world_bin} database:dump --state-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_state.sql" -echo 'REPLACE INTO `instance_list` VALUES (1,25,1,1,0,0,1),(2,25,2,1,0,0,1),(3,151,1,1,0,0,1),(4,114,1,1,0,0,1),(5,344,1,1,0,0,1),(6,202,0,1,0,0,1);' > "${dump_path}create_tables_state.sql" +echo 'REPLACE INTO `instance_list` VALUES (1,25,1,1,0,0,1),(2,25,2,1,0,0,1),(3,151,1,1,0,0,1),(4,114,1,1,0,0,1),(5,344,1,1,0,0,1),(6,202,0,1,0,0,1);' >> "${dump_path}create_tables_state.sql" bash -c "${world_bin} database:dump --query-serv-tables --table-structure-only --dump-output-to-console | sed 's/ AUTO_INCREMENT=[0-9]*\b//g' > ${dump_path}create_tables_queryserv.sql" # with content From d29c0fc3321dbe9bf763f303a37be13e879d8338 Mon Sep 17 00:00:00 2001 From: TurmoilToad Date: Mon, 13 Apr 2020 10:01:22 -0400 Subject: [PATCH 76/84] Update README.md Updated wiki link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31f88be38..1b08d54be 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ forum, although pull requests will be much quicker and easier on all parties. ## Resources - [EQEmulator Forums](http://www.eqemulator.org/forums) -- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki) +- [EQEmulator Wiki](https://eqemu.gitbook.io/) ## Related Repositories * [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests) From 16cfad1966cacd63e0d0ab93be9ec48762312d69 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Tue, 14 Apr 2020 23:28:43 -0500 Subject: [PATCH 77/84] UCS / Raid / Zone Fixes (#1033) * Cache EntityList::GetRaidByClient * Adjustments [skip ci] * Update entity [skip ci] * More cleanup [skip ci] * More tweaks [skip ci] * Cleanup [skip ci] * Fix bugs with UCS reconnection on crash / exit, not adding soft deleted characters, put main loop on UV lib * Reduce log spam that should be debugging; send keepalives to clients so that they properly prune from the connection list * Shutdown the eventloop to properly shutdown the zone versus calling a hard exit --- ucs/chatchannel.cpp | 29 ++++++++++++++----------- ucs/clientlist.cpp | 51 ++++++++++++++++++++++++++++++-------------- ucs/clientlist.h | 4 +++- ucs/database.cpp | 6 +++--- ucs/ucs.cpp | 24 ++++++++++++++------- ucs/worldserver.cpp | 2 +- world/ucs.cpp | 41 +++++++++++++++++++++++++---------- world/ucs.h | 13 ++++++++--- zone/client.cpp | 1 + zone/client.h | 3 +++ zone/entity.cpp | 23 ++++++++++++++------ zone/raids.cpp | 10 +++++---- zone/worldserver.cpp | 6 ++++-- zone/zone.cpp | 2 +- 14 files changed, 146 insertions(+), 69 deletions(-) diff --git a/ucs/chatchannel.cpp b/ucs/chatchannel.cpp index 001f7b1e7..efac898d5 100644 --- a/ucs/chatchannel.cpp +++ b/ucs/chatchannel.cpp @@ -47,8 +47,13 @@ ChatChannel::ChatChannel(std::string inName, std::string inOwner, std::string in Moderated = false; - LogInfo("New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]", - Name.c_str(), Owner.c_str(), Password.c_str(), MinimumStatus); + LogDebug( + "New ChatChannel created: Name: [[{}]], Owner: [[{}]], Password: [[{}]], MinStatus: [{}]", + Name.c_str(), + Owner.c_str(), + Password.c_str(), + MinimumStatus + ); } @@ -154,7 +159,7 @@ void ChatChannelList::SendAllChannels(Client *c) { void ChatChannelList::RemoveChannel(ChatChannel *Channel) { - LogInfo("RemoveChannel([{}])", Channel->GetName().c_str()); + LogDebug("RemoveChannel ([{}])", Channel->GetName().c_str()); LinkedListIterator iterator(ChatChannels); @@ -175,7 +180,7 @@ void ChatChannelList::RemoveChannel(ChatChannel *Channel) { void ChatChannelList::RemoveAllChannels() { - LogInfo("RemoveAllChannels"); + LogDebug("RemoveAllChannels"); LinkedListIterator iterator(ChatChannels); @@ -242,7 +247,7 @@ void ChatChannel::AddClient(Client *c) { int AccountStatus = c->GetAccountStatus(); - LogInfo("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str()); + LogDebug("Adding [{}] to channel [{}]", c->GetName().c_str(), Name.c_str()); LinkedListIterator iterator(ClientsInChannel); @@ -267,7 +272,7 @@ bool ChatChannel::RemoveClient(Client *c) { if(!c) return false; - LogInfo("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str()); + LogDebug("RemoveClient [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str()); bool HideMe = c->GetHideMe(); @@ -304,7 +309,7 @@ bool ChatChannel::RemoveClient(Client *c) { if((Password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0)) return false; - LogInfo("Starting delete timer for empty password protected channel [{}]", Name.c_str()); + LogDebug("Starting delete timer for empty password protected channel [{}]", Name.c_str()); DeleteTimer.Start(RuleI(Channels, DeleteTimer) * 60000); } @@ -402,7 +407,7 @@ void ChatChannel::SendMessageToChannel(std::string Message, Client* Sender) { if(ChannelClient) { - LogInfo("Sending message to [{}] from [{}]", + LogDebug("Sending message to [{}] from [{}]", ChannelClient->GetName().c_str(), Sender->GetName().c_str()); if (cv_messages[static_cast(ChannelClient->GetClientVersion())].length() == 0) { @@ -505,7 +510,7 @@ ChatChannel *ChatChannelList::AddClientToChannel(std::string ChannelName, Client return nullptr; } - LogInfo("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str()); + LogDebug("AddClient to channel [[{}]] with password [[{}]]", NormalisedName.c_str(), Password.c_str()); ChatChannel *RequiredChannel = FindChannel(NormalisedName); @@ -581,7 +586,7 @@ void ChatChannelList::Process() { if(CurrentChannel && CurrentChannel->ReadyToDelete()) { - LogInfo("Empty temporary password protected channel [{}] being destroyed", + LogDebug("Empty temporary password protected channel [{}] being destroyed", CurrentChannel->GetName().c_str()); RemoveChannel(CurrentChannel); @@ -597,7 +602,7 @@ void ChatChannel::AddInvitee(const std::string &Invitee) if (!IsInvitee(Invitee)) { Invitees.push_back(Invitee); - LogInfo("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); + LogDebug("Added [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); } } @@ -608,7 +613,7 @@ void ChatChannel::RemoveInvitee(std::string Invitee) if(it != std::end(Invitees)) { Invitees.erase(it); - LogInfo("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); + LogDebug("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), Name.c_str()); } } diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp index 429f28fbf..0b1d43262 100644 --- a/ucs/clientlist.cpp +++ b/ucs/clientlist.cpp @@ -235,7 +235,7 @@ std::vector ParseRecipients(std::string RecipientString) { static void ProcessMailTo(Client *c, std::string MailMessage) { - LogInfo("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str()); + LogDebug("MAILTO: From [{}], [{}]", c->MailBoxName().c_str(), MailMessage.c_str()); std::vector Recipients; @@ -304,7 +304,7 @@ static void ProcessMailTo(Client *c, std::string MailMessage) { if (!database.SendMail(Recipient, c->MailBoxName(), Subject, Body, RecipientsString)) { - LogInfo("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(), + LogError("Failed in SendMail([{}], [{}], [{}], [{}])", Recipient.c_str(), c->MailBoxName().c_str(), Subject.c_str(), RecipientsString.c_str()); int PacketLength = 10 + Recipient.length() + Subject.length(); @@ -556,6 +556,17 @@ void Client::CloseConnection() { ClientStream->ReleaseFromUse(); } +void Clientlist::CheckForStaleConnectionsAll() +{ + LogDebug("Checking for stale connections"); + + auto it = ClientChatConnections.begin(); + while (it != ClientChatConnections.end()) { + (*it)->SendKeepAlive(); + ++it; + } +} + void Clientlist::CheckForStaleConnections(Client *c) { if (!c) return; @@ -634,10 +645,12 @@ void Clientlist::Process() // std::string::size_type LastPeriod = MailBoxString.find_last_of("."); - if (LastPeriod == std::string::npos) + if (LastPeriod == std::string::npos) { CharacterName = MailBoxString; - else + } + else { CharacterName = MailBoxString.substr(LastPeriod + 1); + } LogInfo("Received login for user [{}] with key [{}]", MailBox, Key); @@ -652,8 +665,9 @@ void Clientlist::Process() database.GetAccountStatus((*it)); - if ((*it)->GetConnectionType() == ConnectionTypeCombined) + if ((*it)->GetConnectionType() == ConnectionTypeCombined) { (*it)->SendFriends(); + } (*it)->SendMailBoxes(); @@ -865,7 +879,9 @@ void Clientlist::CloseAllConnections() { void Client::AddCharacter(int CharID, const char *CharacterName, int Level) { if (!CharacterName) return; - LogInfo("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str()); + + LogDebug("Adding character [{}] with ID [{}] for [{}]", CharacterName, CharID, GetName().c_str()); + CharacterEntry NewCharacter; NewCharacter.CharID = CharID; NewCharacter.Name = CharacterName; @@ -874,6 +890,10 @@ void Client::AddCharacter(int CharID, const char *CharacterName, int Level) { Characters.push_back(NewCharacter); } +void Client::SendKeepAlive() { + QueuePacket(new EQApplicationPacket(OP_SessionReady, 0)); +} + void Client::SendMailBoxes() { int Count = Characters.size(); @@ -930,7 +950,7 @@ void Client::AddToChannelList(ChatChannel *JoinedChannel) { for (int i = 0; i < MAX_JOINED_CHANNELS; i++) if (JoinedChannels[i] == nullptr) { JoinedChannels[i] = JoinedChannel; - LogInfo("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str()); + LogDebug("Added Channel [{}] to slot [{}] for [{}]", JoinedChannel->GetName().c_str(), i + 1, GetName().c_str()); return; } } @@ -2346,18 +2366,17 @@ void Client::SendFriends() { } } -std::string Client::MailBoxName() { +std::string Client::MailBoxName() +{ + if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) { + LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", + CurrentMailBox, Characters.size()); - if ((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) - { - LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", - CurrentMailBox, Characters.size()); - - return ""; + return std::string(); } - LogInfo("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", - CurrentMailBox, Characters.size()); + LogDebug("MailBoxName() called with CurrentMailBox set to [{}] and Characters.size() is [{}]", + CurrentMailBox, Characters.size()); return Characters[CurrentMailBox].Name; diff --git a/ucs/clientlist.h b/ucs/clientlist.h index 6021c5c0e..548fb170c 100644 --- a/ucs/clientlist.h +++ b/ucs/clientlist.h @@ -143,7 +143,7 @@ public: void SetConnectionType(char c); ConnectionType GetConnectionType() { return TypeOfConnection; } EQEmu::versions::ClientVersion GetClientVersion() { return ClientVersion_; } - + inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); } void SendNotification(int MailBoxNumber, std::string From, std::string Subject, int MessageID); void ChangeMailBox(int NewMailBox); @@ -151,6 +151,7 @@ public: void SendFriends(); int GetCharID(); void SendUptime(); + void SendKeepAlive(); private: unsigned int CurrentMailBox; @@ -183,6 +184,7 @@ public: void Process(); void CloseAllConnections(); Client *FindCharacter(std::string CharacterName); + void CheckForStaleConnectionsAll(); void CheckForStaleConnections(Client *c); Client *IsCharacterOnline(std::string CharacterName); void ProcessOPMailCommand(Client *c, std::string CommandString); diff --git a/ucs/database.cpp b/ucs/database.cpp index d756f1ff4..108b17871 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -108,7 +108,7 @@ void Database::GetAccountStatus(Client *client) { std::string query = StringFormat( - "SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = '%i' LIMIT 1", + "SELECT `status`, `hideme`, `karma`, `revoked` FROM `account` WHERE `id` = %i LIMIT 1", client->GetAccountID() ); @@ -173,7 +173,7 @@ int Database::FindAccount(const char *characterName, Client *client) query = StringFormat( "SELECT `id`, `name`, `level` FROM `character_data` " - "WHERE `account_id` = %i AND `name` != '%s'", + "WHERE `account_id` = %i AND `name` != '%s' AND deleted_at is NULL", accountID, characterName ); @@ -320,7 +320,7 @@ void Database::SendHeaders(Client *client) int unknownField3 = 1; int characterID = FindCharacter(client->MailBoxName().c_str()); - LogInfo("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID); + LogDebug("Sendheaders for [{}], CharID is [{}]", client->MailBoxName().c_str(), characterID); if (characterID <= 0) { return; diff --git a/ucs/ucs.cpp b/ucs/ucs.cpp index 0f396252b..46bda530c 100644 --- a/ucs/ucs.cpp +++ b/ucs/ucs.cpp @@ -70,17 +70,18 @@ int main() { // Check every minute for unused channels we can delete // Timer ChannelListProcessTimer(60000); + Timer ClientConnectionPruneTimer(60000); Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect LogInfo("Starting EQEmu Universal Chat Server"); - if (!ucsconfig::LoadConfig()) { - LogInfo("Loading server configuration failed"); + if (!ucsconfig::LoadConfig()) { + LogInfo("Loading server configuration failed"); return 1; } - Config = ucsconfig::get(); + Config = ucsconfig::get(); WorldShortName = Config->ShortName; @@ -144,19 +145,26 @@ int main() { worldserver = new WorldServer; - while(RunLoops) { + auto loop_fn = [&](EQ::Timer* t) { Timer::SetCurrentTime(); g_Clientlist->Process(); - if(ChannelListProcessTimer.Check()) + if (ChannelListProcessTimer.Check()) { ChannelList->Process(); + } - EQ::EventLoop::Get().Process(); + if (ClientConnectionPruneTimer.Check()) { + g_Clientlist->CheckForStaleConnectionsAll(); + } - Sleep(5); - } + }; + + EQ::Timer process_timer(loop_fn); + process_timer.Start(32, true); + + EQ::EventLoop::Get().Run(); ChannelList->RemoveAllChannels(); diff --git a/ucs/worldserver.cpp b/ucs/worldserver.cpp index 72865e416..107624a0d 100644 --- a/ucs/worldserver.cpp +++ b/ucs/worldserver.cpp @@ -61,7 +61,7 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p) ServerPacket tpack(opcode, p); ServerPacket *pack = &tpack; - LogInfo("Received Opcode: {:#04x}", opcode); + LogNetcode("Received Opcode: {:#04x}", opcode); switch (opcode) { diff --git a/world/ucs.cpp b/world/ucs.cpp index f5910da80..cde94b8d9 100644 --- a/world/ucs.cpp +++ b/world/ucs.cpp @@ -6,29 +6,38 @@ #include "../common/misc_functions.h" #include "../common/md5.h" #include "../common/packet_dump.h" +#include "../common/event/timer.h" UCSConnection::UCSConnection() { - Stream = 0; + connection = 0; } void UCSConnection::SetConnection(std::shared_ptr inStream) { - if (Stream && Stream->Handle()) - { + if (inStream && connection && connection->Handle()) { LogInfo("Incoming UCS Connection while we were already connected to a UCS"); - Stream->Handle()->Disconnect(); + connection->Handle()->Disconnect(); + } + + connection = inStream; + if (connection) { + connection->OnMessage( + std::bind( + &UCSConnection::ProcessPacket, + this, + std::placeholders::_1, + std::placeholders::_2 + ) + ); } - Stream = inStream; - if (Stream) { - Stream->OnMessage(std::bind(&UCSConnection::ProcessPacket, this, std::placeholders::_1, std::placeholders::_2)); - } + m_keepalive.reset(new EQ::Timer(5000, true, std::bind(&UCSConnection::OnKeepAlive, this, std::placeholders::_1))); } void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p) { - if (!Stream) + if (!connection) return; ServerPacket tpack(opcode, p); @@ -60,10 +69,10 @@ void UCSConnection::ProcessPacket(uint16 opcode, EQ::Net::Packet &p) void UCSConnection::SendPacket(ServerPacket* pack) { - if (!Stream) + if (!connection) return; - Stream->SendPacket(pack); + connection->SendPacket(pack); } void UCSConnection::SendMessage(const char *From, const char *Message) @@ -78,3 +87,13 @@ void UCSConnection::SendMessage(const char *From, const char *Message) SendPacket(pack); safe_delete(pack); } + +void UCSConnection::OnKeepAlive(EQ::Timer *t) +{ + if (!connection) { + return; + } + + ServerPacket pack(ServerOP_KeepAlive, 0); + connection->SendPacket(&pack); +} diff --git a/world/ucs.h b/world/ucs.h index d2051c0be..c32872ccb 100644 --- a/world/ucs.h +++ b/world/ucs.h @@ -4,6 +4,7 @@ #include "../common/types.h" #include "../common/net/servertalk_server_connection.h" #include "../common/servertalk.h" +#include "../common/event/timer.h" #include class UCSConnection @@ -13,11 +14,17 @@ public: void SetConnection(std::shared_ptr connection); void ProcessPacket(uint16 opcode, EQ::Net::Packet &p); void SendPacket(ServerPacket* pack); - void Disconnect() { if(Stream && Stream->Handle()) Stream->Handle()->Disconnect(); } + void Disconnect() { if(connection && connection->Handle()) connection->Handle()->Disconnect(); } void SendMessage(const char *From, const char *Message); private: - inline std::string GetIP() const { return (Stream && Stream->Handle()) ? Stream->Handle()->RemoteIP() : 0; } - std::shared_ptr Stream; + inline std::string GetIP() const { return (connection && connection->Handle()) ? connection->Handle()->RemoteIP() : 0; } + std::shared_ptr connection; + + /** + * Keepalive + */ + std::unique_ptr m_keepalive; + void OnKeepAlive(EQ::Timer *t); }; #endif /*UCS_H_*/ diff --git a/zone/client.cpp b/zone/client.cpp index 4a7a66954..e730b32ee 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -256,6 +256,7 @@ Client::Client(EQStreamInterface* ieqs) TotalSecondsPlayed = 0; keyring.clear(); bind_sight_target = nullptr; + p_raid_instance = nullptr; mercid = 0; mercSlot = 0; InitializeMercInfo(); diff --git a/zone/client.h b/zone/client.h index 0986a31f5..be842ff50 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1304,6 +1304,8 @@ public: void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update); glm::vec4 &GetLastPositionBeforeBulkUpdate(); + Raid *p_raid_instance; + protected: friend class Mob; void CalcItemBonuses(StatBonuses* newbon); @@ -1343,6 +1345,7 @@ protected: char *adv_data; private: + eqFilterMode ClientFilters[_FilterCount]; int32 HandlePacket(const EQApplicationPacket *app); void OPTGB(const EQApplicationPacket *app); diff --git a/zone/entity.cpp b/zone/entity.cpp index b3805ad63..23ff268fc 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -498,7 +498,7 @@ void EntityList::MobProcess() size_t sz = mob_list.size(); #ifdef IDLE_WHEN_EMPTY - if (numclients > 0 || + if (numclients > 0 || mob->GetWanderType() == 4 || mob->GetWanderType() == 6) { // Normal processing, or assuring that spawns that should // path and depop do that. Otherwise all of these type mobs @@ -931,12 +931,12 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client) memcpy(new_door.name, door->GetDoorName(), 32); auto position = door->GetPosition(); - + new_door.xPos = position.x; new_door.yPos = position.y; new_door.zPos = position.z; new_door.heading = position.w; - + new_door.incline = door->GetIncline(); new_door.size = door->GetSize(); new_door.doorId = door->GetDoorID(); @@ -1984,17 +1984,26 @@ Raid *EntityList::GetRaidByID(uint32 id) Raid *EntityList::GetRaidByClient(Client* client) { - std::list::iterator iterator; + if (client->p_raid_instance) { + return client->p_raid_instance; + } + std::list::iterator iterator; iterator = raid_list.begin(); while (iterator != raid_list.end()) { - for (int x = 0; x < MAX_RAID_MEMBERS; x++) - if ((*iterator)->members[x].member) - if((*iterator)->members[x].member == client) + for (auto &member : (*iterator)->members) { + if (member.member) { + if (member.member == client) { + client->p_raid_instance = *iterator; return *iterator; + } + } + } + ++iterator; } + return nullptr; } diff --git a/zone/raids.cpp b/zone/raids.cpp index a4e1535d3..428b17843 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -177,6 +177,7 @@ void Raid::RemoveMember(const char *characterName) if(client) { client->SetRaidGrouped(false); client->LeaveRaidXTargets(this); + client->p_raid_instance = nullptr; } auto pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct)); @@ -1078,8 +1079,9 @@ void Raid::SendRaidRemoveAll(const char *who) void Raid::SendRaidDisband(Client *to) { - if(!to) + if (!to) { return; + } auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; @@ -1614,7 +1616,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) return; uint32 group_id = 0; - + if(mob->IsClient()) group_id = this->GetGroup(mob->CastToClient()); @@ -1622,7 +1624,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) EQApplicationPacket outapp(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); mob->CreateHPPacket(&hpapp); - + for(int x = 0; x < MAX_RAID_MEMBERS; x++) { if(members[x].member) { if(!mob->IsClient() || ((members[x].member != mob->CastToClient()) && (members[x].GroupNumber == group_id))) { @@ -1633,7 +1635,7 @@ void Raid::SendHPManaEndPacketsFrom(Mob *mob) mana_update->spawn_id = mob->GetID(); mana_update->mana = mob->GetManaPercent(); members[x].member->QueuePacket(&outapp, false); - + outapp.SetOpcode(OP_MobEnduranceUpdate); MobEnduranceUpdate_Struct *endurance_update = (MobEnduranceUpdate_Struct *)outapp.pBuffer; endurance_update->endurance = mob->GetEndurancePercent(); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 87cfb13ef..4b2034067 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1881,9 +1881,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } case ServerOP_UCSServerStatusReply: { - auto ucsss = (UCSServerStatus_Struct*)pack->pBuffer; - if (zone) + auto ucsss = (UCSServerStatus_Struct *) pack->pBuffer; + if (zone) { zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp); + LogInfo("UCS Server is now [{}]", (ucsss->available == 1 ? "online" : "offline")); + } break; } case ServerOP_CZSetEntityVariableByNPCTypeID: diff --git a/zone/zone.cpp b/zone/zone.cpp index 55de2b291..398c985c6 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -734,7 +734,7 @@ void Zone::Shutdown(bool quiet) if (RuleB(Zone, KillProcessOnDynamicShutdown)) { LogInfo("[KillProcessOnDynamicShutdown] Shutting down"); - std::exit(EXIT_SUCCESS); + EQ::EventLoop::Get().Shutdown(); } } From 15f3697df166295ef3e7aa27fce73a0df7013868 Mon Sep 17 00:00:00 2001 From: Ali Date: Fri, 17 Apr 2020 10:56:43 +0300 Subject: [PATCH 78/84] Fix edge case with NPC pet owners charming PCs * Addresses #1036 * Cleaned up if statement formatting * Using Mob::GetOwnerOrSelf() now, which accounts for the edge case NB: The Mob::SpellOnTarget() and Mob::CommonDamage() methods really should be looked at and spell logic combined somehow. Both have if statements that dodge around the other's conditions to decide which method sends the CombatDamage_Struct packet --- zone/spells.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index be1419caa..d9378a23c 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3979,6 +3979,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r cd->hit_heading = action->hit_heading; cd->hit_pitch = action->hit_pitch; cd->damage = 0; + + auto spellOwner = GetOwnerOrSelf(); if(!IsEffectInSpell(spell_id, SE_BindAffinity) && !is_damage_or_lifetap_spell){ entity_list.QueueCloseClients( spelltar, /* Sender */ @@ -3989,14 +3991,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r true, /* Packet ACK */ (spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) /* Message Filter Type: (8 or 9) */ ); - } else if (is_damage_or_lifetap_spell && - (IsClient() || - (HasOwner() && - GetOwner()->IsClient() - ) - ) - ) { - (HasOwner() ? GetOwner() : this)->CastToClient()->QueuePacket( + } else if (is_damage_or_lifetap_spell && spellOwner->IsClient()) { + spellOwner->CastToClient()->QueuePacket( message_packet, true, Mob::CLIENT_CONNECTINGALL, From b8e7e5bb0dd0ce85d1ab8965d6886bc4dfb2cf2c Mon Sep 17 00:00:00 2001 From: Ali Date: Fri, 17 Apr 2020 18:46:07 +0300 Subject: [PATCH 79/84] [skip ci] Added a VS ignore for x64 compiles --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b8ec6881f..1db525804 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,5 @@ cmake-build-debug/ libs/ bin/ /Win32 +/x64 /client_files/**/CMakeFiles/ From 5d4e53bb25fc8a1e2f26a2aef066500e071babf0 Mon Sep 17 00:00:00 2001 From: Ali Date: Fri, 17 Apr 2020 18:48:43 +0300 Subject: [PATCH 80/84] Removed redundant check during enter world --- world/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/client.cpp b/world/client.cpp index 2d4b65e71..18f0aa776 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -714,7 +714,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { EQApplicationPacket *outapp; uint32 tmpaccid = 0; charid = database.GetCharacterInfo(char_name, &tmpaccid, &zone_id, &instance_id); - if (charid == 0 || tmpaccid != GetAccountID()) { + if (charid == 0) { LogInfo("Could not get CharInfo for [{}]", char_name); eqs->Close(); return true; From 21ed02ca52915f7fb96bb4bbb41dda17d3be1b36 Mon Sep 17 00:00:00 2001 From: peterigz Date: Fri, 17 Apr 2020 18:27:45 +0100 Subject: [PATCH 81/84] Add missing break for OP_AppCombined switch statement --- common/net/daybreak_connection.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/net/daybreak_connection.cpp b/common/net/daybreak_connection.cpp index bd0c39489..693a47bf1 100644 --- a/common/net/daybreak_connection.cpp +++ b/common/net/daybreak_connection.cpp @@ -605,6 +605,8 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) ProcessDecodedPacket(StaticPacket(current, subpacket_length)); current += subpacket_length; } + + break; } case OP_SessionRequest: From 54d494da36269eb071141010ab558dc0f480ad18 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Tue, 21 Apr 2020 00:40:18 -0400 Subject: [PATCH 82/84] Fix errant merchant full messages and add logging for later use (#1035) * Fix errant merchant full issues, add logging for later use * Rename merchant list dump more clearly * spaces around '=' * Added line spacing, Co-authored-by: Noudess --- zone/inventory.cpp | 44 ++++++----- zone/zone.cpp | 185 ++++++++++++++++++++++++++++++++------------- zone/zone.h | 1 + 3 files changed, 159 insertions(+), 71 deletions(-) diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 3ee86df47..f9438b32c 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -2913,23 +2913,33 @@ void Client::SendItemPacket(int16 slot_id, const EQEmu::ItemInstance* inst, Item if (!inst) return; - if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) { - if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) - return; - } - else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) { - auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT); - if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0) - return; - } - else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) { - if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank) - return; - } - else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) { - auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT; - if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank) - return; + if (packet_type != ItemPacketMerchant) { + if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) { + if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0) { + LogError("Item not sent to merchant : slot [{}]", slot_id); + return; + } + } + else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) { + auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT); + if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0) { + LogError("Item not sent to merchant2 : slot [{}]", slot_id); + return; + } + } + else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) { + if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize.Bank) { + LogError("Item not sent to merchant3 : slot [{}]", slot_id); + return; + } + } + else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) { + auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT; + if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize.Bank) { + LogError("Item not sent to merchant4 : slot [{}]", slot_id); + return; + } + } } // Serialize item into |-delimited string (Titanium- uses '|' delimiter .. newer clients use pure data serialization) diff --git a/zone/zone.cpp b/zone/zone.cpp index 398c985c6..d64c198d3 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -330,81 +330,156 @@ bool Zone::LoadGroundSpawns() { return(true); } -int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) { - int freeslot = 0; - std::list merlist = merchanttable[merchantid]; - std::list::const_iterator itr; - uint32 i = 1; - for (itr = merlist.begin(); itr != merlist.end(); ++itr) { - MerchantList ml = *itr; - if (ml.item == item) - return 0; - - // Account for merchant lists with gaps in them. - if (ml.slot >= i) - i = ml.slot + 1; - } +void Zone::DumpMerchantList(uint32 npcid) { std::list tmp_merlist = tmpmerchanttable[npcid]; std::list::const_iterator tmp_itr; - bool update_charges = false; TempMerchantList ml; - while (freeslot == 0 && !update_charges) { - freeslot = i; - for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { - ml = *tmp_itr; - if (ml.item == item) { - update_charges = true; - freeslot = 0; - break; - } - if ((ml.slot == i) || (ml.origslot == i)) { - freeslot = 0; - } - } - i++; + + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml = *tmp_itr; + + LogInventory("slot[{}] Orig[{}] Item[{}] Charges[{}]", ml.slot, ml.origslot, ml.item, ml.charges); } - if (update_charges) { +} + +int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) { + + LogInventory("Transaction of [{}] [{}]", charges, item); + //DumpMerchantList(npcid); + // Iterate past main items. + // If the item being transacted is in this list, return 0; + std::list merlist = merchanttable[merchantid]; + std::list::const_iterator itr; + uint32 temp_slot_index = 1; + for (itr = merlist.begin(); itr != merlist.end(); ++itr) { + MerchantList ml = *itr; + if (ml.item == item) { + return 0; + } + + // Account for merchant lists with gaps in them. + if (ml.slot >= temp_slot_index) { + temp_slot_index = ml.slot + 1; + } + } + + LogInventory("Searching Temporary List. Main list ended at [{}]", temp_slot_index-1); + + // Now search the temporary list. + std::list tmp_merlist = tmpmerchanttable[npcid]; + std::list::const_iterator tmp_itr; + TempMerchantList ml; + uint32 first_empty_slot = 0; // Save 1st vacant slot while searching.. + bool found = false; + + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml = *tmp_itr; + + if (ml.item == item) { + found = true; + LogInventory("Item found in temp list at [{}] with [{}] charges", ml.origslot, ml.charges); + break; + } + } + + if (found) { tmp_merlist.clear(); std::list oldtmp_merlist = tmpmerchanttable[npcid]; for (tmp_itr = oldtmp_merlist.begin(); tmp_itr != oldtmp_merlist.end(); ++tmp_itr) { TempMerchantList ml2 = *tmp_itr; if(ml2.item != item) tmp_merlist.push_back(ml2); + else { + if (sold) { + LogInventory("Total charges is [{}] + [{}] charges", ml.charges, charges); + ml.charges = ml.charges + charges; + } + else { + ml.charges = charges; + LogInventory("new charges is [{}] charges", ml.charges); + } + + if (!ml.origslot) { + ml.origslot = ml.slot; + } + + if (charges > 0) { + database.SaveMerchantTemp(npcid, ml.origslot, item, ml.charges); + tmp_merlist.push_back(ml); + } + else { + database.DeleteMerchantTemp(npcid, ml.origslot); + } + } } - if (sold) - ml.charges = ml.charges + charges; - else - ml.charges = charges; - if (!ml.origslot) - ml.origslot = ml.slot; - if (charges > 0) { - database.SaveMerchantTemp(npcid, ml.origslot, item, ml.charges); - tmp_merlist.push_back(ml); - } - else { - database.DeleteMerchantTemp(npcid, ml.origslot); - } + tmpmerchanttable[npcid] = tmp_merlist; - - if (sold) - return ml.slot; - + //DumpMerchantList(npcid); + return ml.slot; } - if (freeslot) { - if (charges < 0) //sanity check only, shouldnt happen + else { + if (charges < 0) { //sanity check only, shouldnt happen charges = 0x7FFF; - database.SaveMerchantTemp(npcid, freeslot, item, charges); + } + + // Find an ununsed db slot # + std::list slots; + TempMerchantList ml3; + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml3 = *tmp_itr; + slots.push_back(ml3.origslot); + } + slots.sort(); + std::list::const_iterator slots_itr; + uint32 first_empty_slot = 0; + uint32 idx = temp_slot_index; + for (slots_itr = slots.begin(); slots_itr != slots.end(); ++slots_itr) { + if (!first_empty_slot && *slots_itr > idx) { + LogInventory("Popped [{}]", *slots_itr); + LogInventory("First Gap Found at [{}]", idx); + break; + } + + ++idx; + } + + first_empty_slot = idx; + + // Find an ununsed mslot + slots.clear(); + for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) { + ml3 = *tmp_itr; + slots.push_back(ml3.slot); + } + slots.sort(); + uint32 first_empty_mslot=0; + idx = temp_slot_index; + for (slots_itr = slots.begin(); slots_itr != slots.end(); ++slots_itr) { + if (!first_empty_mslot && *slots_itr > idx) { + LogInventory("Popped [{}]", *slots_itr); + LogInventory("First Gap Found at [{}]", idx); + break; + } + + ++idx; + } + + first_empty_mslot = idx; + + database.SaveMerchantTemp(npcid, first_empty_slot, item, charges); tmp_merlist = tmpmerchanttable[npcid]; TempMerchantList ml2; ml2.charges = charges; + LogInventory("Adding slot [{}] with [{}] charges.", first_empty_mslot, charges); ml2.item = item; ml2.npcid = npcid; - ml2.slot = freeslot; - ml2.origslot = ml2.slot; + ml2.slot = first_empty_mslot; + ml2.origslot = first_empty_slot; tmp_merlist.push_back(ml2); tmpmerchanttable[npcid] = tmp_merlist; + //DumpMerchantList(npcid); + return ml2.slot; } - return freeslot; } uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) { @@ -413,8 +488,10 @@ uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) { std::list::const_iterator Iterator; for (Iterator = TmpMerchantList.begin(); Iterator != TmpMerchantList.end(); ++Iterator) - if ((*Iterator).slot == Slot) + if ((*Iterator).slot == Slot) { + LogInventory("Slot [{}] has [{}] charges.", Slot, (*Iterator).charges); return (*Iterator).charges; + } return 0; } diff --git a/zone/zone.h b/zone/zone.h index fc7fa8bf7..6d8fc54e6 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -163,6 +163,7 @@ public: inline void ShowNPCGlobalLoot(Client *to, NPC *who) { m_global_loot.ShowNPCGlobalLoot(to, who); } inline void ShowZoneGlobalLoot(Client *to) { m_global_loot.ShowZoneGlobalLoot(to); } int GetZoneTotalBlockedSpells() { return zone_total_blocked_spells; } + void DumpMerchantList(uint32 npcid); int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold = false); int32 MobsAggroCount() { return aggroedmobs; } From 387e1668a5bc3b27e1460dbff74d5337fdfb6383 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 24 Apr 2020 01:25:09 -0500 Subject: [PATCH 83/84] Remove hard delete from `DeleteInstance` so that the purge timer can pick it up later --- common/database_instances.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 10a2ce032..0e6e8b380 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -515,8 +515,8 @@ void Database::BuryCorpsesInInstance(uint16 instance_id) { void Database::DeleteInstance(uint16 instance_id) { - std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id); - QueryDatabase(query); +// std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id); +// QueryDatabase(query); query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id); QueryDatabase(query); From 954247956e6e2c8e3351b6760b0d003d90c842ad Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 24 Apr 2020 02:11:06 -0500 Subject: [PATCH 84/84] Adjust syntax --- common/database_instances.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/database_instances.cpp b/common/database_instances.cpp index 0e6e8b380..617a2baf6 100644 --- a/common/database_instances.cpp +++ b/common/database_instances.cpp @@ -515,8 +515,7 @@ void Database::BuryCorpsesInInstance(uint16 instance_id) { void Database::DeleteInstance(uint16 instance_id) { -// std::string query = StringFormat("DELETE FROM instance_list WHERE id=%u", instance_id); -// QueryDatabase(query); + std::string query; query = StringFormat("DELETE FROM instance_list_player WHERE id=%u", instance_id); QueryDatabase(query);