diff --git a/CMakeLists.txt b/CMakeLists.txt
index 64d53cc6e..dedce5c3f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,8 @@
#EQEMU_BUILD_CLIENT_FILES
#EQEMU_USE_MAP_MMFS
#EQEMU_MAP_DIR
+#EQEMU_ARCH
+#EQEMU_ARCH_ALT
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
IF(POLICY CMP0074)
@@ -49,33 +51,37 @@ ENDIF(MSVC OR MINGW)
IF(MSVC)
IF(CMAKE_CL_64)
- SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64")
- SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64")
- SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x64")
- SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x64")
- SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
- IF(MSVC_VERSION GREATER 1800)
- SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v140/dynamic")
- ELSEIF(MSVC_VERSION EQUAL 1800)
- SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v120/dynamic")
- ELSE()
- SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v110/dynamic")
- ENDIF()
+ SET(EQEMU_ARCH "x64")
+ SET(EQEMU_ARCH_ALT "x64")
ELSE(CMAKE_CL_64)
- SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86")
- SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
- SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
- SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
- SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x86")
- IF(MSVC_VERSION GREATER 1800)
- SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
- ELSEIF(MSVC_VERSION EQUAL 1800)
- SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v120/dynamic")
- ELSE()
- SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v110/dynamic")
- ENDIF()
+ SET(EQEMU_ARCH "x86")
+ SET(EQEMU_ARCH_ALT "Win32")
ENDIF(CMAKE_CL_64)
-
+
+ SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_${EQEMU_ARCH}")
+
+ IF(VCPKG_TOOLCHAIN)
+ IF(NOT MSVC_VERSION GREATER 1800)
+ SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
+ ENDIF()
+ ELSE(VCPKG_TOOLCHAIN)
+ SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_${EQEMU_ARCH}")
+ SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_${EQEMU_ARCH}")
+ SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_${EQEMU_ARCH}")
+
+ SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
+ ENDIF(VCPKG_TOOLCHAIN)
+
+ IF(SODIUM_INCLUDE_HINTS)
+ IF(MSVC_VERSION GREATER 1800)
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/${EQEMU_ARCH_ALT}/Release/v140/dynamic")
+ ELSEIF(MSVC_VERSION EQUAL 1800)
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/${EQEMU_ARCH_ALT}/Release/v120/dynamic")
+ ELSE()
+ SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/${EQEMU_ARCH_ALT}/Release/v110/dynamic")
+ ENDIF()
+ ENDIF(SODIUM_INCLUDE_HINTS)
+
#disable CRT warnings on windows cause they're annoying as shit and we use C functions everywhere
OPTION(EQEMU_DISABLE_CRT_SECURE_WARNINGS "Disable Secure CRT Warnings" ON)
IF(EQEMU_DISABLE_CRT_SECURE_WARNINGS)
@@ -243,6 +249,8 @@ IF(ZLIB_FOUND)
SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY})
ENDIF()
ELSE()
+ MESSAGE(STATUS "Could NOT find ZLIB - using ZLIBSTATIC package.")
+ SET(EQEMU_BUILD_ZLIB ON)
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/README.md b/README.md
index e1126241c..5e4f919fe 100644
--- a/README.md
+++ b/README.md
@@ -70,3 +70,9 @@ forum, although pull requests will be much quicker and easier on all parties.
* GPL Perl - GPL / ActiveState (under the assumption that this is a free project)
* CPPUnit - GLP StringUtilities - Apache
* LUA - MIT
+
+## Contributors
+
+
+
+
diff --git a/changelog.txt b/changelog.txt
index dc9d0f16c..3f69bf570 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,11 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
+== 8/6/2019 ==
+Akkadius: Optimizations to movement updates to eliminate ghosting possibilities in larger zones
+
+== 7/22/2019 ==
+Uleat: Added script 'vcxproj_dependencies.py' - a script to help determine conflicting project dependencies (alpha-stage)
+
== 7/10/2019 ==
Akkadius: Add #npcedit flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating]
diff --git a/common/emu_constants.h b/common/emu_constants.h
index 384aa3768..c6491b3b3 100644
--- a/common/emu_constants.h
+++ b/common/emu_constants.h
@@ -77,6 +77,10 @@ namespace EQEmu
} // namespace invtype
+ namespace DevTools {
+ const int32 GM_ACCOUNT_STATUS_LEVEL = 150;
+ }
+
namespace popupresponse {
const int32 SERVER_INTERNAL_USE_BASE = 2000000000;
const int32 MOB_INFO_DISMISS = 2000000001;
diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp
index 7569b4c5d..bb310a76c 100644
--- a/common/patches/sof.cpp
+++ b/common/patches/sof.cpp
@@ -1116,7 +1116,10 @@ namespace SoF
}
OUT(deity);
OUT(intoxication);
+
OUT_array(spellSlotRefresh, spells::SPELL_GEM_COUNT);
+ eq->spellSlotRefresh[9] = 0; // 10th slot is not valid in this release
+
OUT(abilitySlotRefresh);
OUT(points); // Relocation Test
// OUT(unknown0166[4]);
@@ -1177,7 +1180,10 @@ namespace SoF
}
// OUT(unknown4184[128]);
+
OUT_array(mem_spells, spells::SPELL_GEM_COUNT);
+ eq->mem_spells[9] = 0xFFFFFFFFU; // 10th slot is not valid in this release
+
// OUT(unknown04396[32]);
OUT(platinum);
OUT(gold);
diff --git a/common/patches/sof_limits.h b/common/patches/sof_limits.h
index 399ff8c1a..a03676f2d 100644
--- a/common/patches/sof_limits.h
+++ b/common/patches/sof_limits.h
@@ -328,7 +328,11 @@ namespace SoF
const int SPELL_ID_MAX = 15999;
const int SPELLBOOK_SIZE = 480;
+ // Be careful not to confuse these two..SoF disc release has a special requirement...
+ // - The number of available spell gems HAS NOT increased from 9 at this point
+ // - The profile allocation HAS increased to 10 at this point
const int SPELL_GEM_COUNT = static_cast(CastingSlot::MaxGems);
+ const int SPELL_GEM_PROFILE_SIZE = 10; // special case declaration
const int LONG_BUFFS = 25;
const int SHORT_BUFFS = 15;
diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h
index 93b185e23..4d4a591e1 100644
--- a/common/patches/sof_structs.h
+++ b/common/patches/sof_structs.h
@@ -885,7 +885,7 @@ struct PlayerProfile_Struct //23576 Octets
/*00060*/ BindStruct binds[5]; // Bind points (primary is first)
/*00160*/ uint32 deity; // deity
/*00164*/ uint32 intoxication; // Alcohol level (in ticks till sober?)
-/*00168*/ uint32 spellSlotRefresh[spells::SPELL_GEM_COUNT]; // Refresh time (millis) - 4 Octets Each
+/*00168*/ uint32 spellSlotRefresh[spells::SPELL_GEM_PROFILE_SIZE]; // Refresh time (millis) - 4 Octets Each
/*00208*/ uint32 abilitySlotRefresh;
/*00212*/ uint8 haircolor; // Player hair color
/*00213*/ uint8 beardcolor; // Player beard color
@@ -912,7 +912,7 @@ struct PlayerProfile_Struct //23576 Octets
/*04173*/ uint8 unknown02264[147]; // was [139]
/*04312*/ uint32 spell_book[spells::SPELLBOOK_SIZE]; // List of the Spells in spellbook 480 = 60 pages
/*06232*/ uint8 unknown4184[128]; // was [136]
-/*06396*/ uint32 mem_spells[spells::SPELL_GEM_COUNT]; // List of spells memorized
+/*06396*/ uint32 mem_spells[spells::SPELL_GEM_PROFILE_SIZE]; // List of spells memorized
/*06436*/ uint8 unknown04396[28]; //#### uint8 unknown04396[32]; in Titanium ####[28]
/*06464*/ uint32 platinum; // Platinum Pieces on player
/*06468*/ uint32 gold; // Gold Pieces on player
@@ -3768,7 +3768,7 @@ struct AnnoyingZoneUnknown_Struct {
};
struct LoadSpellSet_Struct {
- uint32 spell[spells::SPELL_GEM_COUNT];
+ uint32 spell[spells::SPELL_GEM_PROFILE_SIZE];
uint32 unknown;
};
diff --git a/common/ruletypes.h b/common/ruletypes.h
index 821f36c0d..16f29fc17 100644
--- a/common/ruletypes.h
+++ b/common/ruletypes.h
@@ -240,7 +240,7 @@ 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_BOOL(World, EnforceCharacterLimitAtLogin, false)
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
diff --git a/common/servertalk.h b/common/servertalk.h
index 1b34d3918..73014e11a 100644
--- a/common/servertalk.h
+++ b/common/servertalk.h
@@ -80,6 +80,7 @@
#define ServerOP_GroupJoin 0x003e //for joining ooz folks
#define ServerOP_UpdateSpawn 0x003f
#define ServerOP_SpawnStatusChange 0x0040
+#define ServerOP_DropClient 0x0041 // DropClient
#define ServerOP_ReloadTasks 0x0060
#define ServerOP_DepopAllPlayersCorpses 0x0061
#define ServerOP_ReloadTitles 0x0062
@@ -320,11 +321,17 @@ struct ServerZoneIncomingClient_Struct {
uint32 accid;
int16 admin;
uint32 charid;
+ uint32 lsid;
bool tellsoff;
char charname[64];
char lskey[30];
};
+struct ServerZoneDropClient_Struct
+{
+ uint32 lsid;
+};
+
struct ServerChangeWID_Struct {
uint32 charid;
uint32 newwid;
diff --git a/queryserv/database.cpp b/queryserv/database.cpp
index 02d985a8b..a1261e3a9 100644
--- a/queryserv/database.cpp
+++ b/queryserv/database.cpp
@@ -379,6 +379,7 @@ void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint3
}
+// this function does not delete the ServerPacket, so it must be handled at call site
void Database::GeneralQueryReceive(ServerPacket *pack) {
/*
These are general queries passed from anywhere in zone instead of packing structures and breaking them down again and again
@@ -393,7 +394,6 @@ void Database::GeneralQueryReceive(ServerPacket *pack) {
Log(Logs::Detail, Logs::QS_Server, "%s", query.c_str());
}
- safe_delete(pack);
safe_delete_array(queryBuffer);
}
diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp
index b7d1f01b3..c5d9c0927 100644
--- a/ucs/clientlist.cpp
+++ b/ucs/clientlist.cpp
@@ -470,7 +470,7 @@ static void ProcessCommandIgnore(Client *c, std::string Ignoree) {
Clientlist::Clientlist(int ChatPort) {
EQStreamManagerInterfaceOptions chat_opts(ChatPort, false, false);
chat_opts.opcode_size = 1;
- chat_opts.daybreak_options.stale_connection_ms = 300000;
+ chat_opts.daybreak_options.stale_connection_ms = 600000;
chat_opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
chat_opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
chat_opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);
diff --git a/utils/scripts/.gitignore b/utils/scripts/.gitignore
index eba9f59cb..76f70485c 100644
--- a/utils/scripts/.gitignore
+++ b/utils/scripts/.gitignore
@@ -1 +1,2 @@
-opcode_handlers_output
\ No newline at end of file
+opcode_handlers_output
+vcxproj_dependencies_output
diff --git a/utils/scripts/eqemu_server.pl b/utils/scripts/eqemu_server.pl
index f05c2c266..b2a53b864 100644
--- a/utils/scripts/eqemu_server.pl
+++ b/utils/scripts/eqemu_server.pl
@@ -1587,22 +1587,24 @@ sub add_login_server_firewall_rules {
print "If firewall rules don't add you must run this script (eqemu_server.pl) as administrator\n";
print "\n";
print "[Install] Instructions \n";
- print "[Install] In order to connect your server to the loginserver you must point your eqemu_config.xml to your local server similar to the following:\n";
+ print "[Install] In order to connect your server to the loginserver you must point your eqemu_config.json to your local server similar to the following:\n";
print "
-
- login.eqemulator.net
- 5998
-
-
-
-
- 127.0.0.1
- 5998
-
-
-
+ \"loginserver1\" : {
+ \"account\" : \"\",
+ \"host\" : \"login.eqemulator.net\",
+ \"password\" : \"\",
+ \"port\" : \"5998\",
+ \"legacy\": \"1\"
+ },
+ \"loginserver2\" : {
+ \"account\" : \"\",
+ \"host\" : \"192.168.197.129\",
+ \"password\" : \"\",
+ \"port\" : \"5998\"
+ },
+ \"localaddress\" : \"192.168.197.129\",
";
- print "[Install] When done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 127.0.0.1) in the eqhosts.txt file\n";
+ print "[Install] When done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 192.168.197.129) in the eqhosts.txt file\n";
}
}
diff --git a/utils/scripts/vcxproj_dependencies.py b/utils/scripts/vcxproj_dependencies.py
new file mode 100644
index 000000000..f50c9aec4
--- /dev/null
+++ b/utils/scripts/vcxproj_dependencies.py
@@ -0,0 +1,793 @@
+#! /usr/bin/env python
+#
+
+"""
+'VCXProj-Dependencies' for EQEmulator
+
+This script locates external dependency paths and generates lists for each
+project. In addition, it will cross-check these lists to determine if any
+discrepancies exist for any dependencies globally and across all projects.
+
+"""
+
+
+import sys
+import os
+import fnmatch
+
+try:
+ import xml.etree.cElementTree as ElementTree
+except ImportError:
+ import xml.etree.ElementTree as ElementTree
+
+from time import time, ctime
+
+
+QUIET_REPORT = True
+
+include_projects = []
+exclude_projects = ['VCTargetsPath', 'CompilerIdC', 'CompilerIdCXX'] # these three should be left in by default
+
+base_path = os.getcwd()[:-14] # '/utils/scripts'
+base_path = base_path.replace('\\', '/')
+
+file_extensions = ['vcxproj']
+project_paths = []
+master_dependencies = []
+# {[project]:{[build]:{[resource]:{[reference]:[paths]}}}}
+project_dependencies = {}
+
+out_files = {}
+
+col1 = '{0}'.format(' ' * 0)
+col2 = '{0}'.format(' ' * 2)
+col3 = '{0}'.format(' ' * 4)
+col4 = '{0}'.format(' ' * 6)
+col5 = '{0}'.format(' ' * 8)
+
+
+def main():
+ """ main """
+
+ if not create_output_directory():
+ exit()
+
+ if not open_output_files():
+ exit()
+
+ print 'Locating project paths...'
+ locate_project_paths()
+ print '..project count: {0}'.format(len(project_paths))
+ print 'Parsing project files...'
+ parse_project_files()
+ print 'Building master dependencies...'
+ build_master_dependencies()
+ print '..dependency count: {0}'.format(len(master_dependencies))
+ print 'Checking for version discrepancies...'
+ check_for_version_discrepancies()
+ close_output_files()
+ print '\n__fin__'
+
+ return
+
+
+def create_output_directory():
+ """ Check for output directory - create if does not exist """
+
+ try:
+ output_path = '{0}/utils/scripts/vcxproj_dependencies_output'.format(base_path)
+ if not os.path.exists(output_path):
+ os.mkdir(output_path)
+
+ return True
+
+ except IOError:
+ print('(Exception Error: {0}) create_output_directory()'.format(sys.exc_info()[0]))
+
+ return False
+
+
+def open_output_files():
+ """ Open all output files """
+
+ try:
+ file_name = '{0}/utils/scripts/vcxproj_dependencies_output/ProjectPaths.txt'.format(base_path)
+ out_files['ProjectPaths'] = open(file_name, 'w')
+ file_name = '{0}/utils/scripts/vcxproj_dependencies_output/MasterDependencies.txt'.format(base_path)
+ out_files['MasterDependencies'] = open(file_name, 'w')
+ file_name = '{0}/utils/scripts/vcxproj_dependencies_output/ProjectDependencies.txt'.format(base_path)
+ out_files['ProjectDependencies'] = open(file_name, 'w')
+ file_name = '{0}/utils/scripts/vcxproj_dependencies_output/ContextTree.txt'.format(base_path)
+ out_files['ContextTree'] = open(file_name, 'w')
+ file_name = '{0}/utils/scripts/vcxproj_dependencies_output/DiscrepancyReport.txt'.format(base_path)
+ out_files['DiscrepancyReport'] = open(file_name, 'w')
+ for file in out_files:
+ out_files[file].write('>> \'VCXProj-Dependencies\' {0} file\n'.format(file))
+ out_files[file].write('>> file generated @ {0}\n\n'.format(ctime(time())))
+
+ return True
+
+ except IOError:
+ print('(Exception Error: {0}) open_output_files()'.format(sys.exc_info()[0]))
+ close_output_files()
+
+ return False
+
+
+def locate_project_paths():
+ """ Locate vcxproj files in the build folder """
+
+ for root, dirs, files in os.walk('{0}/build'.format(base_path)):
+ for name in files:
+ project = name.split('.')[0]
+ if not len(include_projects) == 0 and project not in include_projects:
+ continue
+ if not len(exclude_projects) == 0 and project in exclude_projects:
+ continue
+ for extension in file_extensions:
+ if fnmatch.fnmatch(name, '*.{0}'.format(extension)):
+ project_paths.append(os.path.join(root, name).replace('\\', '/').lower())
+ for path in project_paths:
+ out_files['ProjectPaths'].write('{0};\n'.format(path))
+
+ return
+
+
+def fixup_path(project_path, dependency_path):
+ """ Fix-up malformed dependency paths """
+
+ trailing = dependency_path.replace('\\', '/')
+ if '../' in trailing:
+ if trailing[:3] == '../': # windows
+ leading = project_path[:project_path.rfind('/')]
+ while trailing[:3] == '../':
+ leading = leading[:leading.rfind('/')]
+ trailing = trailing[3:]
+ trailing = trailing.lower()
+ trailing = '{0}/{1}'.format(leading, trailing)
+ else: # unix
+ print '..processing unix-style path fix-up'
+ while '../' in trailing:
+ backout = trailing.find('../')
+ backdir = trailing.rfind('/', 0, backout - 1)
+ trailing = trailing.replace(trailing[backdir:backout + 2], '', 1)
+ trailing = trailing.lower()
+ else:
+ trailing = trailing.lower()
+
+ return trailing
+
+
+def parse_project_files():
+ """ Parse each vcxproj file's xml data """
+
+ for key1 in project_paths:
+ with open(key1, 'r') as vcxproj_file:
+ project_dependencies[key1] = {}
+ xml_tree = ElementTree.ElementTree(file=vcxproj_file)
+ for element1 in xml_tree.getroot():
+ if not element1.tag[-19:] == 'ItemDefinitionGroup':
+ continue
+ # add '.split('|')[0]' to remove the '|Win##' attribute
+ key2 = element1.attrib['Condition'].split('==')[1][1:-1]
+ project_dependencies[key1][key2] = {}
+ for element2 in element1.getiterator():
+ if element2.tag[-9:] == 'ClCompile':
+ key3 = element2.tag[-9:]
+ project_dependencies[key1][key2][key3] = {}
+ for element3 in element2.getiterator():
+ if element3.tag[-28:] == 'AdditionalIncludeDirectories':
+ key4 = element3.tag[-28:]
+ project_dependencies[key1][key2][key3][key4] = []
+ paths = element3.text.split(';')
+ for path in paths:
+ project_dependencies[key1][key2][key3][key4].append(fixup_path(key1, path))
+ elif element2.tag[-15:] == 'ResourceCompile':
+ key3 = element2.tag[-15:]
+ project_dependencies[key1][key2][key3] = {}
+ for element3 in element2.getiterator():
+ if element3.tag[-28:] == 'AdditionalIncludeDirectories':
+ key4 = element3.tag[-28:]
+ project_dependencies[key1][key2][key3][key4] = []
+ paths = element3.text.split(';')
+ for path in paths:
+ project_dependencies[key1][key2][key3][key4].append(fixup_path(key1, path))
+ elif element2.tag[-4:] == 'Midl':
+ key3 = element2.tag[-4:]
+ project_dependencies[key1][key2][key3] = {}
+ for element3 in element2.getiterator():
+ if element3.tag[-28:] == 'AdditionalIncludeDirectories':
+ key4 = element3.tag[-28:]
+ project_dependencies[key1][key2][key3][key4] = []
+ paths = element3.text.split(';')
+ for path in paths:
+ project_dependencies[key1][key2][key3][key4].append(fixup_path(key1, path))
+ elif element2.tag[-4:] == 'Link':
+ key3 = element2.tag[-4:]
+ project_dependencies[key1][key2][key3] = {}
+ for element3 in element2.getiterator():
+ if element3.tag[-22:] == 'AdditionalDependencies':
+ key4 = element3.tag[-22:]
+ project_dependencies[key1][key2][key3][key4] = []
+ paths = element3.text.split(';')
+ for path in paths:
+ project_dependencies[key1][key2][key3][key4].append(fixup_path(key1, path))
+ if element3.tag[-28:] == 'AdditionalLibraryDirectories':
+ key4 = element3.tag[-28:]
+ project_dependencies[key1][key2][key3][key4] = []
+ paths = element3.text.split(';')
+ for path in paths:
+ project_dependencies[key1][key2][key3][key4].append(fixup_path(key1, path))
+ vcxproj_file.close()
+
+ return
+
+
+def build_master_dependencies():
+ """ Build master dependencies list """
+
+ def write(message):
+ """ internal 'ProjectDependencies' write method - performed here so processing takes place after fix-up """
+
+ out_files['ProjectDependencies'].write('{0}\n'.format(message))
+
+ return
+
+ for key1 in project_dependencies:
+ write('{0}'.format(col1, key1))
+ for key2 in project_dependencies[key1]:
+ write('{0}'.format(col2, key2))
+ for key3 in project_dependencies[key1][key2]:
+ write('{0}'.format(col3, key3))
+ for key4 in project_dependencies[key1][key2][key3]:
+ write('{0}'.format(col4, key4))
+ for path in project_dependencies[key1][key2][key3][key4]:
+ write('{0}{1}'.format(col4, path))
+ if path not in master_dependencies:
+ master_dependencies.append(path)
+ write('{0}'.format(col4))
+ write('{0}'.format(col3))
+ write('{0}'.format(col2))
+ write('{0}'.format(col1))
+ master_dependencies.sort()
+ for path in master_dependencies:
+ out_files['MasterDependencies'].write('{0}\n'.format(path))
+
+ return
+
+
+def check_for_version_discrepancies():
+ """ Check for dependency version discrepancies """
+
+ def twrite(message):
+ """ internal 'ContextTree' write method """
+
+ out_files['ContextTree'].write('{0}\n'.format(message))
+
+ return
+
+ def rwrite(message):
+ """ internal 'DiscrepancyReport' write method """
+
+ out_files['DiscrepancyReport'].write('{0}\n'.format(message))
+
+ return
+
+ libraries = [
+ 'mysql',
+ 'zlib',
+ 'perl',
+ 'lua',
+ 'boost',
+ 'sodium',
+ 'openssl'
+ ]
+ references = [
+ 'include',
+ 'source',
+ 'library'
+ ]
+ priorities = {
+ 0: 'NOT FOUND',
+ 1: 'install',
+ 2: 'dependencies',
+ 3: 'libs',
+ 4: 'vcpkg',
+ 5: 'static',
+ 6: 'submodule'
+ }
+ # use all lowercase for path description
+ # use forward slash ('/') for directory name separators
+ # use '|' token for multiple hints ('my_file_path_1|my_file_path_2')
+ # use '!!' token for explicit argument ('/perl/core!!' will find '../perl/core' but not '../perl/core/perl512.lib')
+ # use '##' token for joined hints ('my_file_##_1')
+ # use '&&', '^' and '@' tokens for multiple argument hints ('my_file_&&path_1^path_2^path_3@')
+ # (i.e., 'my_file_path_1|my_file_##_2|my_##_##&&_3^_4!!@')
+ # {[library]:{[reference]:[[priority]:hint]}}
+ hints = {
+ # Notes:
+ 'mysql': {
+ 'include': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/dependencies/mysql_##/include', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'source': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'library': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ 'dependencies/mysql_##/lib', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ]
+ },
+ 'zlib': {
+ 'include': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/zlib_x##/include', # 'dependencies'
+ # not sure if this should be '/libs/zlibng' or '/build/libs/zlibng' based on cmake behavior
+ '/server/build/libs/zlibng!!', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/include', # 'vcpkg'
+ '/server/build/libs/zlibng!!', # 'static'
+ '' # 'submodule'
+ ],
+ 'source': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '', # 'dependencies'
+ '/server/libs/zlibng!!', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'library': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/zlib_x##/lib/zdll.lib', # 'dependencies'
+ '', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/&&lib/zlib.lib!!'
+ '^debug/lib/zlibd.lib!!@', # 'vcpkg'
+ '/server/build/libs/zlibng/&&debug/zlibstaticd.lib!!^minsizerel/zlibstatic.lib!!'
+ '^release/zlibstatic.lib!!^relwithdebinfo/zlibstatic.lib!!@', # 'static'
+ '' # 'submodule'
+ ]
+ },
+ 'perl': {
+ 'include': [
+ '', # 'NOT FOUND'
+ '/perl/lib/core!!', # 'install'
+ '', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'source': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'library': [
+ '', # 'NOT FOUND'
+ '/perl/lib/core/perl51##.lib', # 'install'
+ '', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ]
+ },
+ 'lua': {
+ 'include': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/luaj_x##/src', # 'dependencies'
+ '', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/include', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'source': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/luaj_x##/src', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'library': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/luaj_x##/bin/lua51.lib', # 'dependencies'
+ '', # 'libs'
+ # debug lua package likely incorrect..should be 'lua51d.lib' - or whatever debug version is
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/&&lib/lua51.lib!!'
+ '^debug/lib/lua51.lib!!@', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ]
+ },
+ 'boost': {
+ 'include': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/boost', # 'dependencies'
+ '', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/include', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'source': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '', # 'dependencies'
+ '', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/include', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'library': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/boost', # 'dependencies'
+ '', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/lib!!', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ]
+ },
+ 'sodium': {
+ 'include': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/libsodium/include', # 'dependencies'
+ '', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/include', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'source': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'library': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/libsodium/##/dynamic/libsodium.lib', # 'dependencies'
+ '', # 'libs'
+ # debug libsodium package likely incorrect..should be 'libsodiumd.lib' - or whatever debug version is
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/&&lib/libsodium.lib!!^'
+ 'debug/lib/libsodium.lib!!@', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ]
+ },
+ 'openssl': {
+ 'include': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/openssl_x##/include', # 'dependencies'
+ '', # 'libs'
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/include', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'source': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '', # 'dependencies'
+ '', # 'libs'
+ '', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ],
+ 'library': [
+ '', # 'NOT FOUND'
+ '', # 'install'
+ '/server/dependencies/openssl_x##/lib/VC/&&libeay32MD.lib!!^libeay32MDd.lib!!^'
+ 'ssleay32MD.lib!!^ssleay32MDd.lib!!@', # 'dependencies'
+ '', # 'libs'
+ # debug openssl package likely incorrect..should be
+ # 'libeay32d.lib' and 'ssleay32d.lib' - or whatever debug versions are
+ '/server/vcpkg/vcpkg-export-##/installed/x##-windows/&&lib/libeay32.lib!!^'
+ 'lib/ssleay32.lib!!^debug/lib/libeay32.lib!!^debug/lib/ssleay32.lib!!@', # 'vcpkg'
+ '', # 'static'
+ '' # 'submodule'
+ ]
+ }
+ }
+ # {[project]:{[build]:{[resource]:{[library]:{[reference]:priority}}}}}
+ context_tree = {}
+ # {[library]:priority}
+ global_priorities = {}
+ # {[build]:{[library]:priority}}
+ build_priorities = {}
+ # loop for discovering first occurence dependency sources (assumes same search precedence as compiler includes)
+ for project in project_dependencies:
+ if project not in context_tree.keys():
+ context_tree[project] = {}
+ for build in project_dependencies[project]:
+ if build not in context_tree[project].keys():
+ context_tree[project][build] = {}
+ if build not in build_priorities.keys():
+ build_priorities[build] = {}
+ for resource in project_dependencies[project][build]:
+ if resource not in context_tree[project][build].keys():
+ context_tree[project][build][resource] = {}
+ for reference_project in project_dependencies[project][build][resource]:
+ for path in project_dependencies[project][build][resource][reference_project]:
+ for library in libraries:
+ if library not in context_tree[project][build][resource].keys():
+ context_tree[project][build][resource][library] = {}
+ if library not in build_priorities[build].keys():
+ build_priorities[build][library] = 0
+ if library not in global_priorities.keys():
+ global_priorities[library] = 0
+ for reference in references:
+ if reference not in context_tree[project][build][resource][library].keys():
+ context_tree[project][build][resource][library][reference] = 0
+ elif not context_tree[project][build][resource][library][reference] == 0:
+ continue
+ for priority in priorities:
+ if hints[library][reference][priority] == '':
+ continue
+ hint_found = False
+ for hint in hints[library][reference][priority].split('|'):
+ if not find_hint_in_path(hint, path) == -1:
+ context_tree[project][build][resource][library][reference] = priority
+ if context_tree[project][build][resource][library][reference] >\
+ build_priorities[build][library]:
+ build_priorities[build][library] =\
+ context_tree[project][build][resource][library][reference]
+ if context_tree[project][build][resource][library][reference] >\
+ global_priorities[library]:
+ global_priorities[library] =\
+ context_tree[project][build][resource][library][reference]
+ hint_found = True
+ break
+ if hint_found is True:
+ break
+ # loop for hack to fix odd behavior caused by 'FindZLIB.cmake' - ref: '../server/build/libs/zlibng/zconf.h'
+ # this does not change anything in the build files..only silences a false discrepancy due to mixing priority types
+ if global_priorities['zlib'] == 5:
+ for project in context_tree:
+ for build in context_tree[project]:
+ for resource in context_tree[project][build]:
+ if context_tree[project][build][resource]['zlib']['source'] == 3:
+ context_tree[project][build][resource]['zlib']['source'] = 5
+ if context_tree[project][build][resource]['zlib']['include'] == 3:
+ context_tree[project][build][resource]['zlib']['include'] = 5
+ # loop for dumping 'global_priorities'
+ twrite('{0}'.format(col1))
+ for library in libraries:
+ twrite('{0}{2}'.format(col2, library, global_priorities[library]))
+ twrite('{0}'.format(col1))
+ twrite('')
+ # loop for dumping 'build_priorities'
+ for build in build_priorities:
+ twrite('{0}'.format(col1, build))
+ for library in libraries:
+ twrite('{0}{2}'.format(col2, library, build_priorities[build][library]))
+ twrite('{0}'.format(col1))
+ twrite('')
+ # loop for dumping 'context_tree'
+ for project in context_tree:
+ twrite('{0}'.format(col1, project))
+ for build in context_tree[project]:
+ twrite('{0}'.format(col2, build))
+ for resource in context_tree[project][build]:
+ twrite('{0}'.format(col3, resource))
+ for library in context_tree[project][build][resource]:
+ twrite('{0}'.format(col4, library))
+ for reference in context_tree[project][build][resource][library]:
+ twrite(
+ '{0}{2}'.format(
+ col5,
+ reference,
+ context_tree[project][build][resource][library][reference]
+ )
+ )
+ twrite('{0}'.format(col4))
+ twrite('{0}'.format(col3))
+ twrite('{0}'.format(col2))
+ twrite('{0}'.format(col1))
+ if QUIET_REPORT is False:
+ for library in libraries:
+ rwrite(
+ '> Global Library \'{0}\' status: \'{1}\' ({2})'.format(
+ library,
+ priorities[global_priorities[library]],
+ global_priorities[library]
+ )
+ )
+ # loop for identifying dependency discrepancies
+ for project in context_tree:
+ for build in context_tree[project]:
+ for resource in context_tree[project][build]:
+ for library in context_tree[project][build][resource]:
+ if global_priorities[library] == 0:
+ if QUIET_REPORT is False:
+ rwrite(
+ '> No Global Library \'{0}\' .. skipping Project:Build:Resource'
+ ' "{1}":"{2}":"{3}"'.format(
+ library,
+ project,
+ build,
+ resource
+ )
+ )
+ continue
+ if build_priorities[build][library] == 0:
+ if QUIET_REPORT is False:
+ rwrite(
+ '> No Build Library \'{0}\' .. skipping Project:Build:Resource'
+ ' "{1}":"{2}":"{3}"'.format(
+ library,
+ project,
+ build,
+ resource
+ )
+ )
+ continue
+ for reference in context_tree[project][build][resource][library]:
+ if context_tree[project][build][resource][library][reference] == 0:
+ continue
+ if not global_priorities[library] == context_tree[project][build][resource][library][reference]:
+ rwrite(
+ '> Global-Project Library \'{0}\' mis-match \'{1}!={2}\''
+ ' ({3}!={4}) Project:Build:Resource "{5}":"{6}":"{7}"'.format(
+ library,
+ priorities[global_priorities[library]],
+ priorities[context_tree[project][build][resource][library][reference]],
+ global_priorities[library],
+ context_tree[project][build][resource][library][reference],
+ project,
+ build,
+ resource
+ )
+ )
+ # 'builds' are allowed to have different dependencies..so, we'll start crossing at 'resource'
+ for cross_resource in context_tree[project][build]:
+ for cross_reference in context_tree[project][build][cross_resource][library]:
+ if cross_resource == resource and cross_reference == reference:
+ continue
+ if context_tree[project][build][cross_resource][library][cross_reference] == 0:
+ continue
+ if QUIET_REPORT is False and\
+ not context_tree[project][build][cross_resource][library][cross_reference] ==\
+ context_tree[project][build][resource][library][reference]:
+ rwrite(
+ '> Project Library \'{0}\' mis-match \'{1}:{2}:{3}!={4}:{5}:{6}\''
+ ' ({7}!={8}) Project:Build "{9}":"{10}"'.format(
+ library,
+ resource,
+ reference,
+ priorities[context_tree[project][build][resource][library][reference]],
+ cross_resource,
+ cross_reference,
+ priorities[context_tree[project][build][cross_resource][library]
+ [cross_reference]],
+ context_tree[project][build][resource][library][reference],
+ context_tree[project][build][cross_resource][library][cross_reference],
+ project,
+ build
+ )
+ )
+
+ return
+
+
+def find_hint_in_path(hint, path):
+ """
+ Helper function for parsing and checking for hints in paths
+
+ Hints strings should be split ('|') and passed as a singular hint into this function
+
+ """
+
+ if hint == '' or path == '':
+ return -1
+
+ joined_index = hint.find('##')
+ pretext_index = hint.find('&&')
+ if joined_index == -1 and pretext_index == -1:
+ if '^' in hint or '@' in hint:
+ print '..malformed or improper handling of hint: \'{0}\' path: \'{1}\''.format(hint, path)
+
+ return -1
+
+ explicit_index = hint.find('!!')
+ if explicit_index == -1:
+ return path.find(hint)
+
+ else:
+ explicit_hint = hint[:explicit_index]
+ found_index = path.find(explicit_hint)
+ if (len(explicit_hint) + found_index) == len(path):
+ return found_index
+
+ else:
+ return -1
+
+ elif (not joined_index == -1 and pretext_index == -1) or\
+ (not joined_index == -1 and not pretext_index == -1 and joined_index < pretext_index):
+ start_index = 0
+ for partial_hint in hint.split('##', 1):
+ if partial_hint == '':
+ continue
+ found_index = find_hint_in_path(partial_hint, path[start_index:])
+ if found_index == -1:
+ return found_index
+
+ start_index = found_index + len(partial_hint)
+
+ return start_index
+
+ elif (joined_index == -1 and not pretext_index == -1) or\
+ (not joined_index == -1 and not pretext_index == -1 and joined_index > pretext_index):
+ pretext_hints = hint.split('&&', 1)
+ found_index = 0
+ if not pretext_hints[0] == '':
+ found_index = find_hint_in_path(pretext_hints[0], path)
+ if found_index == -1:
+ return found_index
+
+ start_index = found_index + len(pretext_hints[0])
+ partial_hints = pretext_hints[1].split('@', 1)
+ for partial_hint in partial_hints:
+ if partial_hint == '':
+ continue
+ for alt_hint in partial_hint.split('^'):
+ if alt_hint == '':
+ continue
+ found_index = find_hint_in_path(alt_hint, path[start_index:])
+ if found_index == 0:
+ if not partial_hints[1] == '':
+ print '..unhandled hint method: \'{0}\''.format(partial_hints[1])
+ else:
+ return found_index
+
+ return -1
+
+ else:
+ return -1
+
+
+def close_output_files():
+ """ Close all output files """
+
+ while not len(out_files) == 0:
+ key = out_files.keys()[0]
+ out_files[key].close()
+ del out_files[key]
+
+ return
+
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt
index 92bcfd260..4addfe6ce 100644
--- a/utils/sql/db_update_manifest.txt
+++ b/utils/sql/db_update_manifest.txt
@@ -393,7 +393,7 @@
9137|2018_12_12_client_faction_tables.sql|SHOW TABLES LIKE 'faction_base_data'|empty|
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|
+9140|2019_07_03_update_range.sql|SHOW COLUMNS FROM `zone` LIKE 'max_movement_update_range'|empty|
9141|2019_07_10_npc_flymode.sql|SHOW COLUMNS FROM `npc_types` LIKE 'flymode'|empty|
# Upgrade conditions:
diff --git a/world/adventure.cpp b/world/adventure.cpp
index c984fa831..af3cfe0e2 100644
--- a/world/adventure.cpp
+++ b/world/adventure.cpp
@@ -287,7 +287,7 @@ void Adventure::Finished(AdventureWinStatus ws)
ClientListEntry *current = client_list.FindCharacter((*iter).c_str());
if(current)
{
- if(current->Online() == CLE_Status_InZone)
+ if(current->Online() == CLE_Status::InZone)
{
//We can send our packets only.
auto pack =
diff --git a/world/client.cpp b/world/client.cpp
index 53ea40036..aa69e3ac7 100644
--- a/world/client.cpp
+++ b/world/client.cpp
@@ -88,7 +88,6 @@ extern volatile bool UCSServerAvailable_;
Client::Client(EQStreamInterface* ieqs)
: autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)),
- CLE_keepalive_timer(RuleI(World, ClientKeepaliveTimeoutMS)),
connect(1000),
eqs(ieqs)
{
@@ -105,6 +104,7 @@ Client::Client(EQStreamInterface* ieqs)
char_name[0] = 0;
charid = 0;
zone_waiting_for_bootup = 0;
+ enter_world_triggered = false;
StartInTutorial = false;
m_ClientVersion = eqs->ClientVersion();
@@ -115,7 +115,7 @@ Client::Client(EQStreamInterface* ieqs)
Client::~Client() {
if (RunLoops && cle && zone_id == 0)
- cle->SetOnline(CLE_Status_Offline);
+ cle->SetOnline(CLE_Status::Offline);
numclients--;
@@ -185,7 +185,7 @@ void Client::SendExpansionInfo() {
void Client::SendCharInfo() {
if (cle) {
- cle->SetOnline(CLE_Status_CharSelect);
+ cle->SetOnline(CLE_Status::CharSelect);
}
if (m_ClientVersionBit & EQEmu::versions::maskRoFAndLater) {
@@ -428,7 +428,7 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
// Track who is in and who is out of the game
char *inout= (char *) "";
- if (cle->GetOnline() == CLE_Status_Never) {
+ if (cle->GetOnline() == CLE_Status::Never){
// Desktop -> Char Select
inout = (char *) "In";
}
@@ -441,7 +441,7 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
// Either from a fresh client launch or coming back from the game.
// Exiting the game entirely does not come through here.
// Could use a Logging Out Completely message somewhere.
- cle->SetOnline(CLE_Status_CharSelect);
+ cle->SetOnline(CLE_Status::CharSelect);
Log(Logs::General, Logs::World_Server,
"Account (%s) Logging(%s) to character select :: LSID: %d ",
@@ -1038,7 +1038,7 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
{
// I don't see this getting executed on logout
eqs->Close();
- cle->SetOnline(CLE_Status_Offline); //allows this player to log in again without an ip restriction.
+ cle->SetOnline(CLE_Status::Offline); //allows this player to log in again without an ip restriction.
return false;
}
case OP_ZoneChange:
@@ -1081,15 +1081,15 @@ bool Client::Process() {
Log(Logs::General, Logs::World_Server, "Zone bootup timer expired, bootup failed or too slow.");
TellClientZoneUnavailable();
}
+
if(connect.Check()){
SendGuildList();// Send OPCode: OP_GuildsList
SendApproveWorld();
connect.Disable();
}
- if (CLE_keepalive_timer.Check()) {
- if (cle)
- cle->KeepAlive();
- }
+
+ if (cle)
+ cle->KeepAlive();
/************ Get all packets from packet manager out queue and process them ************/
EQApplicationPacket *app = 0;
@@ -1153,11 +1153,18 @@ void Client::EnterWorld(bool TryBootup) {
else
zone_server = zoneserver_list.FindByZoneID(zone_id);
-
const char *zone_name = database.GetZoneName(zone_id, true);
if (zone_server) {
- // warn the world we're comming, so it knows not to shutdown
- zone_server->IncomingClient(this);
+ if (false == enter_world_triggered) {
+ //Drop any clients we own in other zones.
+ zoneserver_list.DropClient(GetLSID(), zone_server);
+
+ // warn the zone we're coming
+ zone_server->IncomingClient(this);
+
+ //tell the server not to trigger this multiple times before we get a zone unavailable
+ enter_world_triggered = true;
+ }
}
else {
if (TryBootup) {
@@ -1176,9 +1183,17 @@ void Client::EnterWorld(bool TryBootup) {
return;
}
}
+
zone_waiting_for_bootup = 0;
- if(!cle) {
+ if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zone_id)) {
+ Log(Logs::General, Logs::World_Server, "Enter world failed. Zone is locked.");
+ TellClientZoneUnavailable();
+ return;
+ }
+
+ if (!cle) {
+ TellClientZoneUnavailable();
return;
}
@@ -1195,12 +1210,6 @@ void Client::EnterWorld(bool TryBootup) {
);
if (seen_character_select) {
- if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zone_id)) {
- Log(Logs::General, Logs::World_Server, "Enter world failed. Zone is locked.");
- TellClientZoneUnavailable();
- return;
- }
-
auto pack = new ServerPacket;
pack->opcode = ServerOP_AcceptWorldEntrance;
pack->size = sizeof(WorldToZone_Struct);
@@ -1306,7 +1315,7 @@ void Client::Clearance(int8 response)
safe_delete(outapp);
if (cle)
- cle->SetOnline(CLE_Status_Zoning);
+ cle->SetOnline(CLE_Status::Zoning);
}
void Client::TellClientZoneUnavailable() {
@@ -1320,6 +1329,7 @@ void Client::TellClientZoneUnavailable() {
zone_id = 0;
zone_waiting_for_bootup = 0;
+ enter_world_triggered = false;
autobootup_timeout.Disable();
}
diff --git a/world/client.h b/world/client.h
index d36dc692d..4dbad85c5 100644
--- a/world/client.h
+++ b/world/client.h
@@ -82,6 +82,7 @@ private:
bool is_player_zoning;
Timer autobootup_timeout;
uint32 zone_waiting_for_bootup;
+ bool enter_world_triggered;
bool StartInTutorial;
EQEmu::versions::ClientVersion m_ClientVersion;
@@ -94,7 +95,6 @@ private:
void SetClassLanguages(PlayerProfile_Struct *pp);
ClientListEntry* cle;
- Timer CLE_keepalive_timer;
Timer connect;
bool firstlogin;
bool seen_character_select;
diff --git a/world/cliententry.cpp b/world/cliententry.cpp
index 2ce17c53e..df245a930 100644
--- a/world/cliententry.cpp
+++ b/world/cliententry.cpp
@@ -83,8 +83,8 @@ ClientListEntry::ClientListEntry(
memset(pLFGComments, 0, 64);
}
-ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer *iZS, ServerClientList_Struct *scl, int8 iOnline)
- : id(in_id)
+ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, CLE_Status iOnline)
+: id(in_id)
{
ClearVars(true);
@@ -104,7 +104,7 @@ ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer *iZS, ServerClientList
pLFGMatchFilter = false;
memset(pLFGComments, 0, 64);
- if (iOnline >= CLE_Status_Zoning) {
+ if (iOnline >= CLE_Status::Zoning) {
Update(iZS, scl, iOnline);
}
else {
@@ -129,31 +129,39 @@ void ClientListEntry::SetChar(uint32 iCharID, const char *iCharName)
strn0cpy(pname, iCharName, sizeof(pname));
}
-void ClientListEntry::SetOnline(ZoneServer *iZS, int8 iOnline)
-{
+void ClientListEntry::SetOnline(ZoneServer* iZS, CLE_Status iOnline) {
if (iZS == this->Server()) {
SetOnline(iOnline);
}
}
-void ClientListEntry::SetOnline(int8 iOnline)
+void ClientListEntry::SetOnline(CLE_Status iOnline)
{
- if (iOnline >= CLE_Status_Online && pOnline < CLE_Status_Online) {
+ Log(Logs::General,
+ Logs::World_Server,
+ "ClientListEntry::SetOnline for %s(%i) = %i",
+ AccountName(),
+ AccountID(),
+ iOnline);
+
+ if (iOnline >= CLE_Status::Online && pOnline < CLE_Status::Online) {
numplayers++;
}
- else if (iOnline < CLE_Status_Online && pOnline >= CLE_Status_Online) {
+ else if (iOnline < CLE_Status::Online && pOnline >= CLE_Status::Online) {
numplayers--;
}
- if (iOnline != CLE_Status_Online || pOnline < CLE_Status_Online) {
+ if (iOnline != CLE_Status::Online || pOnline < CLE_Status::Online) {
pOnline = iOnline;
}
- if (iOnline < CLE_Status_Zoning) {
+ if (iOnline < CLE_Status::Zoning) {
Camp();
}
- if (pOnline >= CLE_Status_Online) {
+ if (pOnline >= CLE_Status::Online) {
stale = 0;
}
+
}
+
void ClientListEntry::LSUpdate(ZoneServer *iZS)
{
if (WorldConfig::get()->UpdateStats) {
@@ -184,8 +192,8 @@ void ClientListEntry::LSZoneChange(ZoneToZone_Struct *ztz)
safe_delete(pack);
}
}
-void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, int8 iOnline)
-{
+
+void ClientListEntry::Update(ZoneServer* iZS, ServerClientList_Struct* scl, CLE_Status iOnline) {
if (pzoneserver != iZS) {
if (pzoneserver) {
pzoneserver->RemovePlayer();
@@ -232,7 +240,7 @@ void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, int8
SetOnline(iOnline);
}
-void ClientListEntry::LeavingZone(ZoneServer *iZS, int8 iOnline)
+void ClientListEntry::LeavingZone(ZoneServer *iZS, CLE_Status iOnline)
{
if (iZS != 0 && iZS != pzoneserver) {
return;
@@ -250,8 +258,8 @@ void ClientListEntry::LeavingZone(ZoneServer *iZS, int8 iOnline)
void ClientListEntry::ClearVars(bool iAll)
{
if (iAll) {
- pOnline = CLE_Status_Never;
- stale = 0;
+ pOnline = CLE_Status::Never;
+ stale = 0;
pLSID = 0;
memset(loginserver_account_name, 0, sizeof(loginserver_account_name));
@@ -299,12 +307,10 @@ bool ClientListEntry::CheckStale()
{
stale++;
if (stale > 20) {
- if (pOnline > CLE_Status_Offline) {
- SetOnline(CLE_Status_Offline);
- }
- else {
- return true;
- }
+ if (pOnline > CLE_Status::Offline)
+ SetOnline(CLE_Status::Offline);
+
+ return true;
}
return false;
}
diff --git a/world/cliententry.h b/world/cliententry.h
index 30ba002d5..8cd21928c 100644
--- a/world/cliententry.h
+++ b/world/cliententry.h
@@ -8,13 +8,15 @@
#include "../common/rulesys.h"
#include
-
-#define CLE_Status_Never -1
-#define CLE_Status_Offline 0
-#define CLE_Status_Online 1 // Will not overwrite more specific online status
-#define CLE_Status_CharSelect 2
-#define CLE_Status_Zoning 3
-#define CLE_Status_InZone 4
+typedef enum
+{
+ Never,
+ Offline,
+ Online,
+ CharSelect,
+ Zoning,
+ InZone
+} CLE_Status;
class ZoneServer;
struct ServerClientList_Struct;
@@ -49,23 +51,26 @@ public:
* @param scl
* @param iOnline
*/
- ClientListEntry(uint32 id, ZoneServer *iZS, ServerClientList_Struct *scl, int8 iOnline);
+ ClientListEntry(uint32 id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin = 0);
+ ClientListEntry(uint32 id, ZoneServer* iZS, ServerClientList_Struct* scl, CLE_Status iOnline);
~ClientListEntry();
bool CheckStale();
- void Update(ZoneServer* zoneserver, ServerClientList_Struct* scl, int8 iOnline = CLE_Status_InZone);
+ void Update(ZoneServer* zoneserver, ServerClientList_Struct* scl, CLE_Status iOnline = CLE_Status::InZone);
void LSUpdate(ZoneServer* zoneserver);
void LSZoneChange(ZoneToZone_Struct* ztz);
bool CheckAuth(uint32 loginserver_account_id, const char* key_password);
- void SetOnline(ZoneServer* iZS, int8 iOnline);
- void SetOnline(int8 iOnline = CLE_Status_Online);
+ bool CheckAuth(const char* iName, MD5& iMD5Password);
+ bool CheckAuth(uint32 id, const char* key, uint32 ip);
+ void SetOnline(ZoneServer* iZS, CLE_Status iOnline);
+ void SetOnline(CLE_Status iOnline = CLE_Status::Online);
void SetChar(uint32 iCharID, const char* iCharName);
- inline int8 Online() { return pOnline; }
+ inline CLE_Status Online() { return pOnline; }
inline const uint32 GetID() const { return id; }
inline const uint32 GetIP() const { return pIP; }
inline void SetIP(const uint32& iIP) { pIP = iIP; }
inline void KeepAlive() { stale = 0; }
inline uint8 GetStaleCounter() const { return stale; }
- void LeavingZone(ZoneServer* iZS = 0, int8 iOnline = CLE_Status_Offline);
+ void LeavingZone(ZoneServer* iZS = 0, CLE_Status iOnline = CLE_Status::Offline);
void Camp(ZoneServer* iZS = 0);
// Login Server stuff
@@ -75,7 +80,7 @@ public:
inline const char* LSName() const { return loginserver_account_name; }
inline int16 WorldAdmin() const { return pworldadmin; }
inline const char* GetLSKey() const { return plskey; }
- inline const int8 GetOnline() const { return pOnline; }
+ inline const CLE_Status GetOnline() const { return pOnline; }
// Account stuff
inline uint32 AccountID() const { return paccountid; }
@@ -118,8 +123,8 @@ private:
const uint32 id;
uint32 pIP;
- int8 pOnline{};
- uint8 stale{};
+ CLE_Status pOnline;
+ uint8 stale;
// Login Server stuff
char source_loginserver[64]{}; //Loginserver we came from.
diff --git a/world/clientlist.cpp b/world/clientlist.cpp
index 2614d1d71..4ac74e3b3 100644
--- a/world/clientlist.cpp
+++ b/world/clientlist.cpp
@@ -41,7 +41,7 @@ extern ZSList zoneserver_list;
uint32 numplayers = 0; //this really wants to be a member variable of ClientList...
ClientList::ClientList()
-: CLStale_timer(45000)
+: CLStale_timer(10000)
{
NextCLEID = 1;
@@ -64,8 +64,6 @@ void ClientList::Process() {
struct in_addr in;
in.s_addr = iterator.GetData()->GetIP();
Log(Logs::Detail, Logs::World_Server,"Removing client from %s:%d", inet_ntoa(in), iterator.GetData()->GetPort());
-//the client destructor should take care of this.
-// iterator.GetData()->Free();
iterator.RemoveCurrent();
}
else
@@ -122,7 +120,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return;
} else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
- countCLEIPs->SetOnline(CLE_Status_Offline);
+ countCLEIPs->SetOnline(CLE_Status::Offline);
iterator.RemoveCurrent();
continue;
}
@@ -138,7 +136,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return;
} else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
- countCLEIPs->SetOnline(CLE_Status_Offline); // Remove the connection
+ countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection
iterator.RemoveCurrent();
continue;
}
@@ -150,7 +148,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return;
} else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
- countCLEIPs->SetOnline(CLE_Status_Offline); // Remove the connection
+ countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection
iterator.RemoveCurrent();
continue;
}
@@ -161,7 +159,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return;
} else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
- countCLEIPs->SetOnline(CLE_Status_Offline); // Remove the connection
+ countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection
iterator.RemoveCurrent();
continue;
}
@@ -182,7 +180,7 @@ uint32 ClientList::GetCLEIPCount(uint32 iIP) {
while (iterator.MoreElements()) {
countCLEIPs = iterator.GetData();
- if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) && countCLEIPs->Online() >= CLE_Status_Online) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
+ if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) && countCLEIPs->Online() >= CLE_Status::Online) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
IPInstances++; // Increment the occurences of this IP address
}
iterator.Advance();
@@ -208,7 +206,7 @@ void ClientList::DisconnectByIP(uint32 iIP) {
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
- countCLEIPs->SetOnline(CLE_Status_Offline);
+ countCLEIPs->SetOnline(CLE_Status::Offline);
iterator.RemoveCurrent();
}
iterator.Advance();
@@ -255,19 +253,6 @@ ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) {
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) {
LinkedListIterator iterator(clientlist);
char* output = 0;
@@ -343,10 +328,10 @@ void ClientList::ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* s
if (iterator.GetData()->GetID() == scl->wid) {
cle = iterator.GetData();
if (scl->remove == 2){
- cle->LeavingZone(zoneserver, CLE_Status_Offline);
+ cle->LeavingZone(zoneserver, CLE_Status::Offline);
}
else if (scl->remove == 1)
- cle->LeavingZone(zoneserver, CLE_Status_Zoning);
+ cle->LeavingZone(zoneserver, CLE_Status::Zoning);
else
cle->Update(zoneserver, scl);
return;
@@ -354,11 +339,11 @@ void ClientList::ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* s
iterator.Advance();
}
if (scl->remove == 2)
- cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status_Online);
+ cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::Online);
else if (scl->remove == 1)
- cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status_Zoning);
+ cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::Zoning);
else
- cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status_InZone);
+ cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::InZone);
clientlist.Insert(cle);
zoneserver->ChangeWID(scl->charid, cle->GetID());
}
@@ -504,7 +489,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
countcle = countclients.GetData();
const char* tmpZone = database.GetZoneName(countcle->zone());
if (
- (countcle->Online() >= CLE_Status_Zoning) &&
+ (countcle->Online() >= CLE_Status::Zoning) &&
(!countcle->GetGM() || countcle->Anon() != 1 || admin >= countcle->Admin()) &&
(whom == 0 || (
((countcle->Admin() >= 80 && countcle->GetGM()) || whom->gmlookup == 0xFFFF) &&
@@ -584,7 +569,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
const char* tmpZone = database.GetZoneName(cle->zone());
if (
- (cle->Online() >= CLE_Status_Zoning) &&
+ (cle->Online() >= CLE_Status::Zoning) &&
(!cle->GetGM() || cle->Anon() != 1 || admin >= cle->Admin()) &&
(whom == 0 || (
((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
@@ -757,7 +742,7 @@ void ClientList::SendFriendsWho(ServerFriendsWho_Struct *FriendsWho, WorldTCPCon
Friend_[Seperator - FriendsPointer] = 0;
ClientListEntry* CLE = FindCharacter(Friend_);
- if(CLE && CLE->name() && (CLE->Online() >= CLE_Status_Zoning) && !(CLE->GetGM() && CLE->Anon())) {
+ if(CLE && CLE->name() && (CLE->Online() >= CLE_Status::Zoning) && !(CLE->GetGM() && CLE->Anon())) {
FriendsCLEs.push_back(CLE);
TotalLength += strlen(CLE->name());
int GuildNameLength = strlen(guild_mgr.GetGuildName(CLE->GuildID()));
@@ -969,7 +954,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct*
cle = iterator.GetData();
const char* tmpZone = database.GetZoneName(cle->zone());
if (
- (cle->Online() >= CLE_Status_Zoning)
+ (cle->Online() >= CLE_Status::Zoning)
&& (whom == 0 || (
((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
(whom->lvllow == 0xFFFF || (cle->level() >= whom->lvllow && cle->level() <= whom->lvlhigh)) &&
@@ -1258,6 +1243,19 @@ void ClientList::RemoveCLEByLSID(uint32 iLSID)
}
}
+bool ClientList::IsAccountInGame(uint32 iLSID) {
+ LinkedListIterator iterator(clientlist);
+
+ while (iterator.MoreElements()) {
+ if (iterator.GetData()->LSID() == iLSID && iterator.GetData()->Online() == CLE_Status::InZone) {
+ return true;
+ }
+ iterator.Advance();
+ }
+
+ return false;
+}
+
int ClientList::GetClientCount() {
return(numplayers);
}
diff --git a/world/clientlist.h b/world/clientlist.h
index d8b542b02..16259e2e0 100644
--- a/world/clientlist.h
+++ b/world/clientlist.h
@@ -55,7 +55,6 @@ 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);
@@ -65,6 +64,7 @@ public:
void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0);
void UpdateClientGuild(uint32 char_id, uint32 guild_id);
void RemoveCLEByLSID(uint32 iLSID);
+ bool IsAccountInGame(uint32 iLSID);
int GetClientCount();
void GetClients(const char *zone_name, std::vector &into);
diff --git a/world/login_server.cpp b/world/login_server.cpp
index 78c736a0c..112a7c92f 100644
--- a/world/login_server.cpp
+++ b/world/login_server.cpp
@@ -108,19 +108,11 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
return;
}
- if (RuleB(World, DisallowDuplicateAccountLogins)) {
- auto cle = client_list.FindCLEByLSID(utwr->lsaccountid);
- if (cle != nullptr) {
- auto status = cle->GetOnline();
- if (CLE_Status_Zoning == status || CLE_Status_InZone == status) {
- utwrs->response = UserToWorldStatusAlreadyOnline;
- SendPacket(&outpack);
- return;
- }
- else {
- //our existing cle is in a state we can login to, mark the old as stale and remove it.
- client_list.RemoveCLEByLSID(utwr->lsaccountid);
- }
+ if (RuleB(World, EnforceCharacterLimitAtLogin)) {
+ if (client_list.IsAccountInGame(utwr->lsaccountid)) {
+ utwrs->response = UserToWorldStatusAlreadyOnline;
+ SendPacket(&outpack);
+ return;
}
}
diff --git a/world/zonelist.cpp b/world/zonelist.cpp
index 84cd87842..77782ee9b 100644
--- a/world/zonelist.cpp
+++ b/world/zonelist.cpp
@@ -708,6 +708,18 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval)
}
}
+void ZSList::DropClient(uint32 lsid, ZoneServer *ignore_zoneserver) {
+ ServerPacket packet(ServerOP_DropClient, sizeof(ServerZoneDropClient_Struct));
+ auto drop = (ServerZoneDropClient_Struct*)packet.pBuffer;
+ drop->lsid = lsid;
+
+ for (auto &zs : zone_server_list) {
+ if (zs.get() != ignore_zoneserver) {
+ zs->SendPacket(&packet);
+ }
+ }
+}
+
void ZSList::OnTick(EQ::Timer *t)
{
if (!EventSubscriptionWatcher::Get()->IsSubscribed("EQW::ZoneUpdate")) {
diff --git a/world/zonelist.h b/world/zonelist.h
index 947f75a2b..8b8525f57 100644
--- a/world/zonelist.h
+++ b/world/zonelist.h
@@ -57,6 +57,7 @@ public:
void SOPZoneBootup(const char *adminname, uint32 ZoneServerID, const char *zonename, bool iMakeStatic = false);
void UpdateUCSServerAvailable(bool ucss_available = true);
void WorldShutDown(uint32 time, uint32 interval);
+ void DropClient(uint32 lsid, ZoneServer *ignore_zoneserver);
ZoneServer* FindByPort(uint16 port);
ZoneServer* FindByID(uint32 ZoneID);
diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp
index 0d0ba2f5d..21c5d8e65 100644
--- a/world/zoneserver.cpp
+++ b/world/zoneserver.cpp
@@ -437,7 +437,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
- if (cle == 0 || cle->Online() < CLE_Status_Zoning ||
+ if (cle == 0 || cle->Online() < CLE_Status::Zoning ||
(cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from);
@@ -450,7 +450,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
sender->Server()->SendPacket(pack);
}
}
- else if (cle->Online() == CLE_Status_Zoning) {
+ else if (cle->Online() == CLE_Status::Zoning) {
if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from);
if (cle->TellQueueFull()) {
@@ -518,7 +518,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
ClientListEntry* cle = client_list.FindCharacter(svm->To);
- if (!cle || (cle->Online() < CLE_Status_Zoning) || !cle->Server()) {
+ if (!cle || (cle->Online() < CLE_Status::Zoning) || !cle->Server()) {
zoneserver_list.SendEmoteMessage(svm->From, 0, 0, 0, "'%s is not online at this time'", svm->To);
@@ -1457,6 +1457,7 @@ void ZoneServer::IncomingClient(Client* client) {
s->accid = client->GetAccountID();
s->admin = client->GetAdmin();
s->charid = client->GetCharID();
+ s->lsid = client->GetLSID();
if (client->GetCLE())
s->tellsoff = client->GetCLE()->TellsOff();
strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname));
diff --git a/zone/aa.cpp b/zone/aa.cpp
index 48ee715f7..4d9854d86 100644
--- a/zone/aa.cpp
+++ b/zone/aa.cpp
@@ -489,7 +489,7 @@ void Client::ResetAA() {
database.DeleteCharacterLeadershipAAs(CharacterID());
// undefined for these clients
if (ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier)
- Kick();
+ Kick("AA Reset on client that doesn't support it");
}
void Client::SendClearAA()
diff --git a/zone/client.cpp b/zone/client.cpp
index e90dafa8a..7e6baf180 100644
--- a/zone/client.cpp
+++ b/zone/client.cpp
@@ -136,6 +136,7 @@ Client::Client(EQStreamInterface* ieqs)
forget_timer(0),
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000),
+ client_zone_wide_full_position_update_timer(5 * 60 * 1000),
tribute_timer(Tribute_duration),
proximity_timer(ClientProximity_interval),
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
@@ -446,7 +447,7 @@ Client::~Client() {
numclients--;
UpdateWindowTitle();
if(zone)
- zone->RemoveAuth(GetName());
+ zone->RemoveAuth(GetName(), lskey);
//let the stream factory know were done with this stream
eqs->Close();
@@ -845,7 +846,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
{
if(AttemptedMessages > RuleI(Chat, MaxMessagesBeforeKick))
{
- Kick();
+ Kick("Sent too many chat messages at once.");
return;
}
if(GlobalChatLimiterTimer)
@@ -2586,13 +2587,19 @@ void Client::SetPVP(bool toggle, bool message) {
Save();
}
+void Client::Kick(const std::string &reason) {
+ client_state = CLIENT_KICKED;
+
+ Log(Logs::General, Logs::Client_Login, "Client [%s] kicked, reason [%s]", GetCleanName(), reason.c_str());
+}
+
void Client::WorldKick() {
auto outapp = new EQApplicationPacket(OP_GMKick, sizeof(GMKick_Struct));
GMKick_Struct* gmk = (GMKick_Struct *)outapp->pBuffer;
strcpy(gmk->name,GetName());
QueuePacket(outapp);
safe_delete(outapp);
- Kick();
+ Kick("World kick issued");
}
void Client::GMKill() {
@@ -9115,3 +9122,16 @@ bool Client::GotoPlayer(std::string player_name)
return false;
}
+
+glm::vec4 &Client::GetLastPositionBeforeBulkUpdate()
+{
+ return last_position_before_bulk_update;
+}
+
+/**
+ * @param in_last_position_before_bulk_update
+ */
+void Client::SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update)
+{
+ Client::last_position_before_bulk_update = in_last_position_before_bulk_update;
+}
\ No newline at end of file
diff --git a/zone/client.h b/zone/client.h
index c12302b03..1928ff99d 100644
--- a/zone/client.h
+++ b/zone/client.h
@@ -371,9 +371,9 @@ public:
inline bool ClientDataLoaded() const { return client_data_loaded; }
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); }
- inline void Kick() { client_state = CLIENT_KICKED; }
inline void Disconnect() { eqs->Close(); client_state = DISCONNECTED; }
inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); }
+ void Kick(const std::string &reason);
void WorldKick();
inline uint8 GetAnon() const { return m_pp.anon; }
inline PlayerProfile_Struct& GetPP() { return m_pp; }
@@ -1309,6 +1309,9 @@ public:
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
+ void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update);
+ glm::vec4 &GetLastPositionBeforeBulkUpdate();
+
protected:
friend class Mob;
void CalcItemBonuses(StatBonuses* newbon);
@@ -1518,6 +1521,7 @@ private:
Timer forget_timer; // our 2 min everybody forgets you timer
Timer autosave_timer;
Timer client_scan_npc_aggro_timer;
+ Timer client_zone_wide_full_position_update_timer;
Timer tribute_timer;
Timer proximity_timer;
@@ -1540,6 +1544,7 @@ private:
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
glm::vec3 m_Proximity;
+ glm::vec4 last_position_before_bulk_update;
void BulkSendInventoryItems();
diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp
index b1d4b14c5..38838d279 100644
--- a/zone/client_packet.cpp
+++ b/zone/client_packet.cpp
@@ -60,6 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "water_map.h"
#include "worldserver.h"
#include "zone.h"
+#include "mob_movement_manager.h"
#ifdef BOTS
#include "bot.h"
@@ -805,6 +806,8 @@ void Client::CompleteConnect()
parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0);
+ SetLastPositionBeforeBulkUpdate(GetPosition());
+
/* This sub event is for if a player logs in for the first time since entering world. */
if (firstlogon == 1) {
parse->EventPlayer(EVENT_CONNECT, this, "", 0);
@@ -1166,13 +1169,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
*/
Client* client = entity_list.GetClientByName(cze->char_name);
if (!zone->GetAuth(ip, cze->char_name, &WID, &account_id, &character_id, &admin, lskey, &tellsoff)) {
- Log(Logs::General, Logs::Error, "GetAuth() returned false kicking client");
- if (client != 0) {
+ Log(Logs::General, Logs::Client_Login, "%s failed zone auth check.", cze->char_name);
+ if (nullptr != client) {
client->Save();
- client->Kick();
+ client->Kick("Failed auth check");
}
- //ret = false; // TODO: Can we tell the client to get lost in a good way
- client_state = CLIENT_KICKED;
return;
}
@@ -1682,7 +1683,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/**
* DevTools Load Settings
*/
- if (Admin() >= 200) {
+ if (Admin() >= EQEmu::DevTools::GM_ACCOUNT_STATUS_LEVEL) {
std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", AccountID());
if (DataBucket::GetData(dev_tools_window_key) == "true") {
dev_tools_window_enabled = false;
@@ -4467,16 +4468,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
/* Handle client aggro scanning timers NPCs */
is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true;
-
+
if (is_client_moving) {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() > 1000) {
client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(500);
-
}
- } else {
+ }
+ else {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() < 1000) {
@@ -4484,7 +4485,51 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
client_scan_npc_aggro_timer.Start(3000);
}
}
-
+
+ /**
+ * On a normal basis we limit mob movement updates based on distance
+ * This ensures we send a periodic full zone update to a client that has started moving after 5 or so minutes
+ *
+ * For very large zones we will also force a full update based on distance
+ *
+ * We ignore a small distance around us so that we don't interrupt already pathing deltas as those npcs will appear
+ * to full stop when they are actually still pathing
+ */
+
+ float distance_moved = DistanceNoZ(GetLastPositionBeforeBulkUpdate(), GetPosition());
+ bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
+ bool is_ready_to_update = (
+ client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
+ );
+
+ if (is_client_moving && is_ready_to_update) {
+ Log(Logs::Detail, Logs::Normal, "[%s] Client Zone Wide Position Update NPCs", GetCleanName());
+
+ auto &mob_movement_manager = MobMovementManager::Get();
+ auto &mob_list = entity_list.GetMobList();
+
+ for (auto &it : mob_list) {
+ Mob *entity = it.second;
+ if (!entity->IsNPC()) {
+ continue;
+ }
+
+ int animation_speed = 0;
+ if (entity->IsMoving()) {
+ if (entity->IsRunning()) {
+ animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
+ }
+ else {
+ animation_speed = entity->GetWalkspeed();
+ }
+ }
+
+ mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
+ }
+
+ SetLastPositionBeforeBulkUpdate(GetPosition());
+ }
+
float new_heading = EQ12toFloat(ppu->heading);
int32 new_animation = ppu->animation;
@@ -9757,7 +9802,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
casting_spell_id);
database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
safe_delete_array(detect);
- Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots
+ Kick("Inventory desync"); // Kick client to prevent client and server from getting out-of-sync inventory slots
return;
}
}
@@ -9801,7 +9846,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
{
- Kick(); // TODO: lets not desync though
+ Kick("Unimplemented move multiple items"); // TODO: lets not desync though
}
void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)
diff --git a/zone/client_process.cpp b/zone/client_process.cpp
index 493864fea..87655e8bc 100644
--- a/zone/client_process.cpp
+++ b/zone/client_process.cpp
@@ -591,8 +591,8 @@ bool Client::Process() {
// only if client is not feigned
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
int npc_scan_count = 0;
- for (auto it = close_mobs.begin(); it != close_mobs.end(); ++it) {
- Mob *mob = it->first;
+ for (auto & close_mob : close_mobs) {
+ Mob *mob = close_mob.first;
if (!mob)
continue;
@@ -603,6 +603,7 @@ bool Client::Process() {
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
mob->AddToHateList(this, 25);
}
+
npc_scan_count++;
}
Log(Logs::General, Logs::Aggro, "Checking Reverse Aggro (client->npc) scanned_npcs (%i)", npc_scan_count);
diff --git a/zone/command.cpp b/zone/command.cpp
index 673935246..da9ef3bb5 100755
--- a/zone/command.cpp
+++ b/zone/command.cpp
@@ -1912,7 +1912,7 @@ void command_permaclass(Client *c, const Seperator *sep)
Log(Logs::General, Logs::Normal, "Class change request from %s for %s, requested class:%i", c->GetName(), t->GetName(), atoi(sep->arg[1]) );
t->SetBaseClass(atoi(sep->arg[1]));
t->Save();
- t->Kick();
+ t->Kick("Class was changed.");
}
}
@@ -3904,7 +3904,7 @@ void command_kick(Client *c, const Seperator *sep)
client->Message(0, "You have been kicked by %s", c->GetName());
auto outapp = new EQApplicationPacket(OP_GMKick, 0);
client->QueuePacket(outapp);
- client->Kick();
+ client->Kick("Ordered kicked by command");
c->Message(0, "Kick: local: kicking %s", sep->arg[1]);
}
}
@@ -4499,7 +4499,7 @@ void command_gmzone(Client *c, const Seperator *sep)
identifier = sep->arg[3];
}
- std::string bucket_key = StringFormat("%s-%s-instance", zone_short_name, identifier.c_str());
+ std::string bucket_key = StringFormat("%s-%s-%u-instance", zone_short_name, identifier.c_str(), zone_version);
std::string existing_zone_instance = DataBucket::GetData(bucket_key);
if (existing_zone_instance.length() > 0) {
@@ -5196,7 +5196,7 @@ void command_name(Client *c, const Seperator *sep)
c->Message(0, "Successfully renamed %s to %s", oldname, sep->arg[1]);
// until we get the name packet working right this will work
c->Message(0, "Sending player to char select.");
- target->Kick();
+ target->Kick("Name was changed");
}
else
c->Message(13, "ERROR: Unable to rename %s. Check that the new name '%s' isn't already taken.", oldname, sep->arg[2]);
diff --git a/zone/entity.cpp b/zone/entity.cpp
index f7fea532b..1c8de0780 100644
--- a/zone/entity.cpp
+++ b/zone/entity.cpp
@@ -1713,6 +1713,18 @@ Client *EntityList::GetClientByWID(uint32 iWID)
return nullptr;
}
+Client *EntityList::GetClientByLSID(uint32 iLSID)
+{
+ auto it = client_list.begin();
+ while (it != client_list.end()) {
+ if (it->second->LSAccountID() == iLSID) {
+ return it->second;
+ }
+ ++it;
+ }
+ return nullptr;
+}
+
Client *EntityList::GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient)
{
std::vector ClientsInRange;
diff --git a/zone/entity.h b/zone/entity.h
index c50575b5b..a02a8be2e 100644
--- a/zone/entity.h
+++ b/zone/entity.h
@@ -176,6 +176,7 @@ public:
}
Client *GetClientByCharID(uint32 iCharID);
Client *GetClientByWID(uint32 iWID);
+ Client *GetClientByLSID(uint32 iLSID);
Client *GetClient(uint32 ip, uint16 port);
Client *GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient = nullptr);
Group *GetGroupByMob(Mob* mob);
diff --git a/zone/inventory.cpp b/zone/inventory.cpp
index ec4f095b0..96f0fe15b 100644
--- a/zone/inventory.cpp
+++ b/zone/inventory.cpp
@@ -1608,7 +1608,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
banker ? banker->GetName() : "UNKNOWN NPC", distance);
database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName());
safe_delete_array(hacked_string);
- Kick(); // Kicking player to avoid item loss do to client and server inventories not being sync'd
+ Kick("Inventory desync"); // Kicking player to avoid item loss do to client and server inventories not being sync'd
return false;
}
}
@@ -1822,7 +1822,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Step 4: Check for entity trade
if (dst_slot_id >= EQEmu::invslot::TRADE_BEGIN && dst_slot_id <= EQEmu::invslot::TRADE_END) {
if (src_slot_id != EQEmu::invslot::slotCursor) {
- Kick();
+ Kick("Trade with non-cursor item");
return false;
}
if (with) {
diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp
index 9447c48af..c50f6b2f3 100644
--- a/zone/lua_client.cpp
+++ b/zone/lua_client.cpp
@@ -47,7 +47,7 @@ bool Lua_Client::InZone() {
void Lua_Client::Kick() {
Lua_Safe_Call_Void();
- self->Kick();
+ self->Kick("Lua Quest");
}
void Lua_Client::Disconnect() {
diff --git a/zone/mob.cpp b/zone/mob.cpp
index ca844d459..3a307bf3f 100644
--- a/zone/mob.cpp
+++ b/zone/mob.cpp
@@ -1128,7 +1128,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
UpdateActiveLight();
ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive];
- ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
+ if (IsNPC() && race == ERUDITE)
+ ns->spawn.showhelm = 1;
+ else
+ ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
ns->spawn.NPC = IsClient() ? 0 : 1;
diff --git a/zone/mob_movement_manager.cpp b/zone/mob_movement_manager.cpp
index 1fcc19187..4bf1663d3 100644
--- a/zone/mob_movement_manager.cpp
+++ b/zone/mob_movement_manager.cpp
@@ -14,40 +14,41 @@
#include
extern double frame_time;
-extern Zone *zone;
+extern Zone *zone;
-class IMovementCommand
-{
+class IMovementCommand {
public:
IMovementCommand() = default;
virtual ~IMovementCommand() = default;
- virtual bool Process(MobMovementManager *mgr, Mob *m) = 0;
+ virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob) = 0;
virtual bool Started() const = 0;
};
-class RotateToCommand : public IMovementCommand
-{
+class RotateToCommand : public IMovementCommand {
public:
- RotateToCommand(double rotate_to, double dir, MobMovementMode mode) {
- m_rotate_to = rotate_to;
- m_rotate_to_dir = dir;
- m_rotate_to_mode = mode;
- m_started = false;
+ RotateToCommand(double rotate_to, double dir, MobMovementMode mob_movement_mode)
+ {
+ m_rotate_to = rotate_to;
+ m_rotate_to_dir = dir;
+ m_rotate_to_mode = mob_movement_mode;
+ m_started = false;
}
- virtual ~RotateToCommand() {
+ virtual ~RotateToCommand()
+ {
}
- virtual bool Process(MobMovementManager *mgr, Mob *m) {
- if (!m->IsAIControlled()) {
+ virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
+ {
+ if (!mob->IsAIControlled()) {
return true;
}
- auto rotate_to_speed = m_rotate_to_mode == MovementRunning ? 200.0 : 16.0; //todo: get this from mob
+ auto rotate_to_speed = m_rotate_to_mode == MovementRunning ? 200.0 : 16.0; //todo: get this from mob
- auto from = FixHeading(m->GetHeading());
- auto to = FixHeading(m_rotate_to);
+ auto from = FixHeading(mob->GetHeading());
+ auto to = FixHeading(m_rotate_to);
auto diff = to - from;
while (diff < -256.0) {
@@ -62,265 +63,282 @@ public:
if (!m_started) {
m_started = true;
- m->SetMoving(true);
-
+ mob->SetMoving(true);
+
if (dist > 15.0f && rotate_to_speed > 0.0 && rotate_to_speed <= 25.0) { //send basic rotation
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, m_rotate_to_dir * rotate_to_speed, 0, ClientRangeClose);
+ mob_movement_manager->SendCommandToClients(
+ mob,
+ 0.0,
+ 0.0,
+ 0.0,
+ m_rotate_to_dir * rotate_to_speed,
+ 0,
+ ClientRangeClose
+ );
}
}
-
+
auto td = rotate_to_speed * 19.0 * frame_time;
-
+
if (td >= dist) {
- m->SetHeading(to);
- m->SetMoving(false);
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
+ mob->SetHeading(to);
+ mob->SetMoving(false);
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
return true;
}
-
+
from += td * m_rotate_to_dir;
- m->SetHeading(FixHeading(from));
+ mob->SetHeading(FixHeading(from));
return false;
}
- virtual bool Started() const {
+ virtual bool Started() const
+ {
return m_started;
}
private:
- double m_rotate_to;
- double m_rotate_to_dir;
+ double m_rotate_to;
+ double m_rotate_to_dir;
MobMovementMode m_rotate_to_mode;
- bool m_started;
+ bool m_started;
};
-class MoveToCommand : public IMovementCommand
-{
+class MoveToCommand : public IMovementCommand {
public:
- MoveToCommand(float x, float y, float z, MobMovementMode mode) {
+ MoveToCommand(float x, float y, float z, MobMovementMode mob_movement_mode)
+ {
m_distance_moved_since_correction = 0.0;
- m_move_to_x = x;
- m_move_to_y = y;
- m_move_to_z = z;
- m_move_to_mode = mode;
- m_last_sent_time = 0.0;
- m_last_sent_speed = 0;
- m_started = false;
- m_total_h_dist = 0.0;
- m_total_v_dist = 0.0;
+ m_move_to_x = x;
+ m_move_to_y = y;
+ m_move_to_z = z;
+ m_move_to_mode = mob_movement_mode;
+ m_last_sent_time = 0.0;
+ m_last_sent_speed = 0;
+ m_started = false;
+ m_total_h_dist = 0.0;
+ m_total_v_dist = 0.0;
}
- virtual ~MoveToCommand() {
+ virtual ~MoveToCommand()
+ {
}
- virtual bool Process(MobMovementManager *mgr, Mob *m) {
- if (!m->IsAIControlled()) {
+ /**
+ * @param mob_movement_manager
+ * @param mob
+ * @return
+ */
+ virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
+ {
+ if (!mob->IsAIControlled()) {
return true;
}
//Send a movement packet when you start moving
- double current_time = static_cast(Timer::GetCurrentTime()) / 1000.0;
- int current_speed = 0;
+ double current_time = static_cast(Timer::GetCurrentTime()) / 1000.0;
+ int current_speed = 0;
if (m_move_to_mode == MovementRunning) {
- if (m->IsFeared()) {
- current_speed = m->GetFearSpeed();
+ if (mob->IsFeared()) {
+ current_speed = mob->GetFearSpeed();
}
else {
- current_speed = m->GetRunspeed();
+ current_speed = mob->GetRunspeed();
}
}
else {
- current_speed = m->GetWalkspeed();
+ current_speed = mob->GetWalkspeed();
}
if (!m_started) {
m_started = true;
//rotate to the point
- m->SetMoving(true);
- m->SetHeading(m->CalculateHeadingToTarget(m_move_to_x, m_move_to_y));
+ mob->SetMoving(true);
+ mob->SetHeading(mob->CalculateHeadingToTarget(m_move_to_x, m_move_to_y));
m_last_sent_speed = current_speed;
- m_last_sent_time = current_time;
- m_total_h_dist = DistanceNoZ(m->GetPosition(), glm::vec4(m_move_to_x, m_move_to_y, 0.0f, 0.0f));
- m_total_v_dist = m_move_to_z - m->GetZ();
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
+ m_last_sent_time = current_time;
+ m_total_h_dist = DistanceNoZ(mob->GetPosition(), glm::vec4(m_move_to_x, m_move_to_y, 0.0f, 0.0f));
+ m_total_v_dist = m_move_to_z - mob->GetZ();
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
}
//When speed changes
if (current_speed != m_last_sent_speed) {
if (RuleB(Map, FixZWhenPathing)) {
- m->FixZ();
+ mob->FixZ();
}
m_distance_moved_since_correction = 0.0;
m_last_sent_speed = current_speed;
- m_last_sent_time = current_time;
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
+ m_last_sent_time = current_time;
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
}
//If x seconds have passed without sending an update.
if (current_time - m_last_sent_time >= 5.0) {
if (RuleB(Map, FixZWhenPathing)) {
- m->FixZ();
+ mob->FixZ();
}
m_distance_moved_since_correction = 0.0;
m_last_sent_speed = current_speed;
- m_last_sent_time = current_time;
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
+ m_last_sent_time = current_time;
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
}
- auto &p = m->GetPosition();
+ auto &p = mob->GetPosition();
glm::vec2 tar(m_move_to_x, m_move_to_y);
glm::vec2 pos(p.x, p.y);
- double len = glm::distance(pos, tar);
+ double len = glm::distance(pos, tar);
if (len == 0) {
return true;
}
- m->SetMoved(true);
+ mob->SetMoved(true);
- glm::vec2 dir = tar - pos;
- glm::vec2 ndir = glm::normalize(dir);
- double distance_moved = frame_time * current_speed * 0.4f * 1.45f;
+ glm::vec2 dir = tar - pos;
+ glm::vec2 ndir = glm::normalize(dir);
+ double distance_moved = frame_time * current_speed * 0.4f * 1.45f;
- if (distance_moved > len) {
- if (m->IsNPC()) {
- entity_list.ProcessMove(m->CastToNPC(), m_move_to_x, m_move_to_y, m_move_to_z);
+ if (distance_moved > len) {
+ if (mob->IsNPC()) {
+ entity_list.ProcessMove(mob->CastToNPC(), m_move_to_x, m_move_to_y, m_move_to_z);
}
- m->SetPosition(m_move_to_x, m_move_to_y, m_move_to_z);
-
+ mob->SetPosition(m_move_to_x, m_move_to_y, m_move_to_z);
+
if (RuleB(Map, FixZWhenPathing)) {
- m->FixZ();
+ mob->FixZ();
}
return true;
}
else {
glm::vec2 npos = pos + (ndir * static_cast(distance_moved));
-
+
len -= distance_moved;
double total_distance_traveled = m_total_h_dist - len;
- double start_z = m_move_to_z - m_total_v_dist;
- double z_at_pos = start_z + (m_total_v_dist * (total_distance_traveled / m_total_h_dist));
+ double start_z = m_move_to_z - m_total_v_dist;
+ double z_at_pos = start_z + (m_total_v_dist * (total_distance_traveled / m_total_h_dist));
- if (m->IsNPC()) {
- entity_list.ProcessMove(m->CastToNPC(), npos.x, npos.y, z_at_pos);
+ if (mob->IsNPC()) {
+ entity_list.ProcessMove(mob->CastToNPC(), npos.x, npos.y, z_at_pos);
}
- m->SetPosition(npos.x, npos.y, z_at_pos);
+ mob->SetPosition(npos.x, npos.y, z_at_pos);
if (RuleB(Map, FixZWhenPathing)) {
m_distance_moved_since_correction += distance_moved;
if (m_distance_moved_since_correction > RuleR(Map, DistanceCanTravelBeforeAdjustment)) {
m_distance_moved_since_correction = 0.0;
- m->FixZ();
+ mob->FixZ();
}
}
}
-
+
return false;
}
- virtual bool Started() const {
+ virtual bool Started() const
+ {
return m_started;
}
protected:
- double m_distance_moved_since_correction;
- double m_move_to_x;
- double m_move_to_y;
- double m_move_to_z;
+ double m_distance_moved_since_correction;
+ double m_move_to_x;
+ double m_move_to_y;
+ double m_move_to_z;
MobMovementMode m_move_to_mode;
- bool m_started;
+ bool m_started;
double m_last_sent_time;
- int m_last_sent_speed;
+ int m_last_sent_speed;
double m_total_h_dist;
double m_total_v_dist;
};
-class SwimToCommand : public MoveToCommand
-{
+class SwimToCommand : public MoveToCommand {
public:
- SwimToCommand(float x, float y, float z, MobMovementMode mode) : MoveToCommand(x, y, z, mode) {
+ SwimToCommand(float x, float y, float z, MobMovementMode mob_movement_mode) : MoveToCommand(x, y, z, mob_movement_mode)
+ {
}
- virtual bool Process(MobMovementManager *mgr, Mob *m)
+ virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
{
- if (!m->IsAIControlled()) {
+ if (!mob->IsAIControlled()) {
return true;
}
- //Send a movement packet when you start moving
- double current_time = static_cast(Timer::GetCurrentTime()) / 1000.0;
- int current_speed = 0;
+ //Send a movement packet when you start moving
+ double current_time = static_cast(Timer::GetCurrentTime()) / 1000.0;
+ int current_speed = 0;
if (m_move_to_mode == MovementRunning) {
- if (m->IsFeared()) {
- current_speed = m->GetFearSpeed();
+ if (mob->IsFeared()) {
+ current_speed = mob->GetFearSpeed();
}
else {
- current_speed = m->GetRunspeed();
+ current_speed = mob->GetRunspeed();
}
}
else {
- current_speed = m->GetWalkspeed();
+ current_speed = mob->GetWalkspeed();
}
if (!m_started) {
m_started = true;
//rotate to the point
- m->SetMoving(true);
- m->SetHeading(m->CalculateHeadingToTarget(m_move_to_x, m_move_to_y));
+ mob->SetMoving(true);
+ mob->SetHeading(mob->CalculateHeadingToTarget(m_move_to_x, m_move_to_y));
m_last_sent_speed = current_speed;
- m_last_sent_time = current_time;
- m_total_h_dist = DistanceNoZ(m->GetPosition(), glm::vec4(m_move_to_x, m_move_to_y, 0.0f, 0.0f));
- m_total_v_dist = m_move_to_z - m->GetZ();
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
+ m_last_sent_time = current_time;
+ m_total_h_dist = DistanceNoZ(mob->GetPosition(), glm::vec4(m_move_to_x, m_move_to_y, 0.0f, 0.0f));
+ m_total_v_dist = m_move_to_z - mob->GetZ();
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
}
//When speed changes
if (current_speed != m_last_sent_speed) {
m_last_sent_speed = current_speed;
- m_last_sent_time = current_time;
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
+ m_last_sent_time = current_time;
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
}
//If x seconds have passed without sending an update.
if (current_time - m_last_sent_time >= 1.5) {
m_last_sent_speed = current_speed;
- m_last_sent_time = current_time;
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
+ m_last_sent_time = current_time;
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
}
- auto &p = m->GetPosition();
+ auto &p = mob->GetPosition();
glm::vec2 tar(m_move_to_x, m_move_to_y);
glm::vec2 pos(p.x, p.y);
- double len = glm::distance(pos, tar);
+ double len = glm::distance(pos, tar);
if (len == 0) {
return true;
}
- m->SetMoved(true);
+ mob->SetMoved(true);
- glm::vec2 dir = tar - pos;
- glm::vec2 ndir = glm::normalize(dir);
- double distance_moved = frame_time * current_speed * 0.4f * 1.45f;
+ glm::vec2 dir = tar - pos;
+ glm::vec2 ndir = glm::normalize(dir);
+ double distance_moved = frame_time * current_speed * 0.4f * 1.45f;
if (distance_moved > len) {
- if (m->IsNPC()) {
- entity_list.ProcessMove(m->CastToNPC(), m_move_to_x, m_move_to_y, m_move_to_z);
+ if (mob->IsNPC()) {
+ entity_list.ProcessMove(mob->CastToNPC(), m_move_to_x, m_move_to_y, m_move_to_z);
}
- m->SetPosition(m_move_to_x, m_move_to_y, m_move_to_z);
+ mob->SetPosition(m_move_to_x, m_move_to_y, m_move_to_z);
return true;
}
else {
@@ -328,51 +346,54 @@ public:
len -= distance_moved;
double total_distance_traveled = m_total_h_dist - len;
- double start_z = m_move_to_z - m_total_v_dist;
- double z_at_pos = start_z + (m_total_v_dist * (total_distance_traveled / m_total_h_dist));
+ double start_z = m_move_to_z - m_total_v_dist;
+ double z_at_pos = start_z + (m_total_v_dist * (total_distance_traveled / m_total_h_dist));
- if (m->IsNPC()) {
- entity_list.ProcessMove(m->CastToNPC(), npos.x, npos.y, z_at_pos);
+ if (mob->IsNPC()) {
+ entity_list.ProcessMove(mob->CastToNPC(), npos.x, npos.y, z_at_pos);
}
- m->SetPosition(npos.x, npos.y, z_at_pos);
+ mob->SetPosition(npos.x, npos.y, z_at_pos);
}
return false;
}
};
-class TeleportToCommand : public IMovementCommand
-{
+class TeleportToCommand : public IMovementCommand {
public:
- TeleportToCommand(float x, float y, float z, float heading) {
- m_teleport_to_x = x;
- m_teleport_to_y = y;
- m_teleport_to_z = z;
+ TeleportToCommand(float x, float y, float z, float heading)
+ {
+ m_teleport_to_x = x;
+ m_teleport_to_y = y;
+ m_teleport_to_z = z;
m_teleport_to_heading = heading;
}
- virtual ~TeleportToCommand() {
+ virtual ~TeleportToCommand()
+ {
}
- virtual bool Process(MobMovementManager *mgr, Mob *m) {
- if (!m->IsAIControlled()) {
+ virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
+ {
+ if (!mob->IsAIControlled()) {
return true;
}
- if (m->IsNPC()) {
- entity_list.ProcessMove(m->CastToNPC(), m_teleport_to_x, m_teleport_to_y, m_teleport_to_z);
+ if (mob->IsNPC()) {
+ entity_list.ProcessMove(mob->CastToNPC(), m_teleport_to_x, m_teleport_to_y, m_teleport_to_z);
}
- m->SetPosition(m_teleport_to_x, m_teleport_to_y, m_teleport_to_z);
- m->SetHeading(mgr->FixHeading(m_teleport_to_heading));
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
+ mob->SetPosition(m_teleport_to_x, m_teleport_to_y, m_teleport_to_z);
+ mob->SetHeading(mob_movement_manager->FixHeading(m_teleport_to_heading));
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
return true;
}
- virtual bool Started() const {
+ virtual bool Started() const
+ {
return false;
}
@@ -384,93 +405,99 @@ private:
double m_teleport_to_heading;
};
-class StopMovingCommand : public IMovementCommand
-{
+class StopMovingCommand : public IMovementCommand {
public:
- StopMovingCommand() {
+ StopMovingCommand()
+ {
}
- virtual ~StopMovingCommand() {
+ virtual ~StopMovingCommand()
+ {
}
- virtual bool Process(MobMovementManager *mgr, Mob *m) {
- if (!m->IsAIControlled()) {
+ virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
+ {
+ if (!mob->IsAIControlled()) {
return true;
}
- if (m->IsMoving()) {
- m->SetMoving(false);
+ if (mob->IsMoving()) {
+ mob->SetMoving(false);
if (RuleB(Map, FixZWhenPathing)) {
- m->FixZ();
+ mob->FixZ();
}
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
}
return true;
}
- virtual bool Started() const {
+ virtual bool Started() const
+ {
return false;
}
};
-class EvadeCombatCommand : public IMovementCommand
-{
+class EvadeCombatCommand : public IMovementCommand {
public:
- EvadeCombatCommand() {
+ EvadeCombatCommand()
+ {
}
- virtual ~EvadeCombatCommand() {
+ virtual ~EvadeCombatCommand()
+ {
}
- virtual bool Process(MobMovementManager *mgr, Mob *m) {
- if (!m->IsAIControlled()) {
+ virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
+ {
+ if (!mob->IsAIControlled()) {
return true;
}
- if (m->IsMoving()) {
- m->SetMoving(false);
- mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
+ if (mob->IsMoving()) {
+ mob->SetMoving(false);
+ mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
}
- m->BuffFadeAll();
- m->WipeHateList();
- m->Heal();
+ mob->BuffFadeAll();
+ mob->WipeHateList();
+ mob->Heal();
return true;
}
- virtual bool Started() const {
+ virtual bool Started() const
+ {
return false;
}
};
-struct MovementStats
-{
- MovementStats() {
- LastResetTime = static_cast(Timer::GetCurrentTime()) / 1000.0;
- TotalSent = 0ULL;
+struct MovementStats {
+ MovementStats()
+ {
+ LastResetTime = static_cast(Timer::GetCurrentTime()) / 1000.0;
+ TotalSent = 0ULL;
TotalSentMovement = 0ULL;
TotalSentPosition = 0ULL;
- TotalSentHeading = 0ULL;
+ TotalSentHeading = 0ULL;
}
- double LastResetTime;
+ double LastResetTime;
uint64_t TotalSent;
uint64_t TotalSentMovement;
uint64_t TotalSentPosition;
uint64_t TotalSentHeading;
};
-struct NavigateTo
-{
- NavigateTo() {
- navigate_to_x = 0.0;
- navigate_to_y = 0.0;
- navigate_to_z = 0.0;
+struct NavigateTo {
+ NavigateTo()
+ {
+ navigate_to_x = 0.0;
+ navigate_to_y = 0.0;
+ navigate_to_z = 0.0;
navigate_to_heading = 0.0;
- last_set_time = 0.0;
+ last_set_time = 0.0;
}
double navigate_to_x;
@@ -480,13 +507,13 @@ struct NavigateTo
double last_set_time;
};
-struct MobMovementEntry
-{
+struct MobMovementEntry {
std::deque> Commands;
- NavigateTo NavTo;
+ NavigateTo NavTo;
};
-void AdjustRoute(std::list &nodes, Mob *who) {
+void AdjustRoute(std::list &nodes, Mob *who)
+{
if (!zone->HasMap() || !zone->HasWaterMap()) {
return;
}
@@ -494,7 +521,7 @@ void AdjustRoute(std::list &nodes, Mob *who) {
auto offset = who->GetZOffset();
for (auto &node : nodes) {
- if(!zone->watermap->InLiquid(node.pos)) {
+ if (!zone->watermap->InLiquid(node.pos)) {
auto best_z = zone->zonemap->FindBestZ(node.pos, nullptr);
if (best_z != BEST_Z_INVALID) {
node.pos.z = best_z + offset;
@@ -503,11 +530,10 @@ void AdjustRoute(std::list &nodes, Mob *who) {
}
}
-struct MobMovementManager::Implementation
-{
- std::map Entries;
- std::vector Clients;
- MovementStats Stats;
+struct MobMovementManager::Implementation {
+ std::map Entries;
+ std::vector Clients;
+ MovementStats Stats;
};
MobMovementManager::MobMovementManager()
@@ -522,12 +548,12 @@ MobMovementManager::~MobMovementManager()
void MobMovementManager::Process()
{
for (auto &iter : _impl->Entries) {
- auto &ent = iter.second;
+ auto &ent = iter.second;
auto &commands = ent.Commands;
while (true != commands.empty()) {
auto &cmd = commands.front();
- auto r = cmd->Process(this, iter.first);
+ auto r = cmd->Process(this, iter.first);
if (true != r) {
break;
@@ -538,35 +564,52 @@ void MobMovementManager::Process()
}
}
-void MobMovementManager::AddMob(Mob *m)
+/**
+ * @param mob
+ */
+void MobMovementManager::AddMob(Mob *mob)
{
- _impl->Entries.insert(std::make_pair(m, MobMovementEntry()));
+ _impl->Entries.insert(std::make_pair(mob, MobMovementEntry()));
}
-void MobMovementManager::RemoveMob(Mob *m)
+/**
+ * @param mob
+ */
+void MobMovementManager::RemoveMob(Mob *mob)
{
- _impl->Entries.erase(m);
+ _impl->Entries.erase(mob);
}
-void MobMovementManager::AddClient(Client *c)
+/**
+ * @param client
+ */
+void MobMovementManager::AddClient(Client *client)
{
- _impl->Clients.push_back(c);
+ _impl->Clients.push_back(client);
}
-void MobMovementManager::RemoveClient(Client *c)
+/**
+ * @param client
+ */
+void MobMovementManager::RemoveClient(Client *client)
{
auto iter = _impl->Clients.begin();
while (iter != _impl->Clients.end()) {
- if (c == *iter) {
+ if (client == *iter) {
_impl->Clients.erase(iter);
return;
}
-
+
++iter;
}
}
-void MobMovementManager::RotateTo(Mob *who, float to, MobMovementMode mode)
+/**
+ * @param who
+ * @param to
+ * @param mob_movement_mode
+ */
+void MobMovementManager::RotateTo(Mob *who, float to, MobMovementMode mob_movement_mode)
{
auto iter = _impl->Entries.find(who);
auto &ent = (*iter);
@@ -574,20 +617,34 @@ void MobMovementManager::RotateTo(Mob *who, float to, MobMovementMode mode)
if (true != ent.second.Commands.empty()) {
return;
}
-
- PushRotateTo(ent.second, who, to, mode);
+
+ PushRotateTo(ent.second, who, to, mob_movement_mode);
}
+/**
+ * @param who
+ * @param x
+ * @param y
+ * @param z
+ * @param heading
+ */
void MobMovementManager::Teleport(Mob *who, float x, float y, float z, float heading)
{
auto iter = _impl->Entries.find(who);
auto &ent = (*iter);
-
+
ent.second.Commands.clear();
PushTeleportTo(ent.second, x, y, z, heading);
}
+/**
+ * @param who
+ * @param x
+ * @param y
+ * @param z
+ * @param mode
+ */
void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode)
{
if (IsPositionEqualWithinCertainZ(glm::vec3(x, y, z), glm::vec3(who->GetX(), who->GetY(), who->GetZ()), 6.0f)) {
@@ -601,8 +658,13 @@ void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, MobMove
double current_time = static_cast(Timer::GetCurrentTime()) / 1000.0;
if ((current_time - nav.last_set_time) > 0.5) {
//Can potentially recalc
-
- auto within = IsPositionWithinSimpleCylinder(glm::vec3(x, y, z), glm::vec3(nav.navigate_to_x, nav.navigate_to_y, nav.navigate_to_z), 1.5f, 6.0f);
+
+ auto within = IsPositionWithinSimpleCylinder(
+ glm::vec3(x, y, z),
+ glm::vec3(nav.navigate_to_x, nav.navigate_to_y, nav.navigate_to_z),
+ 1.5f,
+ 6.0f
+ );
auto heading_match = IsHeadingEqual(0.0, nav.navigate_to_heading);
if (false == within || false == heading_match || ent.second.Commands.size() == 0) {
@@ -610,23 +672,27 @@ void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, MobMove
//Path is no longer valid, calculate a new path
UpdatePath(who, x, y, z, mode);
- nav.navigate_to_x = x;
- nav.navigate_to_y = y;
- nav.navigate_to_z = z;
+ nav.navigate_to_x = x;
+ nav.navigate_to_y = y;
+ nav.navigate_to_z = z;
nav.navigate_to_heading = 0.0;
- nav.last_set_time = current_time;
+ nav.last_set_time = current_time;
}
}
}
-void MobMovementManager::StopNavigation(Mob *who) {
+/**
+ * @param who
+ */
+void MobMovementManager::StopNavigation(Mob *who)
+{
auto iter = _impl->Entries.find(who);
auto &ent = (*iter);
auto &nav = ent.second.NavTo;
- nav.navigate_to_x = 0.0;
- nav.navigate_to_y = 0.0;
- nav.navigate_to_z = 0.0;
+ nav.navigate_to_x = 0.0;
+ nav.navigate_to_y = 0.0;
+ nav.navigate_to_z = 0.0;
nav.navigate_to_heading = 0.0;
if (true == ent.second.Commands.empty()) {
@@ -643,24 +709,48 @@ void MobMovementManager::StopNavigation(Mob *who) {
PushStopMoving(ent.second);
}
-void MobMovementManager::SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range)
+/**
+ * @param mob
+ * @param delta_x
+ * @param delta_y
+ * @param delta_z
+ * @param delta_heading
+ * @param anim
+ * @param range
+ * @param single_client
+ */
+void MobMovementManager::SendCommandToClients(
+ Mob *mob,
+ float delta_x,
+ float delta_y,
+ float delta_z,
+ float delta_heading,
+ int anim,
+ ClientRange range,
+ Client* single_client
+)
{
if (range == ClientRangeNone) {
return;
}
EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
- PlayerPositionUpdateServer_Struct *spu = (PlayerPositionUpdateServer_Struct*)outapp.pBuffer;
- FillCommandStruct(spu, m, dx, dy, dz, dh, anim);
+ auto *spu = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer;
+
+ FillCommandStruct(spu, mob, delta_x, delta_y, delta_z, delta_heading, anim);
if (range == ClientRangeAny) {
for (auto &c : _impl->Clients) {
+ if (single_client && c != single_client) {
+ continue;
+ }
+
_impl->Stats.TotalSent++;
if (anim != 0) {
_impl->Stats.TotalSentMovement++;
}
- else if (dh != 0) {
+ else if (delta_heading != 0) {
_impl->Stats.TotalSentHeading++;
}
else {
@@ -672,26 +762,30 @@ void MobMovementManager::SendCommandToClients(Mob *m, float dx, float dy, float
}
else {
float short_range = RuleR(Pathing, ShortMovementUpdateRange);
- float long_range = zone->GetMaxMovementUpdateRange();
+ float long_range = zone->GetNpcPositionUpdateDistance();
for (auto &c : _impl->Clients) {
- float dist = c->CalculateDistance(m->GetX(), m->GetY(), m->GetZ());
+ if (single_client && c != single_client) {
+ continue;
+ }
+
+ float distance = c->CalculateDistance(mob->GetX(), mob->GetY(), mob->GetZ());
bool match = false;
if (range & ClientRangeClose) {
- if (dist < short_range) {
+ if (distance < short_range) {
match = true;
}
}
if (!match && range & ClientRangeMedium) {
- if (dist >= short_range && dist < long_range) {
+ if (distance >= short_range && distance < long_range) {
match = true;
}
}
if (!match && range & ClientRangeLong) {
- if (dist >= long_range) {
+ if (distance >= long_range) {
match = true;
}
}
@@ -702,7 +796,7 @@ void MobMovementManager::SendCommandToClients(Mob *m, float dx, float dy, float
if (anim != 0) {
_impl->Stats.TotalSentMovement++;
}
- else if (dh != 0) {
+ else if (delta_heading != 0) {
_impl->Stats.TotalSentHeading++;
}
else {
@@ -715,6 +809,10 @@ void MobMovementManager::SendCommandToClients(Mob *m, float dx, float dy, float
}
}
+/**
+ * @param in
+ * @return
+ */
float MobMovementManager::FixHeading(float in)
{
auto h = in;
@@ -729,83 +827,139 @@ float MobMovementManager::FixHeading(float in)
return h;
}
-void MobMovementManager::DumpStats(Client *to)
+/**
+ * @param client
+ */
+void MobMovementManager::DumpStats(Client *client)
{
auto current_time = static_cast(Timer::GetCurrentTime()) / 1000.0;
- auto total_time = current_time - _impl->Stats.LastResetTime;
+ auto total_time = current_time - _impl->Stats.LastResetTime;
- to->Message(MT_System, "Dumping Movement Stats:");
- to->Message(MT_System, "Total Sent: %u (%.2f / sec)", _impl->Stats.TotalSent, static_cast(_impl->Stats.TotalSent) / total_time);
- to->Message(MT_System, "Total Heading: %u (%.2f / sec)", _impl->Stats.TotalSentHeading, static_cast(_impl->Stats.TotalSentHeading) / total_time);
- to->Message(MT_System, "Total Movement: %u (%.2f / sec)", _impl->Stats.TotalSentMovement, static_cast(_impl->Stats.TotalSentMovement) / total_time);
- to->Message(MT_System, "Total Position: %u (%.2f / sec)", _impl->Stats.TotalSentPosition, static_cast(_impl->Stats.TotalSentPosition) / total_time);
+ client->Message(MT_System, "Dumping Movement Stats:");
+ client->Message(
+ MT_System,
+ "Total Sent: %u (%.2f / sec)",
+ _impl->Stats.TotalSent,
+ static_cast(_impl->Stats.TotalSent) / total_time
+ );
+ client->Message(
+ MT_System,
+ "Total Heading: %u (%.2f / sec)",
+ _impl->Stats.TotalSentHeading,
+ static_cast(_impl->Stats.TotalSentHeading) / total_time
+ );
+ client->Message(
+ MT_System,
+ "Total Movement: %u (%.2f / sec)",
+ _impl->Stats.TotalSentMovement,
+ static_cast(_impl->Stats.TotalSentMovement) / total_time
+ );
+ client->Message(
+ MT_System,
+ "Total Position: %u (%.2f / sec)",
+ _impl->Stats.TotalSentPosition,
+ static_cast(_impl->Stats.TotalSentPosition) / total_time
+ );
}
void MobMovementManager::ClearStats()
{
- _impl->Stats.LastResetTime = static_cast(Timer::GetCurrentTime()) / 1000.0;
- _impl->Stats.TotalSent = 0;
- _impl->Stats.TotalSentHeading = 0;
+ _impl->Stats.LastResetTime = static_cast(Timer::GetCurrentTime()) / 1000.0;
+ _impl->Stats.TotalSent = 0;
+ _impl->Stats.TotalSentHeading = 0;
_impl->Stats.TotalSentMovement = 0;
_impl->Stats.TotalSentPosition = 0;
}
-void MobMovementManager::FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim)
+/**
+ * @param position_update
+ * @param mob
+ * @param delta_x
+ * @param delta_y
+ * @param delta_z
+ * @param delta_heading
+ * @param anim
+ */
+void MobMovementManager::FillCommandStruct(
+ PlayerPositionUpdateServer_Struct *position_update,
+ Mob *mob,
+ float delta_x,
+ float delta_y,
+ float delta_z,
+ float delta_heading,
+ int anim
+)
{
- memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
- spu->spawn_id = m->GetID();
- spu->x_pos = FloatToEQ19(m->GetX());
- spu->y_pos = FloatToEQ19(m->GetY());
- spu->z_pos = FloatToEQ19(m->GetZ());
- spu->heading = FloatToEQ12(m->GetHeading());
- spu->delta_x = FloatToEQ13(dx);
- spu->delta_y = FloatToEQ13(dy);
- spu->delta_z = FloatToEQ13(dz);
- spu->delta_heading = FloatToEQ10(dh);
- spu->animation = (m->IsBot() ? (int)((float)anim / 1.785714f) : anim);
+ memset(position_update, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
+ position_update->spawn_id = mob->GetID();
+ position_update->x_pos = FloatToEQ19(mob->GetX());
+ position_update->y_pos = FloatToEQ19(mob->GetY());
+ position_update->z_pos = FloatToEQ19(mob->GetZ());
+ position_update->heading = FloatToEQ12(mob->GetHeading());
+ position_update->delta_x = FloatToEQ13(delta_x);
+ position_update->delta_y = FloatToEQ13(delta_y);
+ position_update->delta_z = FloatToEQ13(delta_z);
+ position_update->delta_heading = FloatToEQ10(delta_heading);
+ position_update->animation = (mob->IsBot() ? (int) ((float) anim / 1.785714f) : anim);
}
-void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode)
+/**
+ * @param who
+ * @param x
+ * @param y
+ * @param z
+ * @param mob_movement_mode
+ */
+void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode)
{
if (!zone->HasMap() || !zone->HasWaterMap()) {
auto iter = _impl->Entries.find(who);
auto &ent = (*iter);
-
- PushMoveTo(ent.second, x, y, z, mode);
+
+ PushMoveTo(ent.second, x, y, z, mob_movement_mode);
PushStopMoving(ent.second);
return;
}
-
+
if (who->IsBoat()) {
- UpdatePathBoat(who, x, y, z, mode);
- } else if (who->IsUnderwaterOnly()) {
- UpdatePathUnderwater(who, x, y, z, mode);
+ UpdatePathBoat(who, x, y, z, mob_movement_mode);
+ }
+ else if (who->IsUnderwaterOnly()) {
+ UpdatePathUnderwater(who, x, y, z, mob_movement_mode);
}
else {
- UpdatePathGround(who, x, y, z, mode);
+ UpdatePathGround(who, x, y, z, mob_movement_mode);
}
}
-void MobMovementManager::UpdatePathGround(Mob * who, float x, float y, float z, MobMovementMode mode)
+/**
+ * @param who
+ * @param x
+ * @param y
+ * @param z
+ * @param mode
+ */
+void MobMovementManager::UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode)
{
PathfinderOptions opts;
opts.smooth_path = true;
- opts.step_size = RuleR(Pathing, NavmeshStepSize);
- opts.offset = who->GetZOffset();
- opts.flags = PathingNotDisabled ^ PathingZoneLine;
+ opts.step_size = RuleR(Pathing, NavmeshStepSize);
+ opts.offset = who->GetZOffset();
+ opts.flags = PathingNotDisabled ^ PathingZoneLine;
//This is probably pointless since the nav mesh tool currently sets zonelines to disabled anyway
auto partial = false;
- auto stuck = false;
- auto route = zone->pathing->FindPath(
+ auto stuck = false;
+ auto route = zone->pathing->FindPath(
glm::vec3(who->GetX(), who->GetY(), who->GetZ()),
glm::vec3(x, y, z),
partial,
stuck,
- opts);
+ opts
+ );
auto eiter = _impl->Entries.find(who);
- auto &ent = (*eiter);
+ auto &ent = (*eiter);
if (route.size() == 0) {
HandleStuckBehavior(who, x, y, z, mode);
@@ -813,31 +967,26 @@ 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)
- {
+ 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
+ //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();
+ auto routeNode = route.begin();
bool noValidPath = true;
while (routeNode != route.end() && noValidPath == true) {
auto ¤tNode = (*routeNode);
- if (routeNode == route.end())
- {
+ if (routeNode == route.end()) {
continue;
}
- if (!(currentNode.pos.x == who->GetX() && currentNode.pos.y == who->GetY()))
- {
+ 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;
@@ -847,47 +996,62 @@ void MobMovementManager::UpdatePathGround(Mob * who, float x, float y, float z,
}
- if (noValidPath)
- {
+ 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));
+ 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);
-
+
iter++;
-
+
if (iter == route.end()) {
continue;
}
-
+
previous_pos = current_node.pos;
auto &next_node = (*iter);
-
+
if (first_node) {
-
+
if (mode == MovementWalking) {
auto h = who->CalculateHeadingToTarget(next_node.pos.x, next_node.pos.y);
PushRotateTo(ent.second, who, h, mode);
}
-
+
first_node = false;
}
-
+
//move to / teleport to node + 1
if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) {
- PushTeleportTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z,
- CalculateHeadingAngleBetweenPositions(current_node.pos.x, current_node.pos.y, next_node.pos.x, next_node.pos.y));
+ PushTeleportTo(
+ ent.second,
+ next_node.pos.x,
+ next_node.pos.y,
+ next_node.pos.z,
+ CalculateHeadingAngleBetweenPositions(
+ current_node.pos.x,
+ current_node.pos.y,
+ next_node.pos.x,
+ next_node.pos.y
+ )
+ );
}
else {
if (zone->watermap->InLiquid(previous_pos)) {
@@ -907,41 +1071,50 @@ void MobMovementManager::UpdatePathGround(Mob * who, float x, float y, float z,
}
}
-void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode mode)
+/**
+ * @param who
+ * @param x
+ * @param y
+ * @param z
+ * @param movement_mode
+ */
+void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode movement_mode)
{
auto eiter = _impl->Entries.find(who);
- auto &ent = (*eiter);
- if (zone->watermap->InLiquid(who->GetPosition()) && zone->watermap->InLiquid(glm::vec3(x, y, z)) && zone->zonemap->CheckLoS(who->GetPosition(), glm::vec3(x, y, z))) {
- PushSwimTo(ent.second, x, y, z, mode);
+ auto &ent = (*eiter);
+ if (zone->watermap->InLiquid(who->GetPosition()) && zone->watermap->InLiquid(glm::vec3(x, y, z)) &&
+ zone->zonemap->CheckLoS(who->GetPosition(), glm::vec3(x, y, z))) {
+ PushSwimTo(ent.second, x, y, z, movement_mode);
PushStopMoving(ent.second);
return;
}
PathfinderOptions opts;
opts.smooth_path = true;
- opts.step_size = RuleR(Pathing, NavmeshStepSize);
- opts.offset = who->GetZOffset();
- opts.flags = PathingNotDisabled ^ PathingZoneLine;
+ opts.step_size = RuleR(Pathing, NavmeshStepSize);
+ opts.offset = who->GetZOffset();
+ opts.flags = PathingNotDisabled ^ PathingZoneLine;
auto partial = false;
- auto stuck = false;
- auto route = zone->pathing->FindPath(
+ auto stuck = false;
+ auto route = zone->pathing->FindPath(
glm::vec3(who->GetX(), who->GetY(), who->GetZ()),
glm::vec3(x, y, z),
partial,
stuck,
- opts);
+ opts
+ );
if (route.size() == 0) {
- HandleStuckBehavior(who, x, y, z, mode);
+ HandleStuckBehavior(who, x, y, z, movement_mode);
return;
}
AdjustRoute(route, who);
- auto iter = route.begin();
+ auto iter = route.begin();
glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ());
- bool first_node = true;
+ bool first_node = true;
while (iter != route.end()) {
auto ¤t_node = (*iter);
@@ -961,7 +1134,7 @@ void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float
}
if (route.size() == 0) {
- HandleStuckBehavior(who, x, y, z, mode);
+ HandleStuckBehavior(who, x, y, z, movement_mode);
return;
}
@@ -981,9 +1154,9 @@ void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float
if (first_node) {
- if (mode == MovementWalking) {
+ if (movement_mode == MovementWalking) {
auto h = who->CalculateHeadingToTarget(next_node.pos.x, next_node.pos.y);
- PushRotateTo(ent.second, who, h, mode);
+ PushRotateTo(ent.second, who, h, movement_mode);
}
first_node = false;
@@ -991,47 +1164,87 @@ void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float
//move to / teleport to node + 1
if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) {
- PushTeleportTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z,
- CalculateHeadingAngleBetweenPositions(current_node.pos.x, current_node.pos.y, next_node.pos.x, next_node.pos.y));
+ PushTeleportTo(
+ ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z,
+ CalculateHeadingAngleBetweenPositions(
+ current_node.pos.x,
+ current_node.pos.y,
+ next_node.pos.x,
+ next_node.pos.y
+ ));
}
else {
- PushSwimTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, mode);
+ PushSwimTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, movement_mode);
}
}
if (stuck) {
- HandleStuckBehavior(who, x, y, z, mode);
+ HandleStuckBehavior(who, x, y, z, movement_mode);
}
else {
PushStopMoving(ent.second);
}
}
+/**
+ * @param who
+ * @param x
+ * @param y
+ * @param z
+ * @param mode
+ */
void MobMovementManager::UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode)
{
auto eiter = _impl->Entries.find(who);
- auto &ent = (*eiter);
+ auto &ent = (*eiter);
PushSwimTo(ent.second, x, y, z, mode);
PushStopMoving(ent.second);
}
+/**
+ * @param ent
+ * @param x
+ * @param y
+ * @param z
+ * @param heading
+ */
void MobMovementManager::PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading)
{
ent.Commands.push_back(std::unique_ptr(new TeleportToCommand(x, y, z, heading)));
}
-void MobMovementManager::PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode)
+/**
+ * @param ent
+ * @param x
+ * @param y
+ * @param z
+ * @param mob_movement_mode
+ */
+void MobMovementManager::PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
{
- ent.Commands.push_back(std::unique_ptr(new MoveToCommand(x, y, z, mode)));
+ ent.Commands.push_back(std::unique_ptr(new MoveToCommand(x, y, z, mob_movement_mode)));
}
-void MobMovementManager::PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode)
+/**
+ * @param ent
+ * @param x
+ * @param y
+ * @param z
+ * @param mob_movement_mode
+ */
+void MobMovementManager::PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
{
- ent.Commands.push_back(std::unique_ptr(new SwimToCommand(x, y, z, mode)));
+ ent.Commands.push_back(std::unique_ptr(new SwimToCommand(x, y, z, mob_movement_mode)));
}
-void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode)
+/**
+ * @param ent
+ * @param who
+ * @param to
+ * @param mob_movement_mode
+ */
+void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode)
{
auto from = FixHeading(who->GetHeading());
to = FixHeading(to);
@@ -1050,46 +1263,59 @@ void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to,
diff -= 512.0;
}
- ent.Commands.push_back(std::unique_ptr(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mode)));
+ ent.Commands.push_back(std::unique_ptr(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mob_movement_mode)));
}
-void MobMovementManager::PushStopMoving(MobMovementEntry &ent)
+/**
+ * @param mob_movement_entry
+ */
+void MobMovementManager::PushStopMoving(MobMovementEntry &mob_movement_entry)
{
- ent.Commands.push_back(std::unique_ptr(new StopMovingCommand()));
+ mob_movement_entry.Commands.push_back(std::unique_ptr(new StopMovingCommand()));
}
-void MobMovementManager::PushEvadeCombat(MobMovementEntry &ent)
+/**
+ * @param mob_movement_entry
+ */
+void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry)
{
- ent.Commands.push_back(std::unique_ptr(new EvadeCombatCommand()));
+ mob_movement_entry.Commands.push_back(std::unique_ptr(new EvadeCombatCommand()));
}
-void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mode)
+/**
+ * @param who
+ * @param x
+ * @param y
+ * @param z
+ * @param mob_movement_mode
+ */
+void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode)
{
- auto sb = who->GetStuckBehavior();
+ auto sb = who->GetStuckBehavior();
MobStuckBehavior behavior = RunToTarget;
if (sb >= 0 && sb < MaxStuckBehavior) {
- behavior = (MobStuckBehavior)sb;
+ behavior = (MobStuckBehavior) sb;
}
auto eiter = _impl->Entries.find(who);
- auto &ent = (*eiter);
+ auto &ent = (*eiter);
switch (sb) {
- case RunToTarget:
- PushMoveTo(ent.second, x, y, z, mode);
- PushStopMoving(ent.second);
- break;
- case WarpToTarget:
- PushTeleportTo(ent.second, x, y, z, 0.0f);
- PushStopMoving(ent.second);
- break;
- case TakeNoAction:
- PushStopMoving(ent.second);
- break;
- case EvadeCombat:
- //PushEvadeCombat(ent.second);
- PushStopMoving(ent.second);
- break;
+ case RunToTarget:
+ PushMoveTo(ent.second, x, y, z, mob_movement_mode);
+ PushStopMoving(ent.second);
+ break;
+ case WarpToTarget:
+ PushTeleportTo(ent.second, x, y, z, 0.0f);
+ PushStopMoving(ent.second);
+ break;
+ case TakeNoAction:
+ PushStopMoving(ent.second);
+ break;
+ case EvadeCombat:
+ //PushEvadeCombat(ent.second);
+ PushStopMoving(ent.second);
+ break;
}
}
diff --git a/zone/mob_movement_manager.h b/zone/mob_movement_manager.h
index d9b2e7845..3c616cc5a 100644
--- a/zone/mob_movement_manager.h
+++ b/zone/mob_movement_manager.h
@@ -41,18 +41,29 @@ class MobMovementManager
public:
~MobMovementManager();
void Process();
- void AddMob(Mob *m);
- void RemoveMob(Mob *m);
- void AddClient(Client *c);
- void RemoveClient(Client *c);
+ void AddMob(Mob *mob);
+ void RemoveMob(Mob *mob);
+ void AddClient(Client *client);
+ void RemoveClient(Client *client);
- void RotateTo(Mob *who, float to, MobMovementMode mode = MovementRunning);
+ void RotateTo(Mob *who, float to, MobMovementMode mob_movement_mode = MovementRunning);
void Teleport(Mob *who, float x, float y, float z, float heading);
void NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning);
void StopNavigation(Mob *who);
- void SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range);
+
+ void SendCommandToClients(
+ Mob *mob,
+ float delta_x,
+ float delta_y,
+ float delta_z,
+ float delta_heading,
+ int anim,
+ ClientRange range,
+ Client* single_client = nullptr
+ );
+
float FixHeading(float in);
- void DumpStats(Client *to);
+ void DumpStats(Client *client);
void ClearStats();
static MobMovementManager &Get() {
@@ -65,18 +76,18 @@ private:
MobMovementManager(const MobMovementManager&);
MobMovementManager& operator=(const MobMovementManager&);
- void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim);
- void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode);
+ void FillCommandStruct(PlayerPositionUpdateServer_Struct *position_update, Mob *mob, float delta_x, float delta_y, float delta_z, float delta_heading, int anim);
+ void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode);
void UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode);
- void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode mode);
+ void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode movement_mode);
void UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode);
void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading);
- void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
- void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
- void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode);
- void PushStopMoving(MobMovementEntry &ent);
- void PushEvadeCombat(MobMovementEntry &ent);
- void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mode);
+ void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
+ void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
+ void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode);
+ void PushStopMoving(MobMovementEntry &mob_movement_entry);
+ void PushEvadeCombat(MobMovementEntry &mob_movement_entry);
+ void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode);
struct Implementation;
std::unique_ptr _impl;
diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp
index be1bf2a8e..f86228feb 100644
--- a/zone/perl_client.cpp
+++ b/zone/perl_client.cpp
@@ -174,7 +174,7 @@ XS(XS_Client_Kick) {
if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
- THIS->Kick();
+ THIS->Kick("Perl Quest");
}
XSRETURN_EMPTY;
}
diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp
index 79f5af8a5..dafc3f1e6 100644
--- a/zone/questmgr.cpp
+++ b/zone/questmgr.cpp
@@ -809,7 +809,7 @@ void QuestManager::changedeity(int diety_id) {
initiator->SetDeity(diety_id);
initiator->Message(15,"Your Deity has been changed/set to: %i", diety_id);
initiator->Save(1);
- initiator->Kick();
+ initiator->Kick("Deity change by QuestManager");
}
else
{
@@ -943,7 +943,7 @@ void QuestManager::permaclass(int class_id) {
//Makes the client the class specified
initiator->SetBaseClass(class_id);
initiator->Save(2);
- initiator->Kick();
+ initiator->Kick("Base class change by QuestManager");
}
void QuestManager::permarace(int race_id) {
@@ -951,7 +951,7 @@ void QuestManager::permarace(int race_id) {
//Makes the client the race specified
initiator->SetBaseRace(race_id);
initiator->Save(2);
- initiator->Kick();
+ initiator->Kick("Base race change by QuestManager");
}
void QuestManager::permagender(int gender_id) {
@@ -959,7 +959,7 @@ void QuestManager::permagender(int gender_id) {
//Makes the client the gender specified
initiator->SetBaseGender(gender_id);
initiator->Save(2);
- initiator->Kick();
+ initiator->Kick("Base gender change by QuestManager");
}
uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
diff --git a/zone/spells.cpp b/zone/spells.cpp
index 8b1a08d19..fa09727a2 100644
--- a/zone/spells.cpp
+++ b/zone/spells.cpp
@@ -298,7 +298,8 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
if(IsClient()) {
char temp[64];
sprintf(temp, "%d", spell_id);
- parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), temp, 0);
+ if (parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), temp, 0) != 0)
+ return false;
} else if(IsNPC()) {
char temp[64];
sprintf(temp, "%d", spell_id);
diff --git a/zone/trading.cpp b/zone/trading.cpp
index 154fdf148..fe9a72daa 100644
--- a/zone/trading.cpp
+++ b/zone/trading.cpp
@@ -112,7 +112,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
// (it just didn't handle partial stack move actions)
if (stack_size > 0) {
if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) {
- client->Kick();
+ client->Kick("Error stacking item in trade");
return;
}
@@ -138,7 +138,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
}
else {
if (inst2 && inst2->GetID()) {
- client->Kick();
+ client->Kick("Attempting to add null item to trade");
return;
}
diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp
index 94be0eb14..ffe777808 100644
--- a/zone/worldserver.cpp
+++ b/zone/worldserver.cpp
@@ -534,7 +534,15 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*)pack->pBuffer;
if (is_zone_loaded) {
SetZoneData(zone->GetZoneID(), zone->GetInstanceID());
+
if (szic->zoneid == zone->GetZoneID()) {
+ auto client = entity_list.GetClientByLSID(szic->lsid);
+ if (client) {
+ client->Kick("Dropped by world CLE subsystem");
+ client->Save();
+ }
+
+ zone->RemoveAuth(szic->lsid);
zone->AddAuth(szic);
// This packet also doubles as "incoming client" notification, lets not shut down before they get here
zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000);
@@ -547,6 +555,23 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
break;
}
+ case ServerOP_DropClient: {
+ if (pack->size != sizeof(ServerZoneDropClient_Struct)) {
+ break;
+ }
+
+ ServerZoneDropClient_Struct* drop = (ServerZoneDropClient_Struct*)pack->pBuffer;
+ if (zone) {
+ zone->RemoveAuth(drop->lsid);
+
+ auto client = entity_list.GetClientByLSID(drop->lsid);
+ if (client) {
+ client->Kick("Dropped by world CLE subsystem");
+ client->Save();
+ }
+ }
+ break;
+ }
case ServerOP_ZonePlayer: {
ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(szp->name);
diff --git a/zone/zone.cpp b/zone/zone.cpp
index 88b0253a2..d20b2934e 100755
--- a/zone/zone.cpp
+++ b/zone/zone.cpp
@@ -55,6 +55,7 @@
#include "zone_config.h"
#include "mob_movement_manager.h"
#include "npc_scale_manager.h"
+#include "../common/data_verification.h"
#include
#include
@@ -864,6 +865,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
m_last_ucss_update = 0;
mMovementManager = &MobMovementManager::Get();
+
+ SetNpcPositionUpdateDistance(0);
}
Zone::~Zone() {
@@ -1106,6 +1109,7 @@ void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) {
zca->accid = szic->accid;
zca->admin = szic->admin;
zca->charid = szic->charid;
+ zca->lsid = szic->lsid;
zca->tellsoff = szic->tellsoff;
strn0cpy(zca->charname, szic->charname, sizeof(zca->charname));
strn0cpy(zca->lskey, szic->lskey, sizeof(zca->lskey));
@@ -1113,16 +1117,31 @@ void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) {
client_auth_list.Insert(zca);
}
-void Zone::RemoveAuth(const char* iCharName)
+void Zone::RemoveAuth(const char* iCharName, const char* iLSKey)
{
LinkedListIterator iterator(client_auth_list);
iterator.Reset();
while (iterator.MoreElements()) {
ZoneClientAuth_Struct* zca = iterator.GetData();
- if (strcasecmp(zca->charname, iCharName) == 0) {
- iterator.RemoveCurrent();
- return;
+ if (strcasecmp(zca->charname, iCharName) == 0 && strcasecmp(zca->lskey, iLSKey) == 0) {
+ iterator.RemoveCurrent();
+ return;
+ }
+ iterator.Advance();
+ }
+}
+
+void Zone::RemoveAuth(uint32 lsid)
+{
+ LinkedListIterator iterator(client_auth_list);
+
+ iterator.Reset();
+ while (iterator.MoreElements()) {
+ ZoneClientAuth_Struct* zca = iterator.GetData();
+ if (zca->lsid == lsid) {
+ iterator.RemoveCurrent();
+ continue;
}
iterator.Advance();
}
@@ -1178,9 +1197,9 @@ uint32 Zone::CountAuth() {
bool Zone::Process() {
spawn_conditions.Process();
- if(spawn2_timer.Check()) {
+ if (spawn2_timer.Check()) {
- LinkedListIterator iterator(spawn2_list);
+ LinkedListIterator iterator(spawn2_list);
EQEmu::InventoryProfile::CleanDirty();
@@ -1196,10 +1215,15 @@ bool Zone::Process() {
}
}
- if(adv_data && !did_adventure_actions)
+ if (adv_data && !did_adventure_actions) {
DoAdventureActions();
+ }
+ if (GetNpcPositionUpdateDistance() == 0) {
+ CalculateNpcUpdateDistanceSpread();
+ }
}
+
if(initgrids_timer.Check()) {
//delayed grid loading stuff.
initgrids_timer.Disable();
@@ -2349,3 +2373,59 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
if (m_last_ucss_update < update_timestamp)
m_ucss_available = ucss_available;
}
+
+int Zone::GetNpcPositionUpdateDistance() const
+{
+ return npc_position_update_distance;
+}
+
+void Zone::SetNpcPositionUpdateDistance(int in_npc_position_update_distance)
+{
+ Zone::npc_position_update_distance = in_npc_position_update_distance;
+}
+
+void Zone::CalculateNpcUpdateDistanceSpread()
+{
+ float max_x = 0;
+ float max_y = 0;
+ float min_x = 0;
+ float min_y = 0;
+
+ auto &mob_list = entity_list.GetMobList();
+
+ for (auto &it : mob_list) {
+ Mob *entity = it.second;
+ if (!entity->IsNPC()) {
+ continue;
+ }
+
+ if (entity->GetX() <= min_x) {
+ min_x = entity->GetX();
+ }
+
+ if (entity->GetY() <= min_y) {
+ min_y = entity->GetY();
+ }
+
+ if (entity->GetX() >= max_x) {
+ max_x = entity->GetX();
+ }
+
+ if (entity->GetY() >= max_y) {
+ max_y = entity->GetY();
+ }
+ }
+
+ int x_spread = int(abs(max_x - min_x));
+ int y_spread = int(abs(max_y - min_y));
+ int combined_spread = int(abs((x_spread + y_spread) / 2));
+ int update_distance = EQEmu::ClampLower(int(combined_spread / 4), int(zone->GetMaxMovementUpdateRange()));
+
+ SetNpcPositionUpdateDistance(update_distance);
+
+ Log(Logs::General, Logs::Debug,
+ "NPC update spread distance set to [%i] combined_spread [%i]",
+ update_distance,
+ combined_spread
+ );
+}
\ No newline at end of file
diff --git a/zone/zone.h b/zone/zone.h
index e86fdc339..176fe0cb3 100755
--- a/zone/zone.h
+++ b/zone/zone.h
@@ -52,6 +52,7 @@ struct ZoneClientAuth_Struct {
uint32 accid;
int16 admin;
uint32 charid;
+ uint32 lsid;
bool tellsoff;
char charname[64];
char lskey[30];
@@ -125,6 +126,9 @@ public:
bool Process();
bool SaveZoneCFG();
+ int GetNpcPositionUpdateDistance() const;
+ void SetNpcPositionUpdateDistance(int in_npc_position_update_distance);
+
char *adv_data;
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
@@ -218,6 +222,7 @@ public:
void ChangeWeather();
void ClearBlockedSpells();
void ClearNPCTypeCache(int id);
+ void CalculateNpcUpdateDistanceSpread();
void DelAggroMob() { aggroedmobs--; }
void DeleteQGlobal(std::string name, uint32 npcID, uint32 charID, uint32 zoneID);
void Despawn(uint32 spawngroupID);
@@ -243,7 +248,8 @@ public:
void LoadZoneDoors(const char *zone, int16 version);
void ReloadStaticData();
void ReloadWorld(uint32 Option);
- void RemoveAuth(const char *iCharName);
+ void RemoveAuth(const char *iCharName, const char *iLSKey);
+ void RemoveAuth(uint32 lsid);
void Repop(uint32 delay = 0);
void RepopClose(const glm::vec4 &client_position, uint32 repop_distance);
void RequestUCSServerStatus();
@@ -288,7 +294,7 @@ public:
*/
find_replace(message, std::string("%"), std::string("."));
- if (message.find("\n") != std::string::npos) {
+ if (message.find('\n') != std::string::npos) {
auto message_split = SplitString(message, '\n');
entity_list.MessageStatus(
0,
@@ -343,6 +349,7 @@ private:
glm::vec4 m_Graveyard;
int default_ruleset;
int totalBS;
+ int npc_position_update_distance;
int32 aggroedmobs;
uint8 zone_type;
uint16 instanceversion;