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_USE_MAP_MMFS
#EQEMU_MAP_DIR
#EQEMU_ARCH
#EQEMU_ARCH_ALT
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
IF(POLICY CMP0074)
@ -49,33 +51,37 @@ ENDIF(MSVC OR MINGW)
IF(MSVC)
IF(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64")
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x64")
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x64")
SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x64")
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
IF(MSVC_VERSION GREATER 1800)
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v140/dynamic")
ELSEIF(MSVC_VERSION EQUAL 1800)
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v120/dynamic")
ELSE()
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v110/dynamic")
ENDIF()
SET(EQEMU_ARCH "x64")
SET(EQEMU_ARCH_ALT "x64")
ELSE(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86")
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x86")
IF(MSVC_VERSION GREATER 1800)
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
ELSEIF(MSVC_VERSION EQUAL 1800)
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v120/dynamic")
ELSE()
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v110/dynamic")
ENDIF()
SET(EQEMU_ARCH "x86")
SET(EQEMU_ARCH_ALT "Win32")
ENDIF(CMAKE_CL_64)
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_${EQEMU_ARCH}")
IF(VCPKG_TOOLCHAIN)
IF(NOT MSVC_VERSION GREATER 1800)
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
ENDIF()
ELSE(VCPKG_TOOLCHAIN)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_${EQEMU_ARCH}")
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_${EQEMU_ARCH}")
SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_${EQEMU_ARCH}")
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
ENDIF(VCPKG_TOOLCHAIN)
IF(SODIUM_INCLUDE_HINTS)
IF(MSVC_VERSION GREATER 1800)
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/${EQEMU_ARCH_ALT}/Release/v140/dynamic")
ELSEIF(MSVC_VERSION EQUAL 1800)
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/${EQEMU_ARCH_ALT}/Release/v120/dynamic")
ELSE()
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/${EQEMU_ARCH_ALT}/Release/v110/dynamic")
ENDIF()
ENDIF(SODIUM_INCLUDE_HINTS)
#disable CRT warnings on windows cause they're annoying as shit and we use C functions everywhere
OPTION(EQEMU_DISABLE_CRT_SECURE_WARNINGS "Disable Secure CRT Warnings" ON)
IF(EQEMU_DISABLE_CRT_SECURE_WARNINGS)
@ -243,6 +249,8 @@ IF(ZLIB_FOUND)
SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY})
ENDIF()
ELSE()
MESSAGE(STATUS "Could NOT find ZLIB - using ZLIBSTATIC package.")
SET(EQEMU_BUILD_ZLIB ON)
INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic")
ENDIF()

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)
* CPPUnit - GLP StringUtilities - Apache
* 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)
-------------------------------------------------------
== 8/6/2019 ==
Akkadius: Optimizations to movement updates to eliminate ghosting possibilities in larger zones
== 7/22/2019 ==
Uleat: Added script 'vcxproj_dependencies.py' - a script to help determine conflicting project dependencies (alpha-stage)
== 7/10/2019 ==
Akkadius: Add #npcedit flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating]

View File

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

View File

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

View File

