Merge branches 'lsid' and 'master' of https://github.com/EQEmu/Server into lsid

This commit is contained in:
Akkadius 2019-08-10 03:26:40 -05:00
commit eaf31fb14b
46 changed files with 1857 additions and 558 deletions

View File

@ -18,6 +18,8 @@
#EQEMU_BUILD_CLIENT_FILES #EQEMU_BUILD_CLIENT_FILES
#EQEMU_USE_MAP_MMFS #EQEMU_USE_MAP_MMFS
#EQEMU_MAP_DIR #EQEMU_MAP_DIR
#EQEMU_ARCH
#EQEMU_ARCH_ALT
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
IF(POLICY CMP0074) IF(POLICY CMP0074)
@ -49,33 +51,37 @@ ENDIF(MSVC OR MINGW)
IF(MSVC) IF(MSVC)
IF(CMAKE_CL_64) IF(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64") SET(EQEMU_ARCH "x64")
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64") SET(EQEMU_ARCH_ALT "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()
ELSE(CMAKE_CL_64) ELSE(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86") SET(EQEMU_ARCH "x86")
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86") SET(EQEMU_ARCH_ALT "Win32")
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()
ENDIF(CMAKE_CL_64) 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 #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) OPTION(EQEMU_DISABLE_CRT_SECURE_WARNINGS "Disable Secure CRT Warnings" ON)
IF(EQEMU_DISABLE_CRT_SECURE_WARNINGS) IF(EQEMU_DISABLE_CRT_SECURE_WARNINGS)
@ -243,6 +249,8 @@ IF(ZLIB_FOUND)
SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY}) SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY})
ENDIF() ENDIF()
ELSE() 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") INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic") SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic")
ENDIF() ENDIF()

View File

@ -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) * GPL Perl - GPL / ActiveState (under the assumption that this is a free project)
* CPPUnit - GLP StringUtilities - Apache * CPPUnit - GLP StringUtilities - Apache
* LUA - MIT * LUA - MIT
## Contributors
<a href="https://github.com/EQEmu/server/graphs/contributors">
<img src="https://contributors-img.firebaseapp.com/image?repo=EQEmu/server" />
</a>

View File

@ -1,5 +1,11 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) 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 == == 7/10/2019 ==
Akkadius: Add #npcedit flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating] Akkadius: Add #npcedit flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating]

View File

@ -77,6 +77,10 @@ namespace EQEmu
} // namespace invtype } // namespace invtype
namespace DevTools {
const int32 GM_ACCOUNT_STATUS_LEVEL = 150;
}
namespace popupresponse { namespace popupresponse {
const int32 SERVER_INTERNAL_USE_BASE = 2000000000; const int32 SERVER_INTERNAL_USE_BASE = 2000000000;
const int32 MOB_INFO_DISMISS = 2000000001; const int32 MOB_INFO_DISMISS = 2000000001;

View File

@ -1116,7 +1116,10 @@ namespace SoF
} }
OUT(deity); OUT(deity);
OUT(intoxication); OUT(intoxication);
OUT_array(spellSlotRefresh, spells::SPELL_GEM_COUNT); OUT_array(spellSlotRefresh, spells::SPELL_GEM_COUNT);
eq->spellSlotRefresh[9] = 0; // 10th slot is not valid in this release
OUT(abilitySlotRefresh); OUT(abilitySlotRefresh);
OUT(points); // Relocation Test OUT(points); // Relocation Test
// OUT(unknown0166[4]); // OUT(unknown0166[4]);
@ -1177,7 +1180,10 @@ namespace SoF
} }
// OUT(unknown4184[128]); // OUT(unknown4184[128]);
OUT_array(mem_spells, spells::SPELL_GEM_COUNT); 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(unknown04396[32]);
OUT(platinum); OUT(platinum);
OUT(gold); OUT(gold);

View File

@ -328,7 +328,11 @@ namespace SoF
const int SPELL_ID_MAX = 15999; const int SPELL_ID_MAX = 15999;
const int SPELLBOOK_SIZE = 480; 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<uint32>(CastingSlot::MaxGems); const int SPELL_GEM_COUNT = static_cast<uint32>(CastingSlot::MaxGems);
const int SPELL_GEM_PROFILE_SIZE = 10; // special case declaration
const int LONG_BUFFS = 25; const int LONG_BUFFS = 25;
const int SHORT_BUFFS = 15; const int SHORT_BUFFS = 15;

View File

@ -885,7 +885,7 @@ struct PlayerProfile_Struct //23576 Octets
/*00060*/ BindStruct binds[5]; // Bind points (primary is first) /*00060*/ BindStruct binds[5]; // Bind points (primary is first)
/*00160*/ uint32 deity; // deity /*00160*/ uint32 deity; // deity
/*00164*/ uint32 intoxication; // Alcohol level (in ticks till sober?) /*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; /*00208*/ uint32 abilitySlotRefresh;
/*00212*/ uint8 haircolor; // Player hair color /*00212*/ uint8 haircolor; // Player hair color
/*00213*/ uint8 beardcolor; // Player beard color /*00213*/ uint8 beardcolor; // Player beard color
@ -912,7 +912,7 @@ struct PlayerProfile_Struct //23576 Octets
/*04173*/ uint8 unknown02264[147]; // was [139] /*04173*/ uint8 unknown02264[147]; // was [139]
/*04312*/ uint32 spell_book[spells::SPELLBOOK_SIZE]; // List of the Spells in spellbook 480 = 60 pages /*04312*/ uint32 spell_book[spells::SPELLBOOK_SIZE]; // List of the Spells in spellbook 480 = 60 pages
/*06232*/ uint8 unknown4184[128]; // was [136] /*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] /*06436*/ uint8 unknown04396[28]; //#### uint8 unknown04396[32]; in Titanium ####[28]
/*06464*/ uint32 platinum; // Platinum Pieces on player /*06464*/ uint32 platinum; // Platinum Pieces on player
/*06468*/ uint32 gold; // Gold Pieces on player /*06468*/ uint32 gold; // Gold Pieces on player
@ -3768,7 +3768,7 @@ struct AnnoyingZoneUnknown_Struct {
}; };
struct LoadSpellSet_Struct { struct LoadSpellSet_Struct {
uint32 spell[spells::SPELL_GEM_COUNT]; uint32 spell[spells::SPELL_GEM_PROFILE_SIZE];
uint32 unknown; uint32 unknown;
}; };

View File

@ -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_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_INT (World, TellQueueSize, 20)
RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone ALWAYS be the same location as your bind? 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_END()
RULE_CATEGORY(Zone) RULE_CATEGORY(Zone)

View File

