Compare commits

...

41 Commits

Author SHA1 Message Date
KimLS a65d8836af Task scheduler test 2019-08-04 20:12:22 -07:00
Chris Miles f5cfec529e Fix format ordering 2019-08-03 04:10:40 -05:00
Chris Miles 9d9374ec19 Fix #gmzone <zonename> <version> to actually create bucket flags via version 2019-08-03 01:32:56 -05:00
Chris Miles 979c819075 Update README.md 2019-07-29 17:28:58 -05:00
Uleat ff4e549ec0 Fix for cmake 'zlib not found' defaulting to internal libs not working issue [skip ci] 2019-07-26 18:20:01 -04:00
KimLS a8ec176432 Merge branch 'master' of github.com:EQEmu/Server 2019-07-25 22:27:11 -07:00
KimLS 212f8a3062 Minor fixes to CLE stale system 2019-07-25 22:26:56 -07:00
Uleat cca5fe3286 Fix for multiple-argument with explicit token use in 'vcxproj_dependencies' [skip ci] 2019-07-25 19:55:42 -04:00
Uleat 9ac15d7a4b Fix for false elevation of priority in 'vcxproj_dependencies' [skip ci] 2019-07-24 22:48:51 -04:00
KimLS 23a187f6c1 Merge branch 'master' of github.com:EQEmu/Server 2019-07-24 19:20:24 -07:00
KimLS f3255c17da Changes to cle enums, characters will now auto kick on login instead of making you wait at world unless you specifically turn that feature on in the rules. 2019-07-24 19:20:09 -07:00
Uleat 90eb9e9da2 Some more mods and tweaks to 'vcxproj_dependencies' [skip ci] 2019-07-24 21:59:57 -04:00
KimLS ffb5b2393f Merge branch 'master' of github.com:EQEmu/Server 2019-07-23 21:59:32 -07:00
KimLS cd32a5a47a Make the reconnect code only trigger when there's actually a client IN ZONE and try to clean up otherwise 2019-07-23 21:59:22 -07:00
Uleat debc2644b1 Tweaked CMakeLists.txt so CMake will play nicer with 'vcpkg' dependencies [skip ci] 2019-07-23 21:11:30 -04:00
Chris Miles 9c9615e8bb Fix the manifest [skip ci] 2019-07-23 19:06:11 -05:00
Uleat 53ec007459 Fixes and tweaks for 'vcxproj' script [skip ci] (zlib still needs some work) 2019-07-23 19:34:35 -04:00
Uleat f5da6e18fc Changed 'vcxproj_dependencies.py' script criteria to allow zero-length pretext headers in multiple-argument hints [skip ci] 2019-07-22 23:27:38 -04:00
Uleat 72ae1b0e0b Added 'vcxproj_dependencies.py' 2019-07-22 23:05:33 -04:00
KimLS 780f8f8515 Mark old cle entries as stale when you login 2019-07-20 22:12:48 -07:00
Michael Cook (mackal) 186834594f Merge pull request #871 from EQEmu/fix_OP_SpecialMesg
Fix issues with OP_SpecialMesg handling
2019-07-20 01:46:53 -04:00
Michael Cook (mackal) f4310c5a06 Merge branch 'master' into fix_OP_SpecialMesg 2019-07-20 01:27:37 -04:00
Chris Miles 4d77ba28fe Merge pull request #872 from regneq/master
added language paramter to Lua_Mob::Say() and Lua_Mob::Shout() (credi…
2019-07-19 22:08:46 -07:00
Michael Cook (mackal) 222fd060a3 Change lua constants to be less ugly 2019-07-19 13:04:27 -04:00
regneq 31d0adbacc added language paramter to Lua_Mob::Say() and Lua_Mob::Shout() (credit to Torven) 2019-07-18 18:20:22 -07:00
Michael Cook (mackal) 9fe17f4d46 Fix issues with OP_SpecialMesg handling
This should prevent any optimizations being done on the "1 char string"

This also fully documents the packet and expands the uses of
quest::say/QuestSay
2019-07-18 00:56:46 -04:00
Michael Cook (mackal) 16d6014a87 Merge pull request #859 from eqft/feature/rule_for_gm_level_cmd_with_target
Convert constant check in level_command() to a Rule
2019-07-16 13:43:02 -04:00
Michael Cook (mackal) 7801b295d6 Merge pull request #869 from regneq/master
added variable to chatchannels as well as various changed to chatchannel and using language / language skills d…
2019-07-16 13:39:33 -04:00
regneq 460468224e various changed to chatchannel and using language / language skills derived from takp code. 2019-07-14 20:03:30 -07:00
KimLS 6bdc9b6ba5 Add support for single account login to both world and login server, should also work with eqemu login server, can be turned off in rules if you don't mind the side effects double logins cause. Also lowered the linkdead time to 30s + 90s default (2min) 2019-07-13 16:16:15 -07:00
Uleat 7181b46608 Merge branch 'master' of https://github.com/EQEmu/Server 2019-07-13 00:44:09 -04:00
Uleat eb8cd1a5b4 Fix for build zlib option when not using vcpkg 2019-07-13 00:43:56 -04:00
Chris Miles a8e65cdce1 Merge pull request #826 from livermana/master
fix for mob movement getting 'stuck' when paths don't have updated lo…
2019-07-11 18:41:50 -05:00
Michael Cook (mackal) 1ba78d0988 Switch to char_traits::length in SerializeBuffer
This benches a bit faster
2019-07-10 14:33:33 -04:00
Akkadius 35eb5b24dd Implement flymode 2019-07-10 03:39:07 -05:00
Michael Cook (mackal) dfa90aaac5 Fix OP_SpecialMesg encoding
This broke with newer GCCs. It also worked even though the code was just
wrong before???
2019-07-10 01:44:59 -04:00
Michael Cook (mackal) 525813be02 Adjust VARSTRUCT_ENCODE_STRING macros for smarter compilers
This is no more dangerous than what we were doing before (not checking
return value of sprintf) Maybe we should sometime
2019-07-10 01:20:51 -04:00
Uleat 87b1d32ce8 Updated PerlembParser::ExportItemVariables to new inventory standard 2019-07-08 21:58:47 -04:00
Justin Wienckowski 5fdf976137 Add an optional SQL to add the new rule to the rule_values table. Default value is unchanged. 2019-06-21 20:02:42 -07:00
Justin Wienckowski 6a31af81ee Add GM:MinStatusToLevelTarget rule, which determines the GM status needed to use the #level command on your target. 2019-06-16 00:43:18 -07:00
adam 7a28a6e9a7 fix for mob movement getting 'stuck' when paths don't have updated locations. 2019-02-22 19:17:09 -05:00
70 changed files with 1945 additions and 750 deletions
+37 -29
View File
@@ -26,6 +26,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)
@@ -57,33 +59,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)
@@ -290,14 +296,14 @@ ADD_DEFINITIONS(-DGLM_FORCE_CTOR_INIT)
ADD_DEFINITIONS(-DGLM_ENABLE_EXPERIMENTAL)
#Find everything we need
FIND_PACKAGE(ZLIB REQUIRED)
FIND_PACKAGE(ZLIB)
FIND_PACKAGE(MySQL REQUIRED)
IF(EQEMU_BUILD_PERL)
FIND_PACKAGE(PerlLibs REQUIRED)
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
ENDIF(EQEMU_BUILD_PERL)
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} uv_a fmt RecastNavigation::Detour)
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} uv_a fmt RecastNavigation::Detour)
FIND_PACKAGE(Sodium REQUIRED)
IF(SODIUM_FOUND)
@@ -313,14 +319,16 @@ IF(ZLIB_FOUND)
OPTION(EQEMU_BUILD_ZLIB "Build internal version of zlib." OFF)
IF(EQEMU_BUILD_ZLIB)
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
INCLUDE_DIRECTORIES(BEFORE SYSTEM "${CMAKE_CURRENT_BINARY_DIR}/libs/zlibng" "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
SET(SERVER_LIBS ${SERVER_LIBS} "zlibstatic")
ELSE()
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
SET(SERVER_LIBS ${SERVER_LIBS} ${ZLIB_LIBRARY})
ENDIF()
ELSE()
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/zlibng")
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()
+6
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>
+8
View File
@@ -1,5 +1,13 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 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]
Akkadius: Added "flymode" to npc_types database table
== 7/3/2019 ==
Akkadius/KLS:
+1
View File
@@ -213,6 +213,7 @@ SET(common_headers
zone_numbers.h
event/event_loop.h
event/task.h
event/task_scheduler.h
event/timer.h
json/json.h
json/json-forwards.h
+1
View File
@@ -75,6 +75,7 @@ public:
uint32 ReadUInt32() { uint32 value = *(uint32 *)(pBuffer + _rpos); _rpos += sizeof(uint32); return value; }
uint32 ReadUInt32(uint32 Offset) const { uint32 value = *(uint32 *)(pBuffer + Offset); return value; }
void ReadString(char *str) { uint32 len = static_cast<uint32>(strlen((char *)(pBuffer + _rpos))) + 1; memcpy(str, pBuffer + _rpos, len); _rpos += len; }
void ReadString(std::string &str) { str = reinterpret_cast<char *>(pBuffer + _rpos); _rpos += str.length() + 1; }
void ReadString(char *str, uint32 Offset, uint32 MaxLength) const;
uint32 GetWritePosition() { return _wpos; }
+22
View File
@@ -87,6 +87,7 @@ typedef enum {
_eaMaxAppearance
} EmuAppearance;
#define MT_NPCQuestSay 10
// msg_type's for custom usercolors
#define MT_Say 256
#define MT_Tell 257
@@ -523,4 +524,25 @@ static const uint8 SkillDamageTypes[EQEmu::skills::HIGHEST_SKILL + 1] = // chang
static const uint32 MAX_SPELL_DB_ID_VAL = 65535;
enum ChatChannelNames : uint16
{
ChatChannel_Guild = 0,
ChatChannel_Group = 2,
ChatChannel_Shout = 3,
ChatChannel_Auction = 4,
ChatChannel_OOC = 5,
ChatChannel_Broadcast = 6,
ChatChannel_Tell = 7,
ChatChannel_Say = 8,
ChatChannel_Petition = 10,
ChatChannel_GMSAY = 11,
ChatChannel_TellEcho = 14,
ChatChannel_Raid = 15,
ChatChannel_UNKNOWN_Guild = 17,
ChatChannel_UNKNOWN_GMSAY = 18,
ChatChannel_UCSRelay = 20,
ChatChannel_Emotes = 22
};
#endif /*COMMON_EQ_CONSTANTS_H*/
+14
View File
@@ -1188,6 +1188,20 @@ struct SpecialMesg_Struct
/*24*/ char message[1]; // What is being said?
};
struct SpecialMesgHeader_Struct
{
/*00*/ char SpeakMode; // 2 shouts, 4 %1 %2, 3 %2, 5 tells group, 0 copy, default says
/*01*/ char JournalMode; // 1 and 2 go to journal
/*02*/ char language;
/*03*/ uint32 msg_type; // Color of text (see MT_*** below)
/*07*/ uint32 target_spawn_id; // Who is it being said to?
/*11*/ // speaker's name
/*xx*/ // unknown, location, client doesn't care
/*xx*/ // unknown
/*xx*/ // unknown
/*xx*/ // message
};
/*
** When somebody changes what they're wearing or give a pet a weapon (model changes)
** Length: 19 Bytes
+114
View File
@@ -0,0 +1,114 @@
#pragma once
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <queue>
#include <future>
namespace EQ
{
namespace Event
{
class TaskScheduler
{
public:
static const int DefaultThreadCount = 4;
TaskScheduler() : _running(false)
{
Start(DefaultThreadCount);
}
TaskScheduler(size_t threads) : _running(false)
{
Start(threads);
}
~TaskScheduler() {
Stop();
}
void Start(size_t threads) {
if (true == _running) {
return;
}
_running = true;
for (size_t i = 0; i < threads; ++i) {
_threads.push_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
}
}
void Stop() {
if (false == _running) {
return;
}
{
std::unique_lock<std::mutex> lock(_lock);
_running = false;
}
_cv.notify_all();
for (auto &t : _threads) {
t.join();
}
}
template<typename Fn, typename... Args>
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::result_of<Fn(Args...)>::type> {
using return_type = typename std::result_of<Fn(Args...)>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(_lock);
if (false == _running) {
throw std::runtime_error("Enqueue on stopped scheduler.");
}
_tasks.emplace([task]() { (*task)(); });
}
_cv.notify_one();
return res;
}
private:
void ProcessWork() {
for (;;) {
std::function<void()> work;
{
std::unique_lock<std::mutex> lock(_lock);
_cv.wait(lock, [this] { return !_running || !_tasks.empty(); });
if (false == _running) {
return;
}
work = std::move(_tasks.front());
_tasks.pop();
}
work();
}
}
bool _running = true;
std::vector<std::thread> _threads;
std::mutex _lock;
std::condition_variable _cv;
std::queue<std::function<void()>> _tasks;
};
}
}
+2 -2
View File
@@ -32,8 +32,8 @@
//
#define VARSTRUCT_DECODE_TYPE(Type, Buffer) *(Type *)Buffer; Buffer += sizeof(Type);
#define VARSTRUCT_DECODE_STRING(String, Buffer) strcpy(String, Buffer); Buffer += strlen(String)+1;
#define VARSTRUCT_ENCODE_STRING(Buffer, String) { sprintf(Buffer, "%s", String); Buffer += strlen(String) + 1; }
#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) { sprintf(Buffer, "%i", Number); Buffer += strlen(Buffer) + 1; }
#define VARSTRUCT_ENCODE_STRING(Buffer, String) { int length = sprintf(Buffer, "%s", String); Buffer += length + 1; }
#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) { int length = sprintf(Buffer, "%i", Number); Buffer += length + 1; }
#define VARSTRUCT_ENCODE_TYPE(Type, Buffer, Value) { *(Type *)Buffer = Value; Buffer += sizeof(Type); }
#define VARSTRUCT_SKIP_TYPE(Type, Buffer) Buffer += sizeof(Type);
+2 -2
View File
@@ -257,7 +257,7 @@ namespace EQ
resend_delay_min = 150;
resend_delay_max = 5000;
connect_delay_ms = 500;
stale_connection_ms = 90000;
stale_connection_ms = 30000;
connect_stale_ms = 5000;
crc_length = 2;
max_packet_size = 512;
@@ -269,7 +269,7 @@ namespace EQ
simulated_in_packet_loss = 0;
simulated_out_packet_loss = 0;
tic_rate_hertz = 60.0;
resend_timeout = 90000;
resend_timeout = 30000;
connection_close_time = 2000;
outgoing_data_rate = 0.0;
}
+21 -33
View File
@@ -3199,47 +3199,35 @@ namespace RoF
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
SerializeBuffer buf(in->size);
buf.WriteInt8(in->ReadUInt8()); // speak mode
buf.WriteInt8(in->ReadUInt8()); // journal mode
buf.WriteInt8(in->ReadUInt8()); // language
buf.WriteInt32(in->ReadUInt32()); // message type
buf.WriteInt32(in->ReadUInt32()); // target spawn id
unsigned char *__emu_buffer = in->pBuffer;
std::string name;
in->ReadString(name); // NPC names max out at 63 chars
std::string old_message = &emu->message[strlen(emu->sayer)];
buf.WriteString(name);
buf.WriteInt32(in->ReadUInt32()); // loc
buf.WriteInt32(in->ReadUInt32());
buf.WriteInt32(in->ReadUInt32());
std::string old_message;
std::string new_message;
in->ReadString(old_message);
ServerToRoFSayLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = strlen(emu->sayer) + new_message.length() + 25;
in->pBuffer = new unsigned char[in->size];
buf.WriteString(new_message);
char *OutBuffer = (char *)in->pBuffer;
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
dest->FastQueuePacket(&outapp, ack_req);
delete in;
}
ENCODE(OP_Stun)
+21 -33
View File
@@ -3266,47 +3266,35 @@ namespace RoF2
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
SerializeBuffer buf(in->size);
buf.WriteInt8(in->ReadUInt8()); // speak mode
buf.WriteInt8(in->ReadUInt8()); // journal mode
buf.WriteInt8(in->ReadUInt8()); // language
buf.WriteInt32(in->ReadUInt32()); // message type
buf.WriteInt32(in->ReadUInt32()); // target spawn id
unsigned char *__emu_buffer = in->pBuffer;
std::string name;
in->ReadString(name); // NPC names max out at 63 chars
std::string old_message = &emu->message[strlen(emu->sayer)];
buf.WriteString(name);
buf.WriteInt32(in->ReadUInt32()); // loc
buf.WriteInt32(in->ReadUInt32());
buf.WriteInt32(in->ReadUInt32());
std::string old_message;
std::string new_message;
in->ReadString(old_message);
ServerToRoF2SayLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = strlen(emu->sayer) + new_message.length() + 25;
in->pBuffer = new unsigned char[in->size];
buf.WriteString(new_message);
char *OutBuffer = (char *)in->pBuffer;
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
dest->FastQueuePacket(&outapp, ack_req);
delete in;
}
ENCODE(OP_Stun)
+21 -33
View File
@@ -2069,47 +2069,35 @@ namespace SoD
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
SerializeBuffer buf(in->size);
buf.WriteInt8(in->ReadUInt8()); // speak mode
buf.WriteInt8(in->ReadUInt8()); // journal mode
buf.WriteInt8(in->ReadUInt8()); // language
buf.WriteInt32(in->ReadUInt32()); // message type
buf.WriteInt32(in->ReadUInt32()); // target spawn id
unsigned char *__emu_buffer = in->pBuffer;
std::string name;
in->ReadString(name); // NPC names max out at 63 chars
std::string old_message = &emu->message[strlen(emu->sayer)];
buf.WriteString(name);
buf.WriteInt32(in->ReadUInt32()); // loc
buf.WriteInt32(in->ReadUInt32());
buf.WriteInt32(in->ReadUInt32());
std::string old_message;
std::string new_message;
in->ReadString(old_message);
ServerToSoDSayLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = strlen(emu->sayer) + new_message.length() + 25;
in->pBuffer = new unsigned char[in->size];
buf.WriteString(new_message);
char *OutBuffer = (char *)in->pBuffer;
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
dest->FastQueuePacket(&outapp, ack_req);
delete in;
}
ENCODE(OP_Stun)
+21 -33
View File
@@ -1720,47 +1720,35 @@ namespace SoF
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
SerializeBuffer buf(in->size);
buf.WriteInt8(in->ReadUInt8()); // speak mode
buf.WriteInt8(in->ReadUInt8()); // journal mode
buf.WriteInt8(in->ReadUInt8()); // language
buf.WriteInt32(in->ReadUInt32()); // message type
buf.WriteInt32(in->ReadUInt32()); // target spawn id
unsigned char *__emu_buffer = in->pBuffer;
std::string name;
in->ReadString(name);
std::string old_message = &emu->message[strlen(emu->sayer)];
buf.WriteString(name);
buf.WriteInt32(in->ReadUInt32()); // loc
buf.WriteInt32(in->ReadUInt32());
buf.WriteInt32(in->ReadUInt32());
std::string old_message;
std::string new_message;
in->ReadString(old_message);
ServerToSoFSayLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = strlen(emu->sayer) + new_message.length() + 25;
in->pBuffer = new unsigned char[in->size];
buf.WriteString(new_message);
char *OutBuffer = (char *)in->pBuffer;
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
dest->FastQueuePacket(&outapp, ack_req);
delete in;
}
ENCODE(OP_Stun)
+21 -33
View File
@@ -1420,47 +1420,35 @@ namespace Titanium
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
SerializeBuffer buf(in->size);
buf.WriteInt8(in->ReadUInt8()); // speak mode
buf.WriteInt8(in->ReadUInt8()); // journal mode
buf.WriteInt8(in->ReadUInt8()); // language
buf.WriteInt32(in->ReadUInt32()); // message type
buf.WriteInt32(in->ReadUInt32()); // target spawn id
unsigned char *__emu_buffer = in->pBuffer;
std::string name;
in->ReadString(name); // NPC names max out at 63 chars
std::string old_message = &emu->message[strlen(emu->sayer)];
buf.WriteString(name);
buf.WriteInt32(in->ReadUInt32()); // loc
buf.WriteInt32(in->ReadUInt32());
buf.WriteInt32(in->ReadUInt32());
std::string old_message;
std::string new_message;
in->ReadString(old_message);
ServerToTitaniumSayLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = strlen(emu->sayer) + new_message.length() + 25;
in->pBuffer = new unsigned char[in->size];
buf.WriteString(new_message);
char *OutBuffer = (char *)in->pBuffer;
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
dest->FastQueuePacket(&outapp, ack_req);
delete in;
}
ENCODE(OP_TaskDescription)
+21 -33
View File
@@ -2369,47 +2369,35 @@ namespace UF
EQApplicationPacket *in = *p;
*p = nullptr;
SpecialMesg_Struct *emu = (SpecialMesg_Struct *)in->pBuffer;
SerializeBuffer buf(in->size);
buf.WriteInt8(in->ReadUInt8()); // speak mode
buf.WriteInt8(in->ReadUInt8()); // journal mode
buf.WriteInt8(in->ReadUInt8()); // language
buf.WriteInt32(in->ReadUInt32()); // message type
buf.WriteInt32(in->ReadUInt32()); // target spawn id
unsigned char *__emu_buffer = in->pBuffer;
std::string name;
in->ReadString(name); // NPC names max out at 63 chars
std::string old_message = &emu->message[strlen(emu->sayer)];
buf.WriteString(name);
buf.WriteInt32(in->ReadUInt32()); // loc
buf.WriteInt32(in->ReadUInt32());
buf.WriteInt32(in->ReadUInt32());
std::string old_message;
std::string new_message;
in->ReadString(old_message);
ServerToUFSayLink(new_message, old_message);
//in->size = 3 + 4 + 4 + strlen(emu->sayer) + 1 + 12 + new_message.length() + 1;
in->size = strlen(emu->sayer) + new_message.length() + 25;
in->pBuffer = new unsigned char[in->size];
buf.WriteString(new_message);
char *OutBuffer = (char *)in->pBuffer;
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->header[2]);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->msg_type);
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->target_spawn_id);
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sayer);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[0]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[1]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[2]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[3]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[4]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[5]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[6]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[7]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[8]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[9]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[10]);
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]);
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
delete[] __emu_buffer;
dest->FastQueuePacket(&in, ack_req);
dest->FastQueuePacket(&outapp, ack_req);
delete in;
}
ENCODE(OP_Stun)
+3 -3
View File
@@ -205,6 +205,7 @@ RULE_CATEGORY_END()
RULE_CATEGORY(GM)
RULE_INT(GM, MinStatusToSummonItem, 250)
RULE_INT(GM, MinStatusToZoneAnywhere, 250)
RULE_INT(GM, MinStatusToLevelTarget, 100)
RULE_CATEGORY_END()
RULE_CATEGORY(World)
@@ -225,8 +226,6 @@ RULE_BOOL(World, MaxClientsSetByStatus, false) // If True, IP Limiting will be s
RULE_BOOL(World, EnableIPExemptions, false) // If True, ip_exemptions table is used, if there is no entry for the IP it will default to RuleI(World, MaxClientsPerIP)
RULE_BOOL(World, ClearTempMerchantlist, true) // Clears temp merchant items when world boots.
RULE_BOOL(World, DeleteStaleCorpeBackups, true) // Deletes stale corpse backups older than 2 weeks.
RULE_INT(World, AccountSessionLimit, -1) //Max number of characters allowed on at once from a single account (-1 is disabled)
RULE_INT(World, ExemptAccountLimitStatus, -1) //Min status required to be exempt from multi-session per account limiting (-1 is disabled)
RULE_BOOL(World, GMAccountIPList, false) // Check ip list against GM Accounts, AntiHack GM Accounts.
RULE_INT(World, MinGMAntiHackStatus, 1) //Minimum GM status to check against AntiHack list
RULE_INT(World, SoFStartZoneID, -1) //Sets the Starting Zone for SoF Clients separate from Titanium Clients (-1 is disabled)
@@ -241,10 +240,11 @@ RULE_BOOL (World, IPLimitDisconnectAll, false)
RULE_BOOL(World, MaxClientsSimplifiedLogic, false) // New logic that only uses ExemptMaxClientsStatus and MaxClientsPerIP. Done on the loginserver. This mimics the P99-style special IP rules.
RULE_INT (World, TellQueueSize, 20)
RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone ALWAYS be the same location as your bind?
RULE_BOOL(World, EnforceCharacterLimitAtLogin, false)
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
RULE_INT(Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection
RULE_INT(Zone, ClientLinkdeadMS, 90000) //the time a client remains link dead on the server after a sudden disconnection
RULE_INT(Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone
RULE_BOOL(Zone, EnableShadowrest, 1) // enables or disables the shadowrest zone feature for player corpses. Default is turned on.
RULE_BOOL(Zone, UsePlayerCorpseBackups, true) // Keeps backups of player corpses.
+1 -1
View File
@@ -143,7 +143,7 @@ public:
void WriteString(const char *str)
{
assert(str != nullptr);
auto len = strlen(str) + 1;
auto len = std::char_traits<char>::length(str) + 1;
if (m_pos + len > m_capacity)
Grow(m_capacity + len);
memcpy(m_buffer + m_pos, str, len);
+20 -1
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
@@ -213,6 +214,15 @@ enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_
#define ServerOP_Speech 0x4513
enum {
UserToWorldStatusWorldUnavail = 0,
UserToWorldStatusSuccess = 1,
UserToWorldStatusSuspended = -1,
UserToWorldStatusBanned = -2,
UserToWorldStatusWorldAtCapacity = -3,
UserToWorldStatusAlreadyOnline = -4
};
/************ PACKET RELATED STRUCT ************/
class ServerPacket
{
@@ -308,11 +318,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;
@@ -343,7 +359,8 @@ struct ServerChannelMessage_Struct {
bool noreply;
uint16 chan_num;
uint32 guilddbid;
uint16 language;
uint8 language;
uint8 lang_skill;
uint8 queued; // 0 = not queued, 1 = queued, 2 = queue full, 3 = offline
char message[0];
};
@@ -856,6 +873,8 @@ struct ServerRaidGroupAction_Struct { //add / remove depends on opcode.
struct ServerRaidMessage_Struct {
uint32 rid;
uint32 gid;
uint8 language;
uint8 lang_skill;
char from[64];
char message[0];
};
+1 -1
View File
@@ -31,7 +31,7 @@
*/
#define CURRENT_BINARY_DATABASE_VERSION 9140
#define CURRENT_BINARY_DATABASE_VERSION 9141
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9024
+1 -1
View File
@@ -861,5 +861,5 @@ if (ZLIB_ENABLE_TESTS)
endif()
endif()
FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES)
# FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES)
+11 -6
View File
@@ -165,21 +165,26 @@ void WorldServer::ProcessUsertoWorldResp(uint16_t opcode, const EQ::Net::Packet
switch (utwr->response)
{
case 1:
case UserToWorldStatusSuccess:
per->Message = 101;
break;
case 0:
case UserToWorldStatusWorldUnavail:
per->Message = 326;
break;
case -1:
case UserToWorldStatusSuspended:
per->Message = 337;
break;
case -2:
case UserToWorldStatusBanned:
per->Message = 338;
break;
case -3:
per->Message = 303;
case UserToWorldStatusWorldAtCapacity:
per->Message = 339;
break;
case UserToWorldStatusAlreadyOnline:
per->Message = 111;
break;
default:
per->Message = 102;
}
if (server.options.IsTraceOn())
+2 -1
View File
@@ -1 +1,2 @@
opcode_handlers_output
opcode_handlers_output
vcxproj_dependencies_output
+793
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()
+2 -1
View File
@@ -393,7 +393,8 @@
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:
# This won't be needed after this system is implemented, but it is used database that are not
@@ -0,0 +1,2 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`)
VALUES (1, 'GM:MinStatusToLevelTarget', '100', 'GM status needed to use #level on your target');
@@ -0,0 +1,2 @@
UPDATE `rule_values` SET `rule_value`='90000' WHERE `rule_name`='Zone:ClientLinkdeadMS';
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'DisallowDuplicateAccountLogins', 'true', 'Requires account logins to be unique.');
@@ -0,0 +1 @@
ALTER TABLE `npc_types` ADD COLUMN `flymode` tinyint(4) NOT NULL DEFAULT -1;
+1 -1
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 =
+11 -11
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)
{
@@ -115,7 +114,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 +184,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) {
@@ -461,7 +460,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";
}
@@ -474,7 +473,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 ",
@@ -1076,7 +1075,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:
@@ -1124,10 +1123,9 @@ bool Client::Process() {
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;
@@ -1191,6 +1189,8 @@ void Client::EnterWorld(bool TryBootup) {
else
zone_server = zoneserver_list.FindByZoneID(zone_id);
//Tell all the zones to drop any client with this lsid because we're coming back in.
zoneserver_list.DropClient(GetLSID());
const char *zone_name = database.GetZoneName(zone_id, true);
if (zone_server) {
@@ -1344,7 +1344,7 @@ void Client::Clearance(int8 response)
safe_delete(outapp);
if (cle)
cle->SetOnline(CLE_Status_Zoning);
cle->SetOnline(CLE_Status::Zoning);
}
void Client::TellClientZoneUnavailable() {
-1
View File
@@ -94,7 +94,6 @@ private:
void SetClassLanguages(PlayerProfile_Struct *pp);
ClientListEntry* cle;
Timer CLE_keepalive_timer;
Timer connect;
bool firstlogin;
bool seen_character_select;
+18 -16
View File
@@ -73,7 +73,7 @@ ClientListEntry::ClientListEntry(uint32 in_id, uint32 iAccID, const char* iAccNa
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)
{
ClearVars(true);
@@ -94,7 +94,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
SetOnline(iOnline);
@@ -115,22 +115,24 @@ 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) {
if (iOnline >= CLE_Status_Online && pOnline < CLE_Status_Online)
void ClientListEntry::SetOnline(CLE_Status iOnline) {
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){
@@ -161,7 +163,7 @@ 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();
@@ -208,7 +210,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;
SetOnline(iOnline);
@@ -223,7 +225,7 @@ void ClientListEntry::LeavingZone(ZoneServer* iZS, int8 iOnline) {
void ClientListEntry::ClearVars(bool iAll) {
if (iAll) {
pOnline = CLE_Status_Never;
pOnline = CLE_Status::Never;
stale = 0;
pLSID = 0;
@@ -269,10 +271,10 @@ void ClientListEntry::Camp(ZoneServer* iZS) {
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;
}
+17 -15
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;
@@ -23,25 +25,25 @@ class ClientListEntry {
public:
ClientListEntry(uint32 id, uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0);
ClientListEntry(uint32 id, uint32 iAccID, const char* iAccName, MD5& iMD5Pass, int16 iAdmin = 0);
ClientListEntry(uint32 id, ZoneServer* iZS, ServerClientList_Struct* scl, int8 iOnline);
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 iLSID, const char* key);
bool CheckAuth(const char* iName, MD5& iMD5Password);
bool CheckAuth(uint32 id, const char* key, uint32 ip);
void SetOnline(ZoneServer* iZS, int8 iOnline);
void SetOnline(int8 iOnline = CLE_Status_Online);
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
@@ -50,7 +52,7 @@ public:
inline const char* LSName() const { return plsname; }
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; }
@@ -93,7 +95,7 @@ private:
const uint32 id;
uint32 pIP;
int8 pOnline;
CLE_Status pOnline;
uint8 stale;
// Login Server stuff
+44 -67
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
@@ -99,52 +97,6 @@ ClientListEntry* ClientList::GetCLE(uint32 iID) {
return 0;
}
//Account Limiting Code to limit the number of characters allowed on from a single account at once.
void ClientList::EnforceSessionLimit(uint32 iLSAccountID) {
ClientListEntry* ClientEntry = 0;
LinkedListIterator<ClientListEntry*> iterator(clientlist, BACKWARD);
int CharacterCount = 0;
iterator.Reset();
while(iterator.MoreElements()) {
ClientEntry = iterator.GetData();
if ((ClientEntry->LSAccountID() == iLSAccountID) &&
((ClientEntry->Admin() <= (RuleI(World, ExemptAccountLimitStatus))) || (RuleI(World, ExemptAccountLimitStatus) < 0))) {
CharacterCount++;
if (CharacterCount >= (RuleI(World, AccountSessionLimit))){
// If we have a char name, they are in a zone, so send a kick to the zone server
if(strlen(ClientEntry->name())) {
auto pack =
new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer;
strcpy(skp->adminname, "SessionLimit");
strcpy(skp->name, ClientEntry->name());
skp->adminrank = 255;
zoneserver_list.SendPacket(pack);
safe_delete(pack);
}
ClientEntry->SetOnline(CLE_Status_Offline);
iterator.RemoveCurrent();
continue;
}
}
iterator.Advance();
}
}
//Check current CLE Entry IPs against incoming connection
void ClientList::GetCLEIP(uint32 iIP) {
@@ -168,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;
}
@@ -184,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;
}
@@ -196,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;
}
@@ -207,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;
}
@@ -228,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();
@@ -254,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();
@@ -272,7 +224,7 @@ ClientListEntry* ClientList::FindCharacter(const char* name) {
}
iterator.Advance();
}
return 0;
return nullptr;
}
ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) {
@@ -285,7 +237,7 @@ ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) {
}
iterator.Advance();
}
return 0;
return nullptr;
}
ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) {
@@ -298,7 +250,7 @@ ClientListEntry* ClientList::FindCLEByCharacterID(uint32 iCharID) {
}
iterator.Advance();
}
return 0;
return nullptr;
}
void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnection* connection, const char* iName) {
@@ -376,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;
@@ -387,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());
}
@@ -571,7 +523,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) &&
@@ -651,7 +603,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) &&
@@ -824,7 +776,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()));
@@ -1036,7 +988,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)) &&
@@ -1310,7 +1262,32 @@ void ClientList::UpdateClientGuild(uint32 char_id, uint32 guild_id) {
}
}
void ClientList::RemoveCLEByLSID(uint32 iLSID)
{
LinkedListIterator<ClientListEntry*> iterator(clientlist);
iterator.Reset();
while (iterator.MoreElements()) {
if (iterator.GetData()->LSAccountID() == iLSID) {
iterator.RemoveCurrent();
}
else
iterator.Advance();
}
}
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);
+2 -1
View File
@@ -61,11 +61,12 @@ public:
void GetCLEIP(uint32 iIP);
uint32 GetCLEIPCount(uint32 iLSAccountID);
void DisconnectByIP(uint32 iIP);
void EnforceSessionLimit(uint32 iLSAccountID);
void CLCheckStale();
void CLEKeepAlive(uint32 numupdates, uint32* wid);
void CLEAdd(uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0);
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);
+39 -29
View File
@@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "worlddb.h"
#include "zonelist.h"
#include "clientlist.h"
#include "cliententry.h"
#include "world_config.h"
extern ZSList zoneserver_list;
@@ -65,38 +66,54 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) {
uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
int16 status = database.CheckStatus(id);
auto outpack = new ServerPacket;
outpack->opcode = ServerOP_UsertoWorldResp;
outpack->size = sizeof(UsertoWorldResponse_Struct);
outpack->pBuffer = new uchar[outpack->size];
memset(outpack->pBuffer, 0, outpack->size);
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack->pBuffer;
ServerPacket outpack;
outpack.opcode = ServerOP_UsertoWorldResp;
outpack.size = sizeof(UsertoWorldResponse_Struct);
outpack.pBuffer = new uchar[outpack.size];
memset(outpack.pBuffer, 0, outpack.size);
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack.pBuffer;
utwrs->lsaccountid = utwr->lsaccountid;
utwrs->ToID = utwr->FromID;
utwrs->worldid = utwr->worldid;
utwrs->response = UserToWorldStatusSuccess;
if (Config->Locked == true)
{
if ((status == 0 || status < 100) && (status != -2 || status != -1))
utwrs->response = 0;
if (status >= 100)
utwrs->response = 1;
}
else {
utwrs->response = 1;
if (status < 100) {
utwrs->response = UserToWorldStatusWorldUnavail;
SendPacket(&outpack);
return;
}
}
int32 x = Config->MaxClients;
if ((int32)numplayers >= x && x != -1 && x != 255 && status < 80)
utwrs->response = -3;
if ((int32)numplayers >= x && x != -1 && x != 255 && status < 80) {
utwrs->response = UserToWorldStatusWorldAtCapacity;
SendPacket(&outpack);
return;
}
if (status == -1)
utwrs->response = -1;
if (status == -2)
utwrs->response = -2;
if (status == -1) {
utwrs->response = UserToWorldStatusSuspended;
SendPacket(&outpack);
return;
}
utwrs->worldid = utwr->worldid;
SendPacket(outpack);
delete outpack;
if (status == -2) {
utwrs->response = UserToWorldStatusBanned;
SendPacket(&outpack);
return;
}
if (RuleB(World, EnforceCharacterLimitAtLogin)) {
if (client_list.IsAccountInGame(utwr->lsaccountid)) {
utwrs->response = UserToWorldStatusAlreadyOnline;
SendPacket(&outpack);
return;
}
}
SendPacket(&outpack);
}
void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) {
@@ -105,13 +122,6 @@ void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) {
try {
auto slsca = p.GetSerialize<ClientAuth_Struct>(0);
if (RuleI(World, AccountSessionLimit) >= 0) {
// Enforce the limit on the number of characters on the same account that can be
// online at the same time.
client_list.EnforceSessionLimit(slsca.lsaccount_id);
}
client_list.CLEAdd(slsca.lsaccount_id, slsca.name, slsca.key, slsca.worldadmin, slsca.ip, slsca.local);
}
catch (std::exception &ex) {
+7
View File
@@ -708,6 +708,13 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval)
}
}
void ZSList::DropClient(uint32 lsid) {
ServerPacket packet(ServerOP_DropClient, sizeof(ServerZoneDropClient_Struct));
auto drop = (ServerZoneDropClient_Struct*)packet.pBuffer;
drop->lsid = lsid;
SendPacket(&packet);
}
void ZSList::OnTick(EQ::Timer *t)
{
if (!EventSubscriptionWatcher::Get()->IsSubscribed("EQW::ZoneUpdate")) {
+1
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* FindByPort(uint16 port);
ZoneServer* FindByID(uint32 ZoneID);
+8 -6
View File
@@ -409,12 +409,12 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
if (pack->size < sizeof(ServerChannelMessage_Struct))
break;
ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*)pack->pBuffer;
if (scm->chan_num == 20)
if (scm->chan_num == ChatChannel_UCSRelay)
{
UCSLink.SendMessage(scm->from, scm->message);
break;
}
if (scm->chan_num == 7 || scm->chan_num == 14) {
if (scm->chan_num == ChatChannel_Tell || scm->chan_num == ChatChannel_TellEcho) {
if (scm->deliverto[0] == '*') {
if (console) {
@@ -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()) {
@@ -486,7 +486,8 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
cle->Server()->SendPacket(pack);
}
else {
if (scm->chan_num == 5 || scm->chan_num == 6 || scm->chan_num == 11) {
if (scm->chan_num == ChatChannel_OOC || scm->chan_num == ChatChannel_Broadcast
|| scm->chan_num == ChatChannel_GMSAY) {
if (console) {
console->SendChannelMessage(scm, [&scm]() {
auto pack = new ServerPacket(ServerOP_ChannelMessage,
@@ -517,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);
@@ -1456,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));
+64 -105
View File
@@ -446,7 +446,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();
@@ -823,7 +823,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
{
if(strcmp(targetname, "discard") != 0)
{
if(chan_num == 3 || chan_num == 4 || chan_num == 5 || chan_num == 7)
if(chan_num == ChatChannel_Shout || chan_num == ChatChannel_Auction || chan_num == ChatChannel_OOC || chan_num == ChatChannel_Tell)
{
if(GlobalChatLimiterTimer)
{
@@ -869,7 +869,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
auto pack = new ServerPacket(ServerOP_Speech, sizeof(Server_Speech_Struct) + strlen(message) + 1);
Server_Speech_Struct* sem = (Server_Speech_Struct*) pack->pBuffer;
if(chan_num == 0)
if(chan_num == ChatChannel_Guild)
sem->guilddbid = GuildID();
else
sem->guilddbid = 0;
@@ -892,30 +892,38 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
if(!mod_client_message(message, chan_num)) { return; }
// Garble the message based on drunkness
if (m_pp.intoxication > 0) {
if (m_pp.intoxication > 0 && !(RuleB(Chat, ServerWideOOC) && chan_num == ChatChannel_OOC) && !GetGM()) {
GarbleMessage(message, (int)(m_pp.intoxication / 3));
language = 0; // No need for language when drunk
lang_skill = 100;
}
// some channels don't use languages
if (chan_num == ChatChannel_OOC || chan_num == ChatChannel_GMSAY || chan_num == ChatChannel_Broadcast || chan_num == ChatChannel_Petition)
{
language = 0;
lang_skill = 100;
}
// Censor the message
if (EQEmu::ProfanityManager::IsCensorshipActive() && (chan_num != 8))
if (EQEmu::ProfanityManager::IsCensorshipActive() && (chan_num != ChatChannel_Say))
EQEmu::ProfanityManager::RedactMessage(message);
switch(chan_num)
{
case 0: { /* Guild Chat */
case ChatChannel_Guild: { /* Guild Chat */
if (!IsInAGuild())
Message_StringID(MT_DefaultText, GUILD_NOT_MEMBER2); //You are not a member of any guild.
else if (!guild_mgr.CheckPermission(GuildID(), GuildRank(), GUILD_SPEAK))
Message(0, "Error: You dont have permission to speak to the guild.");
else if (!worldserver.SendChannelMessage(this, targetname, chan_num, GuildID(), language, message))
else if (!worldserver.SendChannelMessage(this, targetname, chan_num, GuildID(), language, lang_skill, message))
Message(0, "Error: World server disconnected");
break;
}
case 2: { /* Group Chat */
case ChatChannel_Group: { /* Group Chat */
Raid* raid = entity_list.GetRaidByClient(this);
if(raid) {
raid->RaidGroupSay((const char*) message, this);
raid->RaidGroupSay((const char*) message, this, language, lang_skill);
break;
}
@@ -925,14 +933,14 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
break;
}
case 15: { /* Raid Say */
case ChatChannel_Raid: { /* Raid Say */
Raid* raid = entity_list.GetRaidByClient(this);
if(raid){
raid->RaidSay((const char*) message, this);
raid->RaidSay((const char*) message, this, language, lang_skill);
}
break;
}
case 3: { /* Shout */
case ChatChannel_Shout: { /* Shout */
Mob *sender = this;
if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft))
sender = GetPet();
@@ -940,13 +948,13 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message);
break;
}
case 4: { /* Auction */
case ChatChannel_Auction: { /* Auction */
if(RuleB(Chat, ServerWideAuction))
{
if(!global_channel_timer.Check())
{
if(strlen(targetname) == 0)
ChannelMessageReceived(5, language, lang_skill, message, "discard"); //Fast typer or spammer??
ChannelMessageReceived(chan_num, language, lang_skill, message, "discard"); //Fast typer or spammer??
else
return;
}
@@ -966,7 +974,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
}
if (!worldserver.SendChannelMessage(this, 0, 4, 0, language, message))
if (!worldserver.SendChannelMessage(this, 0, chan_num, 0, language, lang_skill, message))
Message(0, "Error: World server disconnected");
}
else if(!RuleB(Chat, ServerWideAuction)) {
@@ -975,17 +983,17 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft))
sender = GetPet();
entity_list.ChannelMessage(sender, chan_num, language, message);
entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message);
}
break;
}
case 5: { /* OOC */
case ChatChannel_OOC: { /* OOC */
if(RuleB(Chat, ServerWideOOC))
{
if(!global_channel_timer.Check())
{
if(strlen(targetname) == 0)
ChannelMessageReceived(5, language, lang_skill, message, "discard"); //Fast typer or spammer??
ChannelMessageReceived(chan_num, language, lang_skill, message, "discard"); //Fast typer or spammer??
else
return;
}
@@ -1010,7 +1018,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
}
if (!worldserver.SendChannelMessage(this, 0, 5, 0, language, message))
if (!worldserver.SendChannelMessage(this, 0, chan_num, 0, language, lang_skill, message))
{
Message(0, "Error: World server disconnected");
}
@@ -1022,19 +1030,19 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft))
sender = GetPet();
entity_list.ChannelMessage(sender, chan_num, language, message);
entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message);
}
break;
}
case 6: /* Broadcast */
case 11: { /* GM Say */
case ChatChannel_Broadcast: /* Broadcast */
case ChatChannel_GMSAY: { /* GM Say */
if (!(admin >= 80))
Message(0, "Error: Only GMs can use this channel");
else if (!worldserver.SendChannelMessage(this, targetname, chan_num, 0, language, message))
else if (!worldserver.SendChannelMessage(this, targetname, chan_num, 0, language, lang_skill, message))
Message(0, "Error: World server disconnected");
break;
}
case 7: { /* Tell */
case ChatChannel_Tell: { /* Tell */
if(!global_channel_timer.Check())
{
if(strlen(targetname) == 0)
@@ -1078,11 +1086,11 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
target_name[x] = '\0';
}
if(!worldserver.SendChannelMessage(this, target_name, chan_num, 0, language, message))
if(!worldserver.SendChannelMessage(this, target_name, chan_num, 0, language, lang_skill, message))
Message(0, "Error: World server disconnected");
break;
}
case 8: { /* Say */
case ChatChannel_Say: { /* Say */
if(message[0] == COMMAND_CHAR) {
if(command_dispatch(this, message) == -2) {
if(parse->PlayerHasQuestSub(EVENT_COMMAND)) {
@@ -1158,14 +1166,14 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
break;
}
case 20:
case ChatChannel_UCSRelay:
{
// UCS Relay for Underfoot and later.
if(!worldserver.SendChannelMessage(this, 0, chan_num, 0, language, message))
if(!worldserver.SendChannelMessage(this, 0, chan_num, 0, language, lang_skill, message))
Message(0, "Error: World server disconnected");
break;
}
case 22:
case ChatChannel_Emotes:
{
// Emotes for Underfoot and later.
// crash protection -- cheater
@@ -1189,11 +1197,6 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
}
// if no language skill is specified, call the function with a skill of 100.
void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, const char* message, ...) {
ChannelMessageSend(from, to, chan_num, language, 100, message);
}
void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...) {
if ((chan_num==11 && !(this->GetGM())) || (chan_num==10 && this->Admin()<80)) // dont need to send /pr & /petition to everybody
return;
@@ -1218,7 +1221,7 @@ void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num
}
if (to != 0)
strcpy((char *) cm->targetname, to);
else if (chan_num == 7)
else if (chan_num == ChatChannel_Tell)
strcpy(cm->targetname, m_pp.name);
else
cm->targetname[0] = 0;
@@ -1227,7 +1230,7 @@ void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num
if (language < MAX_PP_LANGUAGE) {
ListenerSkill = m_pp.languages[language];
if (ListenerSkill == 0) {
if (ListenerSkill < 24) {
cm->language = (MAX_PP_LANGUAGE - 1); // in an unknown tongue
}
else {
@@ -1253,7 +1256,7 @@ void Client::ChannelMessageSend(const char* from, const char* to, uint8 chan_num
bool weAreNotSender = strcmp(this->GetCleanName(), cm->sender);
if (senderCanTrainSelf || weAreNotSender) {
if ((chan_num == 2) && (ListenerSkill < 100)) { // group message in unmastered language, check for skill up
if ((chan_num == ChatChannel_Group) && (ListenerSkill < 100)) { // group message in unmastered language, check for skill up
if (m_pp.languages[language] <= lang_skill)
CheckLanguageSkillIncrease(language, lang_skill);
}
@@ -1274,21 +1277,19 @@ void Client::Message(uint32 type, const char* message, ...) {
vsnprintf(buffer, 4096, message, argptr);
va_end(argptr);
size_t len = strlen(buffer);
SerializeBuffer buf(sizeof(SpecialMesgHeader_Struct) + 12 + 64 + 64);
buf.WriteInt8(static_cast<int8>(Journal::SpeakMode::Raw));
buf.WriteInt8(static_cast<int8>(Journal::Mode::None));
buf.WriteInt8(0); // language
buf.WriteUInt32(type);
buf.WriteUInt32(0); // target spawn ID used for journal filtering, ignored here
buf.WriteString(""); // send name, not applicable here
buf.WriteInt32(0); // location, client seems to ignore
buf.WriteInt32(0);
buf.WriteInt32(0);
buf.WriteString(buffer);
//client dosent like our packet all the time unless
//we make it really big, then it seems to not care that
//our header is malformed.
//len = 4096 - sizeof(SpecialMesg_Struct);
uint32 len_packet = sizeof(SpecialMesg_Struct)+len;
auto app = new EQApplicationPacket(OP_SpecialMesg, len_packet);
SpecialMesg_Struct* sm=(SpecialMesg_Struct*)app->pBuffer;
sm->header[0] = 0x00; // Header used for #emote style messages..
sm->header[1] = 0x00; // Play around with these to see other types
sm->header[2] = 0x00;
sm->msg_type = type;
memcpy(sm->message, buffer, len+1);
auto app = new EQApplicationPacket(OP_SpecialMesg, buf);
FastQueuePacket(&app);
@@ -1305,67 +1306,25 @@ void Client::FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, cons
vsnprintf(buffer, 4096, message, argptr);
va_end(argptr);
size_t len = strlen(buffer);
SerializeBuffer buf(sizeof(SpecialMesgHeader_Struct) + 12 + 64 + 64);
buf.WriteInt8(static_cast<int8>(Journal::SpeakMode::Raw));
buf.WriteInt8(static_cast<int8>(Journal::Mode::None));
buf.WriteInt8(0); // language
buf.WriteUInt32(type);
buf.WriteUInt32(0); // target spawn ID used for journal filtering, ignored here
buf.WriteString(""); // send name, not applicable here
buf.WriteInt32(0); // location, client seems to ignore
buf.WriteInt32(0);
buf.WriteInt32(0);
buf.WriteString(buffer);
//client dosent like our packet all the time unless
//we make it really big, then it seems to not care that
//our header is malformed.
//len = 4096 - sizeof(SpecialMesg_Struct);
uint32 len_packet = sizeof(SpecialMesg_Struct) + len;
auto app = new EQApplicationPacket(OP_SpecialMesg, len_packet);
SpecialMesg_Struct* sm = (SpecialMesg_Struct*)app->pBuffer;
sm->header[0] = 0x00; // Header used for #emote style messages..
sm->header[1] = 0x00; // Play around with these to see other types
sm->header[2] = 0x00;
sm->msg_type = type;
memcpy(sm->message, buffer, len + 1);
auto app = new EQApplicationPacket(OP_SpecialMesg, buf);
FastQueuePacket(&app);
safe_delete_array(buffer);
}
void Client::QuestJournalledMessage(const char *npcname, const char* message) {
// npcnames longer than 60 characters crash the client when they log back in
const int MaxNPCNameLength = 60;
// I assume there is an upper safe limit on the message length. Don't know what it is, but 4000 doesn't crash
// the client.
const int MaxMessageLength = 4000;
char OutNPCName[MaxNPCNameLength+1];
char OutMessage[MaxMessageLength+1];
// Apparently Visual C++ snprintf is not C99 compliant and doesn't put the null terminator
// in if the formatted string >= the maximum length, so we put it in.
//
snprintf(OutNPCName, MaxNPCNameLength, "%s", npcname); OutNPCName[MaxNPCNameLength]='\0';
snprintf(OutMessage, MaxMessageLength, "%s", message); OutMessage[MaxMessageLength]='\0';
uint32 len_packet = sizeof(SpecialMesg_Struct) + strlen(OutNPCName) + strlen(OutMessage);
auto app = new EQApplicationPacket(OP_SpecialMesg, len_packet);
SpecialMesg_Struct* sm=(SpecialMesg_Struct*)app->pBuffer;
sm->header[0] = 0;
sm->header[1] = 2;
sm->header[2] = 0;
sm->msg_type = 0x0a;
sm->target_spawn_id = GetID();
char *dest = &sm->sayer[0];
memcpy(dest, OutNPCName, strlen(OutNPCName) + 1);
dest = dest + strlen(OutNPCName) + 13;
memcpy(dest, OutMessage, strlen(OutMessage) + 1);
QueuePacket(app);
safe_delete(app);
}
void Client::SetMaxHP() {
if(dead)
return;
-2
View File
@@ -338,11 +338,9 @@ public:
void QueuePacket(const EQApplicationPacket* app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL, eqFilterType filter=FilterNone);
void FastQueuePacket(EQApplicationPacket** app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL);
void ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_skill, const char* orig_message, const char* targetname=nullptr);
void ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, const char* message, ...);
void ChannelMessageSend(const char* from, const char* to, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...);
void Message(uint32 type, const char* message, ...);
void FilteredMessage(Mob *sender, uint32 type, eqFilterType filter, const char* message, ...);
void QuestJournalledMessage(const char *npcname, const char* message);
void VoiceMacroReceived(uint32 Type, char *Target, uint32 MacroNumber);
void SendSound();
void LearnRecipe(uint32 recipeID);
+8 -3
View File
@@ -1166,8 +1166,8 @@ 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();
}
@@ -4181,7 +4181,12 @@ void Client::Handle_OP_ChannelMessage(const EQApplicationPacket *app)
return;
}
ChannelMessageReceived(cm->chan_num, cm->language, cm->skill_in_language, cm->message, cm->targetname);
uint8 skill_in_language = 100;
if (cm->language < MAX_PP_LANGUAGE)
{
skill_in_language = m_pp.languages[cm->language];
}
ChannelMessageReceived(cm->chan_num, cm->language, skill_in_language, cm->message, cm->targetname);
return;
}
+62 -4
View File
@@ -56,6 +56,7 @@
#include "../common/eqemu_logsys.h"
#include "../common/profanity_manager.h"
#include "../common/net/eqstream.h"
#include "../common/event/task_scheduler.h"
#include "data_bucket.h"
#include "command.h"
@@ -78,6 +79,7 @@ extern TaskManager *taskmanager;
extern FastMath g_Math;
void CatchSignal(int sig_num);
EQ::Event::TaskScheduler task_scheduler;
int commandcount; // how many commands we have
@@ -395,6 +397,7 @@ int command_init(void)
command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", 100, command_tempname) ||
command_add("petname", "[newname] - Temporarily renames your pet. Leave name blank to restore the original name.", 100, command_petname) ||
command_add("test", "Test command", 200, command_test) ||
command_add("test_login", "Test login command", 200, command_test_login) ||
command_add("texture", "[texture] [helmtexture] - Change your or your target's appearance, use 255 to show equipment", 10, command_texture) ||
command_add("time", "[HH] [MM] - Set EQ time", 90, command_time) ||
command_add("timers", "- Display persistent timers for target", 200, command_timers) ||
@@ -887,7 +890,7 @@ void command_chat(Client *c, const Seperator *sep)
if (sep->arg[2][0] == 0)
c->Message(0, "Usage: #chat [channum] [message]");
else
if (!worldserver.SendChannelMessage(0, 0, (uint8) atoi(sep->arg[1]), 0, 0, sep->argplus[2]))
if (!worldserver.SendChannelMessage(0, 0, (uint8) atoi(sep->arg[1]), 0, 0, 100, sep->argplus[2]))
c->Message(0, "Error: World server disconnected");
}
@@ -2799,7 +2802,7 @@ void command_level(Client *c, const Seperator *sep)
if ((level <= 0) || ((level > RuleI(Character, MaxLevel)) && (c->Admin() < commandLevelAboveCap))) {
c->Message(0, "Error: #Level: Invalid Level");
}
else if (c->Admin() < 100) {
else if (c->Admin() < RuleI(GM, MinStatusToLevelTarget)) {
c->SetLevel(level, true);
#ifdef BOTS
if(RuleB(Bots, BotLevelsWithOwner))
@@ -4490,7 +4493,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) {
@@ -7342,6 +7345,7 @@ void command_npcedit(Client *c, const Seperator *sep)
c->Message(0, "#npcedit no_target - Set an NPC's ability to be targeted with the target hotkey");
c->Message(0, "#npcedit version - Set an NPC's version");
c->Message(0, "#npcedit slow_mitigation - Set an NPC's slow mitigation");
c->Message(0, "#npcedit flymode - Set an NPC's flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating]");
}
@@ -7355,7 +7359,14 @@ void command_npcedit(Client *c, const Seperator *sep)
if (strcasecmp(sep->arg[1], "lastname") == 0) {
c->Message(15,"NPCID %u now has the lastname %s.", npcTypeID, sep->argplus[2]);
std::string query = StringFormat("UPDATE npc_types SET lastname = '%s' WHERE id = %i", sep->argplus[2],npcTypeID);
std::string query = StringFormat("UPDATE npc_types SET lastname = '%s' WHERE id = %i", sep->argplus[2],npcTypeID);
database.QueryDatabase(query);
return;
}
if (strcasecmp(sep->arg[1], "flymode") == 0) {
c->Message(15,"NPCID %u now has flymode [%s]", npcTypeID, sep->argplus[2]);
std::string query = StringFormat("UPDATE npc_types SET flymode = '%s' WHERE id = %i", sep->argplus[2],npcTypeID);
database.QueryDatabase(query);
return;
}
@@ -12416,6 +12427,53 @@ void command_network(Client *c, const Seperator *sep)
}
}
void command_test_login(Client *c, const Seperator *sep) {
auto res = task_scheduler.Enqueue([]() -> bool {
bool running = true;
bool ret = false;
EQ::Net::DaybreakConnectionManager mgr;
std::shared_ptr<EQ::Net::DaybreakConnection> c;
mgr.OnNewConnection([&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
c = connection;
});
mgr.OnConnectionStateChange([&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) {
if (EQ::Net::StatusConnected == to) {
EQ::Net::DynamicPacket p;
p.PutUInt16(0, 1); //OP_SessionReady
p.PutUInt32(2, 2);
c->QueuePacket(p);
}
else if (EQ::Net::StatusDisconnected == to) {
running = false;
}
});
mgr.OnPacketRecv([&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet & p) {
auto opcode = p.GetUInt16(0);
switch (opcode) {
case 0x0017: //OP_ChatMessage
//Would do the actual sending and parsing here if eqcrypto wasn't in loginserver.
ret = true;
running = false;
break;
}
});
mgr.Connect("127.0.0.1", 5999);
auto &loop = EQ::EventLoop::Get();
while (true == running) {
loop.Process();
}
return ret;
});
c->Message(0, "Result was %s", res.get() ? "true" : "false");
}
// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block.
#ifdef BOTS
#include "bot_command.h"
+1
View File
@@ -304,6 +304,7 @@ void command_petname(Client *c, const Seperator *sep);
void command_test(Client *c, const Seperator *sep);
void command_testspawn(Client *c, const Seperator *sep);
void command_testspawnkill(Client *c, const Seperator *sep);
void command_test_login(Client *c, const Seperator *sep);
void command_texture(Client *c, const Seperator *sep);
void command_time(Client *c, const Seperator *sep);
void command_timers(Client *c, const Seperator *sep);
+25
View File
@@ -272,6 +272,31 @@ enum class LootRequestType : uint8 {
AllowedPVPDefined,
};
namespace Journal {
enum class SpeakMode : uint8 {
Raw = 0, // this just uses the raw message
Say = 1, // prints with "%1 says,%2 '%3'" if in another language else "%1 says '%2'"
Shout = 2, // prints with "%1 shouts,%2 '%3'" if in another language else "%1 shouts '%2'"
EmoteAlt = 3, // prints "%2", this should just be the same as raw ...
Emote = 4, // prints "%1 %2" if message doesn't start with "\" or "@", else "%1%2"
Group = 5 // prints "%1 tells the group,%2 '%3'"
};
enum class Mode : uint8 {
None = 0,
Log1 = 1, // 1 and 2 log to journal
Log2 = 2, // our current code uses 2
};
struct Options {
SpeakMode speak_mode;
Mode journal_mode;
int8 language;
uint32 message_type;
uint32 target_spawn_id; // who the message is talking to (limits journaling)
};
};
//this is our internal representation of the BUFF struct, can put whatever we want in it
struct Buffs_Struct {
uint16 spellid;
+3 -11
View File
@@ -1099,10 +1099,6 @@ void PerlembParser::ExportZoneVariables(std::string &package_name) {
}
}
#define HASITEM_FIRST 0
#define HASITEM_LAST 29 // this includes worn plus 8 base slots
#define HASITEM_ISNULLITEM(item) ((item==-1) || (item==0))
void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) {
if(mob && mob->IsClient())
{
@@ -1111,11 +1107,11 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) {
//start with an empty hash
perl->eval(std::string("%").append(hashname).append(" = ();").c_str());
for(int slot = HASITEM_FIRST; slot <= HASITEM_LAST; slot++)
for(int slot = EQEmu::invslot::EQUIPMENT_BEGIN; slot <= EQEmu::invslot::GENERAL_END; slot++)
{
char *hi_decl=nullptr;
int itemid = mob->CastToClient()->GetItemIDAt(slot);
if(!HASITEM_ISNULLITEM(itemid))
if(itemid != -1 && itemid != 0)
{
MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);", hashname.c_str(), itemid, slot);
perl->eval(hi_decl);
@@ -1129,7 +1125,7 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) {
perl->eval(std::string("%").append(hashname).append(" = ();").c_str());
char *hi_decl = nullptr;
int itemid = mob->CastToClient()->GetItemIDAt(EQEmu::invslot::slotCursor);
if(!HASITEM_ISNULLITEM(itemid)) {
if(itemid != -1 && itemid != 0) {
MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);",hashname.c_str(), itemid, EQEmu::invslot::slotCursor);
perl->eval(hi_decl);
safe_delete_array(hi_decl);
@@ -1137,10 +1133,6 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) {
}
}
#undef HASITEM_FIRST
#undef HASITEM_LAST
#undef HASITEM_ISNULLITEM
void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data,
NPC* npcmob, EQEmu::ItemInstance* item_inst, Mob* mob, uint32 extradata, std::vector<EQEmu::Any> *extra_pointers)
{
+25 -6
View File
@@ -155,12 +155,31 @@ XS(XS__say); // prototype to pass -Wmissing-prototypes
XS(XS__say) {
dXSARGS;
if (items == 1)
quest_manager.say(SvPV_nolen(ST(0)));
else if (items == 2)
quest_manager.say(SvPV_nolen(ST(0)), (int) SvIV(ST(1)));
else
Perl_croak(aTHX_ "Usage: quest::say(string message, int language_id])");
Journal::Options opts;
// we currently default to these
opts.speak_mode = Journal::SpeakMode::Say;
opts.journal_mode = Journal::Mode::Log2;
opts.language = 0;
opts.message_type = MT_NPCQuestSay;
if (items == 0 || items > 5) {
Perl_croak(aTHX_ "Usage: quest::say(string message, [int language_id], [int message_type], [int speak_mode], [int journal_mode])");
} else if (items == 2) {
opts.language = (int)SvIV(ST(1));
} else if (items == 3) {
opts.language = (int)SvIV(ST(1));
opts.message_type = (int)SvIV(ST(2));
} else if (items == 4) {
opts.language = (int)SvIV(ST(1));
opts.message_type = (int)SvIV(ST(2));
opts.speak_mode = (Journal::SpeakMode)SvIV(ST(3));
} else if (items == 5) {
opts.language = (int)SvIV(ST(1));
opts.message_type = (int)SvIV(ST(2));
opts.speak_mode = (Journal::SpeakMode)SvIV(ST(3));
opts.journal_mode = (Journal::Mode)SvIV(ST(4));
}
quest_manager.say(SvPV_nolen(ST(0)), opts);
XSRETURN_EMPTY;
}
+38 -38
View File
@@ -1235,33 +1235,19 @@ void EntityList::ChannelMessage(Mob *from, uint8 chan_num, uint8 language,
while(it != client_list.end()) {
Client *client = it->second;
eqFilterType filter = FilterNone;
if (chan_num == 3) //shout
if (chan_num == ChatChannel_Shout) //shout
filter = FilterShouts;
else if (chan_num == 4) //auction
else if (chan_num == ChatChannel_Auction) //auction
filter = FilterAuctions;
//
// Only say is limited in range
if (chan_num != 8 || Distance(client->GetPosition(), from->GetPosition()) < 200)
if (chan_num != ChatChannel_Say || Distance(client->GetPosition(), from->GetPosition()) < 200)
if (filter == FilterNone || client->GetFilter(filter) != FilterHide)
client->ChannelMessageSend(from->GetName(), 0, chan_num, language, lang_skill, buffer);
++it;
}
}
void EntityList::ChannelMessageSend(Mob *to, uint8 chan_num, uint8 language, const char *message, ...)
{
if (!to->IsClient())
return;
va_list argptr;
char buffer[4096];
va_start(argptr, message);
vsnprintf(buffer, 4096, message, argptr);
va_end(argptr);
to->CastToClient()->ChannelMessageSend(0, 0, chan_num, language, buffer);
}
void EntityList::SendZoneSpawns(Client *client)
{
EQApplicationPacket *app;
@@ -1727,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;
@@ -1995,22 +1993,22 @@ Client *EntityList::GetClientByAccID(uint32 accid)
}
void EntityList::ChannelMessageFromWorld(const char *from, const char *to,
uint8 chan_num, uint32 guild_id, uint8 language, const char *message)
uint8 chan_num, uint32 guild_id, uint8 language, uint8 lang_skill, const char *message)
{
for (auto it = client_list.begin(); it != client_list.end(); ++it) {
Client *client = it->second;
if (chan_num == 0) {
if (chan_num == ChatChannel_Guild) {
if (!client->IsInGuild(guild_id))
continue;
if (!guild_mgr.CheckPermission(guild_id, client->GuildRank(), GUILD_HEAR))
continue;
if (client->GetFilter(FilterGuildChat) == FilterHide)
continue;
} else if (chan_num == 5) {
} else if (chan_num == ChatChannel_OOC) {
if (client->GetFilter(FilterOOC) == FilterHide)
continue;
}
client->ChannelMessageSend(from, to, chan_num, language, message);
client->ChannelMessageSend(from, to, chan_num, language, lang_skill, message);
}
}
@@ -3747,24 +3745,26 @@ bool Entity::CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z,
}
void EntityList::QuestJournalledSayClose(Mob *sender, Client *QuestInitiator,
float dist, const char* mobname, const char* message)
float dist, const char* mobname, const char* message, Journal::Options &opts)
{
Client *c = nullptr;
float dist2 = dist * dist;
SerializeBuffer buf(sizeof(SpecialMesgHeader_Struct) + 12 + 64 + 64);
// Send the message to the quest initiator such that the client will enter it into the NPC Quest Journal
if (QuestInitiator) {
auto buf = new char[strlen(mobname) + strlen(message) + 10];
sprintf(buf, "%s says, '%s'", mobname, message);
QuestInitiator->QuestJournalledMessage(mobname, buf);
safe_delete_array(buf);
}
// Use the old method for all other nearby clients
for (auto it = client_list.begin(); it != client_list.end(); ++it) {
c = it->second;
if(c && (c != QuestInitiator) && DistanceSquared(c->GetPosition(), sender->GetPosition()) <= dist2)
c->Message_StringID(10, GENERIC_SAY, mobname, message);
}
buf.WriteInt8(static_cast<int8>(opts.speak_mode));
buf.WriteInt8(static_cast<int8>(opts.journal_mode));
buf.WriteInt8(opts.language);
buf.WriteInt32(opts.message_type);
buf.WriteInt32(opts.target_spawn_id);
buf.WriteString(mobname);
buf.WriteInt32(0); // location, client doesn't seem to do anything with this
buf.WriteInt32(0);
buf.WriteInt32(0);
buf.WriteString(message);
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
// client only bothers logging if target spawn ID matches, safe to send to everyone
QueueCloseClients(sender, outapp, false, dist);
delete outapp;
}
Corpse *EntityList::GetClosestCorpse(Mob *sender, const char *Name)
@@ -3880,7 +3880,7 @@ void EntityList::GroupMessage(uint32 gid, const char *from, const char *message)
g = it->second->GetGroup();
if (g) {
if (g->GetID() == gid)
it->second->ChannelMessageSend(from, it->second->GetName(), 2, 0, message);
it->second->ChannelMessageSend(from, it->second->GetName(), ChatChannel_Group, 0, 100, message);
}
}
++it;
+4 -3
View File
@@ -29,6 +29,7 @@
#include "position.h"
#include "zonedump.h"
#include "common.h"
class Encounter;
class Beacon;
@@ -175,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);
@@ -323,10 +325,9 @@ public:
void FilteredMessage_StringID(Mob *sender, bool skipsender, uint32 type, eqFilterType filter, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
void MessageClose_StringID(Mob *sender, bool skipsender, float dist, uint32 type, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
void FilteredMessageClose_StringID(Mob *sender, bool skipsender, float dist, uint32 type, eqFilterType filter, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
void ChannelMessageFromWorld(const char* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, const char* message);
void ChannelMessageFromWorld(const char* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, uint8 lang_skill, const char* message);
void ChannelMessage(Mob* from, uint8 chan_num, uint8 language, const char* message, ...);
void ChannelMessage(Mob* from, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...);
void ChannelMessageSend(Mob* to, uint8 chan_num, uint8 language, const char* message, ...);
void SendZoneSpawns(Client*);
void SendZonePVPUpdates(Client *);
void SendZoneSpawnsBulk(Client* client);
@@ -338,7 +339,7 @@ public:
void SendNimbusEffects(Client *c);
void SendUntargetable(Client *c);
void DuelMessage(Mob* winner, Mob* loser, bool flee);
void QuestJournalledSayClose(Mob *sender, Client *QuestIntiator, float dist, const char* mobname, const char* message);
void QuestJournalledSayClose(Mob *sender, Client *QuestIntiator, float dist, const char* mobname, const char* message, Journal::Options &opts);
void GroupMessage(uint32 gid, const char *from, const char *message);
void ExpeditionWarning(uint32 minutes_left);
+2 -2
View File
@@ -910,7 +910,7 @@ void Group::GroupMessage(Mob* sender, uint8 language, uint8 lang_skill, const ch
continue;
if (members[i]->IsClient() && members[i]->CastToClient()->GetFilter(FilterGroupChat)!=0)
members[i]->CastToClient()->ChannelMessageSend(sender->GetName(),members[i]->GetName(),2,language,lang_skill,message);
members[i]->CastToClient()->ChannelMessageSend(sender->GetName(),members[i]->GetName(),ChatChannel_Group,language,lang_skill,message);
}
auto pack =
@@ -2493,4 +2493,4 @@ void Group::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_r
}
}
}
}
}
+26
View File
@@ -36,6 +36,8 @@ struct BodyTypes { };
struct Filters { };
struct MessageTypes { };
struct Rule { };
struct Journal_SpeakMode { };
struct Journal_Mode { };
struct lua_registered_event {
std::string encounter_name;
@@ -2232,6 +2234,7 @@ luabind::scope lua_register_message_types() {
return luabind::class_<MessageTypes>("MT")
.enum_("constants")
[
luabind::value("NPCQuestSay", MT_NPCQuestSay),
luabind::value("Say", MT_Say),
luabind::value("Tell", MT_Tell),
luabind::value("Group", MT_Group),
@@ -2362,4 +2365,27 @@ luabind::scope lua_register_ruleb() {
];
}
luabind::scope lua_register_journal_speakmode() {
return luabind::class_<Journal_SpeakMode>("SpeakMode")
.enum_("constants")
[
luabind::value("Raw", static_cast<int>(Journal::SpeakMode::Raw)),
luabind::value("Say", static_cast<int>(Journal::SpeakMode::Say)),
luabind::value("Shout", static_cast<int>(Journal::SpeakMode::Shout)),
luabind::value("EmoteAlt", static_cast<int>(Journal::SpeakMode::EmoteAlt)),
luabind::value("Emote", static_cast<int>(Journal::SpeakMode::Emote)),
luabind::value("Group", static_cast<int>(Journal::SpeakMode::Group))
];
}
luabind::scope lua_register_journal_mode() {
return luabind::class_<Journal_Mode>("JournalMode")
.enum_("constants")
[
luabind::value("None", static_cast<int>(Journal::Mode::None)),
luabind::value("Log1", static_cast<int>(Journal::Mode::Log1)),
luabind::value("Log2", static_cast<int>(Journal::Mode::Log2))
];
}
#endif
+2
View File
@@ -19,6 +19,8 @@ luabind::scope lua_register_rules_const();
luabind::scope lua_register_rulei();
luabind::scope lua_register_ruler();
luabind::scope lua_register_ruleb();
luabind::scope lua_register_journal_speakmode();
luabind::scope lua_register_journal_mode();
#endif
#endif
+75 -4
View File
@@ -753,9 +753,72 @@ void Lua_Mob::Say(const char *message) {
self->Say(message);
}
void Lua_Mob::Say(const char* message, int language) {
Lua_Safe_Call_Void();
entity_list.ChannelMessage(self, ChatChannel_Say, language, message); // these run through the client channels and probably shouldn't for NPCs, but oh well
}
void Lua_Mob::QuestSay(Lua_Client client, const char *message) {
Lua_Safe_Call_Void();
self->QuestJournalledSay(client, message);
Journal::Options journal_opts;
journal_opts.speak_mode = Journal::SpeakMode::Say;
journal_opts.journal_mode = RuleB(NPC, EnableNPCQuestJournal) ? Journal::Mode::Log2 : Journal::Mode::None;
journal_opts.language = 0;
journal_opts.message_type = MT_NPCQuestSay;
journal_opts.target_spawn_id = 0;
self->QuestJournalledSay(client, message, journal_opts);
}
void Lua_Mob::QuestSay(Lua_Client client, const char *message, luabind::adl::object opts) {
Lua_Safe_Call_Void();
Journal::Options journal_opts;
// defaults
journal_opts.speak_mode = Journal::SpeakMode::Say;
journal_opts.journal_mode = Journal::Mode::Log2;
journal_opts.language = 0;
journal_opts.message_type = MT_NPCQuestSay;
journal_opts.target_spawn_id = 0;
if (luabind::type(opts) == LUA_TTABLE) {
auto cur = opts["speak_mode"];
if (luabind::type(cur) != LUA_TNIL) {
try {
journal_opts.speak_mode = static_cast<Journal::SpeakMode>(luabind::object_cast<int>(cur));
} catch (luabind::cast_failed) {
}
}
cur = opts["journal_mode"];
if (luabind::type(cur) != LUA_TNIL) {
try {
journal_opts.journal_mode = static_cast<Journal::Mode>(luabind::object_cast<int>(cur));
} catch (luabind::cast_failed) {
}
}
cur = opts["language"];
if (luabind::type(cur) != LUA_TNIL) {
try {
journal_opts.language = luabind::object_cast<int>(cur);
} catch (luabind::cast_failed) {
}
}
cur = opts["message_type"];
if (luabind::type(cur) != LUA_TNIL) {
try {
journal_opts.message_type = luabind::object_cast<int>(cur);
} catch (luabind::cast_failed) {
}
}
}
// if rule disables it, we override provided
if (!RuleB(NPC, EnableNPCQuestJournal))
journal_opts.journal_mode = Journal::Mode::None;
self->QuestJournalledSay(client, message, journal_opts);
}
void Lua_Mob::Shout(const char *message) {
@@ -763,6 +826,11 @@ void Lua_Mob::Shout(const char *message) {
self->Shout(message);
}
void Lua_Mob::Shout(const char* message, int language) {
Lua_Safe_Call_Void();
entity_list.ChannelMessage(self, ChatChannel_Shout, language, message);
}
void Lua_Mob::Emote(const char *message) {
Lua_Safe_Call_Void();
self->Emote(message);
@@ -2319,9 +2387,12 @@ luabind::scope lua_register_mob() {
.def("GetSize", &Lua_Mob::GetSize)
.def("Message", &Lua_Mob::Message)
.def("Message_StringID", &Lua_Mob::Message_StringID)
.def("Say", &Lua_Mob::Say)
.def("QuestSay", &Lua_Mob::QuestSay)
.def("Shout", &Lua_Mob::Shout)
.def("Say", (void(Lua_Mob::*)(const char*))& Lua_Mob::Say)
.def("Say", (void(Lua_Mob::*)(const char*, int))& Lua_Mob::Say)
.def("QuestSay", (void(Lua_Mob::*)(Lua_Client,const char *))&Lua_Mob::QuestSay)
.def("QuestSay", (void(Lua_Mob::*)(Lua_Client,const char *,luabind::adl::object))&Lua_Mob::QuestSay)
.def("Shout", (void(Lua_Mob::*)(const char*))& Lua_Mob::Shout)
.def("Shout", (void(Lua_Mob::*)(const char*, int))& Lua_Mob::Shout)
.def("Emote", &Lua_Mob::Emote)
.def("InterruptSpell", (void(Lua_Mob::*)(void))&Lua_Mob::InterruptSpell)
.def("InterruptSpell", (void(Lua_Mob::*)(int))&Lua_Mob::InterruptSpell)
+3
View File
@@ -168,8 +168,11 @@ public:
void Message(int type, const char *message);
void Message_StringID(int type, int string_id, uint32 distance);
void Say(const char *message);
void Say(const char* message, int language);
void QuestSay(Lua_Client client, const char *message);
void QuestSay(Lua_Client client, const char *message, luabind::adl::object opts);
void Shout(const char *message);
void Shout(const char* message, int language);
void Emote(const char *message);
void InterruptSpell();
void InterruptSpell(int spell_id);
+3 -1
View File
@@ -1102,7 +1102,9 @@ void LuaParser::MapFunctions(lua_State *L) {
lua_register_rules_const(),
lua_register_rulei(),
lua_register_ruler(),
lua_register_ruleb()
lua_register_ruleb(),
lua_register_journal_speakmode(),
lua_register_journal_mode()
];
} catch(std::exception &ex) {
+6 -2
View File
@@ -2911,9 +2911,13 @@ void Mob::Emote(const char *format, ...)
GENERIC_EMOTE, GetCleanName(), buf);
}
void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str)
void Mob::QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::Options &opts)
{
entity_list.QuestJournalledSayClose(this, QuestInitiator, 200, GetCleanName(), str);
// just in case
if (opts.target_spawn_id == 0 && QuestInitiator)
opts.target_spawn_id = QuestInitiator->GetID();
entity_list.QuestJournalledSayClose(this, QuestInitiator, 200, GetCleanName(), str, opts);
}
const char *Mob::GetCleanName()
+1 -1
View File
@@ -744,7 +744,7 @@ public:
const char *message6 = 0, const char *message7 = 0, const char *message8 = 0, const char *message9 = 0);
void Shout(const char *format, ...);
void Emote(const char *format, ...);
void QuestJournalledSay(Client *QuestInitiator, const char *str);
void QuestJournalledSay(Client *QuestInitiator, const char *str, Journal::Options &opts);
int32 GetItemStat(uint32 itemid, const char *identifier);
int16 CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, bool best_focus=false);
+44
View File
@@ -813,11 +813,55 @@ void MobMovementManager::UpdatePathGround(Mob * who, float x, float y, float z,
}
AdjustRoute(route, who);
//avoid doing any processing if the mob is stuck to allow normal stuck code to work.
if (!stuck)
{
//there are times when the routes returned are no differen than where the mob is currently standing. What basically happens
//is a mob will get 'stuck' in such a way that it should be moving but the 'moving' place is the exact same spot it is at.
//this is a problem and creates an area of ground that if a mob gets to, will stay there forever. If socal this creates a
//"Ball of Death" (tm). This code tries to prevent this by simply warping the mob to the requested x/y. Better to have a warp than
//have stuck mobs.
auto routeNode = route.begin();
bool noValidPath = true;
while (routeNode != route.end() && noValidPath == true) {
auto &currentNode = (*routeNode);
if (routeNode == route.end())
{
continue;
}
if (!(currentNode.pos.x == who->GetX() && currentNode.pos.y == who->GetY()))
{
//if one of the nodes to move to, is not our current node, pass it.
noValidPath = false;
break;
}
//move to the next node
routeNode++;
}
if (noValidPath)
{
//we are 'stuck' in a path, lets just get out of this by 'teleporting' to the next position.
PushTeleportTo(ent.second, x, y, z,
CalculateHeadingAngleBetweenPositions(who->GetX(), who->GetY(), x, y));
return;
}
}
auto iter = route.begin();
glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ());
bool first_node = true;
while (iter != route.end()) {
auto &current_node = (*iter);
+1 -1
View File
@@ -514,7 +514,7 @@ int main(int argc, char** argv) {
}
else {
if (worldwasconnected && is_zone_loaded) {
entity_list.ChannelMessageFromWorld(0, 0, 6, 0, 0, "WARNING: World server connection lost");
entity_list.ChannelMessageFromWorld(0, 0, ChatChannel_Broadcast, 0, 0, 100, "WARNING: World server connection lost");
worldwasconnected = false;
}
}
+5
View File
@@ -226,6 +226,11 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
merchant_open = GetClass() == MERCHANT;
adventure_template_id = npc_type_data->adventure_template;
flymode = iflymode;
if (npc_type_data->flymode >= 0) {
flymode = static_cast<GravityBehavior>(npc_type_data->flymode);
}
guard_anim = eaStanding;
roambox_distance = 0;
roambox_max_x = -2;
+6 -17
View File
@@ -154,30 +154,19 @@ void QuestManager::echo(int colour, const char *str) {
entity_list.MessageClose(initiator, false, 200, colour, str);
}
void QuestManager::say(const char *str) {
void QuestManager::say(const char *str, Journal::Options &opts) {
QuestManagerCurrentQuestVars();
if (!owner) {
Log(Logs::General, Logs::Quests, "QuestManager::say called with nullptr owner. Probably syntax error in quest file.");
return;
}
else {
if(RuleB(NPC, EnableNPCQuestJournal) && initiator) {
owner->QuestJournalledSay(initiator, str);
if (!RuleB(NPC, EnableNPCQuestJournal))
opts.journal_mode = Journal::Mode::None;
if (initiator) {
opts.target_spawn_id = initiator->GetID();
owner->QuestJournalledSay(initiator, str, opts);
}
else {
owner->Say(str);
}
}
}
void QuestManager::say(const char *str, uint8 language) {
QuestManagerCurrentQuestVars();
if (!owner) {
Log(Logs::General, Logs::Quests, "QuestManager::say called with nullptr owner. Probably syntax error in quest file.");
return;
}
else {
entity_list.ChannelMessage(owner, 8, language, str);
}
}
+1 -2
View File
@@ -62,8 +62,7 @@ public:
//quest functions
void echo(int colour, const char *str);
void say(const char *str);
void say(const char *str, uint8 language);
void say(const char *str, Journal::Options &opts);
void me(const char *str);
void summonitem(uint32 itemid, int16 charges = -1);
void write(const char *file, const char *str);
+7 -3
View File
@@ -446,7 +446,7 @@ uint32 Raid::GetGroup(Client *c)
return 0xFFFFFFFF;
}
void Raid::RaidSay(const char *msg, Client *c)
void Raid::RaidSay(const char *msg, Client *c, uint8 language, uint8 lang_skill)
{
if(!c)
return;
@@ -455,6 +455,8 @@ void Raid::RaidSay(const char *msg, Client *c)
ServerRaidMessage_Struct *rga = (ServerRaidMessage_Struct*)pack->pBuffer;
rga->rid = GetID();
rga->gid = 0xFFFFFFFF;
rga->language = language;
rga->lang_skill = lang_skill;
strn0cpy(rga->from, c->GetName(), 64);
strcpy(rga->message, msg); // this is safe because we are allocating enough space for the entire msg above
@@ -463,7 +465,7 @@ void Raid::RaidSay(const char *msg, Client *c)
safe_delete(pack);
}
void Raid::RaidGroupSay(const char *msg, Client *c)
void Raid::RaidGroupSay(const char *msg, Client *c, uint8 language, uint8 lang_skill)
{
if(!c)
return;
@@ -477,6 +479,8 @@ void Raid::RaidGroupSay(const char *msg, Client *c)
ServerRaidMessage_Struct *rga = (ServerRaidMessage_Struct*)pack->pBuffer;
rga->rid = GetID();
rga->gid = groupToUse;
rga->language = language;
rga->lang_skill = lang_skill;
strn0cpy(rga->from, c->GetName(), 64);
strcpy(rga->message, msg); // this is safe because we are allocating enough space for the entire msg above
@@ -1821,4 +1825,4 @@ void Raid::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_re
}
}
}
}
}
+2 -2
View File
@@ -177,8 +177,8 @@ public:
void SendHPManaEndPacketsFrom(Mob *mob);
void SendManaPacketFrom(Mob *mob);
void SendEndurancePacketFrom(Mob *mob);
void RaidSay(const char *msg, Client *c);
void RaidGroupSay(const char *msg, Client *c);
void RaidSay(const char *msg, Client *c, uint8 language, uint8 lang_skill);
void RaidGroupSay(const char *msg, Client *c, uint8 language, uint8 lang_skill);
//Packet Functions
void SendRaidCreate(Client *to);
+37 -12
View File
@@ -200,29 +200,35 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
break;
ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*)pack->pBuffer;
if (scm->deliverto[0] == 0) {
entity_list.ChannelMessageFromWorld(scm->from, scm->to, scm->chan_num, scm->guilddbid, scm->language, scm->message);
entity_list.ChannelMessageFromWorld(scm->from, scm->to, scm->chan_num, scm->guilddbid, scm->language, scm->lang_skill, scm->message);
}
else {
Client* client = entity_list.GetClientByName(scm->deliverto);
if (client) {
if (client->Connected()) {
if (client && client->Connected()) {
if (scm->chan_num == ChatChannel_TellEcho) {
if (scm->queued == 1) // tell was queued
client->Tell_StringID(QUEUED_TELL, scm->to, scm->message);
else if (scm->queued == 2) // tell queue was full
client->Tell_StringID(QUEUE_TELL_FULL, scm->to, scm->message);
else if (scm->queued == 3) // person was offline
client->Message_StringID(MT_TellEcho, TOLD_NOT_ONLINE, scm->to);
else // normal stuff
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->message);
if (!scm->noreply && scm->chan_num != 2) { //dont echo on group chat
// if it's a tell, echo back so it shows up
scm->noreply = true;
scm->chan_num = 14;
else // normal tell echo "You told Soanso, 'something'"
// tell echo doesn't use language, so it looks normal to you even if nobody can understand your tells
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, 0, 100, scm->message);
}
else if (scm->chan_num == ChatChannel_Tell) {
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->lang_skill, scm->message);
if (scm->queued == 0) { // this is not a queued tell
// if it's a tell, echo back to acknowledge it and make it show on the sender's client
scm->chan_num = ChatChannel_TellEcho;
memset(scm->deliverto, 0, sizeof(scm->deliverto));
strcpy(scm->deliverto, scm->from);
SendPacket(pack);
}
}
else {
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->lang_skill, scm->message);
}
}
}
break;
@@ -528,6 +534,7 @@ 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()) {
zone->AddAuth(szic);
// This packet also doubles as "incoming client" notification, lets not shut down before they get here
@@ -541,6 +548,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();
client->Save();
}
}
break;
}
case ServerOP_ZonePlayer: {
ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*)pack->pBuffer;
Client* client = entity_list.GetClientByName(szp->name);
@@ -1352,7 +1376,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
if (r->members[x].GroupNumber == rmsg->gid) {
if (r->members[x].member->GetFilter(FilterGroupChat) != 0)
{
r->members[x].member->ChannelMessageSend(rmsg->from, r->members[x].member->GetName(), 2, 0, rmsg->message);
r->members[x].member->ChannelMessageSend(rmsg->from, r->members[x].member->GetName(), ChatChannel_Group, rmsg->language, rmsg->lang_skill, rmsg->message);
}
}
}
@@ -1377,7 +1401,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
{
if (r->members[x].member->GetFilter(FilterGroupChat) != 0)
{
r->members[x].member->ChannelMessageSend(rmsg->from, r->members[x].member->GetName(), 15, 0, rmsg->message);
r->members[x].member->ChannelMessageSend(rmsg->from, r->members[x].member->GetName(), ChatChannel_Raid, rmsg->language, rmsg->lang_skill, rmsg->message);
}
}
}
@@ -1950,7 +1974,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
}
}
bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, const char* message, ...) {
bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, uint8 lang_skill, const char* message, ...) {
if (!worldserver.Connected())
return false;
va_list argptr;
@@ -1984,6 +2008,7 @@ bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_nu
scm->chan_num = chan_num;
scm->guilddbid = guilddbid;
scm->language = language;
scm->lang_skill = lang_skill;
scm->queued = 0;
strcpy(scm->message, buffer);
+1 -1
View File
@@ -38,7 +38,7 @@ public:
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
bool SendChannelMessage(Client* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, const char* message, ...);
bool SendChannelMessage(Client* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, uint8 lang_skill, const char* message, ...);
bool SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...);
bool SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...);
bool SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 MacroNumber, uint32 GroupOrRaidID = 0);
+20 -4
View File
@@ -1106,6 +1106,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 +1114,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();
}
+3 -1
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];
@@ -243,7 +244,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();
+149 -132
View File
@@ -2366,29 +2366,33 @@ bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 times
return results.Success();
}
const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)
const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)
{
const NPCType *npc = nullptr;
/* If there is a cached NPC entry, load it */
auto itr = zone->npctable.find(npc_type_id);
if(itr != zone->npctable.end())
if (itr != zone->npctable.end()) {
return itr->second;
}
std::string where_condition = "";
if (bulk_load){
if (bulk_load) {
Log(Logs::General, Logs::Debug, "Performing bulk NPC Types load");
where_condition = StringFormat(
"INNER JOIN spawnentry ON npc_types.id = spawnentry.npcID "
"INNER JOIN spawn2 ON spawnentry.spawngroupID = spawn2.spawngroupID "
"WHERE spawn2.zone = '%s' and spawn2.version = %u GROUP BY npc_types.id", zone->GetShortName(), zone->GetInstanceVersion());
"WHERE spawn2.zone = '%s' and spawn2.version = %u GROUP BY npc_types.id",
zone->GetShortName(),
zone->GetInstanceVersion());
}
else{
else {
where_condition = StringFormat("WHERE id = %u", npc_type_id);
}
std::string query = StringFormat("SELECT "
std::string query = StringFormat(
"SELECT "
"npc_types.id, "
"npc_types.name, "
"npc_types.level, "
@@ -2499,115 +2503,122 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
"npc_types.skip_global_loot, "
"npc_types.rare_spawn, "
"npc_types.stuck_behavior, "
"npc_types.model "
"npc_types.model, "
"npc_types.flymode "
"FROM npc_types %s",
where_condition.c_str()
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return nullptr;
}
auto results = QueryDatabase(query);
if (!results.Success()) {
return nullptr;
}
for (auto row = results.begin(); row != results.end(); ++row) {
for (auto row = results.begin(); row != results.end(); ++row) {
NPCType *temp_npctype_data;
temp_npctype_data = new NPCType;
memset (temp_npctype_data, 0, sizeof *temp_npctype_data);
memset(temp_npctype_data, 0, sizeof *temp_npctype_data);
temp_npctype_data->npc_id = atoi(row[0]);
strn0cpy(temp_npctype_data->name, row[1], 50);
temp_npctype_data->level = atoi(row[2]);
temp_npctype_data->race = atoi(row[3]);
temp_npctype_data->class_ = atoi(row[4]);
temp_npctype_data->max_hp = atoi(row[5]);
temp_npctype_data->current_hp = temp_npctype_data->max_hp;
temp_npctype_data->Mana = atoi(row[6]);
temp_npctype_data->gender = atoi(row[7]);
temp_npctype_data->texture = atoi(row[8]);
temp_npctype_data->helmtexture = atoi(row[9]);
temp_npctype_data->herosforgemodel = atoul(row[10]);
temp_npctype_data->size = atof(row[11]);
temp_npctype_data->loottable_id = atoi(row[12]);
temp_npctype_data->merchanttype = atoi(row[13]);
temp_npctype_data->alt_currency_type = atoi(row[14]);
temp_npctype_data->level = atoi(row[2]);
temp_npctype_data->race = atoi(row[3]);
temp_npctype_data->class_ = atoi(row[4]);
temp_npctype_data->max_hp = atoi(row[5]);
temp_npctype_data->current_hp = temp_npctype_data->max_hp;
temp_npctype_data->Mana = atoi(row[6]);
temp_npctype_data->gender = atoi(row[7]);
temp_npctype_data->texture = atoi(row[8]);
temp_npctype_data->helmtexture = atoi(row[9]);
temp_npctype_data->herosforgemodel = atoul(row[10]);
temp_npctype_data->size = atof(row[11]);
temp_npctype_data->loottable_id = atoi(row[12]);
temp_npctype_data->merchanttype = atoi(row[13]);
temp_npctype_data->alt_currency_type = atoi(row[14]);
temp_npctype_data->adventure_template = atoi(row[15]);
temp_npctype_data->trap_template = atoi(row[16]);
temp_npctype_data->attack_speed = atof(row[17]);
temp_npctype_data->STR = atoi(row[18]);
temp_npctype_data->STA = atoi(row[19]);
temp_npctype_data->DEX = atoi(row[20]);
temp_npctype_data->AGI = atoi(row[21]);
temp_npctype_data->INT = atoi(row[22]);
temp_npctype_data->WIS = atoi(row[23]);
temp_npctype_data->CHA = atoi(row[24]);
temp_npctype_data->MR = atoi(row[25]);
temp_npctype_data->CR = atoi(row[26]);
temp_npctype_data->DR = atoi(row[27]);
temp_npctype_data->FR = atoi(row[28]);
temp_npctype_data->PR = atoi(row[29]);
temp_npctype_data->Corrup = atoi(row[30]);
temp_npctype_data->PhR = atoi(row[31]);
temp_npctype_data->min_dmg = atoi(row[32]);
temp_npctype_data->max_dmg = atoi(row[33]);
temp_npctype_data->attack_count = atoi(row[34]);
temp_npctype_data->trap_template = atoi(row[16]);
temp_npctype_data->attack_speed = atof(row[17]);
temp_npctype_data->STR = atoi(row[18]);
temp_npctype_data->STA = atoi(row[19]);
temp_npctype_data->DEX = atoi(row[20]);
temp_npctype_data->AGI = atoi(row[21]);
temp_npctype_data->INT = atoi(row[22]);
temp_npctype_data->WIS = atoi(row[23]);
temp_npctype_data->CHA = atoi(row[24]);
temp_npctype_data->MR = atoi(row[25]);
temp_npctype_data->CR = atoi(row[26]);
temp_npctype_data->DR = atoi(row[27]);
temp_npctype_data->FR = atoi(row[28]);
temp_npctype_data->PR = atoi(row[29]);
temp_npctype_data->Corrup = atoi(row[30]);
temp_npctype_data->PhR = atoi(row[31]);
temp_npctype_data->min_dmg = atoi(row[32]);
temp_npctype_data->max_dmg = atoi(row[33]);
temp_npctype_data->attack_count = atoi(row[34]);
if (row[35] != nullptr)
if (row[35] != nullptr) {
strn0cpy(temp_npctype_data->special_abilities, row[35], 512);
else
}
else {
temp_npctype_data->special_abilities[0] = '\0';
}
temp_npctype_data->npc_spells_id = atoi(row[36]);
temp_npctype_data->npc_spells_id = atoi(row[36]);
temp_npctype_data->npc_spells_effects_id = atoi(row[37]);
temp_npctype_data->d_melee_texture1 = atoi(row[38]);
temp_npctype_data->d_melee_texture2 = atoi(row[39]);
temp_npctype_data->d_melee_texture1 = atoi(row[38]);
temp_npctype_data->d_melee_texture2 = atoi(row[39]);
strn0cpy(temp_npctype_data->ammo_idfile, row[40], 30);
temp_npctype_data->prim_melee_type = atoi(row[41]);
temp_npctype_data->sec_melee_type = atoi(row[42]);
temp_npctype_data->ranged_type = atoi(row[43]);
temp_npctype_data->runspeed= atof(row[44]);
temp_npctype_data->findable = atoi(row[45]) == 0? false : true;
temp_npctype_data->trackable = atoi(row[46]) == 0? false : true;
temp_npctype_data->hp_regen = atoi(row[47]);
temp_npctype_data->mana_regen = atoi(row[48]);
temp_npctype_data->sec_melee_type = atoi(row[42]);
temp_npctype_data->ranged_type = atoi(row[43]);
temp_npctype_data->runspeed = atof(row[44]);
temp_npctype_data->findable = atoi(row[45]) == 0 ? false : true;
temp_npctype_data->trackable = atoi(row[46]) == 0 ? false : true;
temp_npctype_data->hp_regen = atoi(row[47]);
temp_npctype_data->mana_regen = atoi(row[48]);
// set default value for aggroradius
temp_npctype_data->aggroradius = (int32)atoi(row[49]);
if (temp_npctype_data->aggroradius <= 0)
temp_npctype_data->aggroradius = (int32) atoi(row[49]);
if (temp_npctype_data->aggroradius <= 0) {
temp_npctype_data->aggroradius = 70;
}
temp_npctype_data->assistradius = (int32)atoi(row[50]);
if (temp_npctype_data->assistradius <= 0)
temp_npctype_data->assistradius = (int32) atoi(row[50]);
if (temp_npctype_data->assistradius <= 0) {
temp_npctype_data->assistradius = temp_npctype_data->aggroradius;
}
if (row[51] && strlen(row[51]))
temp_npctype_data->bodytype = (uint8)atoi(row[51]);
else
temp_npctype_data->bodytype = 0;
if (row[51] && strlen(row[51])) {
temp_npctype_data->bodytype = (uint8) atoi(row[51]);
}
else {
temp_npctype_data->bodytype = 0;
}
temp_npctype_data->npc_faction_id = atoi(row[52]);
temp_npctype_data->luclinface = atoi(row[53]);
temp_npctype_data->hairstyle = atoi(row[54]);
temp_npctype_data->haircolor = atoi(row[55]);
temp_npctype_data->eyecolor1 = atoi(row[56]);
temp_npctype_data->eyecolor2 = atoi(row[57]);
temp_npctype_data->beardcolor = atoi(row[58]);
temp_npctype_data->beard = atoi(row[59]);
temp_npctype_data->luclinface = atoi(row[53]);
temp_npctype_data->hairstyle = atoi(row[54]);
temp_npctype_data->haircolor = atoi(row[55]);
temp_npctype_data->eyecolor1 = atoi(row[56]);
temp_npctype_data->eyecolor2 = atoi(row[57]);
temp_npctype_data->beardcolor = atoi(row[58]);
temp_npctype_data->beard = atoi(row[59]);
temp_npctype_data->drakkin_heritage = atoi(row[60]);
temp_npctype_data->drakkin_tattoo = atoi(row[61]);
temp_npctype_data->drakkin_details = atoi(row[62]);
temp_npctype_data->drakkin_tattoo = atoi(row[61]);
temp_npctype_data->drakkin_details = atoi(row[62]);
uint32 armor_tint_id = atoi(row[63]);
temp_npctype_data->armor_tint.Head.Color = (atoi(row[64]) & 0xFF) << 16;
temp_npctype_data->armor_tint.Head.Color |= (atoi(row[65]) & 0xFF) << 8;
temp_npctype_data->armor_tint.Head.Color |= (atoi(row[65]) & 0xFF) << 8;
temp_npctype_data->armor_tint.Head.Color |= (atoi(row[66]) & 0xFF);
temp_npctype_data->armor_tint.Head.Color |= (temp_npctype_data->armor_tint.Head.Color) ? (0xFF << 24) : 0;
if (armor_tint_id != 0) {
std::string armortint_query = StringFormat(
std::string armortint_query = StringFormat(
"SELECT red1h, grn1h, blu1h, "
"red2c, grn2c, blu2c, "
"red3a, grn3a, blu3a, "
@@ -2618,21 +2629,24 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
"red8x, grn8x, blu8x, "
"red9x, grn9x, blu9x "
"FROM npc_types_tint WHERE id = %d",
armor_tint_id);
auto armortint_results = QueryDatabase(armortint_query);
if (!armortint_results.Success() || armortint_results.RowCount() == 0)
armor_tint_id = 0;
else {
auto armorTint_row = armortint_results.begin();
armor_tint_id
);
auto armortint_results = QueryDatabase(armortint_query);
if (!armortint_results.Success() || armortint_results.RowCount() == 0) {
armor_tint_id = 0;
}
else {
auto armorTint_row = armortint_results.begin();
for (int index = EQEmu::textures::textureBegin; index <= EQEmu::textures::LastTexture; index++) {
temp_npctype_data->armor_tint.Slot[index].Color = atoi(armorTint_row[index * 3]) << 16;
temp_npctype_data->armor_tint.Slot[index].Color = atoi(armorTint_row[index * 3]) << 16;
temp_npctype_data->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 1]) << 8;
temp_npctype_data->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 2]);
temp_npctype_data->armor_tint.Slot[index].Color |= (temp_npctype_data->armor_tint.Slot[index].Color) ? (0xFF << 24) : 0;
}
}
}
temp_npctype_data->armor_tint.Slot[index].Color |= (temp_npctype_data->armor_tint.Slot[index].Color)
? (0xFF << 24) : 0;
}
}
}
// Try loading npc_types tint fields if armor tint is 0 or query failed to get results
if (armor_tint_id == 0) {
for (int index = EQEmu::textures::armorChest; index < EQEmu::textures::materialCount; index++) {
@@ -2640,56 +2654,59 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
}
}
temp_npctype_data->see_invis = atoi(row[67]);
temp_npctype_data->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag
temp_npctype_data->see_invis = atoi(row[67]);
temp_npctype_data->see_invis_undead = atoi(row[68]) == 0 ? false : true; // Set see_invis_undead flag
if (row[69] != nullptr)
if (row[69] != nullptr) {
strn0cpy(temp_npctype_data->lastname, row[69], 32);
}
temp_npctype_data->qglobal = atoi(row[70]) == 0? false: true; // qglobal
temp_npctype_data->AC = atoi(row[71]);
temp_npctype_data->npc_aggro = atoi(row[72]) == 0? false: true;
temp_npctype_data->spawn_limit = atoi(row[73]);
temp_npctype_data->see_hide = atoi(row[74]) == 0? false: true;
temp_npctype_data->see_improved_hide = atoi(row[75]) == 0? false: true;
temp_npctype_data->ATK = atoi(row[76]);
temp_npctype_data->accuracy_rating = atoi(row[77]);
temp_npctype_data->avoidance_rating = atoi(row[78]);
temp_npctype_data->slow_mitigation = atoi(row[79]);
temp_npctype_data->maxlevel = atoi(row[80]);
temp_npctype_data->scalerate = atoi(row[81]);
temp_npctype_data->private_corpse = atoi(row[82]) == 1 ? true: false;
temp_npctype_data->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false;
temp_npctype_data->underwater = atoi(row[84]) == 1 ? true: false;
temp_npctype_data->emoteid = atoi(row[85]);
temp_npctype_data->spellscale = atoi(row[86]);
temp_npctype_data->healscale = atoi(row[87]);
temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false : true;
temp_npctype_data->attack_delay = atoi(row[90]) * 100; // TODO: fix DB
temp_npctype_data->light = (atoi(row[91]) & 0x0F);
temp_npctype_data->qglobal = atoi(row[70]) == 0 ? false : true; // qglobal
temp_npctype_data->AC = atoi(row[71]);
temp_npctype_data->npc_aggro = atoi(row[72]) == 0 ? false : true;
temp_npctype_data->spawn_limit = atoi(row[73]);
temp_npctype_data->see_hide = atoi(row[74]) == 0 ? false : true;
temp_npctype_data->see_improved_hide = atoi(row[75]) == 0 ? false : true;
temp_npctype_data->ATK = atoi(row[76]);
temp_npctype_data->accuracy_rating = atoi(row[77]);
temp_npctype_data->avoidance_rating = atoi(row[78]);
temp_npctype_data->slow_mitigation = atoi(row[79]);
temp_npctype_data->maxlevel = atoi(row[80]);
temp_npctype_data->scalerate = atoi(row[81]);
temp_npctype_data->private_corpse = atoi(row[82]) == 1 ? true : false;
temp_npctype_data->unique_spawn_by_name = atoi(row[83]) == 1 ? true : false;
temp_npctype_data->underwater = atoi(row[84]) == 1 ? true : false;
temp_npctype_data->emoteid = atoi(row[85]);
temp_npctype_data->spellscale = atoi(row[86]);
temp_npctype_data->healscale = atoi(row[87]);
temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true : false;
temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false : true;
temp_npctype_data->attack_delay = atoi(row[90]) * 100; // TODO: fix DB
temp_npctype_data->light = (atoi(row[91]) & 0x0F);
temp_npctype_data->armtexture = atoi(row[92]);
temp_npctype_data->bracertexture = atoi(row[93]);
temp_npctype_data->handtexture = atoi(row[94]);
temp_npctype_data->legtexture = atoi(row[95]);
temp_npctype_data->feettexture = atoi(row[96]);
temp_npctype_data->armtexture = atoi(row[92]);
temp_npctype_data->bracertexture = atoi(row[93]);
temp_npctype_data->handtexture = atoi(row[94]);
temp_npctype_data->legtexture = atoi(row[95]);
temp_npctype_data->feettexture = atoi(row[96]);
temp_npctype_data->ignore_despawn = atoi(row[97]) == 1 ? true : false;
temp_npctype_data->show_name = atoi(row[98]) != 0 ? true : false;
temp_npctype_data->untargetable = atoi(row[99]) != 0 ? true : false;
temp_npctype_data->show_name = atoi(row[98]) != 0 ? true : false;
temp_npctype_data->untargetable = atoi(row[99]) != 0 ? true : false;
temp_npctype_data->charm_ac = atoi(row[100]);
temp_npctype_data->charm_min_dmg = atoi(row[101]);
temp_npctype_data->charm_max_dmg = atoi(row[102]);
temp_npctype_data->charm_attack_delay = atoi(row[103]) * 100; // TODO: fix DB
temp_npctype_data->charm_accuracy_rating = atoi(row[104]);
temp_npctype_data->charm_ac = atoi(row[100]);
temp_npctype_data->charm_min_dmg = atoi(row[101]);
temp_npctype_data->charm_max_dmg = atoi(row[102]);
temp_npctype_data->charm_attack_delay = atoi(row[103]) * 100; // TODO: fix DB
temp_npctype_data->charm_accuracy_rating = atoi(row[104]);
temp_npctype_data->charm_avoidance_rating = atoi(row[105]);
temp_npctype_data->charm_atk = atoi(row[106]);
temp_npctype_data->charm_atk = atoi(row[106]);
temp_npctype_data->skip_global_loot = atoi(row[107]) != 0;
temp_npctype_data->rare_spawn = atoi(row[108]) != 0;
temp_npctype_data->stuck_behavior = atoi(row[109]);
temp_npctype_data->use_model = atoi(row[110]);
temp_npctype_data->rare_spawn = atoi(row[108]) != 0;
temp_npctype_data->stuck_behavior = atoi(row[109]);
temp_npctype_data->use_model = atoi(row[110]);
temp_npctype_data->flymode = atoi(row[111]);
temp_npctype_data->skip_auto_scale = false; // hardcoded here for now
// If NPC with duplicate NPC id already in table,
@@ -2700,9 +2717,9 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
return nullptr;
}
zone->npctable[temp_npctype_data->npc_id] = temp_npctype_data;
npc = temp_npctype_data;
}
zone->npctable[temp_npctype_data->npc_id] = temp_npctype_data;
npc = temp_npctype_data;
}
return npc;
}
+1
View File
@@ -146,6 +146,7 @@ struct NPCType
bool skip_auto_scale; // just so it doesn't mess up bots or mercs, probably should add to DB too just in case
int8 stuck_behavior;
uint16 use_model;
int8 flymode;
};
namespace player_lootitem {