@ -328,7 +328,11 @@ namespace SoF
const int SPELL_ID_MAX = 15999;
const int SPELLBOOK_SIZE = 480;
// Be careful not to confuse these two..SoF disc release has a special requirement...
// - The number of available spell gems HAS NOT increased from 9 at this point
// - The profile allocation HAS increased to 10 at this point
const int SPELL_GEM_COUNT = static_cast<uint32>(CastingSlot::MaxGems);
const int SPELL_GEM_PROFILE_SIZE = 10; // special case declaration
const int LONG_BUFFS = 25;
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)
/*00160*/ uint32 deity; // deity
/*00164*/ uint32 intoxication; // Alcohol level (in ticks till sober?)
/*00168*/ uint32 spellSlotRefresh[spells::SPELL_GEM_COUNT]; // Refresh time (millis) - 4 Octets Each
/*00168*/ uint32 spellSlotRefresh[spells::SPELL_GEM_PROFILE_SIZE]; // Refresh time (millis) - 4 Octets Each
/*00208*/ uint32 abilitySlotRefresh;
/*00212*/ uint8 haircolor; // Player hair color
/*00213*/ uint8 beardcolor; // Player beard color
@ -912,7 +912,7 @@ struct PlayerProfile_Struct //23576 Octets
/*04173*/ uint8 unknown02264[147]; // was [139]
/*04312*/ uint32 spell_book[spells::SPELLBOOK_SIZE]; // List of the Spells in spellbook 480 = 60 pages
/*06232*/ uint8 unknown4184[128]; // was [136]
/*06396*/ uint32 mem_spells[spells::SPELL_GEM_COUNT]; // List of spells memorized
/*06396*/ uint32 mem_spells[spells::SPELL_GEM_PROFILE_SIZE]; // List of spells memorized
/*06436*/ uint8 unknown04396[28]; //#### uint8 unknown04396[32]; in Titanium ####[28]
/*06464*/ uint32 platinum; // Platinum Pieces on player
/*06468*/ uint32 gold; // Gold Pieces on player
@ -3768,7 +3768,7 @@ struct AnnoyingZoneUnknown_Struct {
};
struct LoadSpellSet_Struct {
uint32 spell[spells::SPELL_GEM_COUNT];
uint32 spell[spells::SPELL_GEM_PROFILE_SIZE];
uint32 unknown;
};

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