@ -80,6 +80,7 @@
#define ServerOP_GroupJoin 0x003e //for joining ooz folks #define ServerOP_GroupJoin 0x003e //for joining ooz folks
#define ServerOP_UpdateSpawn 0x003f #define ServerOP_UpdateSpawn 0x003f
#define ServerOP_SpawnStatusChange 0x0040 #define ServerOP_SpawnStatusChange 0x0040
#define ServerOP_DropClient 0x0041 // DropClient
#define ServerOP_ReloadTasks 0x0060 #define ServerOP_ReloadTasks 0x0060
#define ServerOP_DepopAllPlayersCorpses 0x0061 #define ServerOP_DepopAllPlayersCorpses 0x0061
#define ServerOP_ReloadTitles 0x0062 #define ServerOP_ReloadTitles 0x0062
@ -320,11 +321,17 @@ struct ServerZoneIncomingClient_Struct {
uint32 accid; uint32 accid;
int16 admin; int16 admin;
uint32 charid; uint32 charid;
uint32 lsid;
bool tellsoff; bool tellsoff;
char charname[64]; char charname[64];
char lskey[30]; char lskey[30];
}; };
struct ServerZoneDropClient_Struct
{
uint32 lsid;
};
struct ServerChangeWID_Struct { struct ServerChangeWID_Struct {
uint32 charid; uint32 charid;
uint32 newwid; uint32 newwid;

View File

@ -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) { 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 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()); Log(Logs::Detail, Logs::QS_Server, "%s", query.c_str());
} }
safe_delete(pack);
safe_delete_array(queryBuffer); safe_delete_array(queryBuffer);
} }

View File

@ -470,7 +470,7 @@ static void ProcessCommandIgnore(Client *c, std::string Ignoree) {
Clientlist::Clientlist(int ChatPort) { Clientlist::Clientlist(int ChatPort) {
EQStreamManagerInterfaceOptions chat_opts(ChatPort, false, false); EQStreamManagerInterfaceOptions chat_opts(ChatPort, false, false);
chat_opts.opcode_size = 1; 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_ms = RuleI(Network, ResendDelayBaseMS);
chat_opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); chat_opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
chat_opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); chat_opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);

View File

@ -1 +1,2 @@
opcode_handlers_output opcode_handlers_output
vcxproj_dependencies_output

View File

@ -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 "If firewall rules don't add you must run this script (eqemu_server.pl) as administrator\n";
print "\n"; print "\n";
print "[Install] Instructions \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 " print "
<loginserver1> \"loginserver1\" : {
<host>login.eqemulator.net</host> \"account\" : \"\",
<port>5998</port> \"host\" : \"login.eqemulator.net\",
<account></account> \"password\" : \"\",
<password></password> \"port\" : \"5998\",
</loginserver1> \"legacy\": \"1\"
<loginserver2> },
<host>127.0.0.1</host> \"loginserver2\" : {
<port>5998</port> \"account\" : \"\",
<account></account> \"host\" : \"192.168.197.129\",
<password></password> \"password\" : \"\",
</loginserver2> \"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";
} }
} }

View File

