From 7a28a6e9a7eabee61e74089127a2ef6184a6a155 Mon Sep 17 00:00:00 2001 From: adam Date: Fri, 22 Feb 2019 19:17:09 -0500 Subject: [PATCH 1/8] fix for mob movement getting 'stuck' when paths don't have updated locations. --- zone/mob_movement_manager.cpp | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/zone/mob_movement_manager.cpp b/zone/mob_movement_manager.cpp index 23cccc8f4..f9f2cd29e 100644 --- a/zone/mob_movement_manager.cpp +++ b/zone/mob_movement_manager.cpp @@ -810,11 +810,55 @@ void MobMovementManager::UpdatePathGround(Mob * who, float x, float y, float z, } AdjustRoute(route, who); + + + + //avoid doing any processing if the mob is stuck to allow normal stuck code to work. + if (!stuck) + { + //there are times when the routes returned are no differen than where the mob is currently standing. What basically happens + //is a mob will get 'stuck' in such a way that it should be moving but the 'moving' place is the exact same spot it is at. + //this is a problem and creates an area of ground that if a mob gets to, will stay there forever. If socal this creates a + //"Ball of Death" (tm). This code tries to prevent this by simply warping the mob to the requested x/y. Better to have a warp than + //have stuck mobs. + + auto routeNode = route.begin(); + bool noValidPath = true; + while (routeNode != route.end() && noValidPath == true) { + auto ¤tNode = (*routeNode); + + if (routeNode == route.end()) + { + continue; + } + + if (!(currentNode.pos.x == who->GetX() && currentNode.pos.y == who->GetY())) + { + //if one of the nodes to move to, is not our current node, pass it. + noValidPath = false; + break; + } + //move to the next node + routeNode++; + + } + + if (noValidPath) + { + //we are 'stuck' in a path, lets just get out of this by 'teleporting' to the next position. + PushTeleportTo(ent.second, x, y, z, + CalculateHeadingAngleBetweenPositions(who->GetX(), who->GetY(), x, y)); + return; + } + + } + auto iter = route.begin(); glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ()); bool first_node = true; + while (iter != route.end()) { auto ¤t_node = (*iter); From 87b1d32ce84bd021426d3907004c511f67d15fa7 Mon Sep 17 00:00:00 2001 From: Uleat Date: Mon, 8 Jul 2019 21:58:47 -0400 Subject: [PATCH 2/8] Updated PerlembParser::ExportItemVariables to new inventory standard --- zone/embparser.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 848299580..759fe5931 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -1099,10 +1099,6 @@ void PerlembParser::ExportZoneVariables(std::string &package_name) { } } -#define HASITEM_FIRST 0 -#define HASITEM_LAST 29 // this includes worn plus 8 base slots -#define HASITEM_ISNULLITEM(item) ((item==-1) || (item==0)) - void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) { if(mob && mob->IsClient()) { @@ -1111,11 +1107,11 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) { //start with an empty hash perl->eval(std::string("%").append(hashname).append(" = ();").c_str()); - for(int slot = HASITEM_FIRST; slot <= HASITEM_LAST; slot++) + for(int slot = EQEmu::invslot::EQUIPMENT_BEGIN; slot <= EQEmu::invslot::GENERAL_END; slot++) { char *hi_decl=nullptr; int itemid = mob->CastToClient()->GetItemIDAt(slot); - if(!HASITEM_ISNULLITEM(itemid)) + if(itemid != -1 && itemid != 0) { MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);", hashname.c_str(), itemid, slot); perl->eval(hi_decl); @@ -1129,7 +1125,7 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) { perl->eval(std::string("%").append(hashname).append(" = ();").c_str()); char *hi_decl = nullptr; int itemid = mob->CastToClient()->GetItemIDAt(EQEmu::invslot::slotCursor); - if(!HASITEM_ISNULLITEM(itemid)) { + if(itemid != -1 && itemid != 0) { MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);",hashname.c_str(), itemid, EQEmu::invslot::slotCursor); perl->eval(hi_decl); safe_delete_array(hi_decl); @@ -1137,10 +1133,6 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) { } } -#undef HASITEM_FIRST -#undef HASITEM_LAST -#undef HASITEM_ISNULLITEM - void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data, NPC* npcmob, EQEmu::ItemInstance* item_inst, Mob* mob, uint32 extradata, std::vector *extra_pointers) { From 525813be025541105b62a79381dd78d4ce51f5db Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 10 Jul 2019 01:20:51 -0400 Subject: [PATCH 3/8] Adjust VARSTRUCT_ENCODE_STRING macros for smarter compilers This is no more dangerous than what we were doing before (not checking return value of sprintf) Maybe we should sometime --- common/misc_functions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/misc_functions.h b/common/misc_functions.h index d5d90d98f..4f295c68a 100644 --- a/common/misc_functions.h +++ b/common/misc_functions.h @@ -32,8 +32,8 @@ // #define VARSTRUCT_DECODE_TYPE(Type, Buffer) *(Type *)Buffer; Buffer += sizeof(Type); #define VARSTRUCT_DECODE_STRING(String, Buffer) strcpy(String, Buffer); Buffer += strlen(String)+1; -#define VARSTRUCT_ENCODE_STRING(Buffer, String) { sprintf(Buffer, "%s", String); Buffer += strlen(String) + 1; } -#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) { sprintf(Buffer, "%i", Number); Buffer += strlen(Buffer) + 1; } +#define VARSTRUCT_ENCODE_STRING(Buffer, String) { int length = sprintf(Buffer, "%s", String); Buffer += length + 1; } +#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) { int length = sprintf(Buffer, "%i", Number); Buffer += length + 1; } #define VARSTRUCT_ENCODE_TYPE(Type, Buffer, Value) { *(Type *)Buffer = Value; Buffer += sizeof(Type); } #define VARSTRUCT_SKIP_TYPE(Type, Buffer) Buffer += sizeof(Type); From dfa90aaac5d2807ee176bef8a258a8d3b54d8c6d Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 10 Jul 2019 01:44:59 -0400 Subject: [PATCH 4/8] Fix OP_SpecialMesg encoding This broke with newer GCCs. It also worked even though the code was just wrong before??? --- common/patches/rof.cpp | 24 ++++++++++-------------- common/patches/rof2.cpp | 24 ++++++++++-------------- common/patches/sod.cpp | 24 ++++++++++-------------- common/patches/sof.cpp | 24 ++++++++++-------------- common/patches/titanium.cpp | 24 ++++++++++-------------- common/patches/uf.cpp | 24 ++++++++++-------------- 6 files changed, 60 insertions(+), 84 deletions(-) diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index be077d750..d7fa21c41 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -3202,14 +3202,18 @@ namespace RoF SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer; unsigned char *__emu_buffer = in->pBuffer; + // break strlen optimizations! + char *message = emu->sayer; + auto sayer_length = std::char_traits::length(message); + message += sayer_length + 1 + 12; // skip over sayer name, null term, and 3 floats - std::string old_message = &emu->message[strlen(emu->sayer)]; + std::string old_message = message; std::string new_message; ServerToRoFSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = strlen(emu->sayer) + new_message.length() + 25; + in->size = sayer_length + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -3223,18 +3227,10 @@ namespace RoF VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); + // TODO: figure this shit out + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 33af8506f..66e699e2a 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3269,14 +3269,18 @@ namespace RoF2 SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer; unsigned char *__emu_buffer = in->pBuffer; + // break strlen optimizations! + char *message = emu->sayer; + auto sayer_length = std::char_traits::length(message); + message += sayer_length + 1 + 12; // skip over sayer name, null term, and 3 floats - std::string old_message = &emu->message[strlen(emu->sayer)]; + std::string old_message = message; std::string new_message; ServerToRoF2SayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = strlen(emu->sayer) + new_message.length() + 25; + in->size = sayer_length + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -3290,18 +3294,10 @@ namespace RoF2 VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); + // TODO: figure this shit out + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 1241e142a..2c9d70edf 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -2072,14 +2072,18 @@ namespace SoD SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer; unsigned char *__emu_buffer = in->pBuffer; + // break strlen optimizations! + char *message = emu->sayer; + auto sayer_length = std::char_traits::length(message); + message += sayer_length + 1 + 12; // skip over sayer name, null term, and 3 floats - std::string old_message = &emu->message[strlen(emu->sayer)]; + std::string old_message = message; std::string new_message; ServerToSoDSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = strlen(emu->sayer) + new_message.length() + 25; + in->size = sayer_length + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -2093,18 +2097,10 @@ namespace SoD VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); + // TODO: figure this shit out + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 247912dfd..0b3043c70 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1723,14 +1723,18 @@ namespace SoF SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer; unsigned char *__emu_buffer = in->pBuffer; + // break strlen optimizations! + char *message = emu->sayer; + auto sayer_length = std::char_traits::length(message); + message += sayer_length + 1 + 12; // skip over sayer name, null term, and 3 floats - std::string old_message = &emu->message[strlen(emu->sayer)]; + std::string old_message = message; std::string new_message; ServerToSoFSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = strlen(emu->sayer) + new_message.length() + 25; + in->size = sayer_length + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -1744,18 +1748,10 @@ namespace SoF VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); + // TODO: figure this shit out + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index e15913669..c4bef5bea 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1423,14 +1423,18 @@ namespace Titanium SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer; unsigned char *__emu_buffer = in->pBuffer; + // break strlen optimizations! + char *message = emu->sayer; + auto sayer_length = std::char_traits::length(message); + message += sayer_length + 1 + 12; // skip over sayer name, null term, and 3 floats - std::string old_message = &emu->message[strlen(emu->sayer)]; + std::string old_message = message; std::string new_message; ServerToTitaniumSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = strlen(emu->sayer) + new_message.length() + 25; + in->size = sayer_length + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -1444,18 +1448,10 @@ namespace Titanium VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); + // TODO: figure this shit out + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 549fa7698..7db0cfb92 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -2372,14 +2372,18 @@ namespace UF SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer; unsigned char *__emu_buffer = in->pBuffer; + // break strlen optimizations! + char *message = emu->sayer; + auto sayer_length = std::char_traits::length(message); + message += sayer_length + 1 + 12; // skip over sayer name, null term, and 3 floats - std::string old_message = &emu->message[strlen(emu->sayer)]; + std::string old_message = message; std::string new_message; ServerToUFSayLink(new_message, old_message); //in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1; - in->size = strlen(emu->sayer) + new_message.length() + 25; + in->size = sayer_length + new_message.length() + 25; in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -2393,18 +2397,10 @@ namespace UF VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]); - VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); + // TODO: figure this shit out + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0.0f); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); From 35eb5b24ddae10adb3fd911b02e2873a7ca39f63 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Wed, 10 Jul 2019 03:39:07 -0500 Subject: [PATCH 5/8] Implement flymode --- changelog.txt | 5 + common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../git/required/2019_07_10_npc_flymode.sql | 1 + zone/command.cpp | 10 +- zone/npc.cpp | 5 + zone/zonedb.cpp | 281 ++++++++++-------- zone/zonedump.h | 1 + 8 files changed, 172 insertions(+), 134 deletions(-) create mode 100644 utils/sql/git/required/2019_07_10_npc_flymode.sql diff --git a/changelog.txt b/changelog.txt index e79e0bb26..dc9d0f16c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 7/10/2019 == + +Akkadius: Add #npcedit flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating] +Akkadius: Added "flymode" to npc_types database table + == 7/3/2019 == Akkadius/KLS: diff --git a/common/version.h b/common/version.h index f77ffcac2..f7a161dc1 100644 --- a/common/version.h +++ b/common/version.h @@ -31,7 +31,7 @@ */ -#define CURRENT_BINARY_DATABASE_VERSION 9140 +#define CURRENT_BINARY_DATABASE_VERSION 9141 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9024 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 682636d12..92bcfd260 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -394,6 +394,7 @@ 9138|2018_12_12_convert_to_client_functions.sql|SELECT `id` FROM `faction_list` WHERE `id` > 4999|empty| 9139|2019_03_25_optional_npc_model.sql|SHOW COLUMNS FROM `npc_types` LIKE 'model'|empty| 9140|2019_07_03_update_range.sql|SHOW COLUMNS FROM `npc_types` LIKE 'max_movement_update_range'|empty| +9141|2019_07_10_npc_flymode.sql|SHOW COLUMNS FROM `npc_types` LIKE 'flymode'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2019_07_10_npc_flymode.sql b/utils/sql/git/required/2019_07_10_npc_flymode.sql new file mode 100644 index 000000000..aacc5ad00 --- /dev/null +++ b/utils/sql/git/required/2019_07_10_npc_flymode.sql @@ -0,0 +1 @@ +ALTER TABLE `npc_types` ADD COLUMN `flymode` tinyint(4) NOT NULL DEFAULT -1; \ No newline at end of file diff --git a/zone/command.cpp b/zone/command.cpp index 0451f87e2..1675be8b8 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -7342,6 +7342,7 @@ void command_npcedit(Client *c, const Seperator *sep) c->Message(0, "#npcedit no_target - Set an NPC's ability to be targeted with the target hotkey"); c->Message(0, "#npcedit version - Set an NPC's version"); c->Message(0, "#npcedit slow_mitigation - Set an NPC's slow mitigation"); + c->Message(0, "#npcedit flymode - Set an NPC's flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating]"); } @@ -7355,7 +7356,14 @@ void command_npcedit(Client *c, const Seperator *sep) if (strcasecmp(sep->arg[1], "lastname") == 0) { c->Message(15,"NPCID %u now has the lastname %s.", npcTypeID, sep->argplus[2]); - std::string query = StringFormat("UPDATE npc_types SET lastname = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET lastname = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); + database.QueryDatabase(query); + return; + } + + if (strcasecmp(sep->arg[1], "flymode") == 0) { + c->Message(15,"NPCID %u now has flymode [%s]", npcTypeID, sep->argplus[2]); + std::string query = StringFormat("UPDATE npc_types SET flymode = '%s' WHERE id = %i", sep->argplus[2],npcTypeID); database.QueryDatabase(query); return; } diff --git a/zone/npc.cpp b/zone/npc.cpp index b0367f469..60e6f73c4 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -226,6 +226,11 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi merchant_open = GetClass() == MERCHANT; adventure_template_id = npc_type_data->adventure_template; flymode = iflymode; + + if (npc_type_data->flymode >= 0) { + flymode = static_cast(npc_type_data->flymode); + } + guard_anim = eaStanding; roambox_distance = 0; roambox_max_x = -2; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 11a90eac5..e2825da5a 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -2366,29 +2366,33 @@ bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 times return results.Success(); } -const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/) +const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/) { const NPCType *npc = nullptr; /* If there is a cached NPC entry, load it */ auto itr = zone->npctable.find(npc_type_id); - if(itr != zone->npctable.end()) + if (itr != zone->npctable.end()) { return itr->second; + } std::string where_condition = ""; - if (bulk_load){ + if (bulk_load) { Log(Logs::General, Logs::Debug, "Performing bulk NPC Types load"); where_condition = StringFormat( "INNER JOIN spawnentry ON npc_types.id = spawnentry.npcID " "INNER JOIN spawn2 ON spawnentry.spawngroupID = spawn2.spawngroupID " - "WHERE spawn2.zone = '%s' and spawn2.version = %u GROUP BY npc_types.id", zone->GetShortName(), zone->GetInstanceVersion()); + "WHERE spawn2.zone = '%s' and spawn2.version = %u GROUP BY npc_types.id", + zone->GetShortName(), + zone->GetInstanceVersion()); } - else{ + else { where_condition = StringFormat("WHERE id = %u", npc_type_id); } - std::string query = StringFormat("SELECT " + std::string query = StringFormat( + "SELECT " "npc_types.id, " "npc_types.name, " "npc_types.level, " @@ -2499,115 +2503,122 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load "npc_types.skip_global_loot, " "npc_types.rare_spawn, " "npc_types.stuck_behavior, " - "npc_types.model " + "npc_types.model, " + "npc_types.flymode " "FROM npc_types %s", where_condition.c_str() ); - auto results = QueryDatabase(query); - if (!results.Success()) { - return nullptr; - } + auto results = QueryDatabase(query); + if (!results.Success()) { + return nullptr; + } - for (auto row = results.begin(); row != results.end(); ++row) { + for (auto row = results.begin(); row != results.end(); ++row) { NPCType *temp_npctype_data; temp_npctype_data = new NPCType; - memset (temp_npctype_data, 0, sizeof *temp_npctype_data); + memset(temp_npctype_data, 0, sizeof *temp_npctype_data); temp_npctype_data->npc_id = atoi(row[0]); strn0cpy(temp_npctype_data->name, row[1], 50); - temp_npctype_data->level = atoi(row[2]); - temp_npctype_data->race = atoi(row[3]); - temp_npctype_data->class_ = atoi(row[4]); - temp_npctype_data->max_hp = atoi(row[5]); - temp_npctype_data->current_hp = temp_npctype_data->max_hp; - temp_npctype_data->Mana = atoi(row[6]); - temp_npctype_data->gender = atoi(row[7]); - temp_npctype_data->texture = atoi(row[8]); - temp_npctype_data->helmtexture = atoi(row[9]); - temp_npctype_data->herosforgemodel = atoul(row[10]); - temp_npctype_data->size = atof(row[11]); - temp_npctype_data->loottable_id = atoi(row[12]); - temp_npctype_data->merchanttype = atoi(row[13]); - temp_npctype_data->alt_currency_type = atoi(row[14]); + temp_npctype_data->level = atoi(row[2]); + temp_npctype_data->race = atoi(row[3]); + temp_npctype_data->class_ = atoi(row[4]); + temp_npctype_data->max_hp = atoi(row[5]); + temp_npctype_data->current_hp = temp_npctype_data->max_hp; + temp_npctype_data->Mana = atoi(row[6]); + temp_npctype_data->gender = atoi(row[7]); + temp_npctype_data->texture = atoi(row[8]); + temp_npctype_data->helmtexture = atoi(row[9]); + temp_npctype_data->herosforgemodel = atoul(row[10]); + temp_npctype_data->size = atof(row[11]); + temp_npctype_data->loottable_id = atoi(row[12]); + temp_npctype_data->merchanttype = atoi(row[13]); + temp_npctype_data->alt_currency_type = atoi(row[14]); temp_npctype_data->adventure_template = atoi(row[15]); - temp_npctype_data->trap_template = atoi(row[16]); - temp_npctype_data->attack_speed = atof(row[17]); - temp_npctype_data->STR = atoi(row[18]); - temp_npctype_data->STA = atoi(row[19]); - temp_npctype_data->DEX = atoi(row[20]); - temp_npctype_data->AGI = atoi(row[21]); - temp_npctype_data->INT = atoi(row[22]); - temp_npctype_data->WIS = atoi(row[23]); - temp_npctype_data->CHA = atoi(row[24]); - temp_npctype_data->MR = atoi(row[25]); - temp_npctype_data->CR = atoi(row[26]); - temp_npctype_data->DR = atoi(row[27]); - temp_npctype_data->FR = atoi(row[28]); - temp_npctype_data->PR = atoi(row[29]); - temp_npctype_data->Corrup = atoi(row[30]); - temp_npctype_data->PhR = atoi(row[31]); - temp_npctype_data->min_dmg = atoi(row[32]); - temp_npctype_data->max_dmg = atoi(row[33]); - temp_npctype_data->attack_count = atoi(row[34]); + temp_npctype_data->trap_template = atoi(row[16]); + temp_npctype_data->attack_speed = atof(row[17]); + temp_npctype_data->STR = atoi(row[18]); + temp_npctype_data->STA = atoi(row[19]); + temp_npctype_data->DEX = atoi(row[20]); + temp_npctype_data->AGI = atoi(row[21]); + temp_npctype_data->INT = atoi(row[22]); + temp_npctype_data->WIS = atoi(row[23]); + temp_npctype_data->CHA = atoi(row[24]); + temp_npctype_data->MR = atoi(row[25]); + temp_npctype_data->CR = atoi(row[26]); + temp_npctype_data->DR = atoi(row[27]); + temp_npctype_data->FR = atoi(row[28]); + temp_npctype_data->PR = atoi(row[29]); + temp_npctype_data->Corrup = atoi(row[30]); + temp_npctype_data->PhR = atoi(row[31]); + temp_npctype_data->min_dmg = atoi(row[32]); + temp_npctype_data->max_dmg = atoi(row[33]); + temp_npctype_data->attack_count = atoi(row[34]); - if (row[35] != nullptr) + if (row[35] != nullptr) { strn0cpy(temp_npctype_data->special_abilities, row[35], 512); - else + } + else { temp_npctype_data->special_abilities[0] = '\0'; + } - temp_npctype_data->npc_spells_id = atoi(row[36]); + temp_npctype_data->npc_spells_id = atoi(row[36]); temp_npctype_data->npc_spells_effects_id = atoi(row[37]); - temp_npctype_data->d_melee_texture1 = atoi(row[38]); - temp_npctype_data->d_melee_texture2 = atoi(row[39]); + temp_npctype_data->d_melee_texture1 = atoi(row[38]); + temp_npctype_data->d_melee_texture2 = atoi(row[39]); strn0cpy(temp_npctype_data->ammo_idfile, row[40], 30); temp_npctype_data->prim_melee_type = atoi(row[41]); - temp_npctype_data->sec_melee_type = atoi(row[42]); - temp_npctype_data->ranged_type = atoi(row[43]); - temp_npctype_data->runspeed= atof(row[44]); - temp_npctype_data->findable = atoi(row[45]) == 0? false : true; - temp_npctype_data->trackable = atoi(row[46]) == 0? false : true; - temp_npctype_data->hp_regen = atoi(row[47]); - temp_npctype_data->mana_regen = atoi(row[48]); + temp_npctype_data->sec_melee_type = atoi(row[42]); + temp_npctype_data->ranged_type = atoi(row[43]); + temp_npctype_data->runspeed = atof(row[44]); + temp_npctype_data->findable = atoi(row[45]) == 0 ? false : true; + temp_npctype_data->trackable = atoi(row[46]) == 0 ? false : true; + temp_npctype_data->hp_regen = atoi(row[47]); + temp_npctype_data->mana_regen = atoi(row[48]); // set default value for aggroradius - temp_npctype_data->aggroradius = (int32)atoi(row[49]); - if (temp_npctype_data->aggroradius <= 0) + temp_npctype_data->aggroradius = (int32) atoi(row[49]); + if (temp_npctype_data->aggroradius <= 0) { temp_npctype_data->aggroradius = 70; + } - temp_npctype_data->assistradius = (int32)atoi(row[50]); - if (temp_npctype_data->assistradius <= 0) + temp_npctype_data->assistradius = (int32) atoi(row[50]); + if (temp_npctype_data->assistradius <= 0) { temp_npctype_data->assistradius = temp_npctype_data->aggroradius; + } - if (row[51] && strlen(row[51])) - temp_npctype_data->bodytype = (uint8)atoi(row[51]); - else - temp_npctype_data->bodytype = 0; + if (row[51] && strlen(row[51])) { + temp_npctype_data->bodytype = (uint8) atoi(row[51]); + } + else { + temp_npctype_data->bodytype = 0; + } temp_npctype_data->npc_faction_id = atoi(row[52]); - temp_npctype_data->luclinface = atoi(row[53]); - temp_npctype_data->hairstyle = atoi(row[54]); - temp_npctype_data->haircolor = atoi(row[55]); - temp_npctype_data->eyecolor1 = atoi(row[56]); - temp_npctype_data->eyecolor2 = atoi(row[57]); - temp_npctype_data->beardcolor = atoi(row[58]); - temp_npctype_data->beard = atoi(row[59]); + temp_npctype_data->luclinface = atoi(row[53]); + temp_npctype_data->hairstyle = atoi(row[54]); + temp_npctype_data->haircolor = atoi(row[55]); + temp_npctype_data->eyecolor1 = atoi(row[56]); + temp_npctype_data->eyecolor2 = atoi(row[57]); + temp_npctype_data->beardcolor = atoi(row[58]); + temp_npctype_data->beard = atoi(row[59]); temp_npctype_data->drakkin_heritage = atoi(row[60]); - temp_npctype_data->drakkin_tattoo = atoi(row[61]); - temp_npctype_data->drakkin_details = atoi(row[62]); + temp_npctype_data->drakkin_tattoo = atoi(row[61]); + temp_npctype_data->drakkin_details = atoi(row[62]); uint32 armor_tint_id = atoi(row[63]); temp_npctype_data->armor_tint.Head.Color = (atoi(row[64]) & 0xFF) << 16; - temp_npctype_data->armor_tint.Head.Color |= (atoi(row[65]) & 0xFF) << 8; + temp_npctype_data->armor_tint.Head.Color |= (atoi(row[65]) & 0xFF) << 8; temp_npctype_data->armor_tint.Head.Color |= (atoi(row[66]) & 0xFF); temp_npctype_data->armor_tint.Head.Color |= (temp_npctype_data->armor_tint.Head.Color) ? (0xFF << 24) : 0; if (armor_tint_id != 0) { - std::string armortint_query = StringFormat( + std::string armortint_query = StringFormat( "SELECT red1h, grn1h, blu1h, " "red2c, grn2c, blu2c, " "red3a, grn3a, blu3a, " @@ -2618,21 +2629,24 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load "red8x, grn8x, blu8x, " "red9x, grn9x, blu9x " "FROM npc_types_tint WHERE id = %d", - armor_tint_id); - auto armortint_results = QueryDatabase(armortint_query); - if (!armortint_results.Success() || armortint_results.RowCount() == 0) - armor_tint_id = 0; - else { - auto armorTint_row = armortint_results.begin(); + armor_tint_id + ); + auto armortint_results = QueryDatabase(armortint_query); + if (!armortint_results.Success() || armortint_results.RowCount() == 0) { + armor_tint_id = 0; + } + else { + auto armorTint_row = armortint_results.begin(); for (int index = EQEmu::textures::textureBegin; index <= EQEmu::textures::LastTexture; index++) { - temp_npctype_data->armor_tint.Slot[index].Color = atoi(armorTint_row[index * 3]) << 16; + temp_npctype_data->armor_tint.Slot[index].Color = atoi(armorTint_row[index * 3]) << 16; temp_npctype_data->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 1]) << 8; temp_npctype_data->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 2]); - temp_npctype_data->armor_tint.Slot[index].Color |= (temp_npctype_data->armor_tint.Slot[index].Color) ? (0xFF << 24) : 0; - } - } - } + temp_npctype_data->armor_tint.Slot[index].Color |= (temp_npctype_data->armor_tint.Slot[index].Color) + ? (0xFF << 24) : 0; + } + } + } // Try loading npc_types tint fields if armor tint is 0 or query failed to get results if (armor_tint_id == 0) { for (int index = EQEmu::textures::armorChest; index < EQEmu::textures::materialCount; index++) { @@ -2640,56 +2654,59 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load } } - temp_npctype_data->see_invis = atoi(row[67]); - temp_npctype_data->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag + temp_npctype_data->see_invis = atoi(row[67]); + temp_npctype_data->see_invis_undead = atoi(row[68]) == 0 ? false : true; // Set see_invis_undead flag - if (row[69] != nullptr) + if (row[69] != nullptr) { strn0cpy(temp_npctype_data->lastname, row[69], 32); + } - temp_npctype_data->qglobal = atoi(row[70]) == 0? false: true; // qglobal - temp_npctype_data->AC = atoi(row[71]); - temp_npctype_data->npc_aggro = atoi(row[72]) == 0? false: true; - temp_npctype_data->spawn_limit = atoi(row[73]); - temp_npctype_data->see_hide = atoi(row[74]) == 0? false: true; - temp_npctype_data->see_improved_hide = atoi(row[75]) == 0? false: true; - temp_npctype_data->ATK = atoi(row[76]); - temp_npctype_data->accuracy_rating = atoi(row[77]); - temp_npctype_data->avoidance_rating = atoi(row[78]); - temp_npctype_data->slow_mitigation = atoi(row[79]); - temp_npctype_data->maxlevel = atoi(row[80]); - temp_npctype_data->scalerate = atoi(row[81]); - temp_npctype_data->private_corpse = atoi(row[82]) == 1 ? true: false; - temp_npctype_data->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false; - temp_npctype_data->underwater = atoi(row[84]) == 1 ? true: false; - temp_npctype_data->emoteid = atoi(row[85]); - temp_npctype_data->spellscale = atoi(row[86]); - temp_npctype_data->healscale = atoi(row[87]); - temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true: false; - temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false : true; - temp_npctype_data->attack_delay = atoi(row[90]) * 100; // TODO: fix DB - temp_npctype_data->light = (atoi(row[91]) & 0x0F); + temp_npctype_data->qglobal = atoi(row[70]) == 0 ? false : true; // qglobal + temp_npctype_data->AC = atoi(row[71]); + temp_npctype_data->npc_aggro = atoi(row[72]) == 0 ? false : true; + temp_npctype_data->spawn_limit = atoi(row[73]); + temp_npctype_data->see_hide = atoi(row[74]) == 0 ? false : true; + temp_npctype_data->see_improved_hide = atoi(row[75]) == 0 ? false : true; + temp_npctype_data->ATK = atoi(row[76]); + temp_npctype_data->accuracy_rating = atoi(row[77]); + temp_npctype_data->avoidance_rating = atoi(row[78]); + temp_npctype_data->slow_mitigation = atoi(row[79]); + temp_npctype_data->maxlevel = atoi(row[80]); + temp_npctype_data->scalerate = atoi(row[81]); + temp_npctype_data->private_corpse = atoi(row[82]) == 1 ? true : false; + temp_npctype_data->unique_spawn_by_name = atoi(row[83]) == 1 ? true : false; + temp_npctype_data->underwater = atoi(row[84]) == 1 ? true : false; + temp_npctype_data->emoteid = atoi(row[85]); + temp_npctype_data->spellscale = atoi(row[86]); + temp_npctype_data->healscale = atoi(row[87]); + temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true : false; + temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false : true; + temp_npctype_data->attack_delay = atoi(row[90]) * 100; // TODO: fix DB + temp_npctype_data->light = (atoi(row[91]) & 0x0F); - temp_npctype_data->armtexture = atoi(row[92]); - temp_npctype_data->bracertexture = atoi(row[93]); - temp_npctype_data->handtexture = atoi(row[94]); - temp_npctype_data->legtexture = atoi(row[95]); - temp_npctype_data->feettexture = atoi(row[96]); + temp_npctype_data->armtexture = atoi(row[92]); + temp_npctype_data->bracertexture = atoi(row[93]); + temp_npctype_data->handtexture = atoi(row[94]); + temp_npctype_data->legtexture = atoi(row[95]); + temp_npctype_data->feettexture = atoi(row[96]); temp_npctype_data->ignore_despawn = atoi(row[97]) == 1 ? true : false; - temp_npctype_data->show_name = atoi(row[98]) != 0 ? true : false; - temp_npctype_data->untargetable = atoi(row[99]) != 0 ? true : false; + temp_npctype_data->show_name = atoi(row[98]) != 0 ? true : false; + temp_npctype_data->untargetable = atoi(row[99]) != 0 ? true : false; - temp_npctype_data->charm_ac = atoi(row[100]); - temp_npctype_data->charm_min_dmg = atoi(row[101]); - temp_npctype_data->charm_max_dmg = atoi(row[102]); - temp_npctype_data->charm_attack_delay = atoi(row[103]) * 100; // TODO: fix DB - temp_npctype_data->charm_accuracy_rating = atoi(row[104]); + temp_npctype_data->charm_ac = atoi(row[100]); + temp_npctype_data->charm_min_dmg = atoi(row[101]); + temp_npctype_data->charm_max_dmg = atoi(row[102]); + temp_npctype_data->charm_attack_delay = atoi(row[103]) * 100; // TODO: fix DB + temp_npctype_data->charm_accuracy_rating = atoi(row[104]); temp_npctype_data->charm_avoidance_rating = atoi(row[105]); - temp_npctype_data->charm_atk = atoi(row[106]); + temp_npctype_data->charm_atk = atoi(row[106]); temp_npctype_data->skip_global_loot = atoi(row[107]) != 0; - temp_npctype_data->rare_spawn = atoi(row[108]) != 0; - temp_npctype_data->stuck_behavior = atoi(row[109]); - temp_npctype_data->use_model = atoi(row[110]); + temp_npctype_data->rare_spawn = atoi(row[108]) != 0; + temp_npctype_data->stuck_behavior = atoi(row[109]); + temp_npctype_data->use_model = atoi(row[110]); + temp_npctype_data->flymode = atoi(row[111]); + temp_npctype_data->skip_auto_scale = false; // hardcoded here for now // If NPC with duplicate NPC id already in table, @@ -2700,9 +2717,9 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load return nullptr; } - zone->npctable[temp_npctype_data->npc_id] = temp_npctype_data; - npc = temp_npctype_data; - } + zone->npctable[temp_npctype_data->npc_id] = temp_npctype_data; + npc = temp_npctype_data; + } return npc; } diff --git a/zone/zonedump.h b/zone/zonedump.h index 71f530171..302d4ee25 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -146,6 +146,7 @@ struct NPCType bool skip_auto_scale; // just so it doesn't mess up bots or mercs, probably should add to DB too just in case int8 stuck_behavior; uint16 use_model; + int8 flymode; }; namespace player_lootitem { From 1ba78d09882ccb9f0b530cd1c1b2c8d8cc5d5dba Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 10 Jul 2019 14:33:33 -0400 Subject: [PATCH 6/8] Switch to char_traits::length in SerializeBuffer This benches a bit faster --- common/serialize_buffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/serialize_buffer.h b/common/serialize_buffer.h index 9b350b4fa..65ae36f70 100644 --- a/common/serialize_buffer.h +++ b/common/serialize_buffer.h @@ -143,7 +143,7 @@ public: void WriteString(const char *str) { assert(str != nullptr); - auto len = strlen(str) + 1; + auto len = std::char_traits::length(str) + 1; if (m_pos + len > m_capacity) Grow(m_capacity + len); memcpy(m_buffer + m_pos, str, len); From eb8cd1a5b44ecc2d00a46fb5bbc6b50352cc010c Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 13 Jul 2019 00:43:56 -0400 Subject: [PATCH 7/8] Fix for build zlib option when not using vcpkg --- CMakeLists.txt | 2 +- libs/zlibng/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c1538b03..2b0b36639 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,7 +313,7 @@ IF(ZLIB_FOUND) OPTION(EQEMU_BUILD_ZLIB "Build internal version of zlib." OFF) IF(EQEMU_BUILD_ZLIB) - INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng") + INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng") SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic") ELSE() INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}") diff --git a/libs/zlibng/CMakeLists.txt b/libs/zlibng/CMakeLists.txt index b1845522b..9767a00c8 100644 --- a/libs/zlibng/CMakeLists.txt +++ b/libs/zlibng/CMakeLists.txt @@ -861,5 +861,5 @@ if (ZLIB_ENABLE_TESTS) endif() endif() -FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES) +# FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES) From 6bdc9b6ba52a30daa1e9a0964370d8d04219f7ed Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 13 Jul 2019 16:16:15 -0700 Subject: [PATCH 8/8] Add support for single account login to both world and login server, should also work with eqemu login server, can be turned off in rules if you don't mind the side effects double logins cause. Also lowered the linkdead time to 30s + 90s default (2min) --- CMakeLists.txt | 6 +- common/net/daybreak_connection.h | 4 +- common/ruletypes.h | 5 +- common/servertalk.h | 9 +++ loginserver/world_server.cpp | 17 +++-- .../optional/2019_07_13_linkdead_changes.sql | 2 + world/clientlist.cpp | 65 +++++------------ world/clientlist.h | 2 +- world/login_server.cpp | 72 +++++++++++-------- 9 files changed, 89 insertions(+), 93 deletions(-) create mode 100644 utils/sql/git/optional/2019_07_13_linkdead_changes.sql diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b0b36639..be92c7d0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -290,14 +290,14 @@ ADD_DEFINITIONS(-DGLM_FORCE_CTOR_INIT) ADD_DEFINITIONS(-DGLM_ENABLE_EXPERIMENTAL) #Find everything we need -FIND_PACKAGE(ZLIB REQUIRED) +FIND_PACKAGE(ZLIB) FIND_PACKAGE(MySQL REQUIRED) IF(EQEMU_BUILD_PERL) FIND_PACKAGE(PerlLibs REQUIRED) INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}") ENDIF(EQEMU_BUILD_PERL) -SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} uv_a fmt RecastNavigation::Detour) +SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} uv_a fmt RecastNavigation::Detour) FIND_PACKAGE(Sodium REQUIRED) IF(SODIUM_FOUND) @@ -320,7 +320,7 @@ IF(ZLIB_FOUND) SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY}) ENDIF() ELSE() - INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng") + INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng") SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic") ENDIF() diff --git a/common/net/daybreak_connection.h b/common/net/daybreak_connection.h index 4d2f62e27..b4f3ca41c 100644 --- a/common/net/daybreak_connection.h +++ b/common/net/daybreak_connection.h @@ -257,7 +257,7 @@ namespace EQ resend_delay_min = 150; resend_delay_max = 5000; connect_delay_ms = 500; - stale_connection_ms = 90000; + stale_connection_ms = 30000; connect_stale_ms = 5000; crc_length = 2; max_packet_size = 512; @@ -269,7 +269,7 @@ namespace EQ simulated_in_packet_loss = 0; simulated_out_packet_loss = 0; tic_rate_hertz = 60.0; - resend_timeout = 90000; + resend_timeout = 30000; connection_close_time = 2000; outgoing_data_rate = 0.0; } diff --git a/common/ruletypes.h b/common/ruletypes.h index 3c9e5d677..ccbef9339 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -225,8 +225,6 @@ RULE_BOOL(World, MaxClientsSetByStatus, false) // If True, IP Limiting will be s RULE_BOOL(World, EnableIPExemptions, false) // If True, ip_exemptions table is used, if there is no entry for the IP it will default to RuleI(World, MaxClientsPerIP) RULE_BOOL(World, ClearTempMerchantlist, true) // Clears temp merchant items when world boots. RULE_BOOL(World, DeleteStaleCorpeBackups, true) // Deletes stale corpse backups older than 2 weeks. -RULE_INT(World, AccountSessionLimit, -1) //Max number of characters allowed on at once from a single account (-1 is disabled) -RULE_INT(World, ExemptAccountLimitStatus, -1) //Min status required to be exempt from multi-session per account limiting (-1 is disabled) RULE_BOOL(World, GMAccountIPList, false) // Check ip list against GM Accounts, AntiHack GM Accounts. RULE_INT(World, MinGMAntiHackStatus, 1) //Minimum GM status to check against AntiHack list RULE_INT(World, SoFStartZoneID, -1) //Sets the Starting Zone for SoF Clients separate from Titanium Clients (-1 is disabled) @@ -241,10 +239,11 @@ RULE_BOOL (World, IPLimitDisconnectAll, false) RULE_BOOL(World, MaxClientsSimplifiedLogic, false) // New logic that only uses ExemptMaxClientsStatus and MaxClientsPerIP. Done on the loginserver. This mimics the P99-style special IP rules. RULE_INT (World, TellQueueSize, 20) RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone ALWAYS be the same location as your bind? +RULE_BOOL(World, DisallowDuplicateAccountLogins, true) RULE_CATEGORY_END() RULE_CATEGORY(Zone) -RULE_INT(Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection +RULE_INT(Zone, ClientLinkdeadMS, 90000) //the time a client remains link dead on the server after a sudden disconnection RULE_INT(Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone RULE_BOOL(Zone, EnableShadowrest, 1) // enables or disables the shadowrest zone feature for player corpses. Default is turned on. RULE_BOOL(Zone, UsePlayerCorpseBackups, true) // Keeps backups of player corpses. diff --git a/common/servertalk.h b/common/servertalk.h index b942eb547..c5cd149d7 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -213,6 +213,15 @@ enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_ #define ServerOP_Speech 0x4513 +enum { + UserToWorldStatusWorldUnavail = 0, + UserToWorldStatusSuccess = 1, + UserToWorldStatusSuspended = -1, + UserToWorldStatusBanned = -2, + UserToWorldStatusWorldAtCapacity = -3, + UserToWorldStatusAlreadyOnline = -4 +}; + /************ PACKET RELATED STRUCT ************/ class ServerPacket { diff --git a/loginserver/world_server.cpp b/loginserver/world_server.cpp index 55fc03b7b..d953ccc3a 100644 --- a/loginserver/world_server.cpp +++ b/loginserver/world_server.cpp @@ -165,21 +165,26 @@ void WorldServer::ProcessUsertoWorldResp(uint16_t opcode, const EQ::Net::Packet switch (utwr->response) { - case 1: + case UserToWorldStatusSuccess: per->Message = 101; break; - case 0: + case UserToWorldStatusWorldUnavail: per->Message = 326; break; - case -1: + case UserToWorldStatusSuspended: per->Message = 337; break; - case -2: + case UserToWorldStatusBanned: per->Message = 338; break; - case -3: - per->Message = 303; + case UserToWorldStatusWorldAtCapacity: + per->Message = 339; break; + case UserToWorldStatusAlreadyOnline: + per->Message = 111; + break; + default: + per->Message = 102; } if (server.options.IsTraceOn()) diff --git a/utils/sql/git/optional/2019_07_13_linkdead_changes.sql b/utils/sql/git/optional/2019_07_13_linkdead_changes.sql new file mode 100644 index 000000000..6bc6bde50 --- /dev/null +++ b/utils/sql/git/optional/2019_07_13_linkdead_changes.sql @@ -0,0 +1,2 @@ +UPDATE `rule_values` SET `rule_value`='90000' WHERE `rule_name`='Zone:ClientLinkdeadMS'; +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'DisallowDuplicateAccountLogins', 'true', 'Requires account logins to be unique.'); diff --git a/world/clientlist.cpp b/world/clientlist.cpp index 96dd45076..1264957a7 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -99,52 +99,6 @@ ClientListEntry* ClientList::GetCLE(uint32 iID) { return 0; } -//Account Limiting Code to limit the number of characters allowed on from a single account at once. -void ClientList::EnforceSessionLimit(uint32 iLSAccountID) { - - ClientListEntry* ClientEntry = 0; - - LinkedListIterator iterator(clientlist, BACKWARD); - - int CharacterCount = 0; - - iterator.Reset(); - - while(iterator.MoreElements()) { - - ClientEntry = iterator.GetData(); - - if ((ClientEntry->LSAccountID() == iLSAccountID) && - ((ClientEntry->Admin() <= (RuleI(World, ExemptAccountLimitStatus))) || (RuleI(World, ExemptAccountLimitStatus) < 0))) { - - CharacterCount++; - - if (CharacterCount >= (RuleI(World, AccountSessionLimit))){ - // If we have a char name, they are in a zone, so send a kick to the zone server - if(strlen(ClientEntry->name())) { - - auto pack = - new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); - ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer; - strcpy(skp->adminname, "SessionLimit"); - strcpy(skp->name, ClientEntry->name()); - skp->adminrank = 255; - zoneserver_list.SendPacket(pack); - safe_delete(pack); - } - - ClientEntry->SetOnline(CLE_Status_Offline); - - iterator.RemoveCurrent(); - - continue; - } - } - iterator.Advance(); - } -} - - //Check current CLE Entry IPs against incoming connection void ClientList::GetCLEIP(uint32 iIP) { @@ -272,7 +226,7 @@ ClientListEntry* ClientList::FindCharacter(const char* name) { } iterator.Advance(); } - return 0; + return nullptr; } ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) { @@ -285,7 +239,7 @@ ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) { } iterator.Advance(); } - return 0; + return nullptr; } ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) { @@ -298,7 +252,20 @@ ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) { } iterator.Advance(); } - return 0; + return nullptr; +} + +ClientListEntry* ClientList::FindCLEByLSID(uint32 iLSID) { + LinkedListIterator iterator(clientlist); + + iterator.Reset(); + while (iterator.MoreElements()) { + if (iterator.GetData()->LSID() == iLSID) { + return iterator.GetData(); + } + iterator.Advance(); + } + return nullptr; } void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnection* connection, const char* iName) { diff --git a/world/clientlist.h b/world/clientlist.h index 3ca6291c2..5b3bad297 100644 --- a/world/clientlist.h +++ b/world/clientlist.h @@ -57,11 +57,11 @@ public: ClientListEntry* FindCharacter(const char* name); ClientListEntry* FindCLEByAccountID(uint32 iAccID); ClientListEntry* FindCLEByCharacterID(uint32 iCharID); + ClientListEntry* FindCLEByLSID(uint32 iLSID); ClientListEntry* GetCLE(uint32 iID); void GetCLEIP(uint32 iIP); uint32 GetCLEIPCount(uint32 iLSAccountID); void DisconnectByIP(uint32 iIP); - void EnforceSessionLimit(uint32 iLSAccountID); void CLCheckStale(); void CLEKeepAlive(uint32 numupdates, uint32* wid); void CLEAdd(uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0); diff --git a/world/login_server.cpp b/world/login_server.cpp index b642e77ad..61cc53bc2 100644 --- a/world/login_server.cpp +++ b/world/login_server.cpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "worlddb.h" #include "zonelist.h" #include "clientlist.h" +#include "cliententry.h" #include "world_config.h" extern ZSList zoneserver_list; @@ -65,38 +66,58 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) { uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid); int16 status = database.CheckStatus(id); - auto outpack = new ServerPacket; - outpack->opcode = ServerOP_UsertoWorldResp; - outpack->size = sizeof(UsertoWorldResponse_Struct); - outpack->pBuffer = new uchar[outpack->size]; - memset(outpack->pBuffer, 0, outpack->size); - UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack->pBuffer; + ServerPacket outpack; + outpack.opcode = ServerOP_UsertoWorldResp; + outpack.size = sizeof(UsertoWorldResponse_Struct); + outpack.pBuffer = new uchar[outpack.size]; + memset(outpack.pBuffer, 0, outpack.size); + UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack.pBuffer; utwrs->lsaccountid = utwr->lsaccountid; utwrs->ToID = utwr->FromID; + utwrs->worldid = utwr->worldid; + utwrs->response = UserToWorldStatusSuccess; if (Config->Locked == true) { - if ((status == 0 || status < 100) && (status != -2 || status != -1)) - utwrs->response = 0; - if (status >= 100) - utwrs->response = 1; - } - else { - utwrs->response = 1; + if (status < 100) { + utwrs->response = UserToWorldStatusWorldUnavail; + SendPacket(&outpack); + return; + } } int32 x = Config->MaxClients; - if ((int32)numplayers >= x && x != -1 && x != 255 && status < 80) - utwrs->response = -3; + if ((int32)numplayers >= x && x != -1 && x != 255 && status < 80) { + utwrs->response = UserToWorldStatusWorldAtCapacity; + SendPacket(&outpack); + return; + } - if (status == -1) - utwrs->response = -1; - if (status == -2) - utwrs->response = -2; + if (status == -1) { + utwrs->response = UserToWorldStatusSuspended; + SendPacket(&outpack); + return; + } - utwrs->worldid = utwr->worldid; - SendPacket(outpack); - delete outpack; + if (status == -2) { + utwrs->response = UserToWorldStatusBanned; + SendPacket(&outpack); + return; + } + + if (RuleB(World, DisallowDuplicateAccountLogins)) { + auto cle = client_list.FindCLEByLSID(utwr->lsaccountid); + if (cle != nullptr) { + auto status = cle->GetOnline(); + if (CLE_Status_Never != status && CLE_Status_Offline != status) { + utwrs->response = UserToWorldStatusAlreadyOnline; + SendPacket(&outpack); + return; + } + } + } + + SendPacket(&outpack); } void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) { @@ -105,13 +126,6 @@ void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) { try { auto slsca = p.GetSerialize(0); - - if (RuleI(World, AccountSessionLimit) >= 0) { - // Enforce the limit on the number of characters on the same account that can be - // online at the same time. - client_list.EnforceSessionLimit(slsca.lsaccount_id); - } - client_list.CLEAdd(slsca.lsaccount_id, slsca.name, slsca.key, slsca.worldadmin, slsca.ip, slsca.local); } catch (std::exception &ex) {