View File

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

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) {
/*
These are general queries passed from anywhere in zone instead of packing structures and breaking them down again and again
@ -393,7 +394,6 @@ void Database::GeneralQueryReceive(ServerPacket *pack) {
Log(Logs::Detail, Logs::QS_Server, "%s", query.c_str());
}
safe_delete(pack);
safe_delete_array(queryBuffer);
}

View File

@ -470,7 +470,7 @@ static void ProcessCommandIgnore(Client *c, std::string Ignoree) {
Clientlist::Clientlist(int ChatPort) {
EQStreamManagerInterfaceOptions chat_opts(ChatPort, false, false);
chat_opts.opcode_size = 1;
chat_opts.daybreak_options.stale_connection_ms = 300000;
chat_opts.daybreak_options.stale_connection_ms = 600000;
chat_opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
chat_opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
chat_opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);

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 "\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 "
<loginserver1>
<host>login.eqemulator.net</host>
<port>5998</port>
<account></account>
<password></password>
</loginserver1>
<loginserver2>
<host>127.0.0.1</host>
<port>5998</port>
<account></account>
<password></password>
</loginserver2>
\"loginserver1\" : {
\"account\" : \"\",
\"host\" : \"login.eqemulator.net\",
\"password\" : \"\",
\"port\" : \"5998\",
\"legacy\": \"1\"
},
\"loginserver2\" : {
\"account\" : \"\",
\"host\" : \"192.168.197.129\",
\"password\" : \"\",
\"port\" : \"5998\"
},
\"localaddress\" : \"192.168.197.129\",
";
print "[Install] When done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 127.0.0.1) in the eqhosts.txt file\n";
print "[Install] When done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 192.168.197.129) in the eqhosts.txt file\n";
}
}

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|
9138|2018_12_12_convert_to_client_functions.sql|SELECT `id` FROM `faction_list` WHERE `id` > 4999|empty|
9139|2019_03_25_optional_npc_model.sql|SHOW COLUMNS FROM `npc_types` LIKE 'model'|empty|
9140|2019_07_03_update_range.sql|SHOW COLUMNS FROM `npc_types` LIKE 'max_movement_update_range'|empty|
9140|2019_07_03_update_range.sql|SHOW COLUMNS FROM `zone` LIKE 'max_movement_update_range'|empty|
9141|2019_07_10_npc_flymode.sql|SHOW COLUMNS FROM `npc_types` LIKE 'flymode'|empty|
# Upgrade conditions:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -55,7 +55,6 @@ public:
ClientListEntry* FindCharacter(const char* name);
ClientListEntry* FindCLEByAccountID(uint32 iAccID);
ClientListEntry* FindCLEByCharacterID(uint32 iCharID);
ClientListEntry* FindCLEByLSID(uint32 iLSID);
ClientListEntry* GetCLE(uint32 iID);
void GetCLEIP(uint32 iIP);
uint32 GetCLEIPCount(uint32 iLSAccountID);
@ -65,6 +64,7 @@ public:
void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0);
void UpdateClientGuild(uint32 char_id, uint32 guild_id);
void RemoveCLEByLSID(uint32 iLSID);
bool IsAccountInGame(uint32 iLSID);
int GetClientCount();
void GetClients(const char *zone_name, std::vector<ClientListEntry *> &into);

View File

@ -108,19 +108,11 @@ void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p)
return;
}
if (RuleB(World, DisallowDuplicateAccountLogins)) {
auto cle = client_list.FindCLEByLSID(utwr->lsaccountid);
if (cle != nullptr) {
auto status = cle->GetOnline();
if (CLE_Status_Zoning == status || CLE_Status_InZone == status) {
utwrs->response = UserToWorldStatusAlreadyOnline;
SendPacket(&outpack);
return;
}
else {
//our existing cle is in a state we can login to, mark the old as stale and remove it.
client_list.RemoveCLEByLSID(utwr->lsaccountid);
}
if (RuleB(World, EnforceCharacterLimitAtLogin)) {
if (client_list.IsAccountInGame(utwr->lsaccountid)) {
utwrs->response = UserToWorldStatusAlreadyOnline;
SendPacket(&outpack);
return;
}
}

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)
{
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 UpdateUCSServerAvailable(bool ucss_available = true);
void WorldShutDown(uint32 time, uint32 interval);
void DropClient(uint32 lsid, ZoneServer *ignore_zoneserver);
ZoneServer* FindByPort(uint16 port);
ZoneServer* FindByID(uint32 ZoneID);

View File

@ -437,7 +437,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
if (cle == 0 || cle->Online() < CLE_Status_Zoning ||
if (cle == 0 || cle->Online() < CLE_Status::Zoning ||
(cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from);
@ -450,7 +450,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
sender->Server()->SendPacket(pack);
}
}
else if (cle->Online() == CLE_Status_Zoning) {
else if (cle->Online() == CLE_Status::Zoning) {
if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from);
if (cle->TellQueueFull()) {
@ -518,7 +518,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
ClientListEntry* cle = client_list.FindCharacter(svm->To);
if (!cle || (cle->Online() < CLE_Status_Zoning) || !cle->Server()) {
if (!cle || (cle->Online() < CLE_Status::Zoning) || !cle->Server()) {
zoneserver_list.SendEmoteMessage(svm->From, 0, 0, 0, "'%s is not online at this time'", svm->To);
@ -1457,6 +1457,7 @@ void ZoneServer::IncomingClient(Client* client) {
s->accid = client->GetAccountID();
s->admin = client->GetAdmin();
s->charid = client->GetCharID();
s->lsid = client->GetLSID();
if (client->GetCLE())
s->tellsoff = client->GetCLE()->TellsOff();
strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname));

View File

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

View File

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

View File

@ -371,9 +371,9 @@ public:
inline bool ClientDataLoaded() const { return client_data_loaded; }
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); }
inline void Kick() { client_state = CLIENT_KICKED; }
inline void Disconnect() { eqs->Close(); client_state = DISCONNECTED; }
inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); }
void Kick(const std::string &reason);
void WorldKick();
inline uint8 GetAnon() const { return m_pp.anon; }
inline PlayerProfile_Struct& GetPP() { return m_pp; }
@ -1309,6 +1309,9 @@ public:
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update);
glm::vec4 &GetLastPositionBeforeBulkUpdate();
protected:
friend class Mob;
void CalcItemBonuses(StatBonuses* newbon);
@ -1518,6 +1521,7 @@ private:
Timer forget_timer; // our 2 min everybody forgets you timer
Timer autosave_timer;
Timer client_scan_npc_aggro_timer;
Timer client_zone_wide_full_position_update_timer;
Timer tribute_timer;
Timer proximity_timer;
@ -1540,6 +1544,7 @@ private:
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
glm::vec3 m_Proximity;
glm::vec4 last_position_before_bulk_update;
void BulkSendInventoryItems();

View File

@ -60,6 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "water_map.h"
#include "worldserver.h"
#include "zone.h"
#include "mob_movement_manager.h"
#ifdef BOTS
#include "bot.h"
@ -805,6 +806,8 @@ void Client::CompleteConnect()
parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0);
SetLastPositionBeforeBulkUpdate(GetPosition());
/* This sub event is for if a player logs in for the first time since entering world. */
if (firstlogon == 1) {
parse->EventPlayer(EVENT_CONNECT, this, "", 0);
@ -1166,13 +1169,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
*/
Client* client = entity_list.GetClientByName(cze->char_name);
if (!zone->GetAuth(ip, cze->char_name, &WID, &account_id, &character_id, &admin, lskey, &tellsoff)) {
Log(Logs::General, Logs::Error, "GetAuth() returned false kicking client");
if (client != 0) {
Log(Logs::General, Logs::Client_Login, "%s failed zone auth check.", cze->char_name);
if (nullptr != client) {
client->Save();
client->Kick();
client->Kick("Failed auth check");
}
//ret = false; // TODO: Can we tell the client to get lost in a good way
client_state = CLIENT_KICKED;
return;
}
@ -1682,7 +1683,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
/**
* DevTools Load Settings
*/
if (Admin() >= 200) {
if (Admin() >= EQEmu::DevTools::GM_ACCOUNT_STATUS_LEVEL) {
std::string dev_tools_window_key = StringFormat("%i-dev-tools-window-disabled", AccountID());
if (DataBucket::GetData(dev_tools_window_key) == "true") {
dev_tools_window_enabled = false;
@ -4467,16 +4468,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
/* Handle client aggro scanning timers NPCs */
is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true;
if (is_client_moving) {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() > 1000) {
client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(500);
}
} else {
}
else {
Log(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u",
client_scan_npc_aggro_timer.GetDuration());
if (client_scan_npc_aggro_timer.GetDuration() < 1000) {
@ -4484,7 +4485,51 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
client_scan_npc_aggro_timer.Start(3000);
}
}
/**
* On a normal basis we limit mob movement updates based on distance
* This ensures we send a periodic full zone update to a client that has started moving after 5 or so minutes
*
* For very large zones we will also force a full update based on distance
*
* We ignore a small distance around us so that we don't interrupt already pathing deltas as those npcs will appear
* to full stop when they are actually still pathing
*/
float distance_moved = DistanceNoZ(GetLastPositionBeforeBulkUpdate(), GetPosition());
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
bool is_ready_to_update = (
client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
);
if (is_client_moving && is_ready_to_update) {
Log(Logs::Detail, Logs::Normal, "[%s] Client Zone Wide Position Update NPCs", GetCleanName());
auto &mob_movement_manager = MobMovementManager::Get();
auto &mob_list = entity_list.GetMobList();
for (auto &it : mob_list) {
Mob *entity = it.second;
if (!entity->IsNPC()) {
continue;
}
int animation_speed = 0;
if (entity->IsMoving()) {
if (entity->IsRunning()) {
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
}
else {
animation_speed = entity->GetWalkspeed();
}
}
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
}
SetLastPositionBeforeBulkUpdate(GetPosition());
}
float new_heading = EQ12toFloat(ppu->heading);
int32 new_animation = ppu->animation;
@ -9757,7 +9802,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
casting_spell_id);
database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
safe_delete_array(detect);
Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots
Kick("Inventory desync"); // Kick client to prevent client and server from getting out-of-sync inventory slots
return;
}
}
@ -9801,7 +9846,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
{
Kick(); // TODO: lets not desync though
Kick("Unimplemented move multiple items"); // TODO: lets not desync though
}
void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)

View File

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

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

View File

@ -1713,6 +1713,18 @@ Client *EntityList::GetClientByWID(uint32 iWID)
return nullptr;
}
Client *EntityList::GetClientByLSID(uint32 iLSID)
{
auto it = client_list.begin();
while (it != client_list.end()) {
if (it->second->LSAccountID() == iLSID) {
return it->second;
}
++it;
}
return nullptr;
}
Client *EntityList::GetRandomClient(const glm::vec3& location, float Distance, Client *ExcludeClient)
{
std::vector<Client *> ClientsInRange;

View File

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

View File

@ -1608,7 +1608,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
banker ? banker->GetName() : "UNKNOWN NPC", distance);
database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName());
safe_delete_array(hacked_string);
Kick(); // Kicking player to avoid item loss do to client and server inventories not being sync'd
Kick("Inventory desync"); // Kicking player to avoid item loss do to client and server inventories not being sync'd
return false;
}
}
@ -1822,7 +1822,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Step 4: Check for entity trade
if (dst_slot_id >= EQEmu::invslot::TRADE_BEGIN && dst_slot_id <= EQEmu::invslot::TRADE_END) {
if (src_slot_id != EQEmu::invslot::slotCursor) {
Kick();
Kick("Trade with non-cursor item");
return false;
}
if (with) {

View File

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

View File

@ -1128,7 +1128,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
UpdateActiveLight();
ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive];
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
if (IsNPC() && race == ERUDITE)
ns->spawn.showhelm = 1;
else
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
ns->spawn.NPC = IsClient() ? 0 : 1;

File diff suppressed because it is too large Load Diff

View File

@ -41,18 +41,29 @@ class MobMovementManager
public:
~MobMovementManager();
void Process();
void AddMob(Mob *m);
void RemoveMob(Mob *m);
void AddClient(Client *c);
void RemoveClient(Client *c);
void AddMob(Mob *mob);
void RemoveMob(Mob *mob);
void AddClient(Client *client);
void RemoveClient(Client *client);
void RotateTo(Mob *who, float to, MobMovementMode mode = MovementRunning);
void RotateTo(Mob *who, float to, MobMovementMode mob_movement_mode = MovementRunning);
void Teleport(Mob *who, float x, float y, float z, float heading);
void NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning);
void StopNavigation(Mob *who);
void SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range);
void SendCommandToClients(
Mob *mob,
float delta_x,
float delta_y,
float delta_z,
float delta_heading,
int anim,
ClientRange range,
Client* single_client = nullptr
);
float FixHeading(float in);
void DumpStats(Client *to);
void DumpStats(Client *client);
void ClearStats();
static MobMovementManager &Get() {
@ -65,18 +76,18 @@ private:
MobMovementManager(const MobMovementManager&);
MobMovementManager& operator=(const MobMovementManager&);
void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim);
void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode);
void FillCommandStruct(PlayerPositionUpdateServer_Struct *position_update, Mob *mob, float delta_x, float delta_y, float delta_z, float delta_heading, int anim);
void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode);
void UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode);
void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode mode);
void UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode movement_mode);
void UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode);
void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading);
void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode);
void PushStopMoving(MobMovementEntry &ent);
void PushEvadeCombat(MobMovementEntry &ent);
void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mode);
void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
void PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode);
void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode);
void PushStopMoving(MobMovementEntry &mob_movement_entry);
void PushEvadeCombat(MobMovementEntry &mob_movement_entry);
void HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode);
struct Implementation;
std::unique_ptr<Implementation> _impl;