@ -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}<Project Path="{1}">'.format(col1, key1))
for key2 in project_dependencies[key1]:
write('{0}<Build Type="{1}">'.format(col2, key2))
for key3 in project_dependencies[key1][key2]:
write('{0}<Resource Type="{1}">'.format(col3, key3))
for key4 in project_dependencies[key1][key2][key3]:
write('{0}<Reference Type="{1}">'.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}</Reference>'.format(col4))
write('{0}</Resource>'.format(col3))
write('{0}</Build>'.format(col2))
write('{0}</Project>'.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}<Global>'.format(col1))
for library in libraries:
twrite('{0}<Library Name="{1}">{2}</Library>'.format(col2, library, global_priorities[library]))
twrite('{0}</Global>'.format(col1))
twrite('')
# loop for dumping 'build_priorities'
for build in build_priorities:
twrite('{0}<Build Type="{1}">'.format(col1, build))
for library in libraries:
twrite('{0}<Library Name="{1}">{2}</Library>'.format(col2, library, build_priorities[build][library]))
twrite('{0}</Build>'.format(col1))
twrite('')
# loop for dumping 'context_tree'
for project in context_tree:
twrite('{0}<Project Path="{1}">'.format(col1, project))
for build in context_tree[project]:
twrite('{0}<Built Type="{1}">'.format(col2, build))
for resource in context_tree[project][build]:
twrite('{0}<Resource Name="{1}">'.format(col3, resource))
for library in context_tree[project][build][resource]:
twrite('{0}<Library Name="{1}">'.format(col4, library))
for reference in context_tree[project][build][resource][library]:
twrite(
'{0}<Reference Name="{1}">{2}</Reference>'.format(
col5,
reference,
context_tree[project][build][resource][library][reference]
)
)
twrite('{0}</Library>'.format(col4))
twrite('{0}</Resource>'.format(col3))
twrite('{0}</Build>'.format(col2))
twrite('{0}</Project>'.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()

View File

@ -393,7 +393,7 @@
9137|2018_12_12_client_faction_tables.sql|SHOW TABLES LIKE 'faction_base_data'|empty| 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| 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| 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| 9141|2019_07_10_npc_flymode.sql|SHOW COLUMNS FROM `npc_types` LIKE 'flymode'|empty|
# Upgrade conditions: # Upgrade conditions:

View File

@ -287,7 +287,7 @@ void Adventure::Finished(AdventureWinStatus ws)
ClientListEntry *current = client_list.FindCharacter((*iter).c_str()); ClientListEntry *current = client_list.FindCharacter((*iter).c_str());
if(current) if(current)
{ {
if(current->Online() == CLE_Status_InZone) if(current->Online() == CLE_Status::InZone)
{ {
//We can send our packets only. //We can send our packets only.
auto pack = auto pack =

View File

@ -88,7 +88,6 @@ extern volatile bool UCSServerAvailable_;
Client::Client(EQStreamInterface* ieqs) Client::Client(EQStreamInterface* ieqs)
: autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)), : autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)),
CLE_keepalive_timer(RuleI(World, ClientKeepaliveTimeoutMS)),
connect(1000), connect(1000),
eqs(ieqs) eqs(ieqs)
{ {
@ -105,6 +104,7 @@ Client::Client(EQStreamInterface* ieqs)
char_name[0] = 0; char_name[0] = 0;
charid = 0; charid = 0;
zone_waiting_for_bootup = 0; zone_waiting_for_bootup = 0;
enter_world_triggered = false;
StartInTutorial = false; StartInTutorial = false;
m_ClientVersion = eqs->ClientVersion(); m_ClientVersion = eqs->ClientVersion();
@ -115,7 +115,7 @@ Client::Client(EQStreamInterface* ieqs)
Client::~Client() { Client::~Client() {
if (RunLoops && cle && zone_id == 0) if (RunLoops && cle && zone_id == 0)
cle->SetOnline(CLE_Status_Offline); cle->SetOnline(CLE_Status::Offline);
numclients--; numclients--;
@ -185,7 +185,7 @@ void Client::SendExpansionInfo() {
void Client::SendCharInfo() { void Client::SendCharInfo() {
if (cle) { if (cle) {
cle->SetOnline(CLE_Status_CharSelect); cle->SetOnline(CLE_Status::CharSelect);
} }
if (m_ClientVersionBit & EQEmu::versions::maskRoFAndLater) { 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 // Track who is in and who is out of the game
char *inout= (char *) ""; char *inout= (char *) "";
if (cle->GetOnline() == CLE_Status_Never) { if (cle->GetOnline() == CLE_Status::Never){
// Desktop -> Char Select // Desktop -> Char Select
inout = (char *) "In"; 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. // Either from a fresh client launch or coming back from the game.
// Exiting the game entirely does not come through here. // Exiting the game entirely does not come through here.
// Could use a Logging Out Completely message somewhere. // Could use a Logging Out Completely message somewhere.
cle->SetOnline(CLE_Status_CharSelect); cle->SetOnline(CLE_Status::CharSelect);
Log(Logs::General, Logs::World_Server, Log(Logs::General, Logs::World_Server,
"Account (%s) Logging(%s) to character select :: LSID: %d ", "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 // I don't see this getting executed on logout
eqs->Close(); 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; return false;
} }
case OP_ZoneChange: 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."); Log(Logs::General, Logs::World_Server, "Zone bootup timer expired, bootup failed or too slow.");
TellClientZoneUnavailable(); TellClientZoneUnavailable();
} }
if(connect.Check()){ if(connect.Check()){
SendGuildList();// Send OPCode: OP_GuildsList SendGuildList();// Send OPCode: OP_GuildsList
SendApproveWorld(); SendApproveWorld();
connect.Disable(); connect.Disable();
} }
if (CLE_keepalive_timer.Check()) {
if (cle) if (cle)
cle->KeepAlive(); cle->KeepAlive();
}
/************ Get all packets from packet manager out queue and process them ************/ /************ Get all packets from packet manager out queue and process them ************/
EQApplicationPacket *app = 0; EQApplicationPacket *app = 0;
@ -1153,11 +1153,18 @@ void Client::EnterWorld(bool TryBootup) {
else else
zone_server = zoneserver_list.FindByZoneID(zone_id); zone_server = zoneserver_list.FindByZoneID(zone_id);
const char *zone_name = database.GetZoneName(zone_id, true); const char *zone_name = database.GetZoneName(zone_id, true);
if (zone_server) { if (zone_server) {
// warn the world we're comming, so it knows not to shutdown if (false == enter_world_triggered) {
zone_server->IncomingClient(this); //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 { else {
if (TryBootup) { if (TryBootup) {
@ -1176,9 +1183,17 @@ void Client::EnterWorld(bool TryBootup) {
return; return;
} }
} }
zone_waiting_for_bootup = 0; 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; return;
} }
@ -1195,12 +1210,6 @@ void Client::EnterWorld(bool TryBootup) {
); );
if (seen_character_select) { 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; auto pack = new ServerPacket;
pack->opcode = ServerOP_AcceptWorldEntrance; pack->opcode = ServerOP_AcceptWorldEntrance;
pack->size = sizeof(WorldToZone_Struct); pack->size = sizeof(WorldToZone_Struct);
@ -1306,7 +1315,7 @@ void Client::Clearance(int8 response)
safe_delete(outapp); safe_delete(outapp);
if (cle) if (cle)
cle->SetOnline(CLE_Status_Zoning); cle->SetOnline(CLE_Status::Zoning);
} }
void Client::TellClientZoneUnavailable() { void Client::TellClientZoneUnavailable() {
@ -1320,6 +1329,7 @@ void Client::TellClientZoneUnavailable() {
zone_id = 0; zone_id = 0;
zone_waiting_for_bootup = 0; zone_waiting_for_bootup = 0;
enter_world_triggered = false;
autobootup_timeout.Disable(); autobootup_timeout.Disable();
} }

View File

@ -82,6 +82,7 @@ private:
bool is_player_zoning; bool is_player_zoning;
Timer autobootup_timeout; Timer autobootup_timeout;
uint32 zone_waiting_for_bootup; uint32 zone_waiting_for_bootup;
bool enter_world_triggered;
bool StartInTutorial; bool StartInTutorial;
EQEmu::versions::ClientVersion m_ClientVersion; EQEmu::versions::ClientVersion m_ClientVersion;
@ -94,7 +95,6 @@ private:
void SetClassLanguages(PlayerProfile_Struct *pp); void SetClassLanguages(PlayerProfile_Struct *pp);
ClientListEntry* cle; ClientListEntry* cle;
Timer CLE_keepalive_timer;
Timer connect; Timer connect;
bool firstlogin; bool firstlogin;
bool seen_character_select; bool seen_character_select;

View File

@ -83,8 +83,8 @@ ClientListEntry::ClientListEntry(
memset(pLFGComments, 0, 64); memset(pLFGComments, 0, 64);
} }
ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer *iZS, ServerClientList_Struct *scl, int8 iOnline) ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, CLE_Status iOnline)
: id(in_id) : id(in_id)
{ {
ClearVars(true); ClearVars(true);
@ -104,7 +104,7 @@ ClientListEntry::ClientListEntry(uint32 in_id, ZoneServer *iZS, ServerClientList
pLFGMatchFilter = false; pLFGMatchFilter = false;
memset(pLFGComments, 0, 64); memset(pLFGComments, 0, 64);
if (iOnline >= CLE_Status_Zoning) { if (iOnline >= CLE_Status::Zoning) {
Update(iZS, scl, iOnline); Update(iZS, scl, iOnline);
} }
else { else {
@ -129,31 +129,39 @@ void ClientListEntry::SetChar(uint32 iCharID, const char *iCharName)
strn0cpy(pname, iCharName, sizeof(pname)); strn0cpy(pname, iCharName, sizeof(pname));
} }
void ClientListEntry::SetOnline(ZoneServer *iZS, int8 iOnline) void ClientListEntry::SetOnline(ZoneServer* iZS, CLE_Status iOnline) {
{
if (iZS == this->Server()) { if (iZS == this->Server()) {
SetOnline(iOnline); 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++; numplayers++;
} }
else if (iOnline < CLE_Status_Online && pOnline >= CLE_Status_Online) { else if (iOnline < CLE_Status::Online && pOnline >= CLE_Status::Online) {
numplayers--; numplayers--;
} }
if (iOnline != CLE_Status_Online || pOnline < CLE_Status_Online) { if (iOnline != CLE_Status::Online || pOnline < CLE_Status::Online) {
pOnline = iOnline; pOnline = iOnline;
} }
if (iOnline < CLE_Status_Zoning) { if (iOnline < CLE_Status::Zoning) {
Camp(); Camp();
} }
if (pOnline >= CLE_Status_Online) { if (pOnline >= CLE_Status::Online) {
stale = 0; stale = 0;
} }
} }
void ClientListEntry::LSUpdate(ZoneServer *iZS) void ClientListEntry::LSUpdate(ZoneServer *iZS)
{ {
if (WorldConfig::get()->UpdateStats) { if (WorldConfig::get()->UpdateStats) {
@ -184,8 +192,8 @@ void ClientListEntry::LSZoneChange(ZoneToZone_Struct *ztz)
safe_delete(pack); 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 != iZS) {
if (pzoneserver) { if (pzoneserver) {
pzoneserver->RemovePlayer(); pzoneserver->RemovePlayer();
@ -232,7 +240,7 @@ void ClientListEntry::Update(ZoneServer *iZS, ServerClientList_Struct *scl, int8
SetOnline(iOnline); SetOnline(iOnline);
} }
void ClientListEntry::LeavingZone(ZoneServer *iZS, int8 iOnline) void ClientListEntry::LeavingZone(ZoneServer *iZS, CLE_Status iOnline)
{ {
if (iZS != 0 && iZS != pzoneserver) { if (iZS != 0 && iZS != pzoneserver) {
return; return;
@ -250,8 +258,8 @@ void ClientListEntry::LeavingZone(ZoneServer *iZS, int8 iOnline)
void ClientListEntry::ClearVars(bool iAll) void ClientListEntry::ClearVars(bool iAll)
{ {
if (iAll) { if (iAll) {
pOnline = CLE_Status_Never; pOnline = CLE_Status::Never;
stale = 0; stale = 0;
pLSID = 0; pLSID = 0;
memset(loginserver_account_name, 0, sizeof(loginserver_account_name)); memset(loginserver_account_name, 0, sizeof(loginserver_account_name));
@ -299,12 +307,10 @@ bool ClientListEntry::CheckStale()
{ {
stale++; stale++;
if (stale > 20) { if (stale > 20) {
if (pOnline > CLE_Status_Offline) { if (pOnline > CLE_Status::Offline)
SetOnline(CLE_Status_Offline); SetOnline(CLE_Status::Offline);
}
else { return true;
return true;
}
} }
return false; return false;
} }

View File

@ -8,13 +8,15 @@
#include "../common/rulesys.h" #include "../common/rulesys.h"
#include <vector> #include <vector>
typedef enum
#define CLE_Status_Never -1 {
#define CLE_Status_Offline 0 Never,
#define CLE_Status_Online 1 // Will not overwrite more specific online status Offline,
#define CLE_Status_CharSelect 2 Online,
#define CLE_Status_Zoning 3 CharSelect,
#define CLE_Status_InZone 4 Zoning,
InZone
} CLE_Status;
class ZoneServer; class ZoneServer;
struct ServerClientList_Struct; struct ServerClientList_Struct;
@ -49,23 +51,26 @@ public:
* @param scl * @param scl
* @param iOnline * @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(); ~ClientListEntry();
bool CheckStale(); 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 LSUpdate(ZoneServer* zoneserver);
void LSZoneChange(ZoneToZone_Struct* ztz); void LSZoneChange(ZoneToZone_Struct* ztz);
bool CheckAuth(uint32 loginserver_account_id, const char* key_password); bool CheckAuth(uint32 loginserver_account_id, const char* key_password);
void SetOnline(ZoneServer* iZS, int8 iOnline); bool CheckAuth(const char* iName, MD5& iMD5Password);
void SetOnline(int8 iOnline = CLE_Status_Online); 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); 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 GetID() const { return id; }
inline const uint32 GetIP() const { return pIP; } inline const uint32 GetIP() const { return pIP; }
inline void SetIP(const uint32& iIP) { pIP = iIP; } inline void SetIP(const uint32& iIP) { pIP = iIP; }
inline void KeepAlive() { stale = 0; } inline void KeepAlive() { stale = 0; }
inline uint8 GetStaleCounter() const { return stale; } 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); void Camp(ZoneServer* iZS = 0);
// Login Server stuff // Login Server stuff
@ -75,7 +80,7 @@ public:
inline const char* LSName() const { return loginserver_account_name; } inline const char* LSName() const { return loginserver_account_name; }
inline int16 WorldAdmin() const { return pworldadmin; } inline int16 WorldAdmin() const { return pworldadmin; }
inline const char* GetLSKey() const { return plskey; } inline const char* GetLSKey() const { return plskey; }
inline const int8 GetOnline() const { return pOnline; } inline const CLE_Status GetOnline() const { return pOnline; }
// Account stuff // Account stuff
inline uint32 AccountID() const { return paccountid; } inline uint32 AccountID() const { return paccountid; }
@ -118,8 +123,8 @@ private:
const uint32 id; const uint32 id;
uint32 pIP; uint32 pIP;
int8 pOnline{}; CLE_Status pOnline;
uint8 stale{}; uint8 stale;
// Login Server stuff // Login Server stuff
char source_loginserver[64]{}; //Loginserver we came from. char source_loginserver[64]{}; //Loginserver we came from.

View File

@ -41,7 +41,7 @@ extern ZSList zoneserver_list;
uint32 numplayers = 0; //this really wants to be a member variable of ClientList... uint32 numplayers = 0; //this really wants to be a member variable of ClientList...
ClientList::ClientList() ClientList::ClientList()
: CLStale_timer(45000) : CLStale_timer(10000)
{ {
NextCLEID = 1; NextCLEID = 1;
@ -64,8 +64,6 @@ void ClientList::Process() {
struct in_addr in; struct in_addr in;
in.s_addr = iterator.GetData()->GetIP(); in.s_addr = iterator.GetData()->GetIP();
Log(Logs::Detail, Logs::World_Server,"Removing client from %s:%d", inet_ntoa(in), iterator.GetData()->GetPort()); 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(); iterator.RemoveCurrent();
} }
else else
@ -122,7 +120,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return; return;
} else { } else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); 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(); iterator.RemoveCurrent();
continue; continue;
} }
@ -138,7 +136,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return; return;
} else { } else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); 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(); iterator.RemoveCurrent();
continue; continue;
} }
@ -150,7 +148,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return; return;
} else { } else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); 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(); iterator.RemoveCurrent();
continue; continue;
} }
@ -161,7 +159,7 @@ void ClientList::GetCLEIP(uint32 iIP) {
return; return;
} else { } else {
Log(Logs::General, Logs::Client_Login, "Disconnect: Account %s on IP %s.", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); 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(); iterator.RemoveCurrent();
continue; continue;
} }
@ -182,7 +180,7 @@ uint32 ClientList::GetCLEIPCount(uint32 iIP) {
while (iterator.MoreElements()) { while (iterator.MoreElements()) {
countCLEIPs = iterator.GetData(); 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 IPInstances++; // Increment the occurences of this IP address
} }
iterator.Advance(); iterator.Advance();
@ -208,7 +206,7 @@ void ClientList::DisconnectByIP(uint32 iIP) {
zoneserver_list.SendPacket(pack); zoneserver_list.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
} }
countCLEIPs->SetOnline(CLE_Status_Offline); countCLEIPs->SetOnline(CLE_Status::Offline);
iterator.RemoveCurrent(); iterator.RemoveCurrent();
} }
iterator.Advance(); iterator.Advance();
@ -255,19 +253,6 @@ ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) {
return nullptr; return nullptr;
} }
ClientListEntry* ClientList::FindCLEByLSID(uint32 iLSID) {
LinkedListIterator<ClientListEntry*> 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) { void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnection* connection, const char* iName) {
LinkedListIterator<ClientListEntry*> iterator(clientlist); LinkedListIterator<ClientListEntry*> iterator(clientlist);
char* output = 0; char* output = 0;
@ -343,10 +328,10 @@ void ClientList::ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* s
if (iterator.GetData()->GetID() == scl->wid) { if (iterator.GetData()->GetID() == scl->wid) {
cle = iterator.GetData(); cle = iterator.GetData();
if (scl->remove == 2){ if (scl->remove == 2){
cle->LeavingZone(zoneserver, CLE_Status_Offline); cle->LeavingZone(zoneserver, CLE_Status::Offline);
} }
else if (scl->remove == 1) else if (scl->remove == 1)
cle->LeavingZone(zoneserver, CLE_Status_Zoning); cle->LeavingZone(zoneserver, CLE_Status::Zoning);
else else
cle->Update(zoneserver, scl); cle->Update(zoneserver, scl);
return; return;
@ -354,11 +339,11 @@ void ClientList::ClientUpdate(ZoneServer* zoneserver, ServerClientList_Struct* s
iterator.Advance(); iterator.Advance();
} }
if (scl->remove == 2) 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) else if (scl->remove == 1)
cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status_Zoning); cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::Zoning);
else else
cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status_InZone); cle = new ClientListEntry(GetNextCLEID(), zoneserver, scl, CLE_Status::InZone);
clientlist.Insert(cle); clientlist.Insert(cle);
zoneserver->ChangeWID(scl->charid, cle->GetID()); 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(); countcle = countclients.GetData();
const char* tmpZone = database.GetZoneName(countcle->zone()); const char* tmpZone = database.GetZoneName(countcle->zone());
if ( if (
(countcle->Online() >= CLE_Status_Zoning) && (countcle->Online() >= CLE_Status::Zoning) &&
(!countcle->GetGM() || countcle->Anon() != 1 || admin >= countcle->Admin()) && (!countcle->GetGM() || countcle->Anon() != 1 || admin >= countcle->Admin()) &&
(whom == 0 || ( (whom == 0 || (
((countcle->Admin() >= 80 && countcle->GetGM()) || whom->gmlookup == 0xFFFF) && ((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()); const char* tmpZone = database.GetZoneName(cle->zone());
if ( if (
(cle->Online() >= CLE_Status_Zoning) && (cle->Online() >= CLE_Status::Zoning) &&
(!cle->GetGM() || cle->Anon() != 1 || admin >= cle->Admin()) && (!cle->GetGM() || cle->Anon() != 1 || admin >= cle->Admin()) &&
(whom == 0 || ( (whom == 0 || (
((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) && ((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
@ -757,7 +742,7 @@ void ClientList::SendFriendsWho(ServerFriendsWho_Struct *FriendsWho, WorldTCPCon
Friend_[Seperator - FriendsPointer] = 0; Friend_[Seperator - FriendsPointer] = 0;
ClientListEntry* CLE = FindCharacter(Friend_); 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); FriendsCLEs.push_back(CLE);
TotalLength += strlen(CLE->name()); TotalLength += strlen(CLE->name());
int GuildNameLength = strlen(guild_mgr.GetGuildName(CLE->GuildID())); 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(); cle = iterator.GetData();
const char* tmpZone = database.GetZoneName(cle->zone()); const char* tmpZone = database.GetZoneName(cle->zone());
if ( if (
(cle->Online() >= CLE_Status_Zoning) (cle->Online() >= CLE_Status::Zoning)
&& (whom == 0 || ( && (whom == 0 || (
((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) && ((cle->Admin() >= 80 && cle->GetGM()) || whom->gmlookup == 0xFFFF) &&
(whom->lvllow == 0xFFFF || (cle->level() >= whom->lvllow && cle->level() <= whom->lvlhigh)) && (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<ClientListEntry*> 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() { int ClientList::GetClientCount() {
return(numplayers); return(numplayers);
} }

View File

@ -55,7 +55,6 @@ public:
ClientListEntry* FindCharacter(const char* name); ClientListEntry* FindCharacter(const char* name);
ClientListEntry* FindCLEByAccountID(uint32 iAccID); ClientListEntry* FindCLEByAccountID(uint32 iAccID);
ClientListEntry* FindCLEByCharacterID(uint32 iCharID); ClientListEntry* FindCLEByCharacterID(uint32 iCharID);
ClientListEntry* FindCLEByLSID(uint32 iLSID);
ClientListEntry* GetCLE(uint32 iID); ClientListEntry* GetCLE(uint32 iID);
void GetCLEIP(uint32 iIP); void GetCLEIP(uint32 iIP);
uint32 GetCLEIPCount(uint32 iLSAccountID); 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 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 UpdateClientGuild(uint32 char_id, uint32 guild_id);
void RemoveCLEByLSID(uint32 iLSID); void RemoveCLEByLSID(uint32 iLSID);
bool IsAccountInGame(uint32 iLSID);
int GetClientCount(); int GetClientCount();
void GetClients(const char *zone_name, std::vector<ClientListEntry *> &into); void GetClients(const char *zone_name, std::vector<ClientListEntry *> &into);

View File

@ -108,19 +108,11 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
return; return;
} }
if (RuleB(World, DisallowDuplicateAccountLogins)) { if (RuleB(World, EnforceCharacterLimitAtLogin)) {
auto cle = client_list.FindCLEByLSID(utwr->lsaccountid); if (client_list.IsAccountInGame(utwr->lsaccountid)) {
if (cle != nullptr) { utwrs->response = UserToWorldStatusAlreadyOnline;
auto status = cle->GetOnline(); SendPacket(&outpack);
if (CLE_Status_Zoning == status || CLE_Status_InZone == status) { return;
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);
}
} }
} }

View File

@ -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) void ZSList::OnTick(EQ::Timer *t)
{ {
if (!EventSubscriptionWatcher::Get()->IsSubscribed("EQW::ZoneUpdate")) { if (!EventSubscriptionWatcher::Get()->IsSubscribed("EQW::ZoneUpdate")) {

View File

@ -57,6 +57,7 @@ public:
void SOPZoneBootup(const char *adminname, uint32 ZoneServerID, const char *zonename, bool iMakeStatic = false); void SOPZoneBootup(const char *adminname, uint32 ZoneServerID, const char *zonename, bool iMakeStatic = false);
void UpdateUCSServerAvailable(bool ucss_available = true); void UpdateUCSServerAvailable(bool ucss_available = true);
void WorldShutDown(uint32 time, uint32 interval); void WorldShutDown(uint32 time, uint32 interval);
void DropClient(uint32 lsid, ZoneServer *ignore_zoneserver);
ZoneServer* FindByPort(uint16 port); ZoneServer* FindByPort(uint16 port);
ZoneServer* FindByID(uint32 ZoneID); ZoneServer* FindByID(uint32 ZoneID);

View File

@ -437,7 +437,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
} }
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto); 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))) { (cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
if (!scm->noreply) { if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from); 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); sender->Server()->SendPacket(pack);
} }
} }
else if (cle->Online() == CLE_Status_Zoning) { else if (cle->Online() == CLE_Status::Zoning) {
if (!scm->noreply) { if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from); ClientListEntry* sender = client_list.FindCharacter(scm->from);
if (cle->TellQueueFull()) { if (cle->TellQueueFull()) {
@ -518,7 +518,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
ClientListEntry* cle = client_list.FindCharacter(svm->To); 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); 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->accid = client->GetAccountID();
s->admin = client->GetAdmin(); s->admin = client->GetAdmin();
s->charid = client->GetCharID(); s->charid = client->GetCharID();
s->lsid = client->GetLSID();
if (client->GetCLE()) if (client->GetCLE())
s->tellsoff = client->GetCLE()->TellsOff(); s->tellsoff = client->GetCLE()->TellsOff();
strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname)); strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname));

View File

@ -489,7 +489,7 @@ void Client::ResetAA() {
database.DeleteCharacterLeadershipAAs(CharacterID()); database.DeleteCharacterLeadershipAAs(CharacterID());
// undefined for these clients // undefined for these clients
if (ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier) if (ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier)
Kick(); Kick("AA Reset on client that doesn't support it");
} }
void Client::SendClearAA() void Client::SendClearAA()

View File

@ -136,6 +136,7 @@ Client::Client(EQStreamInterface* ieqs)
forget_timer(0), forget_timer(0),
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000), autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000), client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000),
client_zone_wide_full_position_update_timer(5 * 60 * 1000),
tribute_timer(Tribute_duration), tribute_timer(Tribute_duration),
proximity_timer(ClientProximity_interval), proximity_timer(ClientProximity_interval),
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000), TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
@ -446,7 +447,7 @@ Client::~Client() {
numclients--; numclients--;
UpdateWindowTitle(); UpdateWindowTitle();
if(zone) if(zone)
zone->RemoveAuth(GetName()); zone->RemoveAuth(GetName(), lskey);
//let the stream factory know were done with this stream //let the stream factory know were done with this stream
eqs->Close(); eqs->Close();
@ -845,7 +846,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
{ {
if(AttemptedMessages > RuleI(Chat, MaxMessagesBeforeKick)) if(AttemptedMessages > RuleI(Chat, MaxMessagesBeforeKick))
{ {
Kick(); Kick("Sent too many chat messages at once.");
return; return;
} }
if(GlobalChatLimiterTimer) if(GlobalChatLimiterTimer)
@ -2586,13 +2587,19 @@ void Client::SetPVP(bool toggle, bool message) {
Save(); 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() { void Client::WorldKick() {
auto outapp = new EQApplicationPacket(OP_GMKick, sizeof(GMKick_Struct)); auto outapp = new EQApplicationPacket(OP_GMKick, sizeof(GMKick_Struct));
GMKick_Struct* gmk = (GMKick_Struct *)outapp->pBuffer; GMKick_Struct* gmk = (GMKick_Struct *)outapp->pBuffer;
strcpy(gmk->name,GetName()); strcpy(gmk->name,GetName());
QueuePacket(outapp); QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
Kick(); Kick("World kick issued");
} }
void Client::GMKill() { void Client::GMKill() {
@ -9115,3 +9122,16 @@ bool Client::GotoPlayer(std::string player_name)
return false; 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;
}

View File

@ -371,9 +371,9 @@ public:
inline bool ClientDataLoaded() const { return client_data_loaded; } inline bool ClientDataLoaded() const { return client_data_loaded; }
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); } inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); } 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 void Disconnect() { eqs->Close(); client_state = DISCONNECTED; }
inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); } inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); }
void Kick(const std::string &reason);
void WorldKick(); void WorldKick();
inline uint8 GetAnon() const { return m_pp.anon; } inline uint8 GetAnon() const { return m_pp.anon; }
inline PlayerProfile_Struct& GetPP() { return m_pp; } 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. 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: protected:
friend class Mob; friend class Mob;
void CalcItemBonuses(StatBonuses* newbon); void CalcItemBonuses(StatBonuses* newbon);
@ -1518,6 +1521,7 @@ private:
Timer forget_timer; // our 2 min everybody forgets you timer Timer forget_timer; // our 2 min everybody forgets you timer
Timer autosave_timer; Timer autosave_timer;
Timer client_scan_npc_aggro_timer; Timer client_scan_npc_aggro_timer;
Timer client_zone_wide_full_position_update_timer;
Timer tribute_timer; Timer tribute_timer;
Timer proximity_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 */ Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
glm::vec3 m_Proximity; glm::vec3 m_Proximity;
glm::vec4 last_position_before_bulk_update;
void BulkSendInventoryItems(); void BulkSendInventoryItems();

View File

@ -60,6 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "water_map.h" #include "water_map.h"
#include "worldserver.h" #include "worldserver.h"
#include "zone.h" #include "zone.h"
#include "mob_movement_manager.h"
#ifdef BOTS #ifdef BOTS
#include "bot.h" #include "bot.h"
@ -805,6 +806,8 @@ void Client::CompleteConnect()
parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0); 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. */ /* This sub event is for if a player logs in for the first time since entering world. */
if (firstlogon == 1) { if (firstlogon == 1) {
parse->EventPlayer(EVENT_CONNECT, this, "", 0); 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); Client* client = entity_list.GetClientByName(cze->char_name);
if (!zone->GetAuth(ip, cze->char_name, &WID, &account_id, &character_id, &admin, lskey, &tellsoff)) { 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"); Log(Logs::General, Logs::Client_Login, "%s failed zone auth check.", cze->char_name);
if (client != 0) { if (nullptr != client) {
client->Save(); 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; return;
} }
@ -1682,7 +1683,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/** /**
* DevTools Load Settings * 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()); std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", AccountID());
if (DataBucket::GetData(dev_tools_window_key) == "true") { if (DataBucket::GetData(dev_tools_window_key) == "true") {
dev_tools_window_enabled = false; dev_tools_window_enabled = false;
@ -4467,16 +4468,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
/* Handle client aggro scanning timers NPCs */ /* Handle client aggro scanning timers NPCs */
is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true; is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true;
if (is_client_moving) { if (is_client_moving) {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u", Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration()); client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() > 1000) { if (client_scan_npc_aggro_timer.GetDuration() > 1000) {
client_scan_npc_aggro_timer.Disable(); client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(500); client_scan_npc_aggro_timer.Start(500);
} }
} else { }
else {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u", Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration()); client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() < 1000) { 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); 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); float new_heading = EQ12toFloat(ppu->heading);
int32 new_animation = ppu->animation; int32 new_animation = ppu->animation;
@ -9757,7 +9802,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
casting_spell_id); casting_spell_id);
database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName()); database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
safe_delete_array(detect); 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; return;
} }
} }
@ -9801,7 +9846,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
void Client::Handle_OP_MoveMultipleItems(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) void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)

View File

@ -591,8 +591,8 @@ bool Client::Process() {
// only if client is not feigned // only if client is not feigned
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) { if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
int npc_scan_count = 0; int npc_scan_count = 0;
for (auto it = close_mobs.begin(); it != close_mobs.end(); ++it) { for (auto & close_mob : close_mobs) {
Mob *mob = it->first; Mob *mob = close_mob.first;
if (!mob) if (!mob)
continue; continue;
@ -603,6 +603,7 @@ bool Client::Process() {
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) { if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
mob->AddToHateList(this, 25); mob->AddToHateList(this, 25);
} }
npc_scan_count++; npc_scan_count++;
} }
Log(Logs::General, Logs::Aggro, "Checking Reverse Aggro (client->npc) scanned_npcs (%i)", npc_scan_count); Log(Logs::General, Logs::Aggro, "Checking Reverse Aggro (client->npc) scanned_npcs (%i)", npc_scan_count);

View File

@ -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]) ); 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->SetBaseClass(atoi(sep->arg[1]));
t->Save(); 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()); client->Message(0, "You have been kicked by %s", c->GetName());
auto outapp = new EQApplicationPacket(OP_GMKick, 0); auto outapp = new EQApplicationPacket(OP_GMKick, 0);
client->QueuePacket(outapp); client->QueuePacket(outapp);
client->Kick(); client->Kick("Ordered kicked by command");
c->Message(0, "Kick: local: kicking %s", sep->arg[1]); 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]; 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); std::string existing_zone_instance = DataBucket::GetData(bucket_key);
if (existing_zone_instance.length() > 0) { 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]); c->Message(0, "Successfully renamed %s to %s", oldname, sep->arg[1]);
// until we get the name packet working right this will work // until we get the name packet working right this will work
c->Message(0, "Sending player to char select."); c->Message(0, "Sending player to char select.");
target->Kick(); target->Kick("Name was changed");
} }
else else
c->Message(13, "ERROR: Unable to rename %s. Check that the new name '%s' isn't already taken.", oldname, sep->arg[2]); c->Message(13, "ERROR: Unable to rename %s. Check that the new name '%s' isn't already taken.", oldname, sep->arg[2]);