View File

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

View File

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

View File

@ -298,7 +298,8 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
if(IsClient()) {
char temp[64];
sprintf(temp, "%d", spell_id);
parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), temp, 0);
if (parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), temp, 0) != 0)
return false;
} else if(IsNPC()) {
char temp[64];
sprintf(temp, "%d", spell_id);

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)
if (stack_size > 0) {
if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) {
client->Kick();
client->Kick("Error stacking item in trade");
return;
}
@ -138,7 +138,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
}
else {
if (inst2 && inst2->GetID()) {
client->Kick();
client->Kick("Attempting to add null item to trade");
return;
}

View File

@ -534,7 +534,15 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*)pack->pBuffer;
if (is_zone_loaded) {
SetZoneData(zone->GetZoneID(), zone->GetInstanceID());
if (szic->zoneid == zone->GetZoneID()) {
auto client = entity_list.GetClientByLSID(szic->lsid);
if (client) {
client->Kick("Dropped by world CLE subsystem");
client->Save();
}
zone->RemoveAuth(szic->lsid);
zone->AddAuth(szic);
// This packet also doubles as "incoming client" notification, lets not shut down before they get here
zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000);
@ -547,6 +555,23 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
break;
}
case ServerOP_DropClient: {
if (pack->size != sizeof(ServerZoneDropClient_Struct)) {
break;
}
ServerZoneDropClient_Struct* drop = (ServerZoneDropClient_Struct*)pack->pBuffer;
if (zone) {
zone->RemoveAuth(drop->lsid);
auto client = entity_list.GetClientByLSID(drop->lsid);
if (client) {
client->Kick("Dropped by world CLE subsystem");
client->Save();
}
}
break;
}
case ServerOP_ZonePlayer: {
ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(szp->name);

View File

@ -55,6 +55,7 @@
#include "zone_config.h"
#include "mob_movement_manager.h"
#include "npc_scale_manager.h"
#include "../common/data_verification.h"
#include <time.h>
#include <ctime>
@ -864,6 +865,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
m_last_ucss_update = 0;
mMovementManager = &MobMovementManager::Get();
SetNpcPositionUpdateDistance(0);
}
Zone::~Zone() {
@ -1106,6 +1109,7 @@ void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) {
zca->accid = szic->accid;
zca->admin = szic->admin;
zca->charid = szic->charid;
zca->lsid = szic->lsid;
zca->tellsoff = szic->tellsoff;
strn0cpy(zca->charname, szic->charname, sizeof(zca->charname));
strn0cpy(zca->lskey, szic->lskey, sizeof(zca->lskey));
@ -1113,16 +1117,31 @@ void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) {
client_auth_list.Insert(zca);
}
void Zone::RemoveAuth(const char* iCharName)
void Zone::RemoveAuth(const char* iCharName, const char* iLSKey)
{
LinkedListIterator<ZoneClientAuth_Struct*> iterator(client_auth_list);
iterator.Reset();
while (iterator.MoreElements()) {
ZoneClientAuth_Struct* zca = iterator.GetData();
if (strcasecmp(zca->charname, iCharName) == 0) {
iterator.RemoveCurrent();
return;
if (strcasecmp(zca->charname, iCharName) == 0 && strcasecmp(zca->lskey, iLSKey) == 0) {
iterator.RemoveCurrent();
return;
}
iterator.Advance();
}
}
void Zone::RemoveAuth(uint32 lsid)
{
LinkedListIterator<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();
}
@ -1178,9 +1197,9 @@ uint32 Zone::CountAuth() {
bool Zone::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();
@ -1196,10 +1215,15 @@ bool Zone::Process() {
}
}
if(adv_data && !did_adventure_actions)
if (adv_data && !did_adventure_actions) {
DoAdventureActions();
}
if (GetNpcPositionUpdateDistance() == 0) {
CalculateNpcUpdateDistanceSpread();
}
}
if(initgrids_timer.Check()) {
//delayed grid loading stuff.
initgrids_timer.Disable();
@ -2349,3 +2373,59 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
if (m_last_ucss_update < update_timestamp)
m_ucss_available = ucss_available;
}
int Zone::GetNpcPositionUpdateDistance() const
{
return npc_position_update_distance;
}
void Zone::SetNpcPositionUpdateDistance(int in_npc_position_update_distance)
{
Zone::npc_position_update_distance = in_npc_position_update_distance;
}
void Zone::CalculateNpcUpdateDistanceSpread()
{
float max_x = 0;
float max_y = 0;
float min_x = 0;
float min_y = 0;
auto &mob_list = entity_list.GetMobList();
for (auto &it : mob_list) {
Mob *entity = it.second;
if (!entity->IsNPC()) {
continue;
}
if (entity->GetX() <= min_x) {
min_x = entity->GetX();
}
if (entity->GetY() <= min_y) {
min_y = entity->GetY();
}
if (entity->GetX() >= max_x) {
max_x = entity->GetX();
}
if (entity->GetY() >= max_y) {
max_y = entity->GetY();
}
}
int x_spread = int(abs(max_x - min_x));
int y_spread = int(abs(max_y - min_y));
int combined_spread = int(abs((x_spread + y_spread) / 2));
int update_distance = EQEmu::ClampLower(int(combined_spread / 4), int(zone->GetMaxMovementUpdateRange()));
SetNpcPositionUpdateDistance(update_distance);
Log(Logs::General, Logs::Debug,
"NPC update spread distance set to [%i] combined_spread [%i]",
update_distance,
combined_spread
);
}

View File

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