View File

@ -1713,6 +1713,18 @@ Client *EntityList::GetClientByWID(uint32 iWID)
return nullptr; 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) Client *EntityList::GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient)
{ {
std::vector<Client *> ClientsInRange; std::vector<Client *> ClientsInRange;

View File

@ -176,6 +176,7 @@ public:
} }
Client *GetClientByCharID(uint32 iCharID); Client *GetClientByCharID(uint32 iCharID);
Client *GetClientByWID(uint32 iWID); Client *GetClientByWID(uint32 iWID);
Client *GetClientByLSID(uint32 iLSID);
Client *GetClient(uint32 ip, uint16 port); Client *GetClient(uint32 ip, uint16 port);
Client *GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient = nullptr); Client *GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient = nullptr);
Group *GetGroupByMob(Mob* mob); Group *GetGroupByMob(Mob* mob);

View File

@ -1608,7 +1608,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
banker ? banker->GetName() : "UNKNOWN NPC", distance); banker ? banker->GetName() : "UNKNOWN NPC", distance);
database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName()); database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName());
safe_delete_array(hacked_string); 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; return false;
} }
} }
@ -1822,7 +1822,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Step 4: Check for entity trade // Step 4: Check for entity trade
if (dst_slot_id >= EQEmu::invslot::TRADE_BEGIN && dst_slot_id <= EQEmu::invslot::TRADE_END) { if (dst_slot_id >= EQEmu::invslot::TRADE_BEGIN && dst_slot_id <= EQEmu::invslot::TRADE_END) {
if (src_slot_id != EQEmu::invslot::slotCursor) { if (src_slot_id != EQEmu::invslot::slotCursor) {
Kick(); Kick("Trade with non-cursor item");
return false; return false;
} }
if (with) { if (with) {

View File

@ -47,7 +47,7 @@ bool Lua_Client::InZone() {
void Lua_Client::Kick() { void Lua_Client::Kick() {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->Kick(); self->Kick("Lua Quest");
} }
void Lua_Client::Disconnect() { void Lua_Client::Disconnect() {

View File

@ -1128,7 +1128,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
UpdateActiveLight(); UpdateActiveLight();
ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive]; 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.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
ns->spawn.NPC = IsClient() ? 0 : 1; ns->spawn.NPC = IsClient() ? 0 : 1;

File diff suppressed because it is too large Load Diff

View File

@ -41,18 +41,29 @@ class MobMovementManager
public: public:
~MobMovementManager(); ~MobMovementManager();
void Process(); void Process();
void AddMob(Mob *m); void AddMob(Mob *mob);
void RemoveMob(Mob *m); void RemoveMob(Mob *mob);
void AddClient(Client *c); void AddClient(Client *client);
void RemoveClient(Client *c); 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 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 NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning);
void StopNavigation(Mob *who); 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); float FixHeading(float in);
void DumpStats(Client *to); void DumpStats(Client *client);
void ClearStats(); void ClearStats();
static MobMovementManager &Get() { static MobMovementManager &Get() {
@ -65,18 +76,18 @@ private:
MobMovementManager(const MobMovementManager&); MobMovementManager(const MobMovementManager&);
MobMovementManager& operator=(const MobMovementManager&); MobMovementManager& operator=(const MobMovementManager&);
void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim); 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 mode); 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 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 UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode);
void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading); 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 PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode); void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode); void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode);
void PushStopMoving(MobMovementEntry &ent); void PushStopMoving(MobMovementEntry &mob_movement_entry);
void PushEvadeCombat(MobMovementEntry &ent); void PushEvadeCombat(MobMovementEntry &mob_movement_entry);
void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mode); void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode);
struct Implementation; struct Implementation;
std::unique_ptr<Implementation> _impl; std::unique_ptr<Implementation> _impl;

View File

@ -174,7 +174,7 @@ XS(XS_Client_Kick) {
if (THIS == nullptr) if (THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->Kick(); THIS->Kick("Perl Quest");
} }
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }

View File

@ -809,7 +809,7 @@ void QuestManager::changedeity(int diety_id) {
initiator->SetDeity(diety_id); initiator->SetDeity(diety_id);
initiator->Message(15,"Your Deity has been changed/set to: %i", diety_id); initiator->Message(15,"Your Deity has been changed/set to: %i", diety_id);
initiator->Save(1); initiator->Save(1);
initiator->Kick(); initiator->Kick("Deity change by QuestManager");
} }
else else
{ {
@ -943,7 +943,7 @@ void QuestManager::permaclass(int class_id) {
//Makes the client the class specified //Makes the client the class specified
initiator->SetBaseClass(class_id); initiator->SetBaseClass(class_id);
initiator->Save(2); initiator->Save(2);
initiator->Kick(); initiator->Kick("Base class change by QuestManager");
} }
void QuestManager::permarace(int race_id) { void QuestManager::permarace(int race_id) {
@ -951,7 +951,7 @@ void QuestManager::permarace(int race_id) {
//Makes the client the race specified //Makes the client the race specified
initiator->SetBaseRace(race_id); initiator->SetBaseRace(race_id);
initiator->Save(2); initiator->Save(2);
initiator->Kick(); initiator->Kick("Base race change by QuestManager");
} }
void QuestManager::permagender(int gender_id) { void QuestManager::permagender(int gender_id) {
@ -959,7 +959,7 @@ void QuestManager::permagender(int gender_id) {
//Makes the client the gender specified //Makes the client the gender specified
initiator->SetBaseGender(gender_id); initiator->SetBaseGender(gender_id);
initiator->Save(2); initiator->Save(2);
initiator->Kick(); initiator->Kick("Base gender change by QuestManager");
} }
uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {

View File

@ -298,7 +298,8 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
if(IsClient()) { if(IsClient()) {
char temp[64]; char temp[64];
sprintf(temp, "%d", spell_id); 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()) { } else if(IsNPC()) {
char temp[64]; char temp[64];
sprintf(temp, "%d", spell_id); sprintf(temp, "%d", spell_id);

View File

@ -112,7 +112,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
// (it just didn't handle partial stack move actions) // (it just didn't handle partial stack move actions)
if (stack_size > 0) { if (stack_size > 0) {
if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) { if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) {
client->Kick(); client->Kick("Error stacking item in trade");
return; return;
} }
@ -138,7 +138,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
} }
else { else {
if (inst2 && inst2->GetID()) { if (inst2 && inst2->GetID()) {
client->Kick(); client->Kick("Attempting to add null item to trade");
return; return;
} }

View File

@ -534,7 +534,15 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*)pack->pBuffer; ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*)pack->pBuffer;
if (is_zone_loaded) { if (is_zone_loaded) {
SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); SetZoneData(zone->GetZoneID(), zone->GetInstanceID());
if (szic->zoneid == zone->GetZoneID()) { 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); zone->AddAuth(szic);
// This packet also doubles as "incoming client" notification, lets not shut down before they get here // This packet also doubles as "incoming client" notification, lets not shut down before they get here
zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000); zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000);
@ -547,6 +555,23 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
} }
break; 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: { case ServerOP_ZonePlayer: {
ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)pack->pBuffer; ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(szp->name); Client* client = entity_list.GetClientByName(szp->name);

View File

@ -55,6 +55,7 @@
#include "zone_config.h" #include "zone_config.h"
#include "mob_movement_manager.h" #include "mob_movement_manager.h"
#include "npc_scale_manager.h" #include "npc_scale_manager.h"
#include "../common/data_verification.h"
#include <time.h> #include <time.h>
#include <ctime> #include <ctime>
@ -864,6 +865,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
m_last_ucss_update = 0; m_last_ucss_update = 0;
mMovementManager = &MobMovementManager::Get(); mMovementManager = &MobMovementManager::Get();
SetNpcPositionUpdateDistance(0);
} }
Zone::~Zone() { Zone::~Zone() {
@ -1106,6 +1109,7 @@ void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) {
zca->accid = szic->accid; zca->accid = szic->accid;
zca->admin = szic->admin; zca->admin = szic->admin;
zca->charid = szic->charid; zca->charid = szic->charid;
zca->lsid = szic->lsid;
zca->tellsoff = szic->tellsoff; zca->tellsoff = szic->tellsoff;
strn0cpy(zca->charname, szic->charname, sizeof(zca->charname)); strn0cpy(zca->charname, szic->charname, sizeof(zca->charname));
strn0cpy(zca->lskey, szic->lskey, sizeof(zca->lskey)); strn0cpy(zca->lskey, szic->lskey, sizeof(zca->lskey));
@ -1113,16 +1117,31 @@ void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) {
client_auth_list.Insert(zca); client_auth_list.Insert(zca);
} }
void Zone::RemoveAuth(const char* iCharName) void Zone::RemoveAuth(const char* iCharName, const char* iLSKey)
{ {
LinkedListIterator<ZoneClientAuth_Struct*> iterator(client_auth_list); LinkedListIterator<ZoneClientAuth_Struct*> iterator(client_auth_list);
iterator.Reset(); iterator.Reset();
while (iterator.MoreElements()) { while (iterator.MoreElements()) {
ZoneClientAuth_Struct* zca = iterator.GetData(); ZoneClientAuth_Struct* zca = iterator.GetData();
if (strcasecmp(zca->charname, iCharName) == 0) { if (strcasecmp(zca->charname, iCharName) == 0 && strcasecmp(zca->lskey, iLSKey) == 0) {
iterator.RemoveCurrent(); iterator.RemoveCurrent();
return; return;
}
iterator.Advance();
}
}
void Zone::RemoveAuth(uint32 lsid)
{
LinkedListIterator<ZoneClientAuth_Struct*> iterator(client_auth_list);
iterator.Reset();
while (iterator.MoreElements()) {
ZoneClientAuth_Struct* zca = iterator.GetData();
if (zca->lsid == lsid) {
iterator.RemoveCurrent();
continue;
} }
iterator.Advance(); iterator.Advance();
} }
@ -1178,9 +1197,9 @@ uint32 Zone::CountAuth() {
bool Zone::Process() { bool Zone::Process() {
spawn_conditions.Process(); spawn_conditions.Process();
if(spawn2_timer.Check()) { if (spawn2_timer.Check()) {
LinkedListIterator<Spawn2*> iterator(spawn2_list); LinkedListIterator<Spawn2 *> iterator(spawn2_list);
EQEmu::InventoryProfile::CleanDirty(); EQEmu::InventoryProfile::CleanDirty();
@ -1196,10 +1215,15 @@ bool Zone::Process() {
} }
} }
if(adv_data && !did_adventure_actions) if (adv_data && !did_adventure_actions) {
DoAdventureActions(); DoAdventureActions();
}
if (GetNpcPositionUpdateDistance() == 0) {
CalculateNpcUpdateDistanceSpread();
}
} }
if(initgrids_timer.Check()) { if(initgrids_timer.Check()) {
//delayed grid loading stuff. //delayed grid loading stuff.
initgrids_timer.Disable(); initgrids_timer.Disable();
@ -2349,3 +2373,59 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
if (m_last_ucss_update < update_timestamp) if (m_last_ucss_update < update_timestamp)
m_ucss_available = ucss_available; 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
);
}

View File

@ -52,6 +52,7 @@ struct ZoneClientAuth_Struct {
uint32 accid; uint32 accid;
int16 admin; int16 admin;
uint32 charid; uint32 charid;
uint32 lsid;
bool tellsoff; bool tellsoff;
char charname[64]; char charname[64];
char lskey[30]; char lskey[30];
@ -125,6 +126,9 @@ public:
bool Process(); bool Process();
bool SaveZoneCFG(); bool SaveZoneCFG();
int GetNpcPositionUpdateDistance() const;
void SetNpcPositionUpdateDistance(int in_npc_position_update_distance);
char *adv_data; char *adv_data;
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location); const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
@ -218,6 +222,7 @@ public:
void ChangeWeather(); void ChangeWeather();
void ClearBlockedSpells(); void ClearBlockedSpells();
void ClearNPCTypeCache(int id); void ClearNPCTypeCache(int id);
void CalculateNpcUpdateDistanceSpread();
void DelAggroMob() { aggroedmobs--; } void DelAggroMob() { aggroedmobs--; }
void DeleteQGlobal(std::string name, uint32 npcID, uint32 charID, uint32 zoneID); void DeleteQGlobal(std::string name, uint32 npcID, uint32 charID, uint32 zoneID);
void Despawn(uint32 spawngroupID); void Despawn(uint32 spawngroupID);
@ -243,7 +248,8 @@ public:
void LoadZoneDoors(const char *zone, int16 version); void LoadZoneDoors(const char *zone, int16 version);
void ReloadStaticData(); void ReloadStaticData();
void ReloadWorld(uint32 Option); 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 Repop(uint32 delay = 0);
void RepopClose(const glm::vec4 &client_position, uint32 repop_distance); void RepopClose(const glm::vec4 &client_position, uint32 repop_distance);
void RequestUCSServerStatus(); void RequestUCSServerStatus();
@ -288,7 +294,7 @@ public:
*/ */
find_replace(message, std::string("%"), std::string(".")); 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'); auto message_split = SplitString(message, '\n');
entity_list.MessageStatus( entity_list.MessageStatus(
0, 0,
@ -343,6 +349,7 @@ private:
glm::vec4 m_Graveyard; glm::vec4 m_Graveyard;
int default_ruleset; int default_ruleset;
int totalBS; int totalBS;
int npc_position_update_distance;
int32 aggroedmobs; int32 aggroedmobs;
uint8 zone_type; uint8 zone_type;
uint16 instanceversion; uint16 instanceversion;