Compare commits

..

1 Commits

Author SHA1 Message Date
Akkadius 1c09a25261 Beginning of zone copy work 2024-10-11 04:10:00 -05:00
630 changed files with 36044 additions and 74270 deletions
-1
View File
@@ -68,4 +68,3 @@ compile_flags.txt
# CMake Files # CMake Files
cmake-build-relwithdebinfo/* cmake-build-relwithdebinfo/*
skill-caps.diff
-1033
View File
File diff suppressed because it is too large Load Diff
-6
View File
@@ -37,12 +37,8 @@ IF(EQEMU_ADD_PROFILER)
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-as-needed,-lprofiler,--as-needed") SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-as-needed,-lprofiler,--as-needed")
ENDIF(EQEMU_ADD_PROFILER) ENDIF(EQEMU_ADD_PROFILER)
IF(USE_MAP_MMFS)
ADD_DEFINITIONS(-DUSE_MAP_MMFS)
ENDIF (USE_MAP_MMFS)
IF(MSVC) IF(MSVC)
add_compile_options(/bigobj)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-DNOMINMAX) ADD_DEFINITIONS(-DNOMINMAX)
ADD_DEFINITIONS(-DCRASH_LOGGING) ADD_DEFINITIONS(-DCRASH_LOGGING)
@@ -363,8 +359,6 @@ MESSAGE(STATUS "**************************************************")
#setup server libs and headers #setup server libs and headers
SET(SERVER_LIBS common ${DATABASE_LIBRARY_LIBS} ${ZLIB_LIBRARY_LIBS} ${Boost_LIBRARIES} uv_a fmt RecastNavigation::Detour) SET(SERVER_LIBS common ${DATABASE_LIBRARY_LIBS} ${ZLIB_LIBRARY_LIBS} ${Boost_LIBRARIES} uv_a fmt RecastNavigation::Detour)
set(FMT_HEADER_ONLY OFF)
INCLUDE_DIRECTORIES(SYSTEM "${DATABASE_LIBRARY_INCLUDE}") INCLUDE_DIRECTORIES(SYSTEM "${DATABASE_LIBRARY_INCLUDE}")
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}") INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}")
INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}") INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}")
+56 -123
View File
@@ -1,150 +1,83 @@
<h1 align="center">EQEmulator Server Platform</h1> # EQEmulator Core Server
| Drone (Linux x64) | Drone (Windows x64) |
<p align="center"> |:---:|:---:|
<img src="https://github.com/user-attachments/assets/11942e15-b512-402d-a619-0543c7f1151e" style="border-radius: 10px"> |[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |
</p>
<p align="center">
<b>EQEmulator - A Fan-Made Project Honoring a Legendary MMORPG</b>
</p>
<p align="center">
<a href="https://github.com/eqemu/server/graphs/contributors"><img src="https://img.shields.io/github/contributors/eqemu/server" alt="Contributors"></a>
<a href="https://discord.gg/QHsm7CD"><img src="https://img.shields.io/discord/212663220849213441?label=Discord&amp;logo=discord&amp;color=7289DA" alt="Discord"></a>
<a href="https://docs.eqemu.io"><img src="https://img.shields.io/badge/docs-MkDocs%20Powered-blueviolet" alt="Docs"></a>
<a href="./LICENSE"><img src="https://img.shields.io/github/license/EQEmu/Server" alt="License"></a>
<a href="https://github.com/eqemu/server/releases"><img src="https://img.shields.io/github/v/release/eqemu/server" alt="Latest Release"></a>
<a href="https://github.com/EQEmu/Server/releases"><img src="https://img.shields.io/github/release-date/EQEmu/Server" alt="Release Date"></a>
<img src="https://img.shields.io/github/downloads/eqemu/server/total.svg" alt="Github All Releases"></a>
<a href="http://drone.akkadius.com/EQEmu/Server"><img src="http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg" alt="Build Status"></a>
<img src="https://img.shields.io/github/issues-pr-closed/eqemu/server" alt="GitHub Issues or Pull Requests">
<img src="https://img.shields.io/docker/pulls/akkadius/eqemu-server" alt="Docker Pulls">
<a href="http://drone.akkadius.com/EQEmu/Server"><img src="http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg" alt="Build Status"></a> <img src="https://jb.gg/badges/official-plastic.svg" alt="Official">
</p>
*** ***
<p align="center"> **EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++**
EQEmulator is a <b>passion-driven</b>, <b>open source server emulator</b> project dedicated to preserving and celebrating the legacy of a groundbreaking classic MMORPG. * MySQL/MariaDB is used as the database engine (over 200+ tables)
</p> * Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events
* Open source database (Project EQ) has content up to expansion OoW (included in server installs)
* Game server environments and databases can be heavily customized to create all new experiences
* Hundreds of Quests/events created and maintained by Project EQ
<p align="center"> ## Server Installs
For over two decades and continuing, EQEmulator has served as a <strong>fan tribute</strong>, providing tools and technology that allow players to explore, customize, and experience the legendary game's iconic gameplay in new ways. This project exists solely out of <strong>deep admiration</strong> for the original developers, artists, designers, and visionaries who created one of the most influential online worlds of all time. | |Windows|Linux|
</p> |:---:|:---:|:---:|
|**Install Count**|![Windows Install Count](http://analytics.akkadius.com/?install_count&windows_count)|![Linux Install Count](http://analytics.akkadius.com/?install_count&linux_count)|
### > Windows
<p align="center"> * [Install Guide](https://docs.eqemu.io/server/installation/server-installation-windows/)
We do not claim ownership of the original game or its assets. <strong>All credit and respect belong to the original creators and Daybreak Game Company</strong>, whose work continues to inspire generations of players and developers alike.
</p>
<p align="center"> ### > Debian/Ubuntu/CentOS/Fedora
EQEmulator has for over 20 years and always will be a <strong>fan-based, non-commercial open-source effort</strong> made by players, for players—preserving the legacy of the game while empowering community-driven creativity, learning and joy that the game and its creators has so strongly inspired in us all.
</p>
*** * [Install Guide](https://docs.eqemu.io/server/installation/server-installation-linux/)
<h3 align="center"> * You can use curl or wget to kick off the installer (whichever your OS has)
Technical Overview & Reverse Engineering Effort > curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
</h1>
<p align="center">EQEmulator represents <strong>over two decades of collaborative reverse engineering</strong>, building the server from the ground up without access to the original source code. This effort was achieved entirely through <strong>community-driven analysis, network protocol decoding, and in-game behavioral research</strong>.</p> > wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
<h1 align="center"> ## Supported Clients
💡 How We Did It
</h1>
<p align="center">
<img src="https://github.com/user-attachments/assets/b6b48cf7-f64a-4497-9750-71f442a3d132" height="300px">
</p>
<p align="center">
<strong>Reverse Engineering</strong>
Every system, packet, opcode, and game mechanic has been reconstructed through countless hours of live packet sniffing, client disassembly, and in-game experimentation by dedicated contributors over the years.
</p>
<p align="center">
No proprietary code or server sources were ever used.
</p>
<p align="center">
All implementations are the result of clean-room engineering.
</p>
<h1 align="center">
🛠️ Technology Stack
</h1>
<p align="center">
<img src="https://github.com/user-attachments/assets/df5ea809-86c5-439d-a8fa-651fb04ba477" style="border-radius: 10px">
</p>
**C++ Core Engine**
* High-performance networking and gameplay logic built in C++
* Cross-platform support for Linux and Windows
**MySQL / MariaDB Backend**
* Fully structured schema with over 200+ tables
* Supports content customization, expansions, and custom worlds
**Scripting Engine**
* Native support for **Perl** and **Lua** scripting
* Powerfully extendable for quests, NPC behaviors, and custom events
**Open Source Content Database**
* Includes ProjectEQs world data up through *Dragons of Norrath*
* 100% customizable to create entirely new game worlds
<h1 align="center">
🚀 Why It Matters
</h1>
<p align="center">🧬 EQEmulator stands as a <strong>technical preservation project</strong>, ensuring that the magic of classic and custom servers lives on for future generations of players, tinkerers, and game designers.
</p>
> We humbly acknowledge and thank the original developers for creating one of the most influential online experiences in gaming history.
<h1 align="center">
🧑‍💻🖥️ Supported Clients
</h1>
|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear| |Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|
|:---:|:---:|:---:|:---:|:---:| |:---:|:---:|:---:|:---:|:---:|
|<img src="http://i.imgur.com/hrwDxoM.jpg" height="150">|<img src="http://i.imgur.com/cRDW5tn.png" height="150">|<img src="http://i.imgur.com/V48kuVn.jpg" height="150">|<img src="http://i.imgur.com/IJQ0XMa.jpg" height="150">|<img src="http://i.imgur.com/OMpHkKa.png" height="100">| |<img src="http://i.imgur.com/hrwDxoM.jpg" height="150">|<img src="http://i.imgur.com/cRDW5tn.png" height="150">|<img src="http://i.imgur.com/V48kuVn.jpg" height="150">|<img src="http://i.imgur.com/IJQ0XMa.jpg" height="150">|<img src="http://i.imgur.com/OMpHkKa.png" height="100">|
## 📚 Resources ## Bug Reports <img src="http://i.imgur.com/daf1Vjw.png" height="20">
* Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug
reports or feature requests.
* The [EQEmu Forums](http://www.eqemulator.org/forums/) are also a place to submit and get help with bugs.
| Resource | Badges | Link | ## Contributions <img src="http://image.flaticon.com/icons/png/512/25/25231.png" width="20">
|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| **EQEmulator Docs** | [![Docs](https://img.shields.io/badge/docs-MkDocs%20Powered-blueviolet)](https://docs.eqemu.io) | [docs.eqemu.io](https://docs.eqemu.io/) |
| **Discord Community**| [![Discord](https://img.shields.io/discord/212663220849213441?label=Discord&logo=discord&color=7289DA)](https://discord.gg/QHsm7CD) | [Join Discord](https://discord.gg/QHsm7CD) |
| **Latest Release** | [![Latest Release](https://img.shields.io/github/v/release/eqemu/server)](https://github.com/eqemu/server/releases) <br> [![Release Date](https://img.shields.io/github/release-date/EQEmu/Server)](https://github.com/EQEmu/Server/releases) <br> [![All Releases](https://img.shields.io/github/downloads/eqemu/server/total.svg)](https://github.com/eqemu/server/releases) | [View Releases](https://github.com/eqemu/server/releases) |
| **License** | [![License](https://img.shields.io/github/license/EQEmu/Server)](./LICENSE) | [View License](./LICENSE) |
| **Build Status** | [![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) | [View Build Status](http://drone.akkadius.com/EQEmu/Server) |
| **Docker Pulls** | [![Docker Pulls](https://img.shields.io/docker/pulls/akkadius/eqemu-server)](https://hub.docker.com/r/akkadius/eqemu-server) | [Docker Hub](https://hub.docker.com/r/akkadius/eqemu-server) |
| **Contributions** | [![GitHub PRs](https://img.shields.io/github/issues-pr-closed/eqemu/server)](https://github.com/eqemu/server/pulls?q=is%3Apr+is%3Aclosed) | [Closed PRs & Issues](https://github.com/eqemu/server/pulls?q=is%3Apr+is%3Aclosed) |
## 🛠️ Getting Started * The preferred way to contribute is to fork the repo and submit a pull request on
GitHub. If you need help with your changes, you can always post on the forums or
try Discord. You can also post unified diffs (`git diff` should do the trick) on the
[Server Code Submissions](http://www.eqemulator.org/forums/forumdisplay.php?f=669)
forum, although pull requests will be much quicker and easier on all parties.
If you want to set up your own EQEmulator server, please refer to the current [server installation guides](https://docs.eqemu.io/#server-installation). We've had 100,000s of players and developers use our guides to set up their own servers, and we hope you will too! ## Contact <img src="http://gamerescape.com/wp-content/uploads/2015/06/discord.png" height="20">
## 🗂️ Related Repositories - Discord Channel: https://discord.gg/QHsm7CD
- **User Discord Channel**: `#general`
- **Developer Discord Channel**: `#eqemucoders`
| Repository | Description | ## Resources
|--------------------|----------------------------------------------------------------------------------| - [EQEmulator Forums](http://www.eqemulator.org/forums)
| [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests) | Official quests and event scripts for ProjectEQ | - [EQEmulator Wiki](https://docs.eqemu.io/)
| [Maps](https://github.com/Akkadius/EQEmuMaps) | EQEmu-compatible zone maps |
| [Installer Resources](https://github.com/Akkadius/EQEmuInstall) | Scripts and assets for setting up EQEmu servers |
| [Zone Utilities](https://github.com/EQEmu/zone-utilities) | Utilities for parsing, rendering, and manipulating EQ zone files |
## Related Repositories
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
* [Maps](https://github.com/Akkadius/EQEmuMaps)
* [Installer Resources](https://github.com/Akkadius/EQEmuInstall)
* [Zone Utilities](https://github.com/EQEmu/zone-utilities) - Various utilities and libraries for parsing, rendering and manipulating EQ Zone files.
## Other License Info
* The server code and utilities are released under **GPLv3**
* We also include some small libraries for convienence that may be under different licensing
* SocketLib - GPL LibXML
* zlib - zlib license
* MariaDB/MySQL - GPL
* GPL Perl - GPL / ActiveState (under the assumption that this is a free project)
* CPPUnit - GLP StringUtilities - Apache
* LUA - MIT
## Contributors ## Contributors
<a href="https://github.com/EQEmu/server/graphs/contributors"> <a href="https://github.com/EQEmu/server/graphs/contributors">
<img src="https://contributors-img.firebaseapp.com/image?repo=EQEmu/server" /> <img src="https://contributors-img.firebaseapp.com/image?repo=EQEmu/server" />
</a> </a>
+15 -10
View File
@@ -36,7 +36,12 @@
#include "../../common/file.h" #include "../../common/file.h"
#include "../../common/events/player_event_logs.h" #include "../../common/events/player_event_logs.h"
#include "../../common/skill_caps.h" #include "../../common/skill_caps.h"
#include "../../common/evolving_items.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
void ExportSpells(SharedDatabase *db); void ExportSpells(SharedDatabase *db);
void ExportSkillCaps(SharedDatabase *db); void ExportSkillCaps(SharedDatabase *db);
@@ -46,10 +51,10 @@ void ExportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
RegisterExecutablePlatform(ExePlatformClientExport); RegisterExecutablePlatform(ExePlatformClientExport);
EQEmuLogSys::Instance()->LoadLogSettingsDefaults(); LogSys.LoadLogSettingsDefaults();
set_exception_handler(); set_exception_handler();
PathManager::Instance()->Init(); path.LoadPaths();
LogInfo("Client Files Export Utility"); LogInfo("Client Files Export Utility");
if (!EQEmuConfig::LoadConfig()) { if (!EQEmuConfig::LoadConfig()) {
@@ -92,8 +97,8 @@ int main(int argc, char **argv)
content_db.SetMySQL(database); content_db.SetMySQL(database);
} }
EQEmuLogSys::Instance()->SetDatabase(&database) LogSys.SetDatabase(&database)
->SetLogPath(PathManager::Instance()->GetLogPath()) ->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings() ->LoadLogDatabaseSettings()
->StartFileLogs(); ->StartFileLogs();
@@ -122,14 +127,14 @@ int main(int argc, char **argv)
ExportBaseData(&content_db); ExportBaseData(&content_db);
ExportDBStrings(&database); ExportDBStrings(&database);
EQEmuLogSys::Instance()->CloseFileLogs(); LogSys.CloseFileLogs();
return 0; return 0;
} }
void ExportSpells(SharedDatabase* db) void ExportSpells(SharedDatabase* db)
{ {
std::ofstream file(fmt::format("{}/export/spells_us.txt", PathManager::Instance()->GetServerPath())); std::ofstream file(fmt::format("{}/export/spells_us.txt", path.GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/spells_us.txt to write, skipping."); LogError("Unable to open export/spells_us.txt to write, skipping.");
return; return;
@@ -148,7 +153,7 @@ void ExportSpells(SharedDatabase* db)
void ExportSkillCaps(SharedDatabase* db) void ExportSkillCaps(SharedDatabase* db)
{ {
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", PathManager::Instance()->GetServerPath())); std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/SkillCaps.txt to write, skipping."); LogError("Unable to open export/SkillCaps.txt to write, skipping.");
return; return;
@@ -167,7 +172,7 @@ void ExportSkillCaps(SharedDatabase* db)
void ExportBaseData(SharedDatabase *db) void ExportBaseData(SharedDatabase *db)
{ {
std::ofstream file(fmt::format("{}/export/BaseData.txt", PathManager::Instance()->GetServerPath())); std::ofstream file(fmt::format("{}/export/BaseData.txt", path.GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/BaseData.txt to write, skipping."); LogError("Unable to open export/BaseData.txt to write, skipping.");
return; return;
@@ -186,7 +191,7 @@ void ExportBaseData(SharedDatabase *db)
void ExportDBStrings(SharedDatabase *db) void ExportDBStrings(SharedDatabase *db)
{ {
std::ofstream file(fmt::format("{}/export/dbstr_us.txt", PathManager::Instance()->GetServerPath())); std::ofstream file(fmt::format("{}/export/dbstr_us.txt", path.GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/dbstr_us.txt to write, skipping."); LogError("Unable to open export/dbstr_us.txt to write, skipping.");
return; return;
+15 -10
View File
@@ -30,7 +30,12 @@
#include "../../common/repositories/base_data_repository.h" #include "../../common/repositories/base_data_repository.h"
#include "../../common/file.h" #include "../../common/file.h"
#include "../../common/events/player_event_logs.h" #include "../../common/events/player_event_logs.h"
#include "../../common/evolving_items.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
void ImportSpells(SharedDatabase *db); void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db); void ImportSkillCaps(SharedDatabase *db);
@@ -39,10 +44,10 @@ void ImportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) { int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientImport); RegisterExecutablePlatform(ExePlatformClientImport);
EQEmuLogSys::Instance()->LoadLogSettingsDefaults(); LogSys.LoadLogSettingsDefaults();
set_exception_handler(); set_exception_handler();
PathManager::Instance()->Init(); path.LoadPaths();
LogInfo("Client Files Import Utility"); LogInfo("Client Files Import Utility");
if(!EQEmuConfig::LoadConfig()) { if(!EQEmuConfig::LoadConfig()) {
@@ -85,8 +90,8 @@ int main(int argc, char **argv) {
content_db.SetMySQL(database); content_db.SetMySQL(database);
} }
EQEmuLogSys::Instance()->SetDatabase(&database) LogSys.SetDatabase(&database)
->SetLogPath(PathManager::Instance()->GetLogPath()) ->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings() ->LoadLogDatabaseSettings()
->StartFileLogs(); ->StartFileLogs();
@@ -95,7 +100,7 @@ int main(int argc, char **argv) {
ImportBaseData(&content_db); ImportBaseData(&content_db);
ImportDBStrings(&database); ImportDBStrings(&database);
EQEmuLogSys::Instance()->CloseFileLogs(); LogSys.CloseFileLogs();
return 0; return 0;
} }
@@ -131,7 +136,7 @@ bool IsStringField(int i) {
void ImportSpells(SharedDatabase *db) { void ImportSpells(SharedDatabase *db) {
LogInfo("Importing Spells"); LogInfo("Importing Spells");
std::string file = fmt::format("{}/import/spells_us.txt", PathManager::Instance()->GetServerPath()); std::string file = fmt::format("{}/import/spells_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "r"); FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open {} to read, skipping.", file);
@@ -221,7 +226,7 @@ void ImportSpells(SharedDatabase *db) {
void ImportSkillCaps(SharedDatabase *db) { void ImportSkillCaps(SharedDatabase *db) {
LogInfo("Importing Skill Caps"); LogInfo("Importing Skill Caps");
std::string file = fmt::format("{}/import/SkillCaps.txt", PathManager::Instance()->GetServerPath()); std::string file = fmt::format("{}/import/SkillCaps.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "r"); FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open {} to read, skipping.", file);
@@ -258,7 +263,7 @@ void ImportBaseData(SharedDatabase *db)
{ {
LogInfo("Importing Base Data"); LogInfo("Importing Base Data");
const std::string& file_name = fmt::format("{}/import/BaseData.txt", PathManager::Instance()->GetServerPath()); const std::string& file_name = fmt::format("{}/import/BaseData.txt", path.GetServerPath());
const auto& file_contents = File::GetContents(file_name); const auto& file_contents = File::GetContents(file_name);
if (!file_contents.error.empty()) { if (!file_contents.error.empty()) {
@@ -298,7 +303,7 @@ void ImportBaseData(SharedDatabase *db)
void ImportDBStrings(SharedDatabase *db) { void ImportDBStrings(SharedDatabase *db) {
LogInfo("Importing DB Strings"); LogInfo("Importing DB Strings");
std::string file = fmt::format("{}/import/dbstr_us.txt", PathManager::Instance()->GetServerPath()); std::string file = fmt::format("{}/import/dbstr_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "r"); FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open {} to read, skipping.", file);
+10 -46
View File
@@ -17,13 +17,11 @@ SET(common_sources
database.cpp database.cpp
database_instances.cpp database_instances.cpp
database/database_update_manifest.cpp database/database_update_manifest.cpp
database/database_update_manifest_custom.cpp
database/database_update_manifest_bots.cpp database/database_update_manifest_bots.cpp
database/database_update.cpp database/database_update.cpp
dbcore.cpp dbcore.cpp
deity.cpp deity.cpp
dynamic_zone_base.cpp dynamic_zone_base.cpp
dynamic_zone_lockout.cpp
emu_constants.cpp emu_constants.cpp
emu_limits.cpp emu_limits.cpp
emu_opcodes.cpp emu_opcodes.cpp
@@ -41,7 +39,7 @@ SET(common_sources
event_sub.cpp event_sub.cpp
events/player_event_logs.cpp events/player_event_logs.cpp
events/player_event_discord_formatter.cpp events/player_event_discord_formatter.cpp
evolving_items.cpp expedition_lockout_timer.cpp
extprofile.cpp extprofile.cpp
discord/discord_manager.cpp discord/discord_manager.cpp
faction.cpp faction.cpp
@@ -64,7 +62,6 @@ SET(common_sources
mutex.cpp mutex.cpp
mysql_request_result.cpp mysql_request_result.cpp
mysql_request_row.cpp mysql_request_row.cpp
mysql_stmt.cpp
opcode_map.cpp opcode_map.cpp
opcodemgr.cpp opcodemgr.cpp
packet_dump.cpp packet_dump.cpp
@@ -90,7 +87,6 @@ SET(common_sources
skills.cpp skills.cpp
skill_caps.cpp skill_caps.cpp
spdat.cpp spdat.cpp
spdat_bot.cpp
strings.cpp strings.cpp
struct_strategy.cpp struct_strategy.cpp
textures.cpp textures.cpp
@@ -99,8 +95,8 @@ SET(common_sources
platform.cpp platform.cpp
json/json.hpp json/json.hpp
json/jsoncpp.cpp json/jsoncpp.cpp
zone_copy.cpp
zone_store.cpp zone_store.cpp
memory/ksm.hpp
net/console_server.cpp net/console_server.cpp
net/console_server_connection.cpp net/console_server_connection.cpp
net/crc32.cpp net/crc32.cpp
@@ -176,7 +172,6 @@ SET(repositories
repositories/base/base_character_currency_repository.h repositories/base/base_character_currency_repository.h
repositories/base/base_character_data_repository.h repositories/base/base_character_data_repository.h
repositories/base/base_character_disciplines_repository.h repositories/base/base_character_disciplines_repository.h
repositories/base/base_character_evolving_items_repository.h
repositories/base/base_character_expedition_lockouts_repository.h repositories/base/base_character_expedition_lockouts_repository.h
repositories/base/base_character_exp_modifiers_repository.h repositories/base/base_character_exp_modifiers_repository.h
repositories/base/base_character_inspect_messages_repository.h repositories/base/base_character_inspect_messages_repository.h
@@ -214,9 +209,10 @@ SET(repositories
repositories/base/base_discovered_items_repository.h repositories/base/base_discovered_items_repository.h
repositories/base/base_doors_repository.h repositories/base/base_doors_repository.h
repositories/base/base_dynamic_zones_repository.h repositories/base/base_dynamic_zones_repository.h
repositories/base/base_dynamic_zone_lockouts_repository.h
repositories/base/base_dynamic_zone_members_repository.h repositories/base/base_dynamic_zone_members_repository.h
repositories/base/base_dynamic_zone_templates_repository.h repositories/base/base_dynamic_zone_templates_repository.h
repositories/base/base_expeditions_repository.h
repositories/base/base_expedition_lockouts_repository.h
repositories/base/base_faction_association_repository.h repositories/base/base_faction_association_repository.h
repositories/base/base_faction_base_data_repository.h repositories/base/base_faction_base_data_repository.h
repositories/base/base_faction_list_repository.h repositories/base/base_faction_list_repository.h
@@ -244,7 +240,6 @@ SET(repositories
repositories/base/base_inventory_snapshots_repository.h repositories/base/base_inventory_snapshots_repository.h
repositories/base/base_ip_exemptions_repository.h repositories/base/base_ip_exemptions_repository.h
repositories/base/base_items_repository.h repositories/base/base_items_repository.h
repositories/base/base_items_evolving_details_repository.h
repositories/base/base_ldon_trap_entries_repository.h repositories/base/base_ldon_trap_entries_repository.h
repositories/base/base_ldon_trap_templates_repository.h repositories/base/base_ldon_trap_templates_repository.h
repositories/base/base_level_exp_mods_repository.h repositories/base/base_level_exp_mods_repository.h
@@ -282,20 +277,8 @@ SET(repositories
repositories/base/base_pets_equipmentset_repository.h repositories/base/base_pets_equipmentset_repository.h
repositories/base/base_pets_equipmentset_entries_repository.h repositories/base/base_pets_equipmentset_entries_repository.h
repositories/base/base_player_titlesets_repository.h repositories/base/base_player_titlesets_repository.h
repositories/base/base_player_event_aa_purchase_repository.h
repositories/base/base_player_event_killed_npc_repository.h
repositories/base/base_player_event_killed_named_npc_repository.h
repositories/base/base_player_event_killed_raid_npc_repository.h
repositories/base/base_player_event_log_settings_repository.h repositories/base/base_player_event_log_settings_repository.h
repositories/base/base_player_event_logs_repository.h repositories/base/base_player_event_logs_repository.h
repositories/base/base_player_event_loot_items_repository.h
repositories/base/base_player_event_merchant_purchase_repository.h
repositories/base/base_player_event_merchant_sell_repository.h
repositories/base/base_player_event_npc_handin_repository.h
repositories/base/base_player_event_npc_handin_entries_repository.h
repositories/base/base_player_event_speech_repository.h
repositories/base/base_player_event_trade_repository.h
repositories/base/base_player_event_trade_entries_repository.h
repositories/base/base_quest_globals_repository.h repositories/base/base_quest_globals_repository.h
repositories/base/base_raid_details_repository.h repositories/base/base_raid_details_repository.h
repositories/base/base_raid_members_repository.h repositories/base/base_raid_members_repository.h
@@ -372,7 +355,6 @@ SET(repositories
repositories/character_currency_repository.h repositories/character_currency_repository.h
repositories/character_data_repository.h repositories/character_data_repository.h
repositories/character_disciplines_repository.h repositories/character_disciplines_repository.h
repositories/character_evolving_items_repository.h
repositories/character_expedition_lockouts_repository.h repositories/character_expedition_lockouts_repository.h
repositories/character_exp_modifiers_repository.h repositories/character_exp_modifiers_repository.h
repositories/character_inspect_messages_repository.h repositories/character_inspect_messages_repository.h
@@ -410,9 +392,10 @@ SET(repositories
repositories/discovered_items_repository.h repositories/discovered_items_repository.h
repositories/doors_repository.h repositories/doors_repository.h
repositories/dynamic_zones_repository.h repositories/dynamic_zones_repository.h
repositories/dynamic_zone_lockouts_repository.h
repositories/dynamic_zone_members_repository.h repositories/dynamic_zone_members_repository.h
repositories/dynamic_zone_templates_repository.h repositories/dynamic_zone_templates_repository.h
repositories/expeditions_repository.h
repositories/expedition_lockouts_repository.h
repositories/faction_association_repository.h repositories/faction_association_repository.h
repositories/faction_base_data_repository.h repositories/faction_base_data_repository.h
repositories/faction_list_repository.h repositories/faction_list_repository.h
@@ -440,7 +423,6 @@ SET(repositories
repositories/inventory_snapshots_repository.h repositories/inventory_snapshots_repository.h
repositories/ip_exemptions_repository.h repositories/ip_exemptions_repository.h
repositories/items_repository.h repositories/items_repository.h
repositories/items_evolving_details_repository.h
repositories/ldon_trap_entries_repository.h repositories/ldon_trap_entries_repository.h
repositories/ldon_trap_templates_repository.h repositories/ldon_trap_templates_repository.h
repositories/level_exp_mods_repository.h repositories/level_exp_mods_repository.h
@@ -478,20 +460,8 @@ SET(repositories
repositories/pets_equipmentset_repository.h repositories/pets_equipmentset_repository.h
repositories/pets_equipmentset_entries_repository.h repositories/pets_equipmentset_entries_repository.h
repositories/player_titlesets_repository.h repositories/player_titlesets_repository.h
repositories/player_event_aa_purchase_repository.h
repositories/player_event_killed_npc_repository.h
repositories/player_event_killed_named_npc_repository.h
repositories/player_event_killed_raid_npc_repository.h
repositories/player_event_log_settings_repository.h repositories/player_event_log_settings_repository.h
repositories/player_event_logs_repository.h repositories/player_event_logs_repository.h
repositories/player_event_loot_items_repository.h
repositories/player_event_merchant_purchase_repository.h
repositories/player_event_merchant_sell_repository.h
repositories/player_event_npc_handin_repository.h
repositories/player_event_npc_handin_entries_repository.h
repositories/player_event_speech_repository.h
repositories/player_event_trade_repository.h
repositories/player_event_trade_entries_repository.h
repositories/quest_globals_repository.h repositories/quest_globals_repository.h
repositories/raid_details_repository.h repositories/raid_details_repository.h
repositories/raid_members_repository.h repositories/raid_members_repository.h
@@ -560,7 +530,6 @@ SET(common_headers
discord/discord.h discord/discord.h
discord/discord_manager.h discord/discord_manager.h
dynamic_zone_base.h dynamic_zone_base.h
dynamic_zone_lockout.h
emu_constants.h emu_constants.h
emu_limits.h emu_limits.h
emu_opcodes.h emu_opcodes.h
@@ -586,7 +555,7 @@ SET(common_headers
events/player_event_discord_formatter.h events/player_event_discord_formatter.h
events/player_events.h events/player_events.h
event_sub.h event_sub.h
evolving_items.h expedition_lockout_timer.h
extprofile.h extprofile.h
faction.h faction.h
file.h file.h
@@ -618,7 +587,6 @@ SET(common_headers
mutex.h mutex.h
mysql_request_result.h mysql_request_result.h
mysql_request_row.h mysql_request_row.h
mysql_stmt.h
op_codes.h op_codes.h
opcode_dispatch.h opcode_dispatch.h
opcodemgr.h opcodemgr.h
@@ -646,7 +614,6 @@ SET(common_headers
server_event_scheduler.h server_event_scheduler.h
serverinfo.h serverinfo.h
servertalk.h servertalk.h
server_reload_types.h
shared_tasks.h shared_tasks.h
shareddb.h shareddb.h
skills.h skills.h
@@ -661,6 +628,7 @@ SET(common_headers
unix.h unix.h
useperl.h useperl.h
version.h version.h
zone_copy.h
zone_store.h zone_store.h
event/event_loop.h event/event_loop.h
event/task.h event/task.h
@@ -672,7 +640,6 @@ SET(common_headers
net/console_server_connection.h net/console_server_connection.h
net/crc32.h net/crc32.h
net/daybreak_connection.h net/daybreak_connection.h
net/daybreak_pooling.h
net/daybreak_structs.h net/daybreak_structs.h
net/dns.h net/dns.h
net/endian.h net/endian.h
@@ -684,7 +651,6 @@ SET(common_headers
net/servertalk_server.h net/servertalk_server.h
net/servertalk_server_connection.h net/servertalk_server_connection.h
net/tcp_connection.h net/tcp_connection.h
net/tcp_connection_pooling.h
net/tcp_server.h net/tcp_server.h
net/websocket_server.h net/websocket_server.h
net/websocket_server_connection.h net/websocket_server_connection.h
@@ -745,7 +711,6 @@ SOURCE_GROUP(Net FILES
net/crc32.h net/crc32.h
net/daybreak_connection.cpp net/daybreak_connection.cpp
net/daybreak_connection.h net/daybreak_connection.h
net/daybreak_pooling.h
net/daybreak_structs.h net/daybreak_structs.h
net/dns.h net/dns.h
net/endian.h net/endian.h
@@ -766,7 +731,6 @@ SOURCE_GROUP(Net FILES
net/servertalk_server_connection.h net/servertalk_server_connection.h
net/tcp_connection.cpp net/tcp_connection.cpp
net/tcp_connection.h net/tcp_connection.h
net/tcp_connection_pooling.h
net/tcp_server.cpp net/tcp_server.cpp
net/tcp_server.h net/tcp_server.h
net/websocket_server.cpp net/websocket_server.cpp
@@ -841,8 +805,8 @@ IF (UNIX)
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
ENDIF (UNIX) ENDIF (UNIX)
IF (EQEMU_BUILD_PCH) IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/std-pch.h) TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h)
ENDIF () ENDIF ()
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+278 -253
View File
@@ -6,17 +6,15 @@
std::vector<BazaarSearchResultsFromDB_Struct> std::vector<BazaarSearchResultsFromDB_Struct>
Bazaar::GetSearchResults( Bazaar::GetSearchResults(
Database &db, SharedDatabase &db,
Database &content_db,
BazaarSearchCriteria_Struct search, BazaarSearchCriteria_Struct search,
uint32 char_zone_id, uint32 char_zone_id
int32 char_zone_instance_id
) )
{ {
LogTrading( LogTrading(
"Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] " "Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] "
"max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] " "max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] "
"search_scope [{}] char_zone_id [{}], char_zone_instance_id [{}]", "search_scope [{}] char_zone_id [{}]",
search.item_name, search.item_name,
search.min_cost, search.min_cost,
search.max_cost, search.max_cost,
@@ -28,11 +26,175 @@ Bazaar::GetSearchResults(
search.trader_entity_id, search.trader_entity_id,
search.trader_id, search.trader_id,
search.search_scope, search.search_scope,
char_zone_id, char_zone_id
char_zone_instance_id
); );
static std::map<uint8, uint32> item_slot_searches_new = { std::string search_criteria_trader("TRUE ");
if (search.search_scope == NonRoFBazaarSearchScope) {
search_criteria_trader.append(
fmt::format(
" AND trader.char_entity_id = {} AND trader.char_zone_id = {}",
search.trader_entity_id,
Zones::BAZAAR
)
);
}
else if (search.search_scope == Local_Scope) {
search_criteria_trader.append(fmt::format(" AND trader.char_zone_id = {}", char_zone_id));
}
else if (search.trader_id > 0) {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
}
if (search.min_cost != 0) {
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000));
}
if (search.max_cost != 0) {
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
}
// not yet implemented
// if (search.prestige != 0) {
// 0xffffffff prestige only, 0xfffffffe non-prestige, 0 all
// search_criteria.append(fmt::format(" AND items.type = {} ", search.prestige));
// }
std::string query = fmt::format(
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6 "
"FROM trader, character_data "
"WHERE {} AND trader.char_id = character_data.id "
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
search_criteria_trader.c_str()
);
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
auto results = db.QueryDatabase(query);
if (!results.Success()) {
return all_entries;
}
struct ItemSearchType {
EQ::item::ItemType type;
bool condition;
};
struct AddititiveSearchCriteria {
bool should_check;
bool condition;
};
for (auto row: results) {
BazaarSearchResultsFromDB_Struct r{};
r.item_id = Strings::ToInt(row[2]);
r.charges = Strings::ToInt(row[4]);
auto item = db.GetItem(r.item_id);
if (!item) {
continue;
}
uint32 aug_slot_1 = Strings::ToUnsignedInt(row[11]);
uint32 aug_slot_2 = Strings::ToUnsignedInt(row[12]);
uint32 aug_slot_3 = Strings::ToUnsignedInt(row[13]);
uint32 aug_slot_4 = Strings::ToUnsignedInt(row[14]);
uint32 aug_slot_5 = Strings::ToUnsignedInt(row[15]);
uint32 aug_slot_6 = Strings::ToUnsignedInt(row[16]);
std::unique_ptr<EQ::ItemInstance> inst(
db.CreateItem(
item,
r.charges,
aug_slot_1,
aug_slot_2,
aug_slot_3,
aug_slot_4,
aug_slot_5,
aug_slot_6
)
);
if (!inst->GetItem()) {
continue;
}
r.count = Strings::ToInt(row[0]);
r.trader_id = Strings::ToInt(row[1]);
r.serial_number = Strings::ToInt(row[3]);
r.cost = Strings::ToInt(row[5]);
r.slot_id = Strings::ToInt(row[6]);
r.sum_charges = Strings::ToInt(row[7]);
r.stackable = item->Stackable;
r.icon_id = item->Icon;
r.trader_zone_id = Strings::ToInt(row[8]);
r.trader_entity_id = Strings::ToInt(row[9]);
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
r.item_name = fmt::format("{:.63}\0", item->Name);
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
LogTradingDetail(
"Searching against item [{}] ({}) for trader [{}]",
item->Name,
item->ID,
r.trader_name
);
// item stat searches
std::map<uint32, uint32> item_stat_searches = {
{STAT_AC, inst->GetItemArmorClass(true)},
{STAT_AGI, static_cast<uint32>(inst->GetItemAgi(true))},
{STAT_CHA, static_cast<uint32>(inst->GetItemCha(true))},
{STAT_DEX, static_cast<uint32>(inst->GetItemDex(true))},
{STAT_INT, static_cast<uint32>(inst->GetItemInt(true))},
{STAT_STA, static_cast<uint32>(inst->GetItemSta(true))},
{STAT_STR, static_cast<uint32>(inst->GetItemStr(true))},
{STAT_WIS, static_cast<uint32>(inst->GetItemWis(true))},
{STAT_COLD, static_cast<uint32>(inst->GetItemCR(true))},
{STAT_DISEASE, static_cast<uint32>(inst->GetItemDR(true))},
{STAT_FIRE, static_cast<uint32>(inst->GetItemFR(true))},
{STAT_MAGIC, static_cast<uint32>(inst->GetItemMR(true))},
{STAT_POISON, static_cast<uint32>(inst->GetItemPR(true))},
{STAT_HP, static_cast<uint32>(inst->GetItemHP(true))},
{STAT_MANA, static_cast<uint32>(inst->GetItemMana(true))},
{STAT_ENDURANCE, static_cast<uint32>(inst->GetItemEndur(true))},
{STAT_ATTACK, static_cast<uint32>(inst->GetItemAttack(true))},
{STAT_HP_REGEN, static_cast<uint32>(inst->GetItemRegen(true))},
{STAT_MANA_REGEN, static_cast<uint32>(inst->GetItemManaRegen(true))},
{STAT_HASTE, static_cast<uint32>(inst->GetItemHaste(true))},
{STAT_DAMAGE_SHIELD, static_cast<uint32>(inst->GetItemDamageShield(true))},
{STAT_DS_MITIGATION, static_cast<uint32>(inst->GetItemDSMitigation(true))},
{STAT_HEAL_AMOUNT, static_cast<uint32>(inst->GetItemHealAmt(true))},
{STAT_SPELL_DAMAGE, static_cast<uint32>(inst->GetItemSpellDamage(true))},
{STAT_CLAIRVOYANCE, static_cast<uint32>(inst->GetItemClairvoyance(true))},
{STAT_HEROIC_AGILITY, static_cast<uint32>(inst->GetItemHeroicAgi(true))},
{STAT_HEROIC_CHARISMA, static_cast<uint32>(inst->GetItemHeroicCha(true))},
{STAT_HEROIC_DEXTERITY, static_cast<uint32>(inst->GetItemHeroicDex(true))},
{STAT_HEROIC_INTELLIGENCE, static_cast<uint32>(inst->GetItemHeroicInt(true))},
{STAT_HEROIC_STAMINA, static_cast<uint32>(inst->GetItemHeroicSta(true))},
{STAT_HEROIC_STRENGTH, static_cast<uint32>(inst->GetItemHeroicStr(true))},
{STAT_HEROIC_WISDOM, static_cast<uint32>(inst->GetItemHeroicWis(true))},
{STAT_BASH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillBash, true))},
{STAT_BACKSTAB, static_cast<uint32>(inst->GetItemBackstabDamage(true))},
{STAT_DRAGON_PUNCH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillDragonPunch, true))},
{STAT_EAGLE_STRIKE, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillEagleStrike, true))},
{STAT_FLYING_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFlyingKick, true))},
{STAT_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillKick, true))},
{STAT_ROUND_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillRoundKick, true))},
{STAT_TIGER_CLAW, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillTigerClaw, true))},
{STAT_FRENZY, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFrenzy, true))},
};
r.item_stat = item_stat_searches.contains(search.item_stat) ? item_stat_searches[search.item_stat] : 0;
if (item_stat_searches.contains(search.item_stat) && item_stat_searches[search.item_stat] <= 0) {
continue;
}
static std::map<uint8, uint32> item_slot_searches = {
{EQ::invslot::slotCharm, 1}, {EQ::invslot::slotCharm, 1},
{EQ::invslot::slotEar1, 2}, {EQ::invslot::slotEar1, 2},
{EQ::invslot::slotHead, 4}, {EQ::invslot::slotHead, 4},
@@ -58,269 +220,132 @@ Bazaar::GetSearchResults(
{EQ::invslot::slotAmmo, 4194304}, {EQ::invslot::slotAmmo, 4194304},
}; };
struct ItemSearchType { auto GetEquipmentSlotBit = [&](uint32 slot) -> uint32 {
EQ::item::ItemType type; return item_slot_searches.contains(slot) ? item_slot_searches[slot] : 0;
std::string condition;
}; };
std::vector<ItemSearchType> item_search_types_new = { auto FindItemAugSlot = [&]() -> bool {
{EQ::item::ItemType::ItemTypeBook, " AND (items.itemclass = 2 or items.itemclass = 31)"}, for (auto const &s: inst->GetItem()->AugSlotType) {
{EQ::item::ItemType::ItemTypeContainer, " AND (items.itemclass = 1 or items.itemclass = 67)"}, return s == search.augment;
{EQ::item::ItemType::ItemTypeAllEffects, " AND (items.scrolleffect > 0 && items.scrolleffect < 65000)"}, }
{EQ::item::ItemType::ItemTypeUnknown9, " AND items.worneffect = 998"}, return false;
{EQ::item::ItemType::ItemTypeUnknown10, " AND (items.worneffect >= 1298 && items.worneffect <= 1307)"},
{EQ::item::ItemType::ItemTypeFocusEffect, " AND items.focuseffect > 0"},
{EQ::item::ItemType::ItemTypeArmor, " AND items.itemtype = 10"},
{EQ::item::ItemType::ItemType1HBlunt, " AND items.itemtype = 3"},
{EQ::item::ItemType::ItemType1HPiercing, " AND items.itemtype = 2"},
{EQ::item::ItemType::ItemType1HSlash, " AND items.itemtype = 0"},
{EQ::item::ItemType::ItemType2HBlunt, " AND items.itemtype = 4"},
{EQ::item::ItemType::ItemType2HSlash, " AND items.itemtype = 1"},
{EQ::item::ItemType::ItemTypeBow, " AND items.itemtype = 5"},
{EQ::item::ItemType::ItemTypeShield, " AND items.itemtype = 8"},
{EQ::item::ItemType::ItemTypeMisc, " AND items.itemtype = 11"},
{EQ::item::ItemType::ItemTypeFood, " AND items.itemtype = 14"},
{EQ::item::ItemType::ItemTypeDrink, " AND items.itemtype = 15"},
{EQ::item::ItemType::ItemTypeLight, " AND items.itemtype = 16"},
{EQ::item::ItemType::ItemTypeCombinable, " AND items.itemtype = 17"},
{EQ::item::ItemType::ItemTypeBandage, " AND items.itemtype = 18"},
{EQ::item::ItemType::ItemTypeSmallThrowing, " AND (items.itemtype = 19 OR items.itemtype = 7)"},
{EQ::item::ItemType::ItemTypeSpell, " AND items.itemtype = 20"},
{EQ::item::ItemType::ItemTypePotion, " AND items.itemtype = 21"},
{EQ::item::ItemType::ItemTypeBrassInstrument, " AND items.itemtype = 25"},
{EQ::item::ItemType::ItemTypeWindInstrument, " AND items.itemtype = 23"},
{EQ::item::ItemType::ItemTypeStringedInstrument, " AND items.itemtype = 24"},
{EQ::item::ItemType::ItemTypePercussionInstrument, " AND items.itemtype = 26"},
{EQ::item::ItemType::ItemTypeArrow, " AND items.itemtype = 27"},
{EQ::item::ItemType::ItemTypeJewelry, " AND items.itemtype = 29"},
{EQ::item::ItemType::ItemTypeNote, " AND items.itemtype = 32"},
{EQ::item::ItemType::ItemTypeKey, " AND items.itemtype = 33"},
{EQ::item::ItemType::ItemType2HPiercing, " AND items.itemtype = 35"},
{EQ::item::ItemType::ItemTypeAlcohol, " AND items.itemtype = 38"},
{EQ::item::ItemType::ItemTypeMartial, " AND items.itemtype = 45"},
{EQ::item::ItemType::ItemTypeAugmentation, " AND items.itemtype = 54"},
{EQ::item::ItemType::ItemTypeAlternateAbility, " AND items.itemtype = 57"},
{EQ::item::ItemType::ItemTypeCount, " AND items.itemtype = 65"},
{EQ::item::ItemType::ItemTypeCollectible, " AND items.itemtype = 66"}
}; };
// item stat searches // item type searches
struct ItemStatSearch { std::vector<ItemSearchType> item_search_types = {
std::string query_string; {EQ::item::ItemType::ItemTypeAll, true},
EQ::skills::SkillType skill_type; {EQ::item::ItemType::ItemTypeBook, item->ItemClass == EQ::item::ItemType::ItemTypeBook},
{EQ::item::ItemType::ItemTypeContainer, item->ItemClass == EQ::item::ItemType::ItemTypeContainer},
{EQ::item::ItemType::ItemTypeAllEffects, item->Scroll.Effect > 0 && item->Scroll.Effect < 65000},
{EQ::item::ItemType::ItemTypeUnknown9, item->Worn.Effect == 998},
{EQ::item::ItemType::ItemTypeUnknown10, item->Worn.Effect >= 1298 && item->Worn.Effect <= 1307},
{EQ::item::ItemType::ItemTypeFocusEffect, item->Focus.Effect > 0},
{EQ::item::ItemType::ItemTypeArmor, item->ItemType == EQ::item::ItemType::ItemTypeArmor},
{EQ::item::ItemType::ItemType1HBlunt, item->ItemType == EQ::item::ItemType::ItemType1HBlunt},
{EQ::item::ItemType::ItemType1HPiercing, item->ItemType == EQ::item::ItemType::ItemType1HPiercing},
{EQ::item::ItemType::ItemType1HSlash, item->ItemType == EQ::item::ItemType::ItemType1HSlash},
{EQ::item::ItemType::ItemType2HBlunt, item->ItemType == EQ::item::ItemType::ItemType2HBlunt},
{EQ::item::ItemType::ItemType2HSlash, item->ItemType == EQ::item::ItemType::ItemType2HSlash},
{EQ::item::ItemType::ItemTypeBow, item->ItemType == EQ::item::ItemType::ItemTypeBow},
{EQ::item::ItemType::ItemTypeShield, item->ItemType == EQ::item::ItemType::ItemTypeShield},
{EQ::item::ItemType::ItemTypeMisc, item->ItemType == EQ::item::ItemType::ItemTypeMisc},
{EQ::item::ItemType::ItemTypeFood, item->ItemType == EQ::item::ItemType::ItemTypeFood},
{EQ::item::ItemType::ItemTypeDrink, item->ItemType == EQ::item::ItemType::ItemTypeDrink},
{EQ::item::ItemType::ItemTypeLight, item->ItemType == EQ::item::ItemType::ItemTypeLight},
{EQ::item::ItemType::ItemTypeCombinable, item->ItemType == EQ::item::ItemType::ItemTypeCombinable},
{EQ::item::ItemType::ItemTypeBandage, item->ItemType == EQ::item::ItemType::ItemTypeBandage},
{EQ::item::ItemType::ItemTypeSmallThrowing, item->ItemType == EQ::item::ItemType::ItemTypeSmallThrowing ||
item->ItemType == EQ::item::ItemType::ItemTypeLargeThrowing},
{EQ::item::ItemType::ItemTypeSpell, item->ItemType == EQ::item::ItemType::ItemTypeSpell},
{EQ::item::ItemType::ItemTypePotion, item->ItemType == EQ::item::ItemType::ItemTypePotion},
{EQ::item::ItemType::ItemTypeBrassInstrument, item->ItemType == EQ::item::ItemType::ItemTypeBrassInstrument},
{EQ::item::ItemType::ItemTypeWindInstrument, item->ItemType == EQ::item::ItemType::ItemTypeWindInstrument},
{EQ::item::ItemType::ItemTypeStringedInstrument, item->ItemType == EQ::item::ItemType::ItemTypeStringedInstrument},
{EQ::item::ItemType::ItemTypePercussionInstrument, item->ItemType == EQ::item::ItemType::ItemTypePercussionInstrument},
{EQ::item::ItemType::ItemTypeArrow, item->ItemType == EQ::item::ItemType::ItemTypeArrow},
{EQ::item::ItemType::ItemTypeJewelry, item->ItemType == EQ::item::ItemType::ItemTypeJewelry},
{EQ::item::ItemType::ItemTypeNote, item->ItemType == EQ::item::ItemType::ItemTypeNote},
{EQ::item::ItemType::ItemTypeKey, item->ItemType == EQ::item::ItemType::ItemTypeKey},
{EQ::item::ItemType::ItemType2HPiercing, item->ItemType == EQ::item::ItemType::ItemType2HPiercing},
{EQ::item::ItemType::ItemTypeAlcohol, item->ItemType == EQ::item::ItemType::ItemTypeAlcohol},
{EQ::item::ItemType::ItemTypeMartial, item->ItemType == EQ::item::ItemType::ItemTypeMartial},
{EQ::item::ItemType::ItemTypeAugmentation, item->ItemType == EQ::item::ItemType::ItemTypeAugmentation},
{EQ::item::ItemType::ItemTypeAlternateAbility, item->ItemType == EQ::item::ItemType::ItemTypeAlternateAbility},
{EQ::item::ItemType::ItemTypeCount, item->ItemType == EQ::item::ItemType::ItemTypeCount},
{EQ::item::ItemType::ItemTypeCollectible, item->ItemType == EQ::item::ItemType::ItemTypeCollectible}
}; };
std::map<uint32, ItemStatSearch> item_stat_searches_new = { bool met_filter = false;
{STAT_AC, {" items.ac" , static_cast<EQ::skills::SkillType>(0)} }, bool has_filter = false;
{STAT_AGI, {" items.aagi", static_cast<EQ::skills::SkillType>(0)} },
{STAT_CHA, {" items.acha", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DEX, {" items.adex", static_cast<EQ::skills::SkillType>(0)} },
{STAT_INT, {" items.aint", static_cast<EQ::skills::SkillType>(0)} },
{STAT_STA, {" items.asta", static_cast<EQ::skills::SkillType>(0)} },
{STAT_STR, {" items.astr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_WIS, {" items.awis", static_cast<EQ::skills::SkillType>(0)} },
{STAT_COLD, {" items.cr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DISEASE, {" items.dr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_FIRE, {" items.fr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_MAGIC, {" items.mr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_POISON, {" items.pr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HP, {" items.hp", static_cast<EQ::skills::SkillType>(0)} },
{STAT_MANA, {" items.mana", static_cast<EQ::skills::SkillType>(0)} },
{STAT_ENDURANCE, {" items.endur", static_cast<EQ::skills::SkillType>(0)} },
{STAT_ATTACK, {" items.attack", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HP_REGEN, {" items.regen", static_cast<EQ::skills::SkillType>(0)} },
{STAT_MANA_REGEN, {" items.manaregen", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HASTE, {" items.haste", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DAMAGE_SHIELD, {" items.damageshield", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DS_MITIGATION, {" items.dsmitigation", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEAL_AMOUNT, {" items.healamt", static_cast<EQ::skills::SkillType>(0)} },
{STAT_SPELL_DAMAGE, {" items.spelldmg", static_cast<EQ::skills::SkillType>(0)} },
{STAT_CLAIRVOYANCE, {" items.clairvoyance", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_AGILITY, {" items.heroic_agi", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_CHARISMA, {" items.heroic_cha", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_DEXTERITY, {" items.heroic_dex", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_INTELLIGENCE, {" items.heroic_int", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_STAMINA, {" items.heroic_sta", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_STRENGTH, {" items.heroic_str", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_WISDOM, {" items.heroic_wis", static_cast<EQ::skills::SkillType>(0)} },
{STAT_BASH, {" items.skillmodvalue", EQ::skills::SkillBash} },
{STAT_BACKSTAB, {" items.backstabdmg", EQ::skills::SkillBackstab} },
{STAT_DRAGON_PUNCH, {" items.skillmodvalue", EQ::skills::SkillDragonPunch} },
{STAT_EAGLE_STRIKE, {" items.skillmodvalue", EQ::skills::SkillEagleStrike} },
{STAT_FLYING_KICK, {" items.skillmodvalue", EQ::skills::SkillFlyingKick} },
{STAT_KICK, {" items.skillmodvalue", EQ::skills::SkillKick} },
{STAT_ROUND_KICK, {" items.skillmodvalue", EQ::skills::SkillRoundKick} },
{STAT_TIGER_CLAW, {" items.skillmodvalue", EQ::skills::SkillTigerClaw} },
{STAT_FRENZY, {" items.skillmodvalue", EQ::skills::SkillFrenzy} },
};
bool convert = false; for (auto &i: item_search_types) {
std::string search_criteria_trader("TRUE"); if (i.type == search.type) {
std::string field_criteria_items("FALSE"); has_filter = true;
std::string where_criteria_items(" TRUE "); if (i.condition) {
LogTradingDetail("Item [{}] met search criteria for type [{}]", item->Name, uint8(i.type));
if (search.search_scope == NonRoFBazaarSearchScope) { met_filter = true;
search_criteria_trader.append(
fmt::format(
" AND trader.char_entity_id = {} AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
search.trader_entity_id,
Zones::BAZAAR,
char_zone_instance_id
)
);
}
else if (search.search_scope == Local_Scope) {
search_criteria_trader.append(fmt::format(
" AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
char_zone_id,
char_zone_instance_id)
);
}
else if (search.trader_id > 0) {
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (search.trader_id >= TraderRepository::TRADER_CONVERT_ID) {
convert = true;
search_criteria_trader.append(fmt::format(
" AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
Zones::BAZAAR,
search.trader_id - TraderRepository::TRADER_CONVERT_ID)
);
}
else {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
}
}
else {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
}
}
if (search.min_cost != 0) {
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000));
}
if (search.max_cost != 0) {
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
}
if (search.slot != std::numeric_limits<uint32>::max()) {
if (item_slot_searches_new.contains(search.slot)) {
where_criteria_items.append(
fmt::format(" AND items.slots & {0} = {0}", item_slot_searches_new[search.slot]));
}
}
if (search.type != std::numeric_limits<uint32>::max()) {
for (auto const &[type, condition]: item_search_types_new) {
if (type == search.type) {
where_criteria_items.append(condition);
break; break;
} }
} }
} }
if (has_filter && !met_filter) {
if (search.race != std::numeric_limits<uint32>::max()) {
where_criteria_items.append(
fmt::format(" AND items.races & {0} = {0}", GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race))));
}
if (search._class != std::numeric_limits<uint32>::max()) {
where_criteria_items.append(fmt::format(" AND items.classes & {0} = {0}", GetPlayerClassBit(search._class)));
}
if (search.item_stat != std::numeric_limits<uint32>::max()) {
if (item_stat_searches_new.contains(search.item_stat)) {
field_criteria_items = fmt::format("{}", item_stat_searches_new[search.item_stat].query_string);
if (item_stat_searches_new[search.item_stat].skill_type) {
where_criteria_items.append(
fmt::format(" AND items.skillmodtype = {} ", item_stat_searches_new[search.item_stat].skill_type));
}
else {
where_criteria_items.append(
fmt::format(" AND {} > 0 ", item_stat_searches_new[search.item_stat].query_string));
}
}
}
if (search.augment) {
where_criteria_items.append(fmt::format(
" AND (items.augslot1type = {0} OR "
"items.augslot2type = {0} OR "
"items.augslot3type = {0} OR "
"items.augslot4type = {0} OR "
"items.augslot5type = {0} OR "
"items.augslot6type = {0})",
search.augment)
);
}
if (search.min_level != 1) {
where_criteria_items.append(fmt::format(" AND items.reclevel >= {}", search.min_level));
}
if (search.max_level != 100) {
where_criteria_items.append(fmt::format(" AND items.reclevel <= {}", search.max_level));
}
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
std::vector<std::string> trader_items_ids{};
auto const trader_results = TraderRepository::GetBazaarTraderDetails(db, search_criteria_trader);
if (trader_results.empty()) {
LogTradingDetail("Bazaar - No traders found in bazaar search.");
return all_entries;
}
for (auto const &i: trader_results) {
trader_items_ids.push_back(std::to_string(i.trader.item_id));
}
auto const item_results = ItemsRepository::GetItemsForBazaarSearch(
content_db,
trader_items_ids,
std::string(search.item_name),
field_criteria_items,
where_criteria_items,
search.max_results
);
if (item_results.empty()) {
LogTradingDetail("Bazaar - No items found in bazaar search.");
return all_entries;
}
all_entries.reserve(trader_results.size());
for (auto const& t:trader_results) {
if (!item_results.contains(t.trader.item_id)) {
continue; continue;
} }
BazaarSearchResultsFromDB_Struct r{}; // TODO: Add catch-all item type filter for specific item types
r.count = 1;
r.trader_id = t.trader.char_id;
r.serial_number = t.trader.item_sn;
r.cost = t.trader.item_cost;
r.slot_id = t.trader.slot_id;
r.charges = t.trader.item_charges;
r.stackable = item_results.at(t.trader.item_id).stackable;
r.icon_id = item_results.at(t.trader.item_id).icon;
r.trader_zone_id = t.trader.char_zone_id;
r.trader_zone_instance_id = t.trader.char_zone_instance_id;
r.trader_entity_id = t.trader.char_entity_id;
r.serial_number_RoF = fmt::format("{:016}\0", t.trader.item_sn);
r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name);
r.trader_name = fmt::format("{:.63}\0", t.trader_name);
r.item_stat = item_results.at(t.trader.item_id).stats;
if (RuleB(Bazaar, UseAlternateBazaarSearch)) { // item additive searches
if (convert || std::vector<AddititiveSearchCriteria> item_additive_searches = {
char_zone_id != Zones::BAZAAR || {
(char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id) .should_check = search.min_level != 1 && inst->GetItemRequiredLevel(true) > 0,
) { .condition = inst->GetItemRequiredLevel(true) >= search.min_level
r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id; },
{
.should_check = search.max_level != 1 && inst->GetItemRequiredLevel(true) > 0,
.condition = inst->GetItemRequiredLevel(true) <= search.max_level
},
{
.should_check = !std::string(search.item_name).empty(),
.condition = Strings::ContainsLower(item->Name, search.item_name)
},
{
.should_check = search._class != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Classes & GetPlayerClassBit(search._class))
},
{
.should_check = search.race != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Races & GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race)))
},
{
.should_check = search.augment != 0,
.condition = FindItemAugSlot()
},
{
.should_check = search.slot != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Slots & GetEquipmentSlotBit(search.slot))
},
};
bool should_add = true;
for (auto &i: item_additive_searches) {
LogTradingDetail(
"Checking item [{}] for search criteria - should_check [{}] condition [{}]",
item->Name,
i.should_check,
i.condition
);
if (i.should_check && !i.condition) {
should_add = false;
continue;
} }
} }
if (!should_add) {
continue;
}
LogTradingDetail("Found item [{}] meeting search criteria.", r.item_name);
all_entries.push_back(r); all_entries.push_back(r);
} }
+1 -3
View File
@@ -3,13 +3,11 @@
#include <vector> #include <vector>
#include "shareddb.h" #include "shareddb.h"
#include "../../common/item_instance.h"
class Bazaar { class Bazaar {
public: public:
static std::vector<BazaarSearchResultsFromDB_Struct> static std::vector<BazaarSearchResultsFromDB_Struct>
GetSearchResults(Database &content_db, Database &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id, int char_zone_instance_id); GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id);
}; };
-2
View File
@@ -131,8 +131,6 @@ static std::map<uint8, std::string> class_names = {
#define ARMOR_TYPE_LAST ARMOR_TYPE_PLATE #define ARMOR_TYPE_LAST ARMOR_TYPE_PLATE
#define ARMOR_TYPE_COUNT 5 #define ARMOR_TYPE_COUNT 5
#define BOT_CLASS_BASE_ID_PREFIX 3000
const char* GetClassIDName(uint8 class_id, uint8 level = 0); const char* GetClassIDName(uint8 class_id, uint8 level = 0);
+5 -5
View File
@@ -27,7 +27,7 @@ WorldContentService *WorldContentService::SetExpansionContext()
// pull expansion from rules // pull expansion from rules
int expansion = RuleI(Expansion, CurrentExpansion); int expansion = RuleI(Expansion, CurrentExpansion);
if (expansion >= Expansion::Classic && expansion <= Expansion::MaxId) { if (expansion >= Expansion::Classic && expansion <= Expansion::MaxId) {
WorldContentService::Instance()->SetCurrentExpansion(expansion); content_service.SetCurrentExpansion(expansion);
} }
LogInfo( LogInfo(
@@ -41,12 +41,12 @@ WorldContentService *WorldContentService::SetExpansionContext()
std::string WorldContentService::GetCurrentExpansionName() std::string WorldContentService::GetCurrentExpansionName()
{ {
if (WorldContentService::Instance()->GetCurrentExpansion() == Expansion::EXPANSION_ALL) { if (content_service.GetCurrentExpansion() == Expansion::EXPANSION_ALL) {
return "All Expansions"; return "All Expansions";
} }
if (current_expansion >= Expansion::Classic && current_expansion <= Expansion::MaxId) { if (current_expansion >= Expansion::Classic && current_expansion <= Expansion::MaxId) {
return Expansion::ExpansionName[WorldContentService::Instance()->GetCurrentExpansion()]; return Expansion::ExpansionName[content_service.GetCurrentExpansion()];
} }
return "Unknown Expansion"; return "Unknown Expansion";
@@ -185,7 +185,7 @@ void WorldContentService::ReloadContentFlags()
SetContentFlags(set_content_flags); SetContentFlags(set_content_flags);
LoadStaticGlobalZoneInstances(); LoadStaticGlobalZoneInstances();
ZoneStore::Instance()->LoadZones(*m_content_database); zone_store.LoadZones(*m_content_database);
} }
Database *WorldContentService::GetDatabase() const Database *WorldContentService::GetDatabase() const
@@ -291,7 +291,7 @@ WorldContentService *WorldContentService::LoadStaticGlobalZoneInstances()
// instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1 // instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id) WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
{ {
for (const auto &z: ZoneStore::Instance()->GetZones()) { for (const auto &z: zone_store.GetZones()) {
for (auto &i: m_zone_static_instances) { for (auto &i: m_zone_static_instances) {
if ( if (
z.zoneidnumber == zone_id && z.zoneidnumber == zone_id &&
+2 -6
View File
@@ -181,12 +181,6 @@ public:
FindZoneResult FindZone(uint32 zone_id, uint32 instance_id); FindZoneResult FindZone(uint32 zone_id, uint32 instance_id);
bool IsInPublicStaticInstance(uint32 instance_id); bool IsInPublicStaticInstance(uint32 instance_id);
static WorldContentService* Instance()
{
static WorldContentService instance;
return &instance;
}
private: private:
int current_expansion{}; int current_expansion{};
std::vector<ContentFlagsRepository::ContentFlags> content_flags; std::vector<ContentFlagsRepository::ContentFlags> content_flags;
@@ -200,4 +194,6 @@ private:
std::vector<InstanceListRepository::InstanceList> m_zone_static_instances; std::vector<InstanceListRepository::InstanceList> m_zone_static_instances;
}; };
extern WorldContentService content_service;
#endif //EQEMU_WORLD_CONTENT_SERVICE_H #endif //EQEMU_WORLD_CONTENT_SERVICE_H
+4 -8
View File
@@ -27,8 +27,6 @@ void SendCrashReport(const std::string &crash_report)
// "http://localhost:3010/api/v1/analytics/server-crash-report", // development // "http://localhost:3010/api/v1/analytics/server-crash-report", // development
}; };
EQEmuLogSys* log = EQEmuLogSys::Instance();
auto config = EQEmuConfig::get(); auto config = EQEmuConfig::get();
for (auto &e: endpoints) { for (auto &e: endpoints) {
uri u(e); uri u(e);
@@ -70,12 +68,12 @@ void SendCrashReport(const std::string &crash_report)
p["cpus"] = cpus.size(); p["cpus"] = cpus.size();
p["origination_info"] = ""; p["origination_info"] = "";
if (!log->origination_info.zone_short_name.empty()) { if (!LogSys.origination_info.zone_short_name.empty()) {
p["origination_info"] = fmt::format( p["origination_info"] = fmt::format(
"{} ({}) instance_id [{}]", "{} ({}) instance_id [{}]",
log->origination_info.zone_short_name, LogSys.origination_info.zone_short_name,
log->origination_info.zone_long_name, LogSys.origination_info.zone_long_name,
log->origination_info.instance_id LogSys.origination_info.instance_id
); );
} }
@@ -296,8 +294,6 @@ void print_trace()
SendCrashReport(crash_report); SendCrashReport(crash_report);
} }
EQEmuLogSys::Instance()->CloseFileLogs();
exit(1); exit(1);
} }
-846
View File
@@ -1,846 +0,0 @@
#include "../common/data_bucket.h"
#include "database.h"
#include <ctime>
#include <cctype>
#include "../common/json/json.hpp"
using json = nlohmann::json;
const std::string NESTED_KEY_DELIMITER = ".";
std::vector<DataBucketsRepository::DataBuckets> g_data_bucket_cache = {};
#if defined(ZONE)
#include "../zone/zonedb.h"
extern ZoneDatabase database;
#elif defined(WORLD)
#include "../world/worlddb.h"
extern WorldDatabase database;
#else
#error "You must define either ZONE or WORLD"
#endif
void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time)
{
auto k = DataBucketKey{
.key = bucket_key,
.value = bucket_value,
.expires = expires_time,
};
DataBucket::SetData(k);
}
void DataBucket::SetData(const DataBucketKey &k_)
{
DataBucketKey k = k_; // copy the key so we can modify it
bool is_nested = k.key.find(NESTED_KEY_DELIMITER) != std::string::npos;
if (is_nested) {
k.key = Strings::Split(k.key, NESTED_KEY_DELIMITER).front();
}
auto b = DataBucketsRepository::NewEntity();
auto r = GetData(k, true);
// if we have an entry, use it
if (r.id > 0) {
b = r;
}
// add scoping to bucket
if (k.character_id > 0) {
b.character_id = k.character_id;
}
else if (k.account_id > 0) {
b.account_id = k.account_id;
}
else if (k.npc_id > 0) {
b.npc_id = k.npc_id;
}
else if (k.bot_id > 0) {
b.bot_id = k.bot_id;
} else if (k.zone_id > 0) {
b.zone_id = k.zone_id;
b.instance_id = k.instance_id;
}
const uint64 bucket_id = b.id;
int64 expires_time_unix = 0;
if (!k.expires.empty()) {
expires_time_unix = static_cast<int64>(std::time(nullptr)) + Strings::ToInt(k.expires);
if (isalpha(k.expires[0]) || isalpha(k.expires[k.expires.length() - 1])) {
expires_time_unix = static_cast<int64>(std::time(nullptr)) + Strings::TimeToSeconds(k.expires);
}
if (is_nested) {
LogDataBuckets("Nested keys can't expire; set expiration on the parent key");
expires_time_unix = 0;
}
}
b.expires = expires_time_unix;
b.value = k.value;
b.key_ = k.key;
// Check for nested keys (keys with dots)
if (k_.key.find(NESTED_KEY_DELIMITER) != std::string::npos) {
// Retrieve existing JSON or create a new one
std::string existing_value = r.id > 0 ? r.value : "{}";
json json_value = json::object();
// Check if the JSON is valid
if (Strings::IsValidJson(existing_value)) {
try {
json_value = json::parse(existing_value);
} catch (json::parse_error &e) {
LogDataBuckets("Failed to parse JSON for key [{}] [{}]", k_.key, e.what());
json_value = json::object(); // Reset to an empty object on error
}
}
// Recursively merge new key-value pair into the JSON object
auto nested_keys = Strings::Split(k_.key, NESTED_KEY_DELIMITER);
auto top_key = nested_keys.front();
// remove the top-level key
nested_keys.erase(nested_keys.begin());
json *current = &json_value;
for (size_t i = 0; i < nested_keys.size(); ++i) {
const std::string &key_part = nested_keys[i];
if (i == nested_keys.size() - 1) {
LogDataBucketsDetail("Setting key [{}] key_part [{}]", k.key, key_part);
// If the key already exists and is an object or array, prevent overwriting to avoid data loss
if (current->contains(key_part) &&
((*current)[key_part].is_object() || (*current)[key_part].is_array())) {
LogDataBuckets("Attempted to overwrite an existing object or array at key [{}] - skipping", k_.key);
return;
}
// Set the value at the final key
(*current)[key_part] = k_.value;
} else {
// Traverse or create nested objects
if (!current->contains(key_part)) {
(*current)[key_part] = json::object();
LogDataBucketsDetail("Creating nested root key [{}] key_part [{}]", k.key, key_part);
} else if (!(*current)[key_part].is_object()) {
// If key exists but is not an object, reset to object to avoid conflicts
(*current)[key_part] = json::object();
}
current = &(*current)[key_part];
}
}
// Serialize JSON back to string
b.value = json_value.dump();
b.key_ = top_key; // Use the top-level key
}
if (bucket_id) {
// update the cache if it exists
if (CanCache(k)) {
for (auto &e: g_data_bucket_cache) {
if (CheckBucketMatch(e, k)) {
e = b;
break;
}
}
}
DataBucketsRepository::UpdateOne(database, b);
}
else {
b = DataBucketsRepository::InsertOne(database, b);
// add to cache if it doesn't exist
if (CanCache(k) && !ExistsInCache(b)) {
DeleteFromMissesCache(b);
g_data_bucket_cache.emplace_back(b);
}
}
}
std::string DataBucket::GetData(const std::string &bucket_key)
{
return GetData(DataBucketKey{.key = bucket_key}).value;
}
DataBucketsRepository::DataBuckets DataBucket::ExtractNestedValue(
const DataBucketsRepository::DataBuckets &bucket,
const std::string &full_key)
{
auto nested_keys = Strings::Split(full_key, NESTED_KEY_DELIMITER);
auto top_key = nested_keys.front();
nested_keys.erase(nested_keys.begin());
json json_value;
// Check if the JSON is valid
if (!Strings::IsValidJson(bucket.value)) {
LogDataBuckets("Invalid JSON for key [{}]", bucket.key_);
return DataBucketsRepository::NewEntity();
}
try {
json_value = json::parse(bucket.value); // Parse the JSON
} catch (json::parse_error &ex) {
LogDataBuckets("Failed to parse JSON for key [{}] [{}]", bucket.key_, ex.what());
return DataBucketsRepository::NewEntity(); // Return empty entity on parse error
}
// Start from the top-level key (e.g., "progression")
json *current = &json_value;
// Traverse the JSON structure
for (const auto &key_part: nested_keys) {
LogDataBuckets("Looking for key part [{}] in JSON", key_part);
if (!current->contains(key_part)) {
LogDataBuckets("Key part [{}] not found in JSON for [{}]", key_part, full_key);
return DataBucketsRepository::NewEntity();
}
current = &(*current)[key_part];
}
// Create a new entity with the extracted value
DataBucketsRepository::DataBuckets result = bucket; // Copy the original bucket
result.value = current->is_string() ? current->get<std::string>() : current->dump();
return result;
}
// GetData fetches bucket data from the database or cache if it exists
// if the bucket doesn't exist, it will be added to the cache as a miss
// if ignore_misses_cache is true, the bucket will not be added to the cache as a miss
// the only place we should be ignoring the misses cache is on the initial read during SetData
DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k_, bool ignore_misses_cache)
{
DataBucketKey k = k_; // Copy the key so we can modify it
bool is_nested_key = k.key.find(NESTED_KEY_DELIMITER) != std::string::npos;
// Extract the top-level key for nested keys
if (is_nested_key) {
k.key = Strings::Split(k.key, NESTED_KEY_DELIMITER).front();
}
LogDataBuckets(
"Getting bucket key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}] zone_id [{}] instance_id [{}]",
k.key,
k.bot_id,
k.account_id,
k.character_id,
k.npc_id,
k.zone_id,
k.instance_id
);
bool can_cache = CanCache(k);
// Attempt to retrieve the value from the cache
if (can_cache) {
for (const auto &e : g_data_bucket_cache) {
if (CheckBucketMatch(e, k)) {
if (e.expires > 0 && e.expires < std::time(nullptr)) {
LogDataBuckets("Attempted to read expired key [{}] removing from cache", e.key_);
DeleteData(k);
return DataBucketsRepository::NewEntity();
}
LogDataBuckets("Returning key [{}] value [{}] from cache", e.key_, e.value);
if (is_nested_key && !k_.key.empty()) {
return ExtractNestedValue(e, k_.key);
}
return e;
}
}
}
// Fetch the value from the database
auto r = DataBucketsRepository::GetWhere(
database,
fmt::format(
" {} `key` = '{}' LIMIT 1",
DataBucket::GetScopedDbFilters(k),
k.key
)
);
if (r.empty()) {
// Handle cache misses
if (!ignore_misses_cache && can_cache) {
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.emplace_back(
DataBucketsRepository::DataBuckets{
.id = 0,
.key_ = k.key,
.value = "",
.expires = 0,
.account_id = k.account_id,
.character_id = k.character_id,
.npc_id = k.npc_id,
.bot_id = k.bot_id,
.zone_id = k.zone_id,
.instance_id = k.instance_id
}
);
LogDataBuckets(
"Key [{}] not found in database, adding to cache as a miss account_id [{}] character_id [{}] npc_id [{}] bot_id [{}] zone_id [{}] instance_id [{}] cache size before [{}] after [{}]",
k.key,
k.account_id,
k.character_id,
k.npc_id,
k.bot_id,
k.zone_id,
k.instance_id,
size_before,
g_data_bucket_cache.size()
);
}
return DataBucketsRepository::NewEntity();
}
auto bucket = r.front();
// If the entry has expired, delete it
if (bucket.expires > 0 && bucket.expires < static_cast<long long>(std::time(nullptr))) {
DeleteData(k);
return DataBucketsRepository::NewEntity();
}
// Add the value to the cache if it doesn't exist
if (can_cache) {
bool has_cache = false;
for (const auto &e : g_data_bucket_cache) {
if (e.id == bucket.id) {
has_cache = true;
break;
}
}
if (!has_cache) {
g_data_bucket_cache.emplace_back(bucket);
}
}
// Handle nested key extraction
if (is_nested_key && !k_.key.empty()) {
return ExtractNestedValue(bucket, k_.key);
}
return bucket;
}
std::string DataBucket::GetDataExpires(const std::string &bucket_key)
{
return GetDataExpires(DataBucketKey{.key = bucket_key});
}
std::string DataBucket::GetDataRemaining(const std::string &bucket_key)
{
return GetDataRemaining(DataBucketKey{.key = bucket_key});
}
bool DataBucket::DeleteData(const std::string &bucket_key)
{
return DeleteData(DataBucketKey{.key = bucket_key});
}
bool DataBucket::DeleteData(const DataBucketKey &k)
{
bool is_nested_key = k.key.find(NESTED_KEY_DELIMITER) != std::string::npos;
if (!is_nested_key) {
// Update cache
if (CanCache(k)) {
// delete from cache where contents match
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketsRepository::DataBuckets &e) {
return CheckBucketMatch(e, k);
}
),
g_data_bucket_cache.end()
);
}
// Regular key deletion, no nesting involved
return DataBucketsRepository::DeleteWhere(
database,
fmt::format("{} `key` = '{}'", DataBucket::GetScopedDbFilters(k), k.key)
);
}
// If it's a nested key, retrieve the top-level JSON object
auto top_level_key = Strings::Split(k.key, NESTED_KEY_DELIMITER).front();
DataBucketKey top_level_k = k;
top_level_k.key = top_level_key;
auto r = GetData(top_level_k);
if (r.id == 0 || r.value.empty() || !Strings::IsValidJson(r.value)) {
LogDataBuckets("Attempted to delete nested key [{}] but parent key [{}] does not exist or is invalid JSON", k.key, top_level_key);
return false;
}
json json_value;
try {
json_value = json::parse(r.value);
} catch (json::parse_error &ex) {
LogDataBuckets("Failed to parse JSON for key [{}] [{}]", top_level_key, ex.what());
return false;
}
// Recursively remove the nested key
auto nested_keys = Strings::Split(k.key, NESTED_KEY_DELIMITER);
auto top_key = nested_keys.front();
nested_keys.erase(nested_keys.begin());
json *current = &json_value;
for (size_t i = 0; i < nested_keys.size(); ++i) {
const std::string &key_part = nested_keys[i];
if (i == nested_keys.size() - 1) {
// Last key in the hierarchy - delete it
if (current->contains(key_part)) {
current->erase(key_part);
LogDataBuckets("Deleted nested key [{}] from [{}]", key_part, k.key);
} else {
LogDataBuckets("Key [{}] not found in JSON - nothing to delete", k.key);
return false;
}
} else {
if (!current->contains(key_part) || !(*current)[key_part].is_object()) {
LogDataBuckets("Parent key [{}] does not exist or is not an object", key_part);
return false;
}
current = &(*current)[key_part];
}
}
// If the JSON object is now empty, delete the top-level key
if (json_value.empty()) {
LogDataBuckets("Top-level key [{}] is now empty, deleting entire entry", top_level_key);
// delete cache
if (CanCache(k)) {
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketsRepository::DataBuckets &e) {
return CheckBucketMatch(e, top_level_k);
}
),
g_data_bucket_cache.end()
);
}
return DataBucketsRepository::DeleteWhere(
database,
fmt::format("{} `key` = '{}'", DataBucket::GetScopedDbFilters(k), top_level_key)
);
}
// Otherwise, update the existing JSON without the deleted key
r.value = json_value.dump();
DataBucketsRepository::UpdateOne(database, r);
// Update cache
if (CanCache(k)) {
for (auto &e : g_data_bucket_cache) {
if (CheckBucketMatch(e, top_level_k)) {
e.value = r.value;
break;
}
}
}
return true;
}
std::string DataBucket::GetDataExpires(const DataBucketKey &k)
{
LogDataBuckets(
"Getting bucket expiration key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}]",
k.key,
k.bot_id,
k.account_id,
k.character_id,
k.npc_id
);
auto r = GetData(k);
if (r.id == 0) {
return {};
}
return std::to_string(r.expires);
}
std::string DataBucket::GetDataRemaining(const DataBucketKey &k)
{
LogDataBuckets(
"Getting bucket remaining key [{}] bot_id [{}] account_id [{}] character_id [{}] npc_id [{}] bot_id [{}] zone_id [{}] instance_id [{}]",
k.key,
k.bot_id,
k.account_id,
k.character_id,
k.npc_id,
k.bot_id,
k.zone_id,
k.instance_id
);
auto r = GetData(k);
if (r.id == 0) {
return "0";
}
return fmt::format("{}", r.expires - (long long) std::time(nullptr));
}
std::string DataBucket::GetScopedDbFilters(const DataBucketKey &k)
{
std::vector<std::string> q = {};
if (k.character_id > 0) {
q.emplace_back(fmt::format("character_id = {}", k.character_id));
}
else {
q.emplace_back("character_id = 0");
}
if (k.account_id > 0) {
q.emplace_back(fmt::format("account_id = {}", k.account_id));
}
else {
q.emplace_back("account_id = 0");
}
if (k.npc_id > 0) {
q.emplace_back(fmt::format("npc_id = {}", k.npc_id));
}
else {
q.emplace_back("npc_id = 0");
}
if (k.bot_id > 0) {
q.emplace_back(fmt::format("bot_id = {}", k.bot_id));
}
else {
q.emplace_back("bot_id = 0");
}
if (k.zone_id > 0) {
q.emplace_back(fmt::format("zone_id = {} AND instance_id = {}", k.zone_id, k.instance_id));
}
else {
q.emplace_back("zone_id = 0 AND instance_id = 0");
}
return fmt::format(
"{} {}",
Strings::Join(q, " AND "),
!q.empty() ? "AND" : ""
);
}
bool DataBucket::CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe, const DataBucketKey &k)
{
return (
dbe.key_ == k.key &&
dbe.bot_id == k.bot_id &&
dbe.account_id == k.account_id &&
dbe.character_id == k.character_id &&
dbe.npc_id == k.npc_id &&
dbe.zone_id == k.zone_id &&
dbe.instance_id == k.instance_id
);
}
void DataBucket::LoadZoneCache(uint16 zone_id, uint16 instance_id)
{
const auto &l = DataBucketsRepository::GetWhere(
database,
fmt::format(
"zone_id = {} AND instance_id = {} AND (`expires` > {} OR `expires` = 0)",
zone_id,
instance_id,
(long long) std::time(nullptr)
)
);
if (l.empty()) {
return;
}
LogDataBucketsDetail("cache size before [{}] l size [{}]", g_data_bucket_cache.size(), l.size());
uint32 added_count = 0;
for (const auto &e: l) {
if (!ExistsInCache(e)) {
added_count++;
}
}
for (const auto &e: l) {
if (!ExistsInCache(e)) {
LogDataBucketsDetail("bucket id [{}] bucket key [{}] bucket value [{}]", e.id, e.key_, e.value);
g_data_bucket_cache.emplace_back(e);
}
}
LogDataBucketsDetail("cache size after [{}]", g_data_bucket_cache.size());
LogDataBuckets(
"Loaded [{}] zone keys new cache size is [{}]",
l.size(),
g_data_bucket_cache.size()
);
}
void DataBucket::BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector<uint32> ids)
{
if (ids.empty()) {
return;
}
if (ids.size() == 1) {
bool has_cache = false;
for (const auto &e: g_data_bucket_cache) {
if (t == DataBucketLoadType::Bot) {
has_cache = e.bot_id == ids[0];
}
else if (t == DataBucketLoadType::Account) {
has_cache = e.account_id == ids[0];
}
else if (t == DataBucketLoadType::Client) {
has_cache = e.character_id == ids[0];
}
}
if (has_cache) {
LogDataBucketsDetail("LoadType [{}] ID [{}] has cache", DataBucketLoadType::Name[t], ids[0]);
return;
}
}
std::string column;
switch (t) {
case DataBucketLoadType::Bot:
column = "bot_id";
break;
case DataBucketLoadType::Client:
column = "character_id";
break;
case DataBucketLoadType::Account:
column = "account_id";
break;
default:
LogError("Incorrect LoadType [{}]", static_cast<int>(t));
break;
}
const auto &l = DataBucketsRepository::GetWhere(
database,
fmt::format(
"{} IN ({}) AND (`expires` > {} OR `expires` = 0)",
column,
Strings::Join(ids, ", "),
(long long) std::time(nullptr)
)
);
if (l.empty()) {
return;
}
LogDataBucketsDetail("cache size before [{}] l size [{}]", g_data_bucket_cache.size(), l.size());
uint32 added_count = 0;
for (const auto &e: l) {
if (!ExistsInCache(e)) {
added_count++;
}
}
for (const auto &e: l) {
if (!ExistsInCache(e)) {
LogDataBucketsDetail("bucket id [{}] bucket key [{}] bucket value [{}]", e.id, e.key_, e.value);
g_data_bucket_cache.emplace_back(e);
}
}
LogDataBucketsDetail("cache size after [{}]", g_data_bucket_cache.size());
LogDataBuckets(
"Bulk Loaded ids [{}] column [{}] new cache size is [{}]",
ids.size(),
column,
g_data_bucket_cache.size()
);
}
void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type type, uint32 id, uint32 secondary_id)
{
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketsRepository::DataBuckets &e) {
return (
(type == DataBucketLoadType::Bot && e.bot_id == id) ||
(type == DataBucketLoadType::Account && e.account_id == id) ||
(type == DataBucketLoadType::Client && e.character_id == id) ||
(type == DataBucketLoadType::Zone && e.zone_id == id && e.instance_id == secondary_id)
);
}
),
g_data_bucket_cache.end()
);
LogDataBuckets(
"LoadType [{}] id [{}] cache size before [{}] after [{}]",
DataBucketLoadType::Name[type],
id,
size_before,
g_data_bucket_cache.size()
);
}
bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &entry)
{
for (const auto &e: g_data_bucket_cache) {
if (e.id == entry.id) {
return true;
}
}
return false;
}
void DataBucket::DeleteFromMissesCache(DataBucketsRepository::DataBuckets e)
{
// delete from cache where there might have been a written bucket miss to the cache
// this is to prevent the cache from growing too large
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketsRepository::DataBuckets &ce) {
return ce.id == 0 && ce.key_ == e.key_ &&
ce.account_id == e.account_id &&
ce.character_id == e.character_id &&
ce.npc_id == e.npc_id &&
ce.bot_id == e.bot_id &&
ce.zone_id == e.zone_id &&
ce.instance_id == e.instance_id;
}
),
g_data_bucket_cache.end()
);
LogDataBucketsDetail(
"Deleted bucket misses from cache where key [{}] size before [{}] after [{}]",
e.key_,
size_before,
g_data_bucket_cache.size()
);
}
void DataBucket::ClearCache()
{
g_data_bucket_cache.clear();
LogInfo("Cleared data buckets cache");
}
void DataBucket::DeleteFromCache(uint64 id, DataBucketLoadType::Type type)
{
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketsRepository::DataBuckets &e) {
switch (type) {
case DataBucketLoadType::Bot:
return e.bot_id == id;
case DataBucketLoadType::Client:
return e.character_id == id;
case DataBucketLoadType::Account:
return e.account_id == id;
default:
return false;
}
}
),
g_data_bucket_cache.end()
);
LogDataBuckets(
"Deleted [{}] id [{}] from cache size before [{}] after [{}]",
DataBucketLoadType::Name[type],
id,
size_before,
g_data_bucket_cache.size()
);
}
void DataBucket::DeleteZoneFromCache(uint16 zone_id, uint16 instance_id, DataBucketLoadType::Type type)
{
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketsRepository::DataBuckets &e) {
switch (type) {
case DataBucketLoadType::Zone:
return e.zone_id == zone_id && e.instance_id == instance_id;
default:
return false;
}
}
),
g_data_bucket_cache.end()
);
LogDataBuckets(
"Deleted zone [{}] instance [{}] from cache size before [{}] after [{}]",
zone_id,
instance_id,
size_before,
g_data_bucket_cache.size()
);
}
// CanCache returns whether a bucket can be cached or not
// characters are only in one zone at a time so we can cache locally to the zone
// bots (not implemented) are only in one zone at a time so we can cache locally to the zone
// npcs (ids) can be in multiple zones so we can't cache locally to the zone
bool DataBucket::CanCache(const DataBucketKey &key)
{
if (key.character_id > 0 || key.account_id > 0 || key.bot_id > 0 || key.zone_id > 0) {
return true;
}
return false;
}
+14 -155
View File
@@ -50,7 +50,6 @@
#include "../common/repositories/raid_members_repository.h" #include "../common/repositories/raid_members_repository.h"
#include "../common/repositories/reports_repository.h" #include "../common/repositories/reports_repository.h"
#include "../common/repositories/variables_repository.h" #include "../common/repositories/variables_repository.h"
#include "../common/repositories/character_pet_name_repository.h"
#include "../common/events/player_event_logs.h" #include "../common/events/player_event_logs.h"
// Disgrace: for windows compile // Disgrace: for windows compile
@@ -245,7 +244,7 @@ uint32 Database::CreateAccount(
e.password = password; e.password = password;
} }
LogInfo("Account attempting to be created loginserver [{}] name [{}] status [{}]", loginserver, name, status); LogInfo("Account Attempting to be created: [{}:{}] status: {}", loginserver, name, status);
e = AccountRepository::InsertOne(*this, e); e = AccountRepository::InsertOne(*this, e);
@@ -314,12 +313,6 @@ bool Database::ReserveName(uint32 account_id, const std::string& name)
return false; return false;
} }
const auto& p = CharacterPetNameRepository::GetWhere(*this, where_filter);
if (!p.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by an Pet", account_id, name);
return false;
}
auto e = CharacterDataRepository::NewEntity(); auto e = CharacterDataRepository::NewEntity();
e.account_id = account_id; e.account_id = account_id;
@@ -708,20 +701,6 @@ const std::string Database::GetNPCNameByID(uint32 npc_id)
return e.id ? e.name : std::string(); return e.id ? e.name : std::string();
} }
template<typename InputIterator, typename OutputIterator>
inline auto CleanMobName(InputIterator first, InputIterator last, OutputIterator result)
{
for (; first != last; ++first) {
if (*first == '_') {
*result = ' ';
}
else if (isalpha(*first) || *first == '`') {
*result = *first;
}
}
return result;
}
const std::string Database::GetCleanNPCNameByID(uint32 npc_id) const std::string Database::GetCleanNPCNameByID(uint32 npc_id)
{ {
const auto& e = NpcTypesRepository::FindOne(*this, npc_id); const auto& e = NpcTypesRepository::FindOne(*this, npc_id);
@@ -969,29 +948,6 @@ bool Database::UpdateName(const std::string& old_name, const std::string& new_na
return CharacterDataRepository::UpdateOne(*this, e); return CharacterDataRepository::UpdateOne(*this, e);
} }
bool Database::UpdateNameByID(const int character_id, const std::string& new_name)
{
LogInfo("Renaming [{}] to [{}]", character_id, new_name);
auto l = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`id` = {}",
character_id
)
);
if (l.empty()) {
return false;
}
auto& e = l.front();
e.name = new_name;
return CharacterDataRepository::UpdateOne(*this, e);
}
bool Database::IsNameUsed(const std::string& name) bool Database::IsNameUsed(const std::string& name)
{ {
if (RuleB(Bots, Enabled)) { if (RuleB(Bots, Enabled)) {
@@ -1019,20 +975,6 @@ bool Database::IsNameUsed(const std::string& name)
return !character_data.empty(); return !character_data.empty();
} }
// Players cannot have the same name as a pet vanity name, or memory corruption occurs.
bool Database::IsPetNameUsed(const std::string& name)
{
const auto& pet_name_data = CharacterPetNameRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}'",
Strings::Escape(name)
)
);
return !pet_name_data.empty();
}
uint32 Database::GetServerType() uint32 Database::GetServerType()
{ {
const auto& l = VariablesRepository::GetWhere(*this, "`varname` = 'ServerType' LIMIT 1"); const auto& l = VariablesRepository::GetWhere(*this, "`varname` = 'ServerType' LIMIT 1");
@@ -1109,11 +1051,11 @@ void Database::SetLFP(uint32 character_id, bool is_lfp)
CharacterDataRepository::UpdateOne(*this, e); CharacterDataRepository::UpdateOne(*this, e);
} }
void Database::SetLoginFlags(uint32 character_id, bool is_lfp, bool is_lfg, uint8 ingame) void Database::SetLoginFlags(uint32 character_id, bool is_lfp, bool is_lfg, uint8 first_logon)
{ {
auto e = CharacterDataRepository::FindOne(*this, character_id); auto e = CharacterDataRepository::FindOne(*this, character_id);
e.ingame = ingame; e.firstlogon = first_logon;
e.lfg = is_lfg ? 1 : 0; e.lfg = is_lfg ? 1 : 0;
e.lfp = is_lfp ? 1 : 0; e.lfp = is_lfp ? 1 : 0;
@@ -1129,11 +1071,11 @@ void Database::SetLFG(uint32 character_id, bool is_lfg)
CharacterDataRepository::UpdateOne(*this, e); CharacterDataRepository::UpdateOne(*this, e);
} }
void Database::SetIngame(uint32 character_id, uint8 ingame) void Database::SetFirstLogon(uint32 character_id, uint8 first_logon)
{ {
auto e = CharacterDataRepository::FindOne(*this, character_id); auto e = CharacterDataRepository::FindOne(*this, character_id);
e.ingame = ingame; e.firstlogon = first_logon;
CharacterDataRepository::UpdateOne(*this, e); CharacterDataRepository::UpdateOne(*this, e);
} }
@@ -1918,36 +1860,7 @@ bool Database::CopyCharacter(
const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1); const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1);
// validate destination name doesn't exist already std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets", "character_instance_safereturns" };
const auto& destination_characters = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}' AND `deleted_at` IS NULL LIMIT 1",
Strings::Escape(destination_character_name)
)
);
if (!destination_characters.empty()) {
LogError("Character [{}] already exists", destination_character_name);
return false;
}
std::vector<std::string> tables_to_zero_id = {
"keyring",
"data_buckets",
"character_evolving_items",
"character_instance_safereturns",
"character_expedition_lockouts",
"character_instance_lockouts",
"character_parcels",
"character_tribute",
"player_titlesets",
};
std::vector<std::string> ignore_tables = {
"guilds",
};
size_t total_rows_copied = 0;
TransactionBegin(); TransactionBegin();
@@ -1955,10 +1868,6 @@ bool Database::CopyCharacter(
const std::string& table_name = t.first; const std::string& table_name = t.first;
const std::string& character_id_column_name = t.second; const std::string& character_id_column_name = t.second;
if (Strings::Contains(ignore_tables, table_name)) {
continue;
}
auto results = QueryDatabase( auto results = QueryDatabase(
fmt::format( fmt::format(
"SHOW COLUMNS FROM {}", "SHOW COLUMNS FROM {}",
@@ -1966,12 +1875,6 @@ bool Database::CopyCharacter(
) )
); );
if (!results.Success()) {
LogError("Transaction failed [{}] rolling back", results.ErrorMessage());
TransactionRollback();
return false;
}
std::vector<std::string> columns = {}; std::vector<std::string> columns = {};
int column_count = 0; int column_count = 0;
@@ -1990,12 +1893,6 @@ bool Database::CopyCharacter(
) )
); );
if (!results.Success()) {
LogError("Transaction failed [{}] rolling back", results.ErrorMessage());
TransactionRollback();
return false;
}
std::vector<std::vector<std::string>> new_rows; std::vector<std::vector<std::string>> new_rows;
for (auto row : results) { for (auto row : results) {
@@ -2021,10 +1918,6 @@ bool Database::CopyCharacter(
value = std::to_string(destination_account_id); value = std::to_string(destination_account_id);
} }
if (!Strings::IsNumber(value)) {
value = Strings::Escape(value);
}
new_values.emplace_back(value); new_values.emplace_back(value);
} }
@@ -2057,31 +1950,14 @@ bool Database::CopyCharacter(
) )
); );
size_t rows_copied = insert_rows.size(); // Rows copied for this table
total_rows_copied += rows_copied; // Increment grand total
LogInfo("Copying table [{}] rows [{}]", table_name, Strings::Commify(rows_copied));
if (!insert.ErrorMessage().empty()) { if (!insert.ErrorMessage().empty()) {
LogError("Error copying table [{}] [{}]", table_name, insert.ErrorMessage());
TransactionRollback(); TransactionRollback();
return false; return false;
} }
} }
} }
auto r = TransactionCommit(); TransactionCommit();
if (!r.Success()) {
LogError("Transaction failed [{}] rolling back", r.ErrorMessage());
return false;
}
LogInfo(
"Character [{}] copied to [{}] total rows [{}]",
source_character_name,
destination_character_name,
Strings::Commify(total_rows_copied)
);
return true; return true;
} }
@@ -2226,12 +2102,12 @@ void Database::PurgeCharacterParcels()
for (auto const &r: results) { for (auto const &r: results) {
pd.from_name = r.from_name; pd.from_name = r.from_name;
pd.item_id = r.item_id; pd.item_id = r.item_id;
pd.augment_1_id = r.aug_slot_1; pd.aug_slot_1 = r.aug_slot_1;
pd.augment_2_id = r.aug_slot_2; pd.aug_slot_2 = r.aug_slot_2;
pd.augment_3_id = r.aug_slot_3; pd.aug_slot_3 = r.aug_slot_3;
pd.augment_4_id = r.aug_slot_4; pd.aug_slot_4 = r.aug_slot_4;
pd.augment_5_id = r.aug_slot_5; pd.aug_slot_5 = r.aug_slot_5;
pd.augment_6_id = r.aug_slot_6; pd.aug_slot_6 = r.aug_slot_6;
pd.note = r.note; pd.note = r.note;
pd.quantity = r.quantity; pd.quantity = r.quantity;
pd.sent_date = r.sent_date; pd.sent_date = r.sent_date;
@@ -2244,7 +2120,7 @@ void Database::PurgeCharacterParcels()
pel.event_data = ss.str(); pel.event_data = ss.str();
pel.created_at = std::time(nullptr); pel.created_at = std::time(nullptr);
PlayerEventLogs::Instance()->AddToQueue(pel); player_event_logs.AddToQueue(pel);
ss.str(""); ss.str("");
ss.clear(); ss.clear();
@@ -2271,20 +2147,3 @@ void Database::ClearBuyerDetails()
{ {
BuyerRepository::DeleteBuyer(*this, 0); BuyerRepository::DeleteBuyer(*this, 0);
} }
uint64_t Database::GetNextTableId(const std::string &table_name)
{
auto results = QueryDatabase(fmt::format("SHOW TABLE STATUS LIKE '{}'", table_name));
for (auto row: results) {
for (int row_index = 0; row_index < results.ColumnCount(); row_index++) {
std::string field_name = Strings::ToLower(results.FieldName(row_index));
if (field_name == "auto_increment") {
std::string value = row[row_index] ? row[row_index] : "null";
return Strings::ToUnsignedBigInt(value, 1);
}
}
}
return 1;
}
+1 -6
View File
@@ -103,7 +103,6 @@ public:
bool ReserveName(uint32 account_id, const std::string& name); bool ReserveName(uint32 account_id, const std::string& name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp); bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool UpdateName(const std::string& old_name, const std::string& new_name); bool UpdateName(const std::string& old_name, const std::string& new_name);
bool UpdateNameByID(const int character_id, const std::string& new_name);
bool CopyCharacter( bool CopyCharacter(
const std::string& source_character_name, const std::string& source_character_name,
const std::string& destination_character_name, const std::string& destination_character_name,
@@ -117,7 +116,6 @@ public:
bool CheckGMIPs(const std::string& login_ip, uint32 account_id); bool CheckGMIPs(const std::string& login_ip, uint32 account_id);
bool CheckNameFilter(const std::string& name, bool surname = false); bool CheckNameFilter(const std::string& name, bool surname = false);
bool IsNameUsed(const std::string& name); bool IsNameUsed(const std::string& name);
bool IsPetNameUsed(const std::string& name);
uint32 GetAccountIDByChar(const std::string& name, uint32* character_id = 0); uint32 GetAccountIDByChar(const std::string& name, uint32* character_id = 0);
uint32 GetAccountIDByChar(uint32 character_id); uint32 GetAccountIDByChar(uint32 character_id);
@@ -141,7 +139,6 @@ public:
bool CheckInstanceExpired(uint16 instance_id); bool CheckInstanceExpired(uint16 instance_id);
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration); bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
bool GetUnusedInstanceID(uint16& instance_id); bool GetUnusedInstanceID(uint16& instance_id);
bool TryGetUnusedInstanceID(uint16& instance_id);
bool IsGlobalInstance(uint16 instance_id); bool IsGlobalInstance(uint16 instance_id);
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id); bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
bool RemoveClientsFromInstance(uint16 instance_id); bool RemoveClientsFromInstance(uint16 instance_id);
@@ -263,7 +260,7 @@ public:
bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year); bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year);
void ClearMerchantTemp(); void ClearMerchantTemp();
void ClearPTimers(uint32 character_id); void ClearPTimers(uint32 character_id);
void SetIngame(uint32 character_id, uint8 ingame); void SetFirstLogon(uint32 character_id, uint8 first_logon);
void SetLFG(uint32 character_id, bool is_lfg); void SetLFG(uint32 character_id, bool is_lfg);
void SetLFP(uint32 character_id, bool is_lfp); void SetLFP(uint32 character_id, bool is_lfp);
void SetLoginFlags(uint32 character_id, bool is_lfp, bool is_lfg, uint8 first_logon); void SetLoginFlags(uint32 character_id, bool is_lfp, bool is_lfg, uint8 first_logon);
@@ -277,8 +274,6 @@ public:
void Encode(std::string &in); void Encode(std::string &in);
void Decode(std::string &in); void Decode(std::string &in);
uint64_t GetNextTableId(const std::string& table_name);
private: private:
Mutex Mvarcache; Mutex Mvarcache;
VarCache_Struct varcache; VarCache_Struct varcache;
+24 -8
View File
@@ -50,7 +50,7 @@ bool DatabaseDumpService::IsMySQLInstalled()
{ {
std::string version_output = GetMySQLVersion(); std::string version_output = GetMySQLVersion();
return version_output.find("mysql") != std::string::npos && (version_output.find("Ver") != std::string::npos || version_output.find("from") != std::string::npos); return version_output.find("mysql") != std::string::npos && version_output.find("Ver") != std::string::npos;
} }
/** /**
@@ -136,6 +136,11 @@ std::string DatabaseDumpService::GetLoginTableList()
return Strings::Join(DatabaseSchema::GetLoginTables(), " "); return Strings::Join(DatabaseSchema::GetLoginTables(), " ");
} }
std::string DatabaseDumpService::GetQueryServTables()
{
return Strings::Join(DatabaseSchema::GetQueryServerTables(), " ");
}
std::string DatabaseDumpService::GetSystemTablesList() std::string DatabaseDumpService::GetSystemTablesList()
{ {
auto system_tables = DatabaseSchema::GetServerTables(); auto system_tables = DatabaseSchema::GetServerTables();
@@ -204,7 +209,7 @@ void DatabaseDumpService::DatabaseDump()
} }
if (IsDumpOutputToConsole()) { if (IsDumpOutputToConsole()) {
EQEmuLogSys::Instance()->SilenceConsoleLogging(); LogSys.SilenceConsoleLogging();
} }
LogInfo("MySQL installed [{}]", GetMySQLVersion()); LogInfo("MySQL installed [{}]", GetMySQLVersion());
@@ -267,6 +272,11 @@ void DatabaseDumpService::DatabaseDump()
tables_to_dump += GetLoginTableList() + " "; tables_to_dump += GetLoginTableList() + " ";
dump_descriptor += "-login"; dump_descriptor += "-login";
} }
if (IsDumpQueryServerTables()) {
tables_to_dump += GetQueryServTables();
dump_descriptor += "-queryserv";
}
} }
if (IsDumpStaticInstanceData()) { if (IsDumpStaticInstanceData()) {
@@ -324,7 +334,7 @@ void DatabaseDumpService::DatabaseDump()
} }
if (!IsDumpOutputToConsole()) { if (!IsDumpOutputToConsole()) {
EQEmuLogSys::Instance()->LoadLogSettingsDefaults(); LogSys.LoadLogSettingsDefaults();
} }
if (!pipe_file.empty()) { if (!pipe_file.empty()) {
@@ -391,6 +401,7 @@ void DatabaseDumpService::DatabaseDump()
// LogDebug("[{}] dump-to-console", IsDumpOutputToConsole()); // LogDebug("[{}] dump-to-console", IsDumpOutputToConsole());
// LogDebug("[{}] dump-path", GetSetDumpPath()); // LogDebug("[{}] dump-path", GetSetDumpPath());
// LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false")); // LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false"));
// LogDebug("[{}] query-serv", (IsDumpQueryServerTables() ? "true" : "false"));
// LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false")); // LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false"));
// LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false")); // LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false"));
// LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false")); // LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false"));
@@ -500,6 +511,16 @@ const std::string &DatabaseDumpService::GetDumpFileName() const
return dump_file_name; return dump_file_name;
} }
bool DatabaseDumpService::IsDumpQueryServerTables() const
{
return dump_query_server_tables;
}
void DatabaseDumpService::SetDumpQueryServerTables(bool dump_query_server_tables)
{
DatabaseDumpService::dump_query_server_tables = dump_query_server_tables;
}
bool DatabaseDumpService::IsDumpOutputToConsole() const bool DatabaseDumpService::IsDumpOutputToConsole() const
{ {
return dump_output_to_console; return dump_output_to_console;
@@ -596,13 +617,8 @@ void DatabaseDumpService::BuildCredentialsFile()
void DatabaseDumpService::RemoveCredentialsFile() void DatabaseDumpService::RemoveCredentialsFile()
{ {
if (File::Exists(CREDENTIALS_FILE)) { if (File::Exists(CREDENTIALS_FILE)) {
try {
std::filesystem::remove(CREDENTIALS_FILE); std::filesystem::remove(CREDENTIALS_FILE);
} }
catch (std::exception &e) {
LogError("std::filesystem::remove err [{}]", e.what());
}
}
} }
bool DatabaseDumpService::IsDumpStaticInstanceData() bool DatabaseDumpService::IsDumpStaticInstanceData()
+4
View File
@@ -45,6 +45,8 @@ public:
void SetDumpPath(const std::string &dump_path); void SetDumpPath(const std::string &dump_path);
const std::string &GetDumpFileName() const; const std::string &GetDumpFileName() const;
void SetDumpFileName(const std::string &dump_file_name); void SetDumpFileName(const std::string &dump_file_name);
bool IsDumpQueryServerTables() const;
void SetDumpQueryServerTables(bool dump_query_server_tables);
bool IsDumpOutputToConsole() const; bool IsDumpOutputToConsole() const;
void SetDumpOutputToConsole(bool dump_output_to_console); void SetDumpOutputToConsole(bool dump_output_to_console);
bool IsDumpDropTableSyntaxOnly() const; bool IsDumpDropTableSyntaxOnly() const;
@@ -65,6 +67,7 @@ private:
bool dump_system_tables = false; bool dump_system_tables = false;
bool dump_content_tables = false; bool dump_content_tables = false;
bool dump_player_tables = false; bool dump_player_tables = false;
bool dump_query_server_tables = false;
bool dump_login_server_tables = false; bool dump_login_server_tables = false;
bool dump_with_no_data = false; bool dump_with_no_data = false;
bool dump_table_lock = false; bool dump_table_lock = false;
@@ -93,6 +96,7 @@ private:
bool HasCompressionBinary(); bool HasCompressionBinary();
std::string GetDumpFileNameWithPath(); std::string GetDumpFileNameWithPath();
std::string GetSetDumpPath(); std::string GetSetDumpPath();
std::string GetQueryServTables();
void RemoveSqlBackup(); void RemoveSqlBackup();
void BuildCredentialsFile(); void BuildCredentialsFile();
void RemoveCredentialsFile(); void RemoveCredentialsFile();
+5 -91
View File
@@ -7,7 +7,6 @@
#include "../http/httplib.h" #include "../http/httplib.h"
#include "database_update_manifest.cpp" #include "database_update_manifest.cpp"
#include "database_update_manifest_custom.cpp"
#include "database_update_manifest_bots.cpp" #include "database_update_manifest_bots.cpp"
#include "database_dump_service.h" #include "database_dump_service.h"
@@ -15,7 +14,7 @@ constexpr int BREAK_LENGTH = 70;
DatabaseVersion DatabaseUpdate::GetDatabaseVersions() DatabaseVersion DatabaseUpdate::GetDatabaseVersions()
{ {
auto results = m_database->QueryDatabase("SELECT `version`, `bots_version`, `custom_version` FROM `db_version` LIMIT 1"); auto results = m_database->QueryDatabase("SELECT `version`, `bots_version` FROM `db_version` LIMIT 1");
if (!results.Success() || !results.RowCount()) { if (!results.Success() || !results.RowCount()) {
LogError("Failed to read from [db_version] table!"); LogError("Failed to read from [db_version] table!");
return DatabaseVersion{}; return DatabaseVersion{};
@@ -26,7 +25,6 @@ DatabaseVersion DatabaseUpdate::GetDatabaseVersions()
return DatabaseVersion{ return DatabaseVersion{
.server_database_version = Strings::ToInt(r[0]), .server_database_version = Strings::ToInt(r[0]),
.bots_database_version = Strings::ToInt(r[1]), .bots_database_version = Strings::ToInt(r[1]),
.custom_database_version = Strings::ToInt(r[2]),
}; };
} }
@@ -35,7 +33,6 @@ DatabaseVersion DatabaseUpdate::GetBinaryDatabaseVersions()
return DatabaseVersion{ return DatabaseVersion{
.server_database_version = CURRENT_BINARY_DATABASE_VERSION, .server_database_version = CURRENT_BINARY_DATABASE_VERSION,
.bots_database_version = (RuleB(Bots, Enabled) ? CURRENT_BINARY_BOTS_DATABASE_VERSION : 0), .bots_database_version = (RuleB(Bots, Enabled) ? CURRENT_BINARY_BOTS_DATABASE_VERSION : 0),
.custom_database_version = CUSTOM_BINARY_DATABASE_VERSION,
}; };
} }
@@ -46,7 +43,6 @@ constexpr int LOOK_BACK_AMOUNT = 10;
// this check will take action // this check will take action
void DatabaseUpdate::CheckDbUpdates() void DatabaseUpdate::CheckDbUpdates()
{ {
InjectCustomVersionColumn();
InjectBotsVersionColumn(); InjectBotsVersionColumn();
auto v = GetDatabaseVersions(); auto v = GetDatabaseVersions();
auto b = GetBinaryDatabaseVersions(); auto b = GetBinaryDatabaseVersions();
@@ -63,15 +59,6 @@ void DatabaseUpdate::CheckDbUpdates()
m_database->QueryDatabase(fmt::format("UPDATE `db_version` SET `version` = {}", b.server_database_version)); m_database->QueryDatabase(fmt::format("UPDATE `db_version` SET `version` = {}", b.server_database_version));
} }
if (UpdateManifest(manifest_entries_custom, v.custom_database_version, b.custom_database_version)) {
LogInfo(
"Updates ran successfully, setting database version to [{}] from [{}]",
b.custom_database_version,
v.custom_database_version
);
m_database->QueryDatabase(fmt::format("UPDATE `db_version` SET `custom_version` = {}", b.custom_database_version));
}
if (b.bots_database_version > 0) { if (b.bots_database_version > 0) {
if (UpdateManifest(bot_manifest_entries, v.bots_database_version, b.bots_database_version)) { if (UpdateManifest(bot_manifest_entries, v.bots_database_version, b.bots_database_version)) {
LogInfo( LogInfo(
@@ -154,8 +141,7 @@ bool DatabaseUpdate::UpdateManifest(
std::vector<int> missing_migrations = {}; std::vector<int> missing_migrations = {};
if (version_low != version_high) { if (version_low != version_high) {
EQEmuLogSys::Instance()->DisableMySQLErrorLogs(); LogSys.DisableMySQLErrorLogs();
bool force_interactive = false;
for (int version = version_low + 1; version <= version_high; ++version) { for (int version = version_low + 1; version <= version_high; ++version) {
for (auto &e: entries) { for (auto &e: entries) {
if (e.version == version) { if (e.version == version) {
@@ -177,20 +163,13 @@ bool DatabaseUpdate::UpdateManifest(
prefix, prefix,
e.description e.description
); );
if (!has_migration && e.force_interactive) {
force_interactive = true;
} }
} }
} }
} LogSys.EnableMySQLErrorLogs();
EQEmuLogSys::Instance()->EnableMySQLErrorLogs();
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
if (!missing_migrations.empty() && m_skip_backup) { if (!missing_migrations.empty()) {
LogInfo("Skipping database backup");
}
else if (!missing_migrations.empty()) {
LogInfo("Automatically backing up database before applying updates"); LogInfo("Automatically backing up database before applying updates");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
auto s = DatabaseDumpService(); auto s = DatabaseDumpService();
@@ -205,42 +184,6 @@ bool DatabaseUpdate::UpdateManifest(
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
} }
if (force_interactive && !std::getenv("FORCE_INTERACTIVE")) {
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
LogInfo("Some migrations require user input. Running interactively");
LogInfo("This is usually due to a major change that could cause data loss");
LogInfo("Your server is automatically backed up before these updates are applied");
LogInfo("but you should also make sure you take a backup prior to running this update");
LogInfo("Would you like to run this update? [y/n] (Timeout 60s)");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
// user input
std::string input;
bool gave_input = false;
time_t start_time = time(nullptr);
time_t wait_time_seconds = 60;
// spawn a concurrent thread that waits for input from std::cin
std::thread t1(
[&]() {
std::cin >> input;
gave_input = true;
}
);
t1.detach();
// check the inputReceived flag once every 50ms for 10 seconds
while (time(nullptr) < start_time + wait_time_seconds && !gave_input) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
// prompt for user skip
if (Strings::Trim(input) != "y") {
LogInfo("Exiting due to user input");
std::exit(1);
}
}
for (auto &m: missing_migrations) { for (auto &m: missing_migrations) {
for (auto &e: entries) { for (auto &e: entries) {
if (e.version == m) { if (e.version == m) {
@@ -328,13 +271,6 @@ DatabaseUpdate *DatabaseUpdate::SetContentDatabase(Database *db)
return this; return this;
} }
DatabaseUpdate *DatabaseUpdate::SetSkipBackup(bool skip)
{
m_skip_backup = skip;
return this;
}
bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b) bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
{ {
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
@@ -357,16 +293,6 @@ bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
); );
} }
if (b.custom_database_version > 0) {
LogInfo(
"{:>8} | database [{}] binary [{}] {}",
"Custom",
v.custom_database_version,
b.custom_database_version,
(v.custom_database_version == b.custom_database_version) ? "up to date" : "checking updates"
);
}
LogInfo("{:>8} | [server.auto_database_updates] [<green>true]", "Config"); LogInfo("{:>8} | [server.auto_database_updates] [<green>true]", "Config");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
@@ -376,10 +302,7 @@ bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
// bots database version is optional, if not enabled then it is always up-to-date // bots database version is optional, if not enabled then it is always up-to-date
bool bots_up_to_date = RuleB(Bots, Enabled) ? v.bots_database_version >= b.bots_database_version : true; bool bots_up_to_date = RuleB(Bots, Enabled) ? v.bots_database_version >= b.bots_database_version : true;
// custom database version is optional, if not enabled then it is always up-to-date return server_up_to_date && bots_up_to_date;
bool custom_up_to_date = v.custom_database_version >= b.custom_database_version;
return server_up_to_date && bots_up_to_date && custom_up_to_date;
} }
// checks to see if there are pending updates // checks to see if there are pending updates
@@ -399,12 +322,3 @@ void DatabaseUpdate::InjectBotsVersionColumn()
m_database->QueryDatabase("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version"); m_database->QueryDatabase("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version");
} }
} }
void DatabaseUpdate::InjectCustomVersionColumn()
{
auto results = m_database->QueryDatabase("SHOW COLUMNS FROM `db_version` LIKE 'custom_version'");
if (!results.Success() || results.RowCount() == 0) {
LogInfo("Adding custom_version column to db_version table");
m_database->QueryDatabase("ALTER TABLE `db_version` ADD COLUMN `custom_version` INT(11) UNSIGNED NOT NULL DEFAULT 0");
}
}
-13
View File
@@ -11,13 +11,11 @@ struct ManifestEntry {
std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains] std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains]
std::string sql{}; // the SQL DDL that gets ran when the condition is true std::string sql{}; // the SQL DDL that gets ran when the condition is true
bool content_schema_update{}; // if true, this migration is a content schema update and should be ran against the content database bool content_schema_update{}; // if true, this migration is a content schema update and should be ran against the content database
bool force_interactive; // if true, this migration will always be run interactively
}; };
struct DatabaseVersion { struct DatabaseVersion {
int server_database_version; int server_database_version;
int bots_database_version; int bots_database_version;
int custom_database_version;
}; };
class DatabaseUpdate { class DatabaseUpdate {
@@ -31,23 +29,12 @@ public:
DatabaseUpdate *SetDatabase(Database *db); DatabaseUpdate *SetDatabase(Database *db);
DatabaseUpdate *SetContentDatabase(Database *db); DatabaseUpdate *SetContentDatabase(Database *db);
DatabaseUpdate *SetSkipBackup(bool skip);
bool HasPendingUpdates(); bool HasPendingUpdates();
static DatabaseUpdate* Instance()
{
static DatabaseUpdate instance;
return &instance;
}
private: private:
bool m_skip_backup = false;
Database *m_database; Database *m_database;
Database *m_content_database; Database *m_content_database;
static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b); static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b);
void InjectBotsVersionColumn(); void InjectBotsVersionColumn();
void InjectCustomVersionColumn();
}; };
#endif //EQEMU_DATABASE_UPDATE_H #endif //EQEMU_DATABASE_UPDATE_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,55 +0,0 @@
#include "database_update.h"
std::vector<ManifestEntry> manifest_entries_custom = {
ManifestEntry{
.version = 1,
.description = "2025_05_16_new_database_check_test",
.check = "SHOW TABLES LIKE 'new_table'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `new_table` (
`id` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
);
)",
.content_schema_update = false,
},
// Used for testing
// ManifestEntry{
// .version = 9229,
// .description = "new_database_check_test",
// .check = "SHOW TABLES LIKE 'new_table'",
// .condition = "empty",
// .match = "",
// .sql = R"(
//CREATE TABLE `new_table` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//CREATE TABLE `new_table1` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//CREATE TABLE `new_table2` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//CREATE TABLE `new_table3` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//)",
// }
};
// see struct definitions for what each field does
// struct ManifestEntry {
// int version{}; // database version of the migration
// std::string description{}; // description of the migration ex: "add_new_table" or "add_index_to_table"
// std::string check{}; // query that checks against the condition
// std::string condition{}; // condition or "match_type" - Possible values [contains|match|missing|empty|not_empty]
// std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains]
// std::string sql{}; // the SQL DDL that gets ran when the condition is true
// };
+23 -58
View File
@@ -30,8 +30,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/repositories/respawn_times_repository.h" #include "../common/repositories/respawn_times_repository.h"
#include "../common/repositories/spawn_condition_values_repository.h" #include "../common/repositories/spawn_condition_values_repository.h"
#include "repositories/spawn2_disabled_repository.h" #include "repositories/spawn2_disabled_repository.h"
#include "repositories/data_buckets_repository.h"
#include "repositories/zone_state_spawns_repository.h"
#include "database.h" #include "database.h"
#include <iomanip> #include <iomanip>
@@ -114,9 +114,7 @@ bool Database::CheckInstanceExpired(uint16 instance_id)
timeval tv{}; timeval tv{};
gettimeofday(&tv, nullptr); gettimeofday(&tv, nullptr);
// Use uint64_t for the addition to prevent overflow return (i.start_time + i.duration) <= tv.tv_sec;
uint64_t expiration_time = static_cast<uint64_t>(i.start_time) + static_cast<uint64_t>(i.duration);
return expiration_time <= tv.tv_sec;
} }
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration) bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
@@ -128,35 +126,11 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version
e.version = version; e.version = version;
e.start_time = std::time(nullptr); e.start_time = std::time(nullptr);
e.duration = duration; e.duration = duration;
e.expire_at = e.start_time + duration;
RespawnTimesRepository::ClearInstanceTimers(*this, e.id); return InstanceListRepository::InsertOne(*this, e).id;
InstanceListRepository::ReplaceOne(*this, e);
return instance_id > 0 && e.id;
} }
bool Database::GetUnusedInstanceID(uint16 &instance_id) bool Database::GetUnusedInstanceID(uint16 &instance_id)
{
// attempt to get an unused instance id
for (int a = 0; a < 10; a++) {
uint16 attempted_id = 0;
if (TryGetUnusedInstanceID(attempted_id)) {
auto i = InstanceListRepository::NewEntity();
i.id = attempted_id;
i.notes = "Prefetching";
auto n = InstanceListRepository::InsertOne(*this, i);
if (n.id > 0) {
instance_id = n.id;
return true;
}
}
}
instance_id = 0;
return false;
}
bool Database::TryGetUnusedInstanceID(uint16 &instance_id)
{ {
uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances); uint32 max_reserved_instance_id = RuleI(Instances, ReservedInstances);
uint32 max_instance_id = 32000; uint32 max_instance_id = 32000;
@@ -495,18 +469,16 @@ void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
void Database::DeleteInstance(uint16 instance_id) void Database::DeleteInstance(uint16 instance_id)
{ {
// I'm not sure why this isn't in here but we should add it in a later change and make sure it's tested
// InstanceListRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id)); InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id)); RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id)); SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id); DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id)); DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
CharacterCorpsesRepository::BuryInstance(*this, instance_id); CharacterCorpsesRepository::BuryInstance(*this, instance_id);
DataBucketsRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
if (RuleB(Zone, StateSavingOnShutdown)) {
ZoneStateSpawnsRepository::DeleteWhere(*this, fmt::format("`instance_id` = {}", instance_id));
}
} }
void Database::FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id) void Database::FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id)
@@ -561,12 +533,14 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
void Database::PurgeExpiredInstances() void Database::PurgeExpiredInstances()
{ {
/**
* Delay purging by a day so that we can continue using adjacent free instance id's
* from the table without risking the chance we immediately re-allocate a zone that freshly expired but
* has not been fully de-allocated
*/
auto l = InstanceListRepository::GetWhere( auto l = InstanceListRepository::GetWhere(
*this, *this,
fmt::format( "(start_time + duration) <= (UNIX_TIMESTAMP() - 86400) AND never_expires = 0"
"expire_at <= (UNIX_TIMESTAMP() - {}) and expire_at != 0 AND never_expires = 0",
RuleI(Instances, ExpireOffsetTimeSeconds)
)
); );
if (l.empty()) { if (l.empty()) {
return; return;
@@ -577,24 +551,16 @@ void Database::PurgeExpiredInstances()
instance_ids.emplace_back(std::to_string(e.id)); instance_ids.emplace_back(std::to_string(e.id));
} }
const auto ids = Strings::Implode(",", instance_ids); const auto imploded_instance_ids = Strings::Implode(",", instance_ids);
TransactionBegin(); InstanceListRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
InstanceListRepository::DeleteWhere(*this, fmt::format("id IN ({})", ids)); InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id IN ({})", imploded_instance_ids));
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id IN ({})", ids)); RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", ids)); SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", ids)); CharacterCorpsesRepository::BuryInstances(*this, imploded_instance_ids);
CharacterCorpsesRepository::BuryInstances(*this, ids); DynamicZoneMembersRepository::DeleteByManyInstances(*this, imploded_instance_ids);
DynamicZoneMembersRepository::DeleteByManyInstances(*this, ids); DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", ids)); Spawn2DisabledRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", imploded_instance_ids));
Spawn2DisabledRepository::DeleteWhere(*this, fmt::format("instance_id IN ({})", ids));
DataBucketsRepository::DeleteWhere(*this, fmt::format("instance_id != 0 and instance_id IN ({})", ids));
if (RuleB(Zone, StateSavingOnShutdown)) {
ZoneStateSpawnsRepository::DeleteWhere(*this, fmt::format("`instance_id` IN ({})", ids));
}
TransactionCommit();
LogInfo("Purged [{}] expired instances", l.size());
} }
void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
@@ -606,7 +572,6 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
i.start_time = std::time(nullptr); i.start_time = std::time(nullptr);
i.duration = new_duration; i.duration = new_duration;
i.expire_at = i.start_time + i.duration;
InstanceListRepository::UpdateOne(*this, i); InstanceListRepository::UpdateOne(*this, i);
} }
+29 -22
View File
@@ -51,7 +51,6 @@ namespace DatabaseSchema {
{"character_enabledtasks", "charid"}, {"character_enabledtasks", "charid"},
{"character_expedition_lockouts", "character_id"}, {"character_expedition_lockouts", "character_id"},
{"character_exp_modifiers", "character_id"}, {"character_exp_modifiers", "character_id"},
{"character_evolving_items", "character_id"},
{"character_inspect_messages", "id"}, {"character_inspect_messages", "id"},
{"character_instance_safereturns", "character_id"}, {"character_instance_safereturns", "character_id"},
{"character_item_recast", "id"}, {"character_item_recast", "id"},
@@ -64,7 +63,6 @@ namespace DatabaseSchema {
{"character_pet_buffs", "char_id"}, {"character_pet_buffs", "char_id"},
{"character_pet_info", "char_id"}, {"character_pet_info", "char_id"},
{"character_pet_inventory", "char_id"}, {"character_pet_inventory", "char_id"},
{"character_pet_name", "character_id"},
{"character_peqzone_flags", "id"}, {"character_peqzone_flags", "id"},
{"character_potionbelt", "id"}, {"character_potionbelt", "id"},
{"character_skills", "id"}, {"character_skills", "id"},
@@ -80,7 +78,7 @@ namespace DatabaseSchema {
{"guild_members", "char_id"}, {"guild_members", "char_id"},
{"guilds", "id"}, {"guilds", "id"},
{"instance_list_player", "id"}, {"instance_list_player", "id"},
{"inventory", "character_id"}, {"inventory", "charid"},
{"inventory_snapshots", "charid"}, {"inventory_snapshots", "charid"},
{"keyring", "char_id"}, {"keyring", "char_id"},
{"mail", "charid"}, {"mail", "charid"},
@@ -126,7 +124,6 @@ namespace DatabaseSchema {
"character_enabledtasks", "character_enabledtasks",
"character_expedition_lockouts", "character_expedition_lockouts",
"character_exp_modifiers", "character_exp_modifiers",
"character_evolving_items",
"character_inspect_messages", "character_inspect_messages",
"character_instance_safereturns", "character_instance_safereturns",
"character_item_recast", "character_item_recast",
@@ -139,7 +136,6 @@ namespace DatabaseSchema {
"character_pet_buffs", "character_pet_buffs",
"character_pet_info", "character_pet_info",
"character_pet_inventory", "character_pet_inventory",
"character_pet_name",
"character_peqzone_flags", "character_peqzone_flags",
"character_potionbelt", "character_potionbelt",
"character_skills", "character_skills",
@@ -216,7 +212,6 @@ namespace DatabaseSchema {
"ground_spawns", "ground_spawns",
"horses", "horses",
"items", "items",
"items_evolving_details",
"ldon_trap_entries", "ldon_trap_entries",
"ldon_trap_templates", "ldon_trap_templates",
"lootdrop", "lootdrop",
@@ -292,6 +287,32 @@ namespace DatabaseSchema {
}; };
} }
/**
* Gets QueryServer tables
*
* @return
*/
static std::vector<std::string> GetQueryServerTables()
{
return {
"qs_merchant_transaction_record",
"qs_merchant_transaction_record_entries",
"qs_player_aa_rate_hourly",
"qs_player_delete_record",
"qs_player_delete_record_entries",
"qs_player_events",
"qs_player_handin_record",
"qs_player_handin_record_entries",
"qs_player_move_record",
"qs_player_move_record_entries",
"qs_player_npc_kill_record",
"qs_player_npc_kill_record_entries",
"qs_player_speech",
"qs_player_trade_record",
"qs_player_trade_record_entries",
};
}
/** /**
* Gets state tables * Gets state tables
* Tables that keep track of server state * Tables that keep track of server state
@@ -312,9 +333,10 @@ namespace DatabaseSchema {
"completed_shared_task_members", "completed_shared_task_members",
"completed_shared_tasks", "completed_shared_tasks",
"discord_webhooks", "discord_webhooks",
"dynamic_zone_lockouts",
"dynamic_zone_members", "dynamic_zone_members",
"dynamic_zones", "dynamic_zones",
"expedition_lockouts",
"expeditions",
"gm_ips", "gm_ips",
"group_id", "group_id",
"group_leaders", "group_leaders",
@@ -333,25 +355,12 @@ namespace DatabaseSchema {
"saylink", "saylink",
"server_scheduled_events", "server_scheduled_events",
"spawn2_disabled", "spawn2_disabled",
"player_event_aa_purchase",
"player_event_killed_npc",
"player_event_killed_named_npc",
"player_event_killed_raid_npc",
"player_event_log_settings", "player_event_log_settings",
"player_event_logs", "player_event_logs",
"player_event_loot_items",
"player_event_merchant_purchase",
"player_event_merchant_sell",
"player_event_npc_handin",
"player_event_npc_handin_entries",
"player_event_speech",
"player_event_trade",
"player_event_trade_entries",
"shared_task_activity_state", "shared_task_activity_state",
"shared_task_dynamic_zones", "shared_task_dynamic_zones",
"shared_task_members", "shared_task_members",
"shared_tasks", "shared_tasks",
"zone_state_spawns",
}; };
} }
@@ -393,7 +402,6 @@ namespace DatabaseSchema {
static std::vector<std::string> GetBotTables() static std::vector<std::string> GetBotTables()
{ {
return { return {
"bot_blocked_buffs",
"bot_buffs", "bot_buffs",
"bot_command_settings", "bot_command_settings",
"bot_create_combinations", "bot_create_combinations",
@@ -407,7 +415,6 @@ namespace DatabaseSchema {
"bot_pet_buffs", "bot_pet_buffs",
"bot_pet_inventories", "bot_pet_inventories",
"bot_pets", "bot_pets",
"bot_settings",
"bot_spell_casting_chances", "bot_spell_casting_chances",
"bot_spell_settings", "bot_spell_settings",
"bot_spells_entries", "bot_spells_entries",
+3 -11
View File
@@ -7,7 +7,6 @@
#include "timer.h" #include "timer.h"
#include "dbcore.h" #include "dbcore.h"
#include "mysql_stmt.h"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
@@ -160,7 +159,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
(uint32) mysql_insert_id(mysql) (uint32) mysql_insert_id(mysql)
); );
if (EQEmuLogSys::Instance()->log_settings[Logs::MySQLQuery].is_category_enabled == 1) { if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
if ((strncasecmp(query, "select", 6) == 0)) { if ((strncasecmp(query, "select", 6) == 0)) {
LogMySQLQuery( LogMySQLQuery(
"{0} -- ({1} row{2} returned) ({3}s)", "{0} -- ({1} row{2} returned) ({3}s)",
@@ -189,9 +188,9 @@ void DBcore::TransactionBegin()
QueryDatabase("START TRANSACTION"); QueryDatabase("START TRANSACTION");
} }
MySQLRequestResult DBcore::TransactionCommit() void DBcore::TransactionCommit()
{ {
return QueryDatabase("COMMIT"); QueryDatabase("COMMIT");
} }
void DBcore::TransactionRollback() void DBcore::TransactionRollback()
@@ -302,9 +301,7 @@ std::string DBcore::Escape(const std::string& s)
void DBcore::SetMutex(Mutex *mutex) void DBcore::SetMutex(Mutex *mutex)
{ {
if (m_mutex && m_mutex != mutex) {
safe_delete(m_mutex); safe_delete(m_mutex);
}
DBcore::m_mutex = mutex; DBcore::m_mutex = mutex;
} }
@@ -439,8 +436,3 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
return r; return r;
} }
mysql::PreparedStmt DBcore::Prepare(std::string query)
{
return mysql::PreparedStmt(*mysql, std::move(query), m_mutex);
}
+1 -8
View File
@@ -17,8 +17,6 @@
#define CR_SERVER_GONE_ERROR 2006 #define CR_SERVER_GONE_ERROR 2006
#define CR_SERVER_LOST 2013 #define CR_SERVER_LOST 2013
namespace mysql { class PreparedStmt; }
class DBcore { class DBcore {
public: public:
enum eStatus { enum eStatus {
@@ -32,7 +30,7 @@ public:
MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true); MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true);
MySQLRequestResult QueryDatabaseMulti(const std::string &query); MySQLRequestResult QueryDatabaseMulti(const std::string &query);
void TransactionBegin(); void TransactionBegin();
MySQLRequestResult TransactionCommit(); void TransactionCommit();
void TransactionRollback(); void TransactionRollback();
std::string Escape(const std::string& s); std::string Escape(const std::string& s);
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen); uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
@@ -50,11 +48,6 @@ public:
} }
void SetMutex(Mutex *mutex); void SetMutex(Mutex *mutex);
// only safe on connections shared with other threads if results buffered
// unsafe to use off main thread due to internal server logging
// throws std::runtime_error on failure
mysql::PreparedStmt Prepare(std::string query);
protected: protected:
bool Open( bool Open(
const char *iHost, const char *iHost,
+1
View File
@@ -4,6 +4,7 @@
#include <string> #include <string>
#include "../types.h" #include "../types.h"
#include "../http/httplib.h"
#include "../repositories/player_event_logs_repository.h" #include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h" #include "../events/player_events.h"
+2 -2
View File
@@ -26,7 +26,7 @@ void DiscordManager::ProcessMessageQueue()
continue; continue;
} }
auto webhook = EQEmuLogSys::Instance()->GetDiscordWebhooks()[q.first]; auto webhook = LogSys.GetDiscordWebhooks()[q.first];
std::string message; std::string message;
for (auto &m: q.second) { for (auto &m: q.second) {
@@ -68,7 +68,7 @@ void DiscordManager::ProcessMessageQueue()
void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e) void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e)
{ {
auto w = PlayerEventLogs::Instance()->GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id); auto w = player_event_logs.GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id);
if (!w.empty()) { if (!w.empty()) {
Discord::SendPlayerEventMessage(e, w); Discord::SendPlayerEventMessage(e, w);
} }
-6
View File
@@ -13,12 +13,6 @@ public:
void QueueWebhookMessage(uint32 webhook_id, const std::string& message); void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
void ProcessMessageQueue(); void ProcessMessageQueue();
void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e); void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e);
static DiscordManager* Instance()
{
static DiscordManager instance;
return &instance;
}
private: private:
std::mutex webhook_queue_lock{}; std::mutex webhook_queue_lock{};
std::map<uint32, std::vector<std::string>> webhook_message_queue{}; std::map<uint32, std::vector<std::string>> webhook_message_queue{};
+67 -297
View File
@@ -1,13 +1,11 @@
#include "dynamic_zone_base.h" #include "dynamic_zone_base.h"
#include "database.h" #include "database.h"
#include "eqemu_logsys.h" #include "eqemu_logsys.h"
#include "repositories/instance_list_repository.h"
#include "repositories/instance_list_player_repository.h"
#include "rulesys.h" #include "rulesys.h"
#include "servertalk.h" #include "servertalk.h"
#include "util/uuid.h" #include "util/uuid.h"
#include "repositories/character_expedition_lockouts_repository.h"
#include "repositories/dynamic_zone_lockouts_repository.h"
#include "repositories/instance_list_repository.h"
#include "repositories/instance_list_player_repository.h"
DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry) DynamicZoneBase::DynamicZoneBase(DynamicZonesRepository::DynamicZoneInstance&& entry)
{ {
@@ -58,16 +56,15 @@ uint32_t DynamicZoneBase::CreateInstance()
insert_instance.start_time = static_cast<int>(std::chrono::system_clock::to_time_t(m_start_time)); insert_instance.start_time = static_cast<int>(std::chrono::system_clock::to_time_t(m_start_time));
insert_instance.duration = static_cast<int>(m_duration.count()); insert_instance.duration = static_cast<int>(m_duration.count());
insert_instance.never_expires = m_never_expires; insert_instance.never_expires = m_never_expires;
insert_instance.expire_at = insert_instance.start_time + insert_instance.duration;
auto instance = InstanceListRepository::ReplaceOne(GetDatabase(), insert_instance); auto instance = InstanceListRepository::InsertOne(GetDatabase(), insert_instance);
if (!instance) if (instance.id == 0)
{ {
LogDynamicZones("Failed to create instance [{}] for zone [{}]", unused_instance_id, m_zone_id); LogDynamicZones("Failed to create instance [{}] for zone [{}]", unused_instance_id, m_zone_id);
return 0; return 0;
} }
m_instance_id = unused_instance_id; m_instance_id = instance.id;
return m_instance_id; return m_instance_id;
} }
@@ -96,15 +93,13 @@ void DynamicZoneBase::LoadRepositoryResult(DynamicZonesRepository::DynamicZoneIn
m_zonein.y = dz_entry.zone_in_y; m_zonein.y = dz_entry.zone_in_y;
m_zonein.z = dz_entry.zone_in_z; m_zonein.z = dz_entry.zone_in_z;
m_zonein.heading = dz_entry.zone_in_heading; m_zonein.heading = dz_entry.zone_in_heading;
m_has_zonein = dz_entry.has_zone_in != 0; m_has_zonein = (dz_entry.has_zone_in != 0);
m_is_locked = dz_entry.is_locked;
m_add_replay = dz_entry.add_replay;
// instance_list portion // instance_list portion
m_zone_id = dz_entry.zone; m_zone_id = dz_entry.zone;
m_zone_version = dz_entry.version; m_zone_version = dz_entry.version;
m_start_time = std::chrono::system_clock::from_time_t(dz_entry.start_time); m_start_time = std::chrono::system_clock::from_time_t(dz_entry.start_time);
m_duration = std::chrono::seconds(dz_entry.duration); m_duration = std::chrono::seconds(dz_entry.duration);
m_never_expires = dz_entry.never_expires != 0; m_never_expires = (dz_entry.never_expires != 0);
m_expire_time = m_start_time + m_duration; m_expire_time = m_start_time + m_duration;
} }
@@ -124,40 +119,37 @@ void DynamicZoneBase::AddMemberFromRepositoryResult(
uint32_t DynamicZoneBase::SaveToDatabase() uint32_t DynamicZoneBase::SaveToDatabase()
{ {
LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id); LogDynamicZonesDetail("Saving dz instance [{}] to database", m_instance_id);
if (m_instance_id == 0)
if (m_instance_id != 0)
{ {
return 0; auto insert_dz = DynamicZonesRepository::NewEntity();
insert_dz.uuid = m_uuid;
insert_dz.name = m_name;
insert_dz.leader_id = m_leader.id;
insert_dz.min_players = m_min_players;
insert_dz.max_players = m_max_players;
insert_dz.instance_id = m_instance_id,
insert_dz.type = static_cast<int>(m_type);
insert_dz.dz_switch_id = m_dz_switch_id;
insert_dz.compass_zone_id = m_compass.zone_id;
insert_dz.compass_x = m_compass.x;
insert_dz.compass_y = m_compass.y;
insert_dz.compass_z = m_compass.z;
insert_dz.safe_return_zone_id = m_safereturn.zone_id;
insert_dz.safe_return_x = m_safereturn.x;
insert_dz.safe_return_y = m_safereturn.y;
insert_dz.safe_return_z = m_safereturn.z;
insert_dz.safe_return_heading = m_safereturn.heading;
insert_dz.zone_in_x = m_zonein.x;
insert_dz.zone_in_y = m_zonein.y;
insert_dz.zone_in_z = m_zonein.z;
insert_dz.zone_in_heading = m_zonein.heading;
insert_dz.has_zone_in = m_has_zonein;
auto inserted_dz = DynamicZonesRepository::InsertOne(GetDatabase(), insert_dz);
return inserted_dz.id;
} }
return 0;
auto dz = DynamicZonesRepository::NewEntity();
dz.uuid = m_uuid;
dz.name = m_name;
dz.leader_id = m_leader.id;
dz.min_players = m_min_players;
dz.max_players = m_max_players;
dz.instance_id = static_cast<int32_t>(m_instance_id),
dz.type = static_cast<uint8_t>(m_type);
dz.dz_switch_id = m_dz_switch_id;
dz.compass_zone_id = m_compass.zone_id;
dz.compass_x = m_compass.x;
dz.compass_y = m_compass.y;
dz.compass_z = m_compass.z;
dz.safe_return_zone_id = m_safereturn.zone_id;
dz.safe_return_x = m_safereturn.x;
dz.safe_return_y = m_safereturn.y;
dz.safe_return_z = m_safereturn.z;
dz.safe_return_heading = m_safereturn.heading;
dz.zone_in_x = m_zonein.x;
dz.zone_in_y = m_zonein.y;
dz.zone_in_z = m_zonein.z;
dz.zone_in_heading = m_zonein.heading;
dz.has_zone_in = static_cast<uint8_t>(m_has_zonein);
dz.is_locked = static_cast<int8_t>(m_is_locked);
dz.add_replay = static_cast<int8_t>(m_add_replay);
dz = DynamicZonesRepository::InsertOne(GetDatabase(), std::move(dz));
return dz.id;
} }
bool DynamicZoneBase::AddMember(const DynamicZoneMember& add_member) bool DynamicZoneBase::AddMember(const DynamicZoneMember& add_member)
@@ -204,9 +196,10 @@ bool DynamicZoneBase::RemoveMember(const DynamicZoneMember& remove_member)
return true; return true;
} }
bool DynamicZoneBase::SwapMember(const DynamicZoneMember& add_member, const std::string& remove_name) bool DynamicZoneBase::SwapMember(
const DynamicZoneMember& add_member, const std::string& remove_char_name)
{ {
auto remove_member = GetMemberData(remove_name); auto remove_member = GetMemberData(remove_char_name);
if (!add_member.IsValid() || !remove_member.IsValid()) if (!add_member.IsValid() || !remove_member.IsValid())
{ {
return false; return false;
@@ -237,18 +230,9 @@ void DynamicZoneBase::RemoveAllMembers()
void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members) void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members)
{ {
if (members.empty())
{
return;
}
LogDynamicZonesDetail("Saving [{}] member(s) for dz [{}]", members.size(), m_id); LogDynamicZonesDetail("Saving [{}] member(s) for dz [{}]", members.size(), m_id);
m_members = members; m_members = members;
if (m_members.size() > m_max_players)
{
m_members.resize(m_max_players);
}
// the lower level instance_list_players needs to be kept updated as well // the lower level instance_list_players needs to be kept updated as well
std::vector<DynamicZoneMembersRepository::DynamicZoneMembers> insert_members; std::vector<DynamicZoneMembersRepository::DynamicZoneMembers> insert_members;
@@ -258,12 +242,12 @@ void DynamicZoneBase::SaveMembers(const std::vector<DynamicZoneMember>& members)
DynamicZoneMembersRepository::DynamicZoneMembers member_entry{}; DynamicZoneMembersRepository::DynamicZoneMembers member_entry{};
member_entry.dynamic_zone_id = m_id; member_entry.dynamic_zone_id = m_id;
member_entry.character_id = member.id; member_entry.character_id = member.id;
insert_members.push_back(member_entry); insert_members.emplace_back(member_entry);
InstanceListPlayerRepository::InstanceListPlayer player_entry{}; InstanceListPlayerRepository::InstanceListPlayer player_entry;
player_entry.id = m_instance_id; player_entry.id = static_cast<int>(m_instance_id);
player_entry.charid = member.id; player_entry.charid = static_cast<int>(member.id);
insert_players.push_back(player_entry); insert_players.emplace_back(player_entry);
} }
DynamicZoneMembersRepository::InsertOrUpdateMany(GetDatabase(), insert_members); DynamicZoneMembersRepository::InsertOrUpdateMany(GetDatabase(), insert_members);
@@ -355,44 +339,6 @@ void DynamicZoneBase::SetLeader(const DynamicZoneMember& new_leader, bool update
} }
} }
void DynamicZoneBase::SetLocked(bool lock, bool update_db, DzLockMsg lock_msg, uint32_t color)
{
m_is_locked = lock;
if (update_db)
{
DynamicZonesRepository::UpdateLocked(GetDatabase(), m_id, lock);
ServerPacket pack(ServerOP_DzLock, sizeof(ServerDzLock_Struct));
auto buf = reinterpret_cast<ServerDzLock_Struct*>(pack.pBuffer);
buf->dz_id = GetID();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->lock = m_is_locked;
buf->lock_msg = static_cast<uint8_t>(lock_msg);
buf->color = color;
SendServerPacket(&pack);
}
}
void DynamicZoneBase::SetReplayOnJoin(bool enabled, bool update_db)
{
m_add_replay = enabled;
if (update_db)
{
DynamicZonesRepository::UpdateReplayOnJoin(GetDatabase(), m_id, enabled);
ServerPacket pack(ServerOP_DzReplayOnJoin, sizeof(ServerDzBool_Struct));
auto buf = reinterpret_cast<ServerDzBool_Struct*>(pack.pBuffer);
buf->dz_id = GetID();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->enabled = enabled;
SendServerPacket(&pack);
}
}
uint32_t DynamicZoneBase::GetSecondsRemaining() const uint32_t DynamicZoneBase::GetSecondsRemaining() const
{ {
auto remaining = std::chrono::duration_cast<std::chrono::seconds>(GetDurationRemaining()).count(); auto remaining = std::chrono::duration_cast<std::chrono::seconds>(GetDurationRemaining()).count();
@@ -532,13 +478,13 @@ void DynamicZoneBase::RemoveInternalMember(uint32_t character_id)
), m_members.end()); ), m_members.end());
} }
bool DynamicZoneBase::HasMember(uint32_t character_id) const bool DynamicZoneBase::HasMember(uint32_t character_id)
{ {
return std::any_of(m_members.begin(), m_members.end(), return std::any_of(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) { return member.id == character_id; }); [&](const DynamicZoneMember& member) { return member.id == character_id; });
} }
bool DynamicZoneBase::HasMember(const std::string& character_name) const bool DynamicZoneBase::HasMember(const std::string& character_name)
{ {
return std::any_of(m_members.begin(), m_members.end(), return std::any_of(m_members.begin(), m_members.end(),
[&](const DynamicZoneMember& member) { [&](const DynamicZoneMember& member) {
@@ -644,34 +590,35 @@ std::string DynamicZoneBase::GetDynamicZoneTypeName(DynamicZoneType dz_type)
} }
} }
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerPacket(uint16_t zone_id, uint16_t instance_id) EQ::Net::DynamicPacket DynamicZoneBase::GetSerializedDzPacket()
{ {
std::ostringstream ss = GetSerialized(); EQ::Net::DynamicPacket dyn_pack;
std::string_view sv = ss.view(); dyn_pack.PutSerialize(0, *this);
auto pack_size = sizeof(ServerDzCreate_Struct) + sv.size(); LogDynamicZonesDetail("Serialized server dz size [{}]", dyn_pack.Length());
return dyn_pack;
}
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateServerDzCreatePacket(
uint16_t origin_zone_id, uint16_t origin_instance_id)
{
EQ::Net::DynamicPacket dyn_pack = GetSerializedDzPacket();
auto pack_size = sizeof(ServerDzCreateSerialized_Struct) + dyn_pack.Length();
auto pack = std::make_unique<ServerPacket>(ServerOP_DzCreated, static_cast<uint32_t>(pack_size)); auto pack = std::make_unique<ServerPacket>(ServerOP_DzCreated, static_cast<uint32_t>(pack_size));
auto buf = reinterpret_cast<ServerDzCreate_Struct*>(pack->pBuffer); auto buf = reinterpret_cast<ServerDzCreateSerialized_Struct*>(pack->pBuffer);
buf->origin_zone_id = zone_id; buf->origin_zone_id = origin_zone_id;
buf->origin_instance_id = instance_id; buf->origin_instance_id = origin_instance_id;
buf->dz_id = GetID(); buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
buf->cereal_size = static_cast<uint32_t>(sv.size()); memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
memcpy(buf->cereal_data, sv.data(), sv.size());
return pack; return pack;
} }
std::ostringstream DynamicZoneBase::GetSerialized() void DynamicZoneBase::LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size)
{ {
std::ostringstream ss; LogDynamicZonesDetail("Deserializing server dz size [{}]", cereal_size);
cereal::BinaryOutputArchive archive(ss); EQ::Util::MemoryStreamReader ss(cereal_data, cereal_size);
archive(*this);
return ss;
}
void DynamicZoneBase::Unserialize(std::span<char> buf)
{
EQ::Util::MemoryStreamReader ss(buf.data(), buf.size());
cereal::BinaryInputArchive archive(ss); cereal::BinaryInputArchive archive(ss);
archive(*this); archive(*this);
} }
@@ -700,180 +647,3 @@ void DynamicZoneBase::LoadTemplate(const DynamicZoneTemplatesRepository::Dynamic
m_zonein.z = dz_template.zone_in_z; m_zonein.z = dz_template.zone_in_z;
m_zonein.heading = dz_template.zone_in_h; m_zonein.heading = dz_template.zone_in_h;
} }
std::vector<uint32_t> DynamicZoneBase::GetMemberIds()
{
std::vector<uint32_t> ids;
ids.reserve(m_members.size());
for (const auto& member : m_members)
{
ids.push_back(member.id);
}
return ids;
}
bool DynamicZoneBase::HasLockout(const std::string& event)
{
return std::ranges::any_of(m_lockouts, [&](const auto& l) { return l.IsEvent(event); });
}
bool DynamicZoneBase::HasReplayLockout()
{
return HasLockout(DzLockout::ReplayTimer);
}
void DynamicZoneBase::AddLockout(const std::string& event, uint32_t seconds)
{
auto lockout = DzLockout::Create(m_name, event, seconds, m_uuid);
AddLockout(lockout);
}
void DynamicZoneBase::AddLockout(const DzLockout& lockout, bool members_only)
{
if (!members_only)
{
DynamicZoneLockoutsRepository::InsertLockouts(GetDatabase(), GetID(), { lockout });
}
CharacterExpeditionLockoutsRepository::InsertLockout(GetDatabase(), GetMemberIds(), lockout);
HandleLockoutUpdate(lockout, false, members_only);
SendServerPacket(CreateLockoutPacket(lockout, false, members_only).get());
}
void DynamicZoneBase::AddLockoutDuration(const std::string& event, int seconds, bool members_only)
{
auto lockout = DzLockout::Create(m_name, event, std::max(0, seconds), m_uuid);
// lockout has unsigned duration, pass original seconds to support reducing existing timers
int secs = static_cast<int>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
CharacterExpeditionLockoutsRepository::AddLockoutDuration(GetDatabase(), GetMemberIds(), lockout, secs);
HandleLockoutDuration(lockout, seconds, members_only, true);
SendServerPacket(CreateLockoutDurationPacket(lockout, seconds, members_only).get());
}
void DynamicZoneBase::UpdateLockoutDuration(const std::string& event, uint32_t seconds, bool members_only)
{
// some live expeditions update existing lockout timers during progression
auto it = std::ranges::find_if(m_lockouts, [&](const auto& l) { return l.IsEvent(event); });
if (it != m_lockouts.end())
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
DzLockout lockout(m_uuid, m_name, event, it->GetStartTime() + seconds, seconds);
AddLockout(lockout, members_only);
}
}
void DynamicZoneBase::RemoveLockout(const std::string& event)
{
DynamicZoneLockoutsRepository::DeleteWhere(GetDatabase(), fmt::format(
"dynamic_zone_id = {} AND event_name = '{}'", GetID(), Strings::Escape(event)));
CharacterExpeditionLockoutsRepository::DeleteWhere(GetDatabase(), fmt::format(
"character_id IN ({}) AND expedition_name = '{}' AND event_name = '{}'",
fmt::join(GetMemberIds(), ","), Strings::Escape(m_name), Strings::Escape(event)));
DzLockout lockout{m_uuid, m_name, event, 0, 0};
HandleLockoutUpdate(lockout, true, false);
SendServerPacket(CreateLockoutPacket(lockout, true).get());
}
void DynamicZoneBase::HandleLockoutUpdate(const DzLockout& lockout, bool remove, bool members_only)
{
if (!members_only)
{
std::erase_if(m_lockouts, [&](const auto& l) { return l.IsEvent(lockout.Event()); });
if (!remove)
{
m_lockouts.push_back(lockout);
}
}
}
void DynamicZoneBase::HandleLockoutDuration(const DzLockout& lockout, int seconds, bool members_only, bool insert_db)
{
if (!members_only)
{
auto it = std::ranges::find_if(m_lockouts, [&](const auto& l) { return l.IsEvent(lockout.Event()); });
if (it != m_lockouts.end())
{
it->AddLockoutTime(seconds);
}
else
{
it = m_lockouts.insert(m_lockouts.end(), lockout);
}
if (insert_db)
{
DynamicZoneLockoutsRepository::InsertLockouts(GetDatabase(), GetID(), { *it });
}
}
}
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateLockoutPacket(const DzLockout& lockout, bool remove, bool members_only) const
{
uint32_t pack_size = sizeof(ServerDzLockout_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_DzLockout, pack_size);
auto buf = reinterpret_cast<ServerDzLockout_Struct*>(pack->pBuffer);
buf->dz_id = GetID();
buf->expire_time = lockout.GetExpireTime();
buf->duration = lockout.GetDuration();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->remove = remove;
buf->members_only = members_only;
strn0cpy(buf->event_name, lockout.Event().c_str(), sizeof(buf->event_name));
return pack;
}
std::unique_ptr<ServerPacket> DynamicZoneBase::CreateLockoutDurationPacket(const DzLockout& lockout, int seconds, bool members_only) const
{
uint32_t pack_size = sizeof(ServerDzLockout_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_DzLockoutDuration, pack_size);
auto buf = reinterpret_cast<ServerDzLockout_Struct*>(pack->pBuffer);
buf->dz_id = GetID();
buf->expire_time = lockout.GetExpireTime();
buf->duration = lockout.GetDuration();
buf->sender_zone_id = GetCurrentZoneID();
buf->sender_instance_id = GetCurrentInstanceID();
buf->members_only = members_only;
buf->seconds = seconds;
strn0cpy(buf->event_name, lockout.Event().c_str(), sizeof(buf->event_name));
return pack;
}
void DynamicZoneBase::SyncCharacterLockouts(uint32_t char_id, std::vector<DzLockout>& lockouts)
{
// adds missing event lockouts to client for this expedition and updates
// client timers that are both shorter and from another expedition
bool modified = false;
for (const auto& lockout : m_lockouts)
{
if (lockout.IsReplay() || lockout.IsExpired() || lockout.UUID() != m_uuid)
{
continue;
}
auto it = std::find_if(lockouts.begin(), lockouts.end(), [&](const DzLockout& l) { return l.IsSame(lockout); });
if (it == lockouts.end())
{
modified = true;
lockouts.push_back(lockout); // insert missing
}
else if (it->GetSecondsRemaining() < lockout.GetSecondsRemaining() && it->UUID() != m_uuid)
{
// only update lockout timer not uuid so loot event apis still work
modified = true;
it->SetDuration(lockout.GetDuration());
it->SetExpireTime(lockout.GetExpireTime());
}
}
if (modified)
{
CharacterExpeditionLockoutsRepository::InsertLockouts(GetDatabase(), char_id, lockouts);
}
}
+14 -68
View File
@@ -1,8 +1,8 @@
#ifndef COMMON_DYNAMIC_ZONE_BASE_H #ifndef COMMON_DYNAMIC_ZONE_BASE_H
#define COMMON_DYNAMIC_ZONE_BASE_H #define COMMON_DYNAMIC_ZONE_BASE_H
#include "dynamic_zone_lockout.h"
#include "eq_constants.h" #include "eq_constants.h"
#include "net/packet.h"
#include "repositories/dynamic_zones_repository.h" #include "repositories/dynamic_zones_repository.h"
#include "repositories/dynamic_zone_members_repository.h" #include "repositories/dynamic_zone_members_repository.h"
#include "repositories/dynamic_zone_templates_repository.h" #include "repositories/dynamic_zone_templates_repository.h"
@@ -10,40 +10,12 @@
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <span>
#include <string> #include <string>
#include <vector> #include <vector>
class Database; class Database;
class ServerPacket; class ServerPacket;
// message string 8312 added in September 08 2020 Test patch (used by both dz and shared tasks)
inline constexpr char DzNotAllAdded[] = "Not all players in your {0} were added to the {1}. The {1} can take a maximum of {2} players, and your {0} has {3}.";
enum class DzLockMsg : uint8_t
{
None = 0, Close, Begin
};
enum class DynamicZoneType
{
None = 0,
Expedition,
Tutorial,
Task,
Mission, // Shared Task
Quest
};
enum class DynamicZoneMemberStatus
{
Unknown = 0,
Online,
Offline,
InDynamicZone,
LinkDead
};
struct DynamicZoneMember struct DynamicZoneMember
{ {
uint32_t id = 0; uint32_t id = 0;
@@ -121,7 +93,6 @@ public:
const std::string& GetName() const { return m_name; } const std::string& GetName() const { return m_name; }
const std::string& GetUUID() const { return m_uuid; } const std::string& GetUUID() const { return m_uuid; }
const DynamicZoneMember& GetLeader() const { return m_leader; } const DynamicZoneMember& GetLeader() const { return m_leader; }
const std::vector<DzLockout>& GetLockouts() const { return m_lockouts; }
const std::vector<DynamicZoneMember>& GetMembers() const { return m_members; } const std::vector<DynamicZoneMember>& GetMembers() const { return m_members; }
const DynamicZoneLocation& GetCompassLocation() const { return m_compass; } const DynamicZoneLocation& GetCompassLocation() const { return m_compass; }
const DynamicZoneLocation& GetSafeReturnLocation() const { return m_safereturn; } const DynamicZoneLocation& GetSafeReturnLocation() const { return m_safereturn; }
@@ -133,34 +104,31 @@ public:
uint32_t GetDatabaseMemberCount(); uint32_t GetDatabaseMemberCount();
DynamicZoneMember GetMemberData(uint32_t character_id); DynamicZoneMember GetMemberData(uint32_t character_id);
DynamicZoneMember GetMemberData(const std::string& character_name); DynamicZoneMember GetMemberData(const std::string& character_name);
std::vector<uint32_t> GetMemberIds(); EQ::Net::DynamicPacket GetSerializedDzPacket();
std::ostringstream GetSerialized();
bool HasDatabaseMember(uint32_t character_id); bool HasDatabaseMember(uint32_t character_id);
bool HasMember(uint32_t character_id) const; bool HasMember(uint32_t character_id);
bool HasMember(const std::string& character_name) const; bool HasMember(const std::string& character_name);
bool HasMembers() const { return !m_members.empty(); } bool HasMembers() const { return !m_members.empty(); }
bool HasZoneInLocation() const { return m_has_zonein; } bool HasZoneInLocation() const { return m_has_zonein; }
bool IsExpedition() const { return m_type == DynamicZoneType::Expedition; }
bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); } bool IsExpired() const { return m_expire_time < std::chrono::system_clock::now(); }
bool IsInstanceID(uint32_t instance_id) const { return (m_instance_id != 0 && m_instance_id == instance_id); } bool IsInstanceID(uint32_t instance_id) const { return (m_instance_id != 0 && m_instance_id == instance_id); }
bool IsLocked() const { return m_is_locked; }
bool IsValid() const { return m_instance_id != 0; } bool IsValid() const { return m_instance_id != 0; }
bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; } bool IsSameDz(uint32_t zone_id, uint32_t instance_id) const { return zone_id == m_zone_id && instance_id == m_instance_id; }
void LoadSerializedDzPacket(char* cereal_data, uint32_t cereal_size);
void LoadTemplate(const DynamicZoneTemplatesRepository::DynamicZoneTemplates& dz_template); void LoadTemplate(const DynamicZoneTemplatesRepository::DynamicZoneTemplates& dz_template);
void RemoveAllMembers(); void RemoveAllMembers();
bool RemoveMember(uint32_t character_id); bool RemoveMember(uint32_t character_id);
bool RemoveMember(const std::string& character_name); bool RemoveMember(const std::string& character_name);
bool RemoveMember(const DynamicZoneMember& remove_member); bool RemoveMember(const DynamicZoneMember& remove_member);
void SaveMembers(const std::vector<DynamicZoneMember>& members);
void SetCompass(const DynamicZoneLocation& location, bool update_db = false); void SetCompass(const DynamicZoneLocation& location, bool update_db = false);
void SetCompass(uint32_t zone_id, float x, float y, float z, bool update_db = false); void SetCompass(uint32_t zone_id, float x, float y, float z, bool update_db = false);
void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); } void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
void SetLeader(const DynamicZoneMember& leader, bool update_db = false); void SetLeader(const DynamicZoneMember& leader, bool update_db = false);
void SetLocked(bool lock, bool update_db = false, DzLockMsg lock_msg = DzLockMsg::None, uint32_t color = Chat::Yellow);
void SetMaxPlayers(uint32_t max_players) { m_max_players = max_players; } void SetMaxPlayers(uint32_t max_players) { m_max_players = max_players; }
void SetMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status); void SetMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
void SetMinPlayers(uint32_t min_players) { m_min_players = min_players; } void SetMinPlayers(uint32_t min_players) { m_min_players = min_players; }
void SetName(const std::string& name) { m_name = name; } void SetName(const std::string& name) { m_name = name; }
void SetReplayOnJoin(bool enabled, bool update_db = false);
void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false); void SetSafeReturn(const DynamicZoneLocation& location, bool update_db = false);
void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false); void SetSafeReturn(uint32_t zone_id, float x, float y, float z, float heading, bool update_db = false);
void SetSwitchID(int dz_switch_id, bool update_db = false); void SetSwitchID(int dz_switch_id, bool update_db = false);
@@ -168,48 +136,34 @@ public:
void SetUUID(std::string uuid) { m_uuid = std::move(uuid); } void SetUUID(std::string uuid) { m_uuid = std::move(uuid); }
void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false); void SetZoneInLocation(const DynamicZoneLocation& location, bool update_db = false);
void SetZoneInLocation(float x, float y, float z, float heading, bool update_db = false); void SetZoneInLocation(float x, float y, float z, float heading, bool update_db = false);
bool SwapMember(const DynamicZoneMember& add_member, const std::string& remove_name); bool SwapMember(const DynamicZoneMember& add_member, const std::string& remove_char_name);
void AddLockout(const std::string& event, uint32_t seconds);
void AddLockoutDuration(const std::string& event, int seconds, bool members_only = true);
bool HasLockout(const std::string& event);
bool HasReplayLockout();
void RemoveLockout(const std::string& event);
void SyncCharacterLockouts(uint32_t char_id, std::vector<DzLockout>& lockouts);
void UpdateLockoutDuration(const std::string& event, uint32_t seconds, bool members_only = true);
protected: protected:
virtual uint16_t GetCurrentInstanceID() const { return 0; } virtual uint16_t GetCurrentInstanceID() { return 0; }
virtual uint16_t GetCurrentZoneID() const { return 0; } virtual uint16_t GetCurrentZoneID() { return 0; }
virtual Database& GetDatabase() = 0; virtual Database& GetDatabase() = 0;
virtual void HandleLockoutDuration(const DzLockout& lockout, int seconds, bool members_only, bool insert_db);
virtual void HandleLockoutUpdate(const DzLockout& lockout, bool remove, bool members_only);
virtual void ProcessCompassChange(const DynamicZoneLocation& location) { m_compass = location; } virtual void ProcessCompassChange(const DynamicZoneLocation& location) { m_compass = location; }
virtual void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed); virtual void ProcessMemberAddRemove(const DynamicZoneMember& member, bool removed);
virtual bool ProcessMemberStatusChange(uint32_t character_id, DynamicZoneMemberStatus status); virtual bool ProcessMemberStatusChange(uint32_t member_id, DynamicZoneMemberStatus status);
virtual void ProcessRemoveAllMembers() { m_members.clear(); } virtual void ProcessRemoveAllMembers(bool silent = false) { m_members.clear(); }
virtual void ProcessSetSwitchID(int dz_switch_id) { m_dz_switch_id = dz_switch_id; } virtual void ProcessSetSwitchID(int dz_switch_id) { m_dz_switch_id = dz_switch_id; }
virtual bool SendServerPacket(ServerPacket* packet) = 0; virtual bool SendServerPacket(ServerPacket* packet) = 0;
void AddLockout(const DzLockout& lockout, bool members_only = false);
void AddInternalMember(const DynamicZoneMember& member); void AddInternalMember(const DynamicZoneMember& member);
uint32_t Create(); uint32_t Create();
uint32_t CreateInstance(); uint32_t CreateInstance();
void LoadRepositoryResult(DynamicZonesRepository::DynamicZoneInstance&& dz_entry); void LoadRepositoryResult(DynamicZonesRepository::DynamicZoneInstance&& dz_entry);
void RemoveInternalMember(uint32_t character_id); void RemoveInternalMember(uint32_t character_id);
void SaveMembers(const std::vector<DynamicZoneMember>& members);
uint32_t SaveToDatabase(); uint32_t SaveToDatabase();
bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status); bool SetInternalMemberStatus(uint32_t character_id, DynamicZoneMemberStatus status);
std::unique_ptr<ServerPacket> CreateServerPacket(uint16_t zone_id, uint16_t instance_id); std::unique_ptr<ServerPacket> CreateServerDzCreatePacket(uint16_t origin_zone_id, uint16_t origin_instance_id);
std::unique_ptr<ServerPacket> CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location); std::unique_ptr<ServerPacket> CreateServerDzLocationPacket(uint16_t server_opcode, const DynamicZoneLocation& location);
std::unique_ptr<ServerPacket> CreateServerDzSwitchIDPacket(); std::unique_ptr<ServerPacket> CreateServerDzSwitchIDPacket();
std::unique_ptr<ServerPacket> CreateServerMemberAddRemovePacket(const DynamicZoneMember& member, bool removed); std::unique_ptr<ServerPacket> CreateServerMemberAddRemovePacket(const DynamicZoneMember& member, bool removed);
std::unique_ptr<ServerPacket> CreateServerMemberStatusPacket(uint32_t character_id, DynamicZoneMemberStatus status); std::unique_ptr<ServerPacket> CreateServerMemberStatusPacket(uint32_t character_id, DynamicZoneMemberStatus status);
std::unique_ptr<ServerPacket> CreateServerMemberSwapPacket(const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member); std::unique_ptr<ServerPacket> CreateServerMemberSwapPacket(const DynamicZoneMember& remove_member, const DynamicZoneMember& add_member);
std::unique_ptr<ServerPacket> CreateServerRemoveAllMembersPacket(); std::unique_ptr<ServerPacket> CreateServerRemoveAllMembersPacket();
std::unique_ptr<ServerPacket> CreateLockoutPacket(const DzLockout& lockout, bool remove, bool members_only = false) const;
std::unique_ptr<ServerPacket> CreateLockoutDurationPacket(const DzLockout& lockout, int seconds, bool members_only = false) const;
uint32_t m_id = 0; uint32_t m_id = 0;
uint32_t m_zone_id = 0; uint32_t m_zone_id = 0;
@@ -221,8 +175,6 @@ protected:
bool m_never_expires = false; bool m_never_expires = false;
bool m_has_zonein = false; bool m_has_zonein = false;
bool m_has_member_statuses = false; bool m_has_member_statuses = false;
bool m_is_locked = false;
bool m_add_replay = true;
std::string m_name; std::string m_name;
std::string m_uuid; std::string m_uuid;
DynamicZoneMember m_leader; DynamicZoneMember m_leader;
@@ -230,15 +182,12 @@ protected:
DynamicZoneLocation m_compass; DynamicZoneLocation m_compass;
DynamicZoneLocation m_safereturn; DynamicZoneLocation m_safereturn;
DynamicZoneLocation m_zonein; DynamicZoneLocation m_zonein;
std::chrono::seconds m_duration = {}; std::chrono::seconds m_duration;
std::chrono::time_point<std::chrono::system_clock> m_start_time; std::chrono::time_point<std::chrono::system_clock> m_start_time;
std::chrono::time_point<std::chrono::system_clock> m_expire_time; std::chrono::time_point<std::chrono::system_clock> m_expire_time;
std::vector<DynamicZoneMember> m_members; std::vector<DynamicZoneMember> m_members;
std::vector<DzLockout> m_lockouts;
public: public:
void Unserialize(std::span<char> buf);
template<class Archive> template<class Archive>
void serialize(Archive& archive) void serialize(Archive& archive)
{ {
@@ -253,8 +202,6 @@ public:
m_never_expires, m_never_expires,
m_has_zonein, m_has_zonein,
m_has_member_statuses, m_has_member_statuses,
m_is_locked,
m_add_replay,
m_name, m_name,
m_uuid, m_uuid,
m_leader, m_leader,
@@ -265,8 +212,7 @@ public:
m_duration, m_duration,
m_start_time, m_start_time,
m_expire_time, m_expire_time,
m_members, m_members
m_lockouts
); );
} }
}; };
-92
View File
@@ -1,92 +0,0 @@
#include "dynamic_zone_lockout.h"
#include "strings.h"
#include "rulesys.h"
#include "util/uuid.h"
#include <fmt/format.h>
#include <cereal/types/chrono.hpp>
DzLockout::DzLockout(std::string uuid, std::string expedition, std::string event, uint64_t expire_time, uint32_t duration)
: m_uuid(std::move(uuid))
, m_name(std::move(expedition))
, m_event(std::move(event))
, m_expire_time(std::chrono::system_clock::from_time_t(expire_time))
, m_duration(duration)
{
m_is_replay = m_event == ReplayTimer;
}
DzLockout::DzLockout(std::string_view name, BaseDynamicZoneLockoutsRepository::DynamicZoneLockouts&& lockout)
: m_uuid(std::move(lockout.from_expedition_uuid))
, m_name(name)
, m_event(std::move(lockout.event_name))
, m_expire_time(std::chrono::system_clock::from_time_t(lockout.expire_time))
, m_duration(lockout.duration)
{
m_is_replay = m_event == ReplayTimer;
}
DzLockout DzLockout::Create(const std::string& expedition, const std::string& event, uint32_t seconds, std::string uuid)
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
if (uuid.empty())
{
uuid = EQ::Util::UUID::Generate().ToString();
}
DzLockout lockout{uuid, expedition, event, 0, seconds};
lockout.Reset(); // sets expire time
return lockout;
}
uint32_t DzLockout::GetSecondsRemaining() const
{
auto now = std::chrono::system_clock::now();
if (m_expire_time > now)
{
auto remaining = m_expire_time - now;
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(remaining).count());
}
return 0;
}
DzLockout::TimeStrings DzLockout::GetTimeRemainingStrs() const
{
auto seconds = GetSecondsRemaining();
return DzLockout::TimeStrings{
fmt::format_int(seconds / 86400).str(), // days
fmt::format_int(seconds / 3600 % 24).str(), // hours
fmt::format_int(seconds / 60 % 60).str(), // minutes
fmt::format_int(seconds % 60).str() // seconds
};
}
bool DzLockout::IsSame(const DzLockout& other) const
{
return other.IsSame(m_name, m_event);
}
bool DzLockout::IsSame(const std::string& expedition, const std::string& event) const
{
return m_name == expedition && m_event == event;
}
void DzLockout::AddLockoutTime(int seconds)
{
seconds = static_cast<int>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
auto new_duration = std::max(0, static_cast<int>(m_duration.count()) + seconds);
auto start_time = m_expire_time - m_duration;
m_duration = std::chrono::seconds(new_duration);
m_expire_time = start_time + m_duration;
}
template <typename T>
void DzLockout::serialize(T& archive)
{
archive(m_is_replay, m_uuid, m_name, m_event, m_duration, m_expire_time);
}
template void DzLockout::serialize(cereal::BinaryOutputArchive&);
template void DzLockout::serialize(cereal::BinaryInputArchive&);
-56
View File
@@ -1,56 +0,0 @@
#pragma once
#include <chrono>
#include <string>
#include "repositories/base/base_dynamic_zone_lockouts_repository.h"
class DzLockout
{
public:
DzLockout() = default;
DzLockout(std::string uuid, std::string expedition, std::string event, uint64_t expire_time, uint32_t duration);
DzLockout(std::string_view name, BaseDynamicZoneLockoutsRepository::DynamicZoneLockouts&& lockout);
static constexpr char ReplayTimer[] = "Replay Timer";
static DzLockout Create(const std::string& expedition, const std::string& event, uint32_t seconds, std::string uuid = {});
struct TimeStrings
{
std::string days;
std::string hours;
std::string mins;
std::string secs;
};
void AddLockoutTime(int seconds);
uint32_t GetDuration() const { return static_cast<uint32_t>(m_duration.count()); }
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
uint64_t GetStartTime() const { return std::chrono::system_clock::to_time_t(m_expire_time - m_duration); }
uint32_t GetSecondsRemaining() const;
TimeStrings GetTimeRemainingStrs() const;
const std::string& DzName() const { return m_name; }
const std::string& Event() const { return m_event; }
const std::string& UUID() const { return m_uuid; }
bool IsEvent(std::string_view event) const { return m_event == event; }
bool IsExpired() const { return GetSecondsRemaining() == 0; }
bool IsReplay() const { return m_is_replay; }
bool IsSame(const DzLockout& other) const;
bool IsSame(const std::string& expedition, const std::string& event) const;
bool IsUUID(const std::string& uuid) const { return uuid == m_uuid; }
void Reset() { m_expire_time = std::chrono::system_clock::now() + m_duration; }
void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
void SetExpireTime(uint64_t expire_time) { m_expire_time = std::chrono::system_clock::from_time_t(expire_time); }
void SetUUID(const std::string& uuid) { m_uuid = uuid; }
template <typename T>
void serialize(T& archive);
private:
bool m_is_replay = false;
std::string m_uuid; // dz received in
std::string m_name;
std::string m_event;
std::chrono::seconds m_duration = {};
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
};
+23 -15
View File
@@ -140,6 +140,29 @@ std::string EQ::constants::GetLanguageName(uint8 language_id)
return EQ::constants::GetLanguageMap().find(language_id)->second; return EQ::constants::GetLanguageMap().find(language_id)->second;
} }
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
{
static const std::map<uint32, std::string> ldon_theme_map = {
{ LDoNThemes::Unused, "Unused" },
{ LDoNThemes::GUK, "Deepest Guk" },
{ LDoNThemes::MIR, "Miragul's Menagerie" },
{ LDoNThemes::MMC, "Mistmoore Catacombs" },
{ LDoNThemes::RUJ, "Rujarkian Hills" },
{ LDoNThemes::TAK, "Takish-Hiz" },
};
return ldon_theme_map;
}
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
{
if (!EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
return std::string();
}
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
}
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap() const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
{ {
static const std::map<int8, std::string> flymode_map = { static const std::map<int8, std::string> flymode_map = {
@@ -436,18 +459,3 @@ bool ComparisonType::IsValid(uint8 type)
{ {
return comparison_types.find(type) != comparison_types.end(); return comparison_types.find(type) != comparison_types.end();
} }
uint32 LDoNTheme::GetBitmask(uint32 theme_id)
{
return IsValid(theme_id) ? ldon_theme_names[theme_id].second : LDoNTheme::UnusedBit;
}
std::string LDoNTheme::GetName(uint32 theme_id)
{
return IsValid(theme_id) ? ldon_theme_names[theme_id].first : "UNKNOWN LDON THEME";
}
bool LDoNTheme::IsValid(uint32 theme_id)
{
return ldon_theme_names.find(theme_id) != ldon_theme_names.end();
}
+28 -58
View File
@@ -130,11 +130,9 @@ namespace EQ
using RoF2::invtype::MAIL_SIZE; using RoF2::invtype::MAIL_SIZE;
using RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE; using RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE;
using RoF2::invtype::KRONO_SIZE; using RoF2::invtype::KRONO_SIZE;
using RoF2::invtype::GUILD_BANK_MAIN_SIZE;
using RoF2::invtype::GUILD_BANK_DEPOSIT_SIZE;
using RoF2::invtype::OTHER_SIZE; using RoF2::invtype::OTHER_SIZE;
using RoF2::invtype::TRADE_NPC_SIZE; using Titanium::invtype::TRADE_NPC_SIZE;
using RoF2::invtype::TYPE_INVALID; using RoF2::invtype::TYPE_INVALID;
using RoF2::invtype::TYPE_BEGIN; using RoF2::invtype::TYPE_BEGIN;
@@ -161,7 +159,7 @@ namespace EQ
using RoF2::invslot::SLOT_INVALID; using RoF2::invslot::SLOT_INVALID;
using RoF2::invslot::SLOT_BEGIN; using RoF2::invslot::SLOT_BEGIN;
using RoF2::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE; using Titanium::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
const int16 SLOT_AUGMENT_GENERIC_RETURN = 1001; // clients don't appear to use this method... (internal inventory return value) const int16 SLOT_AUGMENT_GENERIC_RETURN = 1001; // clients don't appear to use this method... (internal inventory return value)
@@ -181,25 +179,25 @@ namespace EQ
using RoF2::invslot::BONUS_STAT_END; using RoF2::invslot::BONUS_STAT_END;
using RoF2::invslot::BONUS_SKILL_END; using RoF2::invslot::BONUS_SKILL_END;
using RoF2::invslot::BANK_BEGIN; using Titanium::invslot::BANK_BEGIN;
using RoF2::invslot::BANK_END; using SoF::invslot::BANK_END;
using RoF2::invslot::SHARED_BANK_BEGIN; using Titanium::invslot::SHARED_BANK_BEGIN;
using RoF2::invslot::SHARED_BANK_END; using Titanium::invslot::SHARED_BANK_END;
using RoF2::invslot::TRADE_BEGIN; using Titanium::invslot::TRADE_BEGIN;
using RoF2::invslot::TRADE_END; using Titanium::invslot::TRADE_END;
using RoF2::invslot::TRADE_NPC_END; using Titanium::invslot::TRADE_NPC_END;
using RoF2::invslot::WORLD_BEGIN; using Titanium::invslot::WORLD_BEGIN;
using RoF2::invslot::WORLD_END; using Titanium::invslot::WORLD_END;
using RoF2::invslot::TRIBUTE_BEGIN; using Titanium::invslot::TRIBUTE_BEGIN;
using RoF2::invslot::TRIBUTE_END; using Titanium::invslot::TRIBUTE_END;
using RoF2::invslot::GUILD_TRIBUTE_BEGIN; using Titanium::invslot::GUILD_TRIBUTE_BEGIN;
using RoF2::invslot::GUILD_TRIBUTE_END; using Titanium::invslot::GUILD_TRIBUTE_END;
const int16 CORPSE_BEGIN = invslot::slotGeneral1; const int16 CORPSE_BEGIN = invslot::slotGeneral1;
const int16 CORPSE_END = CORPSE_BEGIN + invslot::slotCursor; const int16 CORPSE_END = CORPSE_BEGIN + invslot::slotCursor;
@@ -216,40 +214,38 @@ namespace EQ
} // namespace invslot } // namespace invslot
namespace invbag { namespace invbag {
using RoF2::invbag::SLOT_INVALID; using Titanium::invbag::SLOT_INVALID;
using RoF2::invbag::SLOT_BEGIN; using Titanium::invbag::SLOT_BEGIN;
using RoF2::invbag::SLOT_END; using Titanium::invbag::SLOT_END;
using RoF2::invbag::SLOT_COUNT; using Titanium::invbag::SLOT_COUNT;
using RoF2::invslot::WORLD_END; using Titanium::invbag::GENERAL_BAGS_BEGIN;
const int16 GENERAL_BAGS_BEGIN = WORLD_END + 1;
const int16 GENERAL_BAGS_COUNT = invslot::GENERAL_COUNT * SLOT_COUNT; const int16 GENERAL_BAGS_COUNT = invslot::GENERAL_COUNT * SLOT_COUNT;
const int16 GENERAL_BAGS_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_COUNT) - 1; const int16 GENERAL_BAGS_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_COUNT) - 1;
const int16 GENERAL_BAGS_8_COUNT = 8 * SLOT_COUNT; const int16 GENERAL_BAGS_8_COUNT = 8 * SLOT_COUNT;
const int16 GENERAL_BAGS_8_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_8_COUNT) - 1; const int16 GENERAL_BAGS_8_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_8_COUNT) - 1;
const int16 CURSOR_BAG_BEGIN = GENERAL_BAGS_END + 1; const int16 CURSOR_BAG_BEGIN = 351;
const int16 CURSOR_BAG_COUNT = SLOT_COUNT; const int16 CURSOR_BAG_COUNT = SLOT_COUNT;
const int16 CURSOR_BAG_END = (CURSOR_BAG_BEGIN + CURSOR_BAG_COUNT) - 1; const int16 CURSOR_BAG_END = (CURSOR_BAG_BEGIN + CURSOR_BAG_COUNT) - 1;
const int16 BANK_BAGS_BEGIN = CURSOR_BAG_END + 1; using Titanium::invbag::BANK_BAGS_BEGIN;
const int16 BANK_BAGS_COUNT = (invtype::BANK_SIZE * SLOT_COUNT); const int16 BANK_BAGS_COUNT = (invtype::BANK_SIZE * SLOT_COUNT);
const int16 BANK_BAGS_END = (BANK_BAGS_BEGIN + BANK_BAGS_COUNT) - 1; const int16 BANK_BAGS_END = (BANK_BAGS_BEGIN + BANK_BAGS_COUNT) - 1;
const int16 BANK_BAGS_16_COUNT = 16 * SLOT_COUNT; const int16 BANK_BAGS_16_COUNT = 16 * SLOT_COUNT;
const int16 BANK_BAGS_16_END = (BANK_BAGS_BEGIN + BANK_BAGS_16_COUNT) - 1; const int16 BANK_BAGS_16_END = (BANK_BAGS_BEGIN + BANK_BAGS_16_COUNT) - 1;
const int16 SHARED_BANK_BAGS_BEGIN = BANK_BAGS_END + 1; using Titanium::invbag::SHARED_BANK_BAGS_BEGIN;
const int16 SHARED_BANK_BAGS_COUNT = invtype::SHARED_BANK_SIZE * SLOT_COUNT; const int16 SHARED_BANK_BAGS_COUNT = invtype::SHARED_BANK_SIZE * SLOT_COUNT;
const int16 SHARED_BANK_BAGS_END = (SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_COUNT) - 1; const int16 SHARED_BANK_BAGS_END = (SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_COUNT) - 1;
const int16 TRADE_BAGS_BEGIN = SHARED_BANK_BAGS_END + 1; using Titanium::invbag::TRADE_BAGS_BEGIN;
const int16 TRADE_BAGS_COUNT = invtype::TRADE_SIZE * SLOT_COUNT; const int16 TRADE_BAGS_COUNT = invtype::TRADE_SIZE * SLOT_COUNT;
const int16 TRADE_BAGS_END = (TRADE_BAGS_BEGIN + TRADE_BAGS_COUNT) - 1; const int16 TRADE_BAGS_END = (TRADE_BAGS_BEGIN + TRADE_BAGS_COUNT) - 1;
using RoF2::invbag::GetInvBagIndexName; using Titanium::invbag::GetInvBagIndexName;
} // namespace invbag } // namespace invbag
@@ -356,6 +352,9 @@ namespace EQ
extern const std::map<uint8, std::string>& GetLanguageMap(); extern const std::map<uint8, std::string>& GetLanguageMap();
std::string GetLanguageName(uint8 language_id); std::string GetLanguageName(uint8 language_id);
extern const std::map<uint32, std::string>& GetLDoNThemeMap();
std::string GetLDoNThemeName(uint32 theme_id);
extern const std::map<int8, std::string>& GetFlyModeMap(); extern const std::map<int8, std::string>& GetFlyModeMap();
std::string GetFlyModeName(int8 flymode_id); std::string GetFlyModeName(int8 flymode_id);
@@ -752,35 +751,6 @@ static std::map<uint32, std::string> stance_names = {
{ Stance::AEBurn, "AE Burn" } { Stance::AEBurn, "AE Burn" }
}; };
namespace LDoNTheme {
constexpr uint32 Unused = 0;
constexpr uint32 GUK = 1;
constexpr uint32 MIR = 2;
constexpr uint32 MMC = 3;
constexpr uint32 RUJ = 4;
constexpr uint32 TAK = 5;
constexpr uint32 UnusedBit = 0;
constexpr uint32 GUKBit = 1;
constexpr uint32 MIRBit = 2;
constexpr uint32 MMCBit = 4;
constexpr uint32 RUJBit = 8;
constexpr uint32 TAKBit = 16;
uint32 GetBitmask(uint32 theme_id);
std::string GetName(uint32 theme_id);
bool IsValid(uint32 theme_id);
}
static std::map<uint32, std::pair<std::string, uint32>> ldon_theme_names = {
{ LDoNTheme::Unused, { "Unused", LDoNTheme::UnusedBit }, },
{ LDoNTheme::GUK, { "Deepest Guk", LDoNTheme::GUKBit }, },
{ LDoNTheme::MIR, { "Miragul's Menagerie", LDoNTheme::MIRBit }, },
{ LDoNTheme::MMC, { "Mistmoore Catacombs", LDoNTheme::MMCBit }, },
{ LDoNTheme::RUJ, { "Rujarkian Hills", LDoNTheme::RUJBit }, },
{ LDoNTheme::TAK, { "Takish-Hiz", LDoNTheme::TAKBit }, },
};
namespace PCNPCOnlyFlagType { namespace PCNPCOnlyFlagType {
constexpr int PC = 1; constexpr int PC = 1;
constexpr int NPC = 2; constexpr int NPC = 2;
-10
View File
@@ -77,7 +77,6 @@ N(OP_CashReward),
N(OP_CastSpell), N(OP_CastSpell),
N(OP_ChangeSize), N(OP_ChangeSize),
N(OP_ChannelMessage), N(OP_ChannelMessage),
N(OP_ChangePetName),
N(OP_CharacterCreate), N(OP_CharacterCreate),
N(OP_CharacterCreateRequest), N(OP_CharacterCreateRequest),
N(OP_CharInventory), N(OP_CharInventory),
@@ -163,7 +162,6 @@ N(OP_EnduranceUpdate),
N(OP_EnterChat), N(OP_EnterChat),
N(OP_EnterWorld), N(OP_EnterWorld),
N(OP_EnvDamage), N(OP_EnvDamage),
N(OP_EvolveItem),
N(OP_ExpansionInfo), N(OP_ExpansionInfo),
N(OP_ExpUpdate), N(OP_ExpUpdate),
N(OP_FaceChange), N(OP_FaceChange),
@@ -285,17 +283,12 @@ N(OP_InspectMessageUpdate),
N(OP_InspectRequest), N(OP_InspectRequest),
N(OP_InstillDoubt), N(OP_InstillDoubt),
N(OP_InterruptCast), N(OP_InterruptCast),
N(OP_InvokeChangePetName),
N(OP_InvokeChangePetNameImmediate),
N(OP_InvokeNameChangeImmediate),
N(OP_InvokeNameChangeLazy),
N(OP_ItemLinkClick), N(OP_ItemLinkClick),
N(OP_ItemLinkResponse), N(OP_ItemLinkResponse),
N(OP_ItemLinkText), N(OP_ItemLinkText),
N(OP_ItemName), N(OP_ItemName),
N(OP_ItemPacket), N(OP_ItemPacket),
N(OP_ItemPreview), N(OP_ItemPreview),
N(OP_ItemPreviewRequest),
N(OP_ItemRecastDelay), N(OP_ItemRecastDelay),
N(OP_ItemVerifyReply), N(OP_ItemVerifyReply),
N(OP_ItemVerifyRequest), N(OP_ItemVerifyRequest),
@@ -407,8 +400,6 @@ N(OP_PetitionSearchText),
N(OP_PetitionUnCheckout), N(OP_PetitionUnCheckout),
N(OP_PetitionUpdate), N(OP_PetitionUpdate),
N(OP_PickPocket), N(OP_PickPocket),
N(OP_PickZone),
N(OP_PickZoneWindow),
N(OP_PlayerProfile), N(OP_PlayerProfile),
N(OP_PlayerStateAdd), N(OP_PlayerStateAdd),
N(OP_PlayerStateRemove), N(OP_PlayerStateRemove),
@@ -576,7 +567,6 @@ N(OP_TradeRequestAck),
N(OP_TraderItemUpdate), N(OP_TraderItemUpdate),
N(OP_TraderShop), N(OP_TraderShop),
N(OP_TradeSkillCombine), N(OP_TradeSkillCombine),
N(OP_TradeSkillRecipeInspect),
N(OP_Translocate), N(OP_Translocate),
N(OP_TributeInfo), N(OP_TributeInfo),
N(OP_TributeItem), N(OP_TributeItem),
+38 -3
View File
@@ -974,6 +974,43 @@ namespace ZoneBlockedSpellTypes {
const uint8 Region = 2; const uint8 Region = 2;
}; };
enum class DynamicZoneType
{
None = 0,
Expedition,
Tutorial,
Task,
Mission, // Shared Task
Quest
};
enum class DynamicZoneMemberStatus : uint8_t
{
Unknown = 0,
Online,
Offline,
InDynamicZone,
LinkDead
};
enum LDoNThemes {
Unused = 0,
GUK,
MIR,
MMC,
RUJ,
TAK
};
enum LDoNThemeBits {
UnusedBit = 0,
GUKBit = 1,
MIRBit = 2,
MMCBit = 4,
RUJBit = 8,
TAKBit = 16
};
enum StartZoneIndex { enum StartZoneIndex {
Odus = 0, Odus = 0,
Qeynos, Qeynos,
@@ -988,8 +1025,7 @@ enum StartZoneIndex {
Felwithe, Felwithe,
Akanon, Akanon,
Cabilis, Cabilis,
SharVahl, SharVahl
RatheMtn
}; };
enum FVNoDropFlagRule enum FVNoDropFlagRule
@@ -1096,5 +1132,4 @@ enum ExpSource
namespace DoorType { namespace DoorType {
constexpr uint32 BuyerStall = 155; constexpr uint32 BuyerStall = 155;
} }
#endif /*COMMON_EQ_CONSTANTS_H*/ #endif /*COMMON_EQ_CONSTANTS_H*/
+28 -36
View File
@@ -47,7 +47,6 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
ClientUnknown::constants::EXPANSION_BIT, ClientUnknown::constants::EXPANSION_BIT,
ClientUnknown::constants::EXPANSIONS_MASK, ClientUnknown::constants::EXPANSIONS_MASK,
ClientUnknown::INULL, ClientUnknown::INULL,
ClientUnknown::INULL,
ClientUnknown::INULL ClientUnknown::INULL
), ),
/*[ClientVersion::Client62] =*/ /*[ClientVersion::Client62] =*/
@@ -56,7 +55,6 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
Client62::constants::EXPANSION_BIT, Client62::constants::EXPANSION_BIT,
Client62::constants::EXPANSIONS_MASK, Client62::constants::EXPANSIONS_MASK,
Client62::INULL, Client62::INULL,
Client62::INULL,
Client62::INULL Client62::INULL
), ),
/*[ClientVersion::Titanium] =*/ /*[ClientVersion::Titanium] =*/
@@ -65,8 +63,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
Titanium::constants::EXPANSION_BIT, Titanium::constants::EXPANSION_BIT,
Titanium::constants::EXPANSIONS_MASK, Titanium::constants::EXPANSIONS_MASK,
Titanium::constants::CHARACTER_CREATION_LIMIT, Titanium::constants::CHARACTER_CREATION_LIMIT,
Titanium::constants::SAY_LINK_BODY_SIZE, Titanium::constants::SAY_LINK_BODY_SIZE
Titanium::INULL
), ),
/*[ClientVersion::SoF] =*/ /*[ClientVersion::SoF] =*/
EQ::constants::LookupEntry( EQ::constants::LookupEntry(
@@ -74,8 +71,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
SoF::constants::EXPANSION_BIT, SoF::constants::EXPANSION_BIT,
SoF::constants::EXPANSIONS_MASK, SoF::constants::EXPANSIONS_MASK,
SoF::constants::CHARACTER_CREATION_LIMIT, SoF::constants::CHARACTER_CREATION_LIMIT,
SoF::constants::SAY_LINK_BODY_SIZE, SoF::constants::SAY_LINK_BODY_SIZE
SoF::INULL
), ),
/*[ClientVersion::SoD] =*/ /*[ClientVersion::SoD] =*/
EQ::constants::LookupEntry( EQ::constants::LookupEntry(
@@ -83,8 +79,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
SoD::constants::EXPANSION_BIT, SoD::constants::EXPANSION_BIT,
SoD::constants::EXPANSIONS_MASK, SoD::constants::EXPANSIONS_MASK,
SoD::constants::CHARACTER_CREATION_LIMIT, SoD::constants::CHARACTER_CREATION_LIMIT,
SoD::constants::SAY_LINK_BODY_SIZE, SoD::constants::SAY_LINK_BODY_SIZE
SoD::INULL
), ),
/*[ClientVersion::UF] =*/ /*[ClientVersion::UF] =*/
EQ::constants::LookupEntry( EQ::constants::LookupEntry(
@@ -92,8 +87,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
UF::constants::EXPANSION_BIT, UF::constants::EXPANSION_BIT,
UF::constants::EXPANSIONS_MASK, UF::constants::EXPANSIONS_MASK,
UF::constants::CHARACTER_CREATION_LIMIT, UF::constants::CHARACTER_CREATION_LIMIT,
UF::constants::SAY_LINK_BODY_SIZE, UF::constants::SAY_LINK_BODY_SIZE
UF::INULL
), ),
/*[ClientVersion::RoF] =*/ /*[ClientVersion::RoF] =*/
EQ::constants::LookupEntry( EQ::constants::LookupEntry(
@@ -101,8 +95,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
RoF::constants::EXPANSION_BIT, RoF::constants::EXPANSION_BIT,
RoF::constants::EXPANSIONS_MASK, RoF::constants::EXPANSIONS_MASK,
RoF::constants::CHARACTER_CREATION_LIMIT, RoF::constants::CHARACTER_CREATION_LIMIT,
RoF::constants::SAY_LINK_BODY_SIZE, RoF::constants::SAY_LINK_BODY_SIZE
RoF::INULL
), ),
/*[ClientVersion::RoF2] =*/ /*[ClientVersion::RoF2] =*/
EQ::constants::LookupEntry( EQ::constants::LookupEntry(
@@ -110,8 +103,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
RoF2::constants::EXPANSION_BIT, RoF2::constants::EXPANSION_BIT,
RoF2::constants::EXPANSIONS_MASK, RoF2::constants::EXPANSIONS_MASK,
RoF2::constants::CHARACTER_CREATION_LIMIT, RoF2::constants::CHARACTER_CREATION_LIMIT,
RoF2::constants::SAY_LINK_BODY_SIZE, RoF2::constants::SAY_LINK_BODY_SIZE
RoF2::constants::MAX_BAZAAR_TRADERS
) )
}; };
@@ -173,7 +165,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL,
ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL,
ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL,
ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL ClientUnknown::INULL
), ),
ClientUnknown::INULL, ClientUnknown::INULL,
@@ -200,7 +192,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL,
Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL,
Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL,
Client62::INULL, Client62::INULL, Client62::INULL Client62::INULL
), ),
Client62::INULL, Client62::INULL,
@@ -227,7 +219,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
Titanium::invtype::VIEW_MOD_PC_SIZE, Titanium::invtype::VIEW_MOD_BANK_SIZE, Titanium::invtype::VIEW_MOD_SHARED_BANK_SIZE, Titanium::invtype::VIEW_MOD_PC_SIZE, Titanium::invtype::VIEW_MOD_BANK_SIZE, Titanium::invtype::VIEW_MOD_SHARED_BANK_SIZE,
Titanium::invtype::VIEW_MOD_LIMBO_SIZE, Titanium::invtype::ALT_STORAGE_SIZE, Titanium::invtype::ARCHIVED_SIZE, Titanium::invtype::VIEW_MOD_LIMBO_SIZE, Titanium::invtype::ALT_STORAGE_SIZE, Titanium::invtype::ARCHIVED_SIZE,
Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL,
Titanium::INULL, Titanium::INULL, Titanium::invtype::OTHER_SIZE Titanium::invtype::OTHER_SIZE
), ),
Titanium::invslot::EQUIPMENT_BITMASK, Titanium::invslot::EQUIPMENT_BITMASK,
@@ -254,7 +246,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
SoF::invtype::VIEW_MOD_PC_SIZE, SoF::invtype::VIEW_MOD_BANK_SIZE, SoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoF::invtype::VIEW_MOD_PC_SIZE, SoF::invtype::VIEW_MOD_BANK_SIZE, SoF::invtype::VIEW_MOD_SHARED_BANK_SIZE,
SoF::invtype::VIEW_MOD_LIMBO_SIZE, SoF::invtype::ALT_STORAGE_SIZE, SoF::invtype::ARCHIVED_SIZE, SoF::invtype::VIEW_MOD_LIMBO_SIZE, SoF::invtype::ALT_STORAGE_SIZE, SoF::invtype::ARCHIVED_SIZE,
SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL,
SoF::INULL, SoF::INULL, SoF::invtype::OTHER_SIZE SoF::invtype::OTHER_SIZE
), ),
SoF::invslot::EQUIPMENT_BITMASK, SoF::invslot::EQUIPMENT_BITMASK,
@@ -281,7 +273,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
SoD::invtype::VIEW_MOD_PC_SIZE, SoD::invtype::VIEW_MOD_BANK_SIZE, SoD::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoD::invtype::VIEW_MOD_PC_SIZE, SoD::invtype::VIEW_MOD_BANK_SIZE, SoD::invtype::VIEW_MOD_SHARED_BANK_SIZE,
SoD::invtype::VIEW_MOD_LIMBO_SIZE, SoD::invtype::ALT_STORAGE_SIZE, SoD::invtype::ARCHIVED_SIZE, SoD::invtype::VIEW_MOD_LIMBO_SIZE, SoD::invtype::ALT_STORAGE_SIZE, SoD::invtype::ARCHIVED_SIZE,
SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL,
SoD::INULL, SoD::INULL, SoD::invtype::OTHER_SIZE SoD::invtype::OTHER_SIZE
), ),
SoD::invslot::EQUIPMENT_BITMASK, SoD::invslot::EQUIPMENT_BITMASK,
@@ -308,7 +300,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
UF::invtype::VIEW_MOD_PC_SIZE, UF::invtype::VIEW_MOD_BANK_SIZE, UF::invtype::VIEW_MOD_SHARED_BANK_SIZE, UF::invtype::VIEW_MOD_PC_SIZE, UF::invtype::VIEW_MOD_BANK_SIZE, UF::invtype::VIEW_MOD_SHARED_BANK_SIZE,
UF::invtype::VIEW_MOD_LIMBO_SIZE, UF::invtype::ALT_STORAGE_SIZE, UF::invtype::ARCHIVED_SIZE, UF::invtype::VIEW_MOD_LIMBO_SIZE, UF::invtype::ALT_STORAGE_SIZE, UF::invtype::ARCHIVED_SIZE,
UF::INULL, UF::INULL, UF::INULL, UF::INULL, UF::INULL, UF::INULL,
UF::INULL, UF::INULL, UF::invtype::OTHER_SIZE UF::invtype::OTHER_SIZE
), ),
UF::invslot::EQUIPMENT_BITMASK, UF::invslot::EQUIPMENT_BITMASK,
@@ -335,7 +327,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
RoF::invtype::VIEW_MOD_PC_SIZE, RoF::invtype::VIEW_MOD_BANK_SIZE, RoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF::invtype::VIEW_MOD_PC_SIZE, RoF::invtype::VIEW_MOD_BANK_SIZE, RoF::invtype::VIEW_MOD_SHARED_BANK_SIZE,
RoF::invtype::VIEW_MOD_LIMBO_SIZE, RoF::invtype::ALT_STORAGE_SIZE, RoF::invtype::ARCHIVED_SIZE, RoF::invtype::VIEW_MOD_LIMBO_SIZE, RoF::invtype::ALT_STORAGE_SIZE, RoF::invtype::ARCHIVED_SIZE,
RoF::invtype::MAIL_SIZE, RoF::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF::INULL, RoF::invtype::MAIL_SIZE, RoF::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF::INULL,
RoF::INULL,RoF::INULL,RoF::invtype::OTHER_SIZE RoF::invtype::OTHER_SIZE
), ),
RoF::invslot::EQUIPMENT_BITMASK, RoF::invslot::EQUIPMENT_BITMASK,
@@ -362,7 +354,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE,
RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::invtype::ALT_STORAGE_SIZE, RoF2::invtype::ARCHIVED_SIZE, RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::invtype::ALT_STORAGE_SIZE, RoF2::invtype::ARCHIVED_SIZE,
RoF2::invtype::MAIL_SIZE, RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF2::invtype::KRONO_SIZE, RoF2::invtype::MAIL_SIZE, RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF2::invtype::KRONO_SIZE,
RoF2::invtype::GUILD_BANK_MAIN_SIZE,RoF2::invtype::GUILD_BANK_DEPOSIT_SIZE, RoF2::invtype::OTHER_SIZE RoF2::invtype::OTHER_SIZE
), ),
RoF2::invslot::EQUIPMENT_BITMASK, RoF2::invslot::EQUIPMENT_BITMASK,
@@ -389,7 +381,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL,
EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL,
EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL, EntityLimits::NPC::INULL,
EntityLimits::NPC::INULL, EntityLimits::NPC::INULL,EntityLimits::NPC::INULL EntityLimits::NPC::INULL
), ),
EntityLimits::NPC::INULL, EntityLimits::NPC::INULL,
@@ -416,7 +408,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL,
EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL,
EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL,
EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL EntityLimits::NPCMerchant::INULL
), ),
EntityLimits::NPCMerchant::INULL, EntityLimits::NPCMerchant::INULL,
@@ -443,7 +435,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL,
EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL,
EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL,
EntityLimits::Merc::INULL, EntityLimits::Merc::INULL, EntityLimits::Merc::INULL EntityLimits::Merc::INULL
), ),
EntityLimits::Merc::INULL, EntityLimits::Merc::INULL,
@@ -470,7 +462,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL,
EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL,
EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL,
EntityLimits::Bot::INULL, EntityLimits::Bot::INULL, EntityLimits::Bot::INULL EntityLimits::Bot::INULL
), ),
EntityLimits::Bot::invslot::EQUIPMENT_BITMASK, EntityLimits::Bot::invslot::EQUIPMENT_BITMASK,
@@ -497,7 +489,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL,
EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL,
EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL,
EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL EntityLimits::ClientPet::INULL
), ),
EntityLimits::ClientPet::INULL, EntityLimits::ClientPet::INULL,
@@ -524,7 +516,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL,
EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL,
EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL,
EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL EntityLimits::NPCPet::INULL
), ),
EntityLimits::NPCPet::INULL, EntityLimits::NPCPet::INULL,
@@ -551,7 +543,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL,
EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL,
EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL,
EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL EntityLimits::MercPet::INULL
), ),
EntityLimits::MercPet::INULL, EntityLimits::MercPet::INULL,
@@ -578,7 +570,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL,
EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL,
EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL,
EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL EntityLimits::BotPet::INULL
), ),
EntityLimits::BotPet::INULL, EntityLimits::BotPet::INULL,
@@ -605,7 +597,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
Titanium::invtype::VIEW_MOD_PC_SIZE, Titanium::invtype::VIEW_MOD_BANK_SIZE, Titanium::invtype::VIEW_MOD_SHARED_BANK_SIZE, Titanium::invtype::VIEW_MOD_PC_SIZE, Titanium::invtype::VIEW_MOD_BANK_SIZE, Titanium::invtype::VIEW_MOD_SHARED_BANK_SIZE,
Titanium::invtype::VIEW_MOD_LIMBO_SIZE, Titanium::INULL, Titanium::INULL, Titanium::invtype::VIEW_MOD_LIMBO_SIZE, Titanium::INULL, Titanium::INULL,
Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::INULL,
Titanium::INULL, Titanium::INULL, Titanium::INULL Titanium::INULL
), ),
Titanium::INULL, Titanium::INULL,
@@ -632,7 +624,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
SoF::invtype::VIEW_MOD_PC_SIZE, SoF::invtype::VIEW_MOD_BANK_SIZE, SoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoF::invtype::VIEW_MOD_PC_SIZE, SoF::invtype::VIEW_MOD_BANK_SIZE, SoF::invtype::VIEW_MOD_SHARED_BANK_SIZE,
SoF::invtype::VIEW_MOD_LIMBO_SIZE, SoF::INULL, SoF::INULL, SoF::invtype::VIEW_MOD_LIMBO_SIZE, SoF::INULL, SoF::INULL,
SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL, SoF::INULL,
SoF::INULL, SoF::INULL, SoF::INULL SoF::INULL
), ),
SoF::INULL, SoF::INULL,
@@ -659,7 +651,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
SoD::invtype::VIEW_MOD_PC_SIZE, SoD::invtype::VIEW_MOD_BANK_SIZE, SoD::invtype::VIEW_MOD_SHARED_BANK_SIZE, SoD::invtype::VIEW_MOD_PC_SIZE, SoD::invtype::VIEW_MOD_BANK_SIZE, SoD::invtype::VIEW_MOD_SHARED_BANK_SIZE,
SoD::invtype::VIEW_MOD_LIMBO_SIZE, SoD::INULL, SoD::INULL, SoD::invtype::VIEW_MOD_LIMBO_SIZE, SoD::INULL, SoD::INULL,
SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL, SoD::INULL,
SoD::INULL, SoD::INULL, SoD::INULL SoD::INULL
), ),
SoD::INULL, SoD::INULL,
@@ -686,7 +678,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
UF::invtype::VIEW_MOD_PC_SIZE, UF::invtype::VIEW_MOD_BANK_SIZE, UF::invtype::VIEW_MOD_SHARED_BANK_SIZE, UF::invtype::VIEW_MOD_PC_SIZE, UF::invtype::VIEW_MOD_BANK_SIZE, UF::invtype::VIEW_MOD_SHARED_BANK_SIZE,
UF::invtype::VIEW_MOD_LIMBO_SIZE, UF::INULL, UF::INULL, UF::invtype::VIEW_MOD_LIMBO_SIZE, UF::INULL, UF::INULL,
UF::INULL, UF::INULL, UF::INULL, UF::INULL, UF::INULL, UF::INULL,
UF::INULL, UF::INULL, UF::INULL UF::INULL
), ),
UF::INULL, UF::INULL,
@@ -713,7 +705,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
RoF::invtype::VIEW_MOD_PC_SIZE, RoF::invtype::VIEW_MOD_BANK_SIZE, RoF::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF::invtype::VIEW_MOD_PC_SIZE, RoF::invtype::VIEW_MOD_BANK_SIZE, RoF::invtype::VIEW_MOD_SHARED_BANK_SIZE,
RoF::invtype::VIEW_MOD_LIMBO_SIZE, RoF::INULL, RoF::INULL, RoF::invtype::VIEW_MOD_LIMBO_SIZE, RoF::INULL, RoF::INULL,
RoF::INULL, RoF::INULL, RoF::INULL, RoF::INULL, RoF::INULL, RoF::INULL,
RoF::INULL, RoF::INULL, RoF::INULL RoF::INULL
), ),
RoF::INULL, RoF::INULL,
@@ -740,7 +732,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE, RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE,
RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::INULL, RoF2::INULL, RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::INULL, RoF2::INULL,
RoF2::INULL, RoF2::INULL, RoF2::INULL, RoF2::INULL, RoF2::INULL, RoF2::INULL,
RoF2::INULL, RoF2::INULL, RoF2::INULL RoF2::INULL
), ),
RoF2::INULL, RoF2::INULL,
+5 -8
View File
@@ -42,7 +42,6 @@ namespace EQ
uint32 ExpansionsMask; uint32 ExpansionsMask;
int16 CharacterCreationLimit; int16 CharacterCreationLimit;
size_t SayLinkBodySize; size_t SayLinkBodySize;
uint32 BazaarTraderLimit;
LookupEntry(const LookupEntry *lookup_entry) { } LookupEntry(const LookupEntry *lookup_entry) { }
LookupEntry( LookupEntry(
@@ -50,15 +49,13 @@ namespace EQ
uint32 ExpansionBit, uint32 ExpansionBit,
uint32 ExpansionsMask, uint32 ExpansionsMask,
int16 CharacterCreationLimit, int16 CharacterCreationLimit,
size_t SayLinkBodySize, size_t SayLinkBodySize
uint32 BazaarTraderLimit
) : ) :
Expansion(Expansion), Expansion(Expansion),
ExpansionBit(ExpansionBit), ExpansionBit(ExpansionBit),
ExpansionsMask(ExpansionsMask), ExpansionsMask(ExpansionsMask),
CharacterCreationLimit(CharacterCreationLimit), CharacterCreationLimit(CharacterCreationLimit),
SayLinkBodySize(SayLinkBodySize), SayLinkBodySize(SayLinkBodySize)
BazaarTraderLimit(BazaarTraderLimit)
{ } { }
}; };
@@ -87,7 +84,7 @@ namespace EQ
int16 ViewMODPC, ViewMODBank, ViewMODSharedBank; int16 ViewMODPC, ViewMODBank, ViewMODSharedBank;
int16 ViewMODLimbo, AltStorage, Archived; int16 ViewMODLimbo, AltStorage, Archived;
int16 Mail, GuildTrophyTribute, Krono; int16 Mail, GuildTrophyTribute, Krono;
int16 GuildBankMain,GuildBankDeposit, Other; int16 Other;
InventoryTypeSize_Struct( InventoryTypeSize_Struct(
int16 Possessions, int16 Bank, int16 SharedBank, int16 Possessions, int16 Bank, int16 SharedBank,
@@ -98,7 +95,7 @@ namespace EQ
int16 ViewMODPC, int16 ViewMODBank, int16 ViewMODSharedBank, int16 ViewMODPC, int16 ViewMODBank, int16 ViewMODSharedBank,
int16 ViewMODLimbo, int16 AltStorage, int16 Archived, int16 ViewMODLimbo, int16 AltStorage, int16 Archived,
int16 Mail, int16 GuildTrophyTribute, int16 Krono, int16 Mail, int16 GuildTrophyTribute, int16 Krono,
int16 GuildBankMain,int16 GuildBankDeposit, int16 Other int16 Other
) : ) :
Possessions(Possessions), Bank(Bank), SharedBank(SharedBank), Possessions(Possessions), Bank(Bank), SharedBank(SharedBank),
Trade(Trade), World(World), Limbo(Limbo), Trade(Trade), World(World), Limbo(Limbo),
@@ -108,7 +105,7 @@ namespace EQ
ViewMODPC(ViewMODPC), ViewMODBank(ViewMODBank), ViewMODSharedBank(ViewMODSharedBank), ViewMODPC(ViewMODPC), ViewMODBank(ViewMODBank), ViewMODSharedBank(ViewMODSharedBank),
ViewMODLimbo(ViewMODLimbo), AltStorage(AltStorage), Archived(Archived), ViewMODLimbo(ViewMODLimbo), AltStorage(AltStorage), Archived(Archived),
Mail(Mail), GuildTrophyTribute(GuildTrophyTribute), Krono(Krono), Mail(Mail), GuildTrophyTribute(GuildTrophyTribute), Krono(Krono),
GuildBankMain(GuildBankMain), GuildBankDeposit(GuildBankDeposit), Other(Other) Other(Other)
{ } { }
}; };
+40 -166
View File
@@ -19,17 +19,17 @@
#ifndef EQ_PACKET_STRUCTS_H #ifndef EQ_PACKET_STRUCTS_H
#define EQ_PACKET_STRUCTS_H #define EQ_PACKET_STRUCTS_H
#include <list> #include "types.h"
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <list>
#include <time.h> #include <time.h>
#include "../cereal/include/cereal/archives/binary.hpp"
#include "../cereal/include/cereal/types/string.hpp"
#include "../cereal/include/cereal/types/vector.hpp"
#include "../common/version.h" #include "../common/version.h"
#include "emu_constants.h" #include "emu_constants.h"
#include "textures.h" #include "textures.h"
#include "types.h" #include "../cereal/include/cereal/archives/binary.hpp"
#include "../cereal/include/cereal/types/string.hpp"
#include "../cereal/include/cereal/types/vector.hpp"
static const uint32 BUFF_COUNT = 42; static const uint32 BUFF_COUNT = 42;
static const uint32 PET_BUFF_COUNT = 30; static const uint32 PET_BUFF_COUNT = 30;
@@ -47,7 +47,7 @@ static const uint32 ADVANCED_LORE_LENGTH = 8192;
*/ */
#pragma pack(1) #pragma pack(1)
struct LoginInfo { struct LoginInfo_Struct {
/*000*/ char login_info[64]; /*000*/ char login_info[64];
/*064*/ uint8 unknown064[124]; /*064*/ uint8 unknown064[124];
/*188*/ uint8 zoning; // 01 if zoning, 00 if not /*188*/ uint8 zoning; // 01 if zoning, 00 if not
@@ -324,8 +324,6 @@ union
bool guild_show; bool guild_show;
bool trader; bool trader;
bool buyer; bool buyer;
bool untargetable;
uint32 npc_tint_id;
}; };
struct PlayerState_Struct { struct PlayerState_Struct {
@@ -3223,7 +3221,6 @@ struct BuyerMessaging_Struct {
char item_name[64]; char item_name[64];
uint32 slot; uint32 slot;
uint32 seller_quantity; uint32 seller_quantity;
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
}; };
struct BuyerAddBuyertoBarterWindow_Struct { struct BuyerAddBuyertoBarterWindow_Struct {
@@ -3744,8 +3741,7 @@ struct GetItems_Struct{
struct BecomeTrader_Struct { struct BecomeTrader_Struct {
uint32 action; uint32 action;
uint16 zone_id; uint32 zone_id;
uint16 zone_instance_id;
uint32 trader_id; uint32 trader_id;
uint32 entity_id; uint32 entity_id;
char trader_name[64]; char trader_name[64];
@@ -4285,10 +4281,6 @@ struct NewCombine_Struct {
/*04*/ /*04*/
}; };
struct TradeSkillRecipeInspect_Struct {
uint32 recipe_id;
uint32 padding[17]; // unknown
};
//client requesting favorite recipies //client requesting favorite recipies
struct TradeskillFavorites_Struct { struct TradeskillFavorites_Struct {
@@ -5531,55 +5523,46 @@ struct GuildBankWithdrawItem_Struct
struct GuildBankItemUpdate_Struct struct GuildBankItemUpdate_Struct
{ {
void Init( void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity,
uint32 inAction, uint32 inPermissions, uint32 inAllowMerge, bool inUseable)
uint32 inUnknown004,
uint16 inSlotID,
uint16 inArea,
uint16 inUnknown012,
uint32 inItemID,
uint32 inIcon,
uint32 inQuantity,
uint32 inPermissions,
uint32 inAllowMerge,
bool inUseable)
{ {
action = inAction; Action = inAction;
unknown004 = inUnknown004; Unknown004 = inUnknown004;
slot_id = inSlotID; SlotID = inSlotID;
area = inArea; Area = inArea;
display = inUnknown012; Unknown012 = inUnknown012;
item_id = inItemID; ItemID = inItemID;
icon_id = inIcon; Icon = inIcon;
quantity = inQuantity; Quantity = inQuantity;
permissions = inPermissions; Permissions = inPermissions;
allow_merge = inAllowMerge; AllowMerge = inAllowMerge;
is_useable = inUseable; Useable = inUseable;
item_name[0] = '\0'; ItemName[0] = '\0';
donator[0] = '\0'; Donator[0] = '\0';
who_for[0] = '\0'; WhoFor[0] = '\0';
}; };
/*000*/ uint32 action; /*000*/ uint32 Action;
/*004*/ uint32 unknown004; /*004*/ uint32 Unknown004;
/*008*/ uint16 slot_id; /*008*/ uint16 SlotID;
/*010*/ uint16 area; /*010*/ uint16 Area;
/*012*/ uint32 display; /*012*/ uint32 Unknown012;
/*016*/ uint32 item_id; /*016*/ uint32 ItemID;
/*020*/ uint32 icon_id; /*020*/ uint32 Icon;
/*024*/ uint32 quantity; /*024*/ uint32 Quantity;
/*028*/ uint32 permissions; /*028*/ uint32 Permissions;
/*032*/ uint8 allow_merge; /*032*/ uint8 AllowMerge;
/*033*/ uint8 is_useable; // Used in conjunction with the Public-if-useable permission. /*033*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission.
/*034*/ char item_name[64]; /*034*/ char ItemName[64];
/*098*/ char donator[64]; /*098*/ char Donator[64];
/*162*/ char who_for[64]; /*162*/ char WhoFor[64];
/*226*/ uint16 unknown226; /*226*/ uint16 Unknown226;
}; };
// newer clients (RoF+) send a list that contains 240 entries // newer clients (RoF+) send a list that contains 240 entries
// The packets don't actually use all 64 chars in the strings, but we'll just overallocate for these // The packets don't actually use all 64 chars in the strings, but we'll just overallocate for these
struct GuildBankItemListEntry_Struct { struct GuildBankItemListEntry_Struct
{
uint8 vaild; uint8 vaild;
uint32 permissions; uint32 permissions;
char whofor[64]; char whofor[64];
@@ -5834,28 +5817,6 @@ struct ChangeSize_Struct
/*16*/ /*16*/
}; };
enum ChangeNameResponse : int {
Denied = 0, // 5167: "You have requested an invalid name or a Customer Service Representative has denied your name request. Please try another name."
Accepted = 1, // 5976: "Your request for a name change was successful."
Timeout = -1, // 5977: "Your request for a name change has timed out. Please try again later."
ServerError = -2, // 5978: "The server had an error while processing your name request. Please try again later."
RateLimited = -3, // 5979: "You must wait longer before submitting another name request. Please try again in a few minutes."
Ineligible = -4, // 5980: "Your character is not eligible for a name change."
Pending = -5 // 5193: "You already have a name change pending. Please wait until it is fully processed before attempting another name change."
};
struct AltChangeName_Struct {
/*00*/ char new_name[64];
/*40*/ char old_name[64];
/*80*/ int response_code;
};
struct ChangePetName_Struct {
/*00*/ char new_pet_name[64];
/*40*/ char pet_owner_name[64];
/*80*/ int response_code;
};
// New OpCode/Struct for SoD+ // New OpCode/Struct for SoD+
struct GroupMakeLeader_Struct struct GroupMakeLeader_Struct
{ {
@@ -6385,7 +6346,6 @@ enum BazaarTraderBarterActions {
TraderAck2 = 22, TraderAck2 = 22,
AddTraderToBazaarWindow = 24, AddTraderToBazaarWindow = 24,
RemoveTraderFromBazaarWindow = 25, RemoveTraderFromBazaarWindow = 25,
FirstOpenSearch = 26,
ClickTrader = 28, ClickTrader = 28,
DeliveryCostUpdate = 29 DeliveryCostUpdate = 29
}; };
@@ -6425,7 +6385,6 @@ struct BazaarSearchResultsFromDB_Struct {
uint32 icon_id; uint32 icon_id;
uint32 sum_charges; uint32 sum_charges;
uint32 trader_zone_id; uint32 trader_zone_id;
int32 trader_zone_instance_id;
uint32 trader_entity_id; uint32 trader_entity_id;
uint32 item_stat; uint32 item_stat;
bool stackable; bool stackable;
@@ -6447,7 +6406,6 @@ struct BazaarSearchResultsFromDB_Struct {
CEREAL_NVP(icon_id), CEREAL_NVP(icon_id),
CEREAL_NVP(sum_charges), CEREAL_NVP(sum_charges),
CEREAL_NVP(trader_zone_id), CEREAL_NVP(trader_zone_id),
CEREAL_NVP(trader_zone_instance_id),
CEREAL_NVP(trader_entity_id), CEREAL_NVP(trader_entity_id),
CEREAL_NVP(item_stat), CEREAL_NVP(item_stat),
CEREAL_NVP(stackable), CEREAL_NVP(stackable),
@@ -6477,90 +6435,6 @@ struct BuylineItemDetails_Struct {
uint32 item_quantity; uint32 item_quantity;
}; };
struct PickZoneEntry_Struct {
int16 zone_id;
int16 unknown;
int32 player_count;
int32 instance_id;
};
struct PickZoneWindow_Struct {
char padding000[64];
int64 session_id;
int8 option_count;
char padding073[23];
PickZoneEntry_Struct entries[10];
};
struct PickZone_Struct {
int64 session_id;
int32 selection_id;
};
struct EvolveItemToggle {
uint32 action;
uint32 unknown_004;
uint64 unique_id;
uint32 percentage;
uint32 activated;
};
struct EvolveXPWindowReceive {
uint32 action;
uint32 unknown_004;
uint64 item1_unique_id;
uint64 item2_unique_id;
};
struct EvolveItemMessaging {
uint32 action;
char serialized_data[];
};
struct EvolveXPWindowSend {
/*000*/ uint32 action;
/*004*/ uint64 item1_unique_id;
/*012*/ uint64 item2_unique_id;
/*020*/ uint32 compatibility;
/*024*/ uint32 max_transfer_level;
/*028*/ uint8 item1_present;
/*029*/ uint8 item2_present;
/*030*/ std::string serialize_item_1;
/*034*/ std::string serialize_item_2;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(item1_unique_id),
CEREAL_NVP(item2_unique_id),
CEREAL_NVP(compatibility),
CEREAL_NVP(max_transfer_level),
CEREAL_NVP(item1_present),
CEREAL_NVP(item2_present),
CEREAL_NVP(serialize_item_1),
CEREAL_NVP(serialize_item_2)
);
}
};
struct EvolveTransfer {
uint32 item_from_id;
uint32 item_from_current_amount;
uint32 item_to_id;
uint32 item_to_current_amount;
uint32 compatibility;
uint32 max_transfer_level;
};
struct EvolveGetNextItem {
uint32 new_item_id;
uint64 new_current_amount;
uint64 from_current_amount;
uint32 max_transfer_level;
};
// Restore structure packing to default // Restore structure packing to default
#pragma pack() #pragma pack()
+2 -2
View File
@@ -545,13 +545,13 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
uint32 chunksize, used; uint32 chunksize, used;
uint32 length; uint32 length;
if (EQEmuLogSys::Instance()->log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){ if (LogSys.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){
if (p->GetOpcode() != OP_SpecialMesg){ if (p->GetOpcode() != OP_SpecialMesg){
Log(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size()); Log(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
} }
} }
if (EQEmuLogSys::Instance()->log_settings[Logs::Server_Client_Packet_With_Dump].is_category_enabled == 1){ if (LogSys.log_settings[Logs::Server_Client_Packet_With_Dump].is_category_enabled == 1){
if (p->GetOpcode() != OP_SpecialMesg){ if (p->GetOpcode() != OP_SpecialMesg){
Log(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); Log(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
} }
+3 -21
View File
@@ -94,7 +94,7 @@ void EQEmuConfig::parse_config()
auto_database_updates = true; auto_database_updates = true;
} }
WorldIP = _root["server"]["world"]["tcp"].get("ip", "127.0.0.1").asString(); WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString()); WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString());
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString(); TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
@@ -147,8 +147,6 @@ void EQEmuConfig::parse_config()
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString(); QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString(); QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString(); QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
QSHost = _root["server"]["queryserver"].get("host", "localhost").asString();
QSPort = Strings::ToUnsignedInt(_root["server"]["queryserver"].get("port", "9500").asString());
/** /**
* Zones * Zones
@@ -173,25 +171,9 @@ void EQEmuConfig::parse_config()
PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString(); PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString();
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString(); LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
PatchDir = _root["server"]["directories"].get("patches", "./").asString(); PatchDir = _root["server"]["directories"].get("patches", "./").asString();
OpcodeDir = _root["server"]["directories"].get("opcodes", "./").asString();
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString(); SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
LogDir = _root["server"]["directories"].get("logs", "logs/").asString(); LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
auto load_paths = [&](const std::string& key, std::vector<std::string>& target) {
const auto& paths = _root["server"]["directories"][key];
if (paths.isArray()) {
for (const auto& dir : paths) {
if (dir.isString()) {
target.push_back(dir.asString());
}
}
}
};
load_paths("quest_paths", m_quest_directories);
load_paths("plugin_paths", m_plugin_directories);
load_paths("lua_module_paths", m_lua_module_directories);
/** /**
* Logs * Logs
*/ */
@@ -436,11 +418,11 @@ void EQEmuConfig::CheckUcsConfigConversion()
LogInfo("Migrating old [eqemu_config] UCS configuration to new configuration"); LogInfo("Migrating old [eqemu_config] UCS configuration to new configuration");
std::string config_file_path = std::filesystem::path{ std::string config_file_path = std::filesystem::path{
PathManager::Instance()->GetServerPath() + "/eqemu_config.json" path.GetServerPath() + "/eqemu_config.json"
}.string(); }.string();
std::string config_file_bak_path = std::filesystem::path{ std::string config_file_bak_path = std::filesystem::path{
PathManager::Instance()->GetServerPath() + "/eqemu_config.ucs-migrate-json.bak" path.GetServerPath() + "/eqemu_config.ucs-migrate-json.bak"
}.string(); }.string();
// copy eqemu_config.json to eqemu_config.json.bak // copy eqemu_config.json to eqemu_config.json.bak
+2 -26
View File
@@ -82,8 +82,6 @@ class EQEmuConfig
std::string QSDatabasePassword; std::string QSDatabasePassword;
std::string QSDatabaseDB; std::string QSDatabaseDB;
uint16 QSDatabasePort; uint16 QSDatabasePort;
std::string QSHost;
int QSPort;
// From <files/> // From <files/>
std::string SpellsFile; std::string SpellsFile;
@@ -97,7 +95,6 @@ class EQEmuConfig
std::string PluginDir; std::string PluginDir;
std::string LuaModuleDir; std::string LuaModuleDir;
std::string PatchDir; std::string PatchDir;
std::string OpcodeDir;
std::string SharedMemDir; std::string SharedMemDir;
std::string LogDir; std::string LogDir;
@@ -120,22 +117,6 @@ class EQEmuConfig
const std::string &GetUCSHost() const; const std::string &GetUCSHost() const;
uint16 GetUCSPort() const; uint16 GetUCSPort() const;
std::vector<std::string> GetQuestDirectories() const
{
return m_quest_directories;
}
std::vector<std::string> GetPluginsDirectories() const
{
return m_plugin_directories;
}
std::vector<std::string> GetLuaModuleDirectories() const
{
return m_lua_module_directories;
}
// uint16 DynamicCount; // uint16 DynamicCount;
// map<string,uint16> StaticZones; // map<string,uint16> StaticZones;
@@ -149,20 +130,15 @@ class EQEmuConfig
Json::Value _root; Json::Value _root;
static std::string ConfigFile; static std::string ConfigFile;
std::vector<std::string> m_quest_directories = {};
std::vector<std::string> m_plugin_directories = {};
std::vector<std::string> m_lua_module_directories = {};
protected:
void parse_config(); void parse_config();
EQEmuConfig() EQEmuConfig()
{ {
} }
virtual ~EQEmuConfig() {}
public: public:
virtual ~EQEmuConfig() {}
// Produce a const singleton // Produce a const singleton
static const EQEmuConfig *get() static const EQEmuConfig *get()
@@ -191,7 +167,7 @@ class EQEmuConfig
std::string file = fmt::format( std::string file = fmt::format(
"{}/{}", "{}/{}",
(file_path.empty() ? PathManager::Instance()->GetServerPath() : file_path), (file_path.empty() ? path.GetServerPath() : file_path),
EQEmuConfig::ConfigFile EQEmuConfig::ConfigFile
); );
+10 -49
View File
@@ -25,8 +25,6 @@
#include "repositories/discord_webhooks_repository.h" #include "repositories/discord_webhooks_repository.h"
#include "repositories/logsys_categories_repository.h" #include "repositories/logsys_categories_repository.h"
#include "termcolor/rang.hpp" #include "termcolor/rang.hpp"
#include "path_manager.h"
#include "file.h"
#include <iostream> #include <iostream>
#include <string> #include <string>
@@ -87,7 +85,6 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
* Set Defaults * Set Defaults
*/ */
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_file = static_cast<uint8>(Logs::General);
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
@@ -105,8 +102,6 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::EqTime].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_gmsay = static_cast<uint8>(Logs::General); log_settings[Logs::EqTime].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::NpcHandin].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NpcHandin].log_to_gmsay = static_cast<uint8>(Logs::General);
/** /**
* RFC 5424 * RFC 5424
@@ -537,11 +532,6 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
{ {
EQEmuLogSys::CloseFileLogs(); EQEmuLogSys::CloseFileLogs();
if (!File::Exists(PathManager::Instance()->GetLogPath())) {
LogInfo("Logs directory not found, creating [{}]", PathManager::Instance()->GetLogPath());
File::Makedir(PathManager::Instance()->GetLogPath());
}
/** /**
* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one... * When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one...
*/ */
@@ -601,8 +591,6 @@ void EQEmuLogSys::SilenceConsoleLogging()
log_settings[log_index].is_category_enabled = 0; log_settings[log_index].is_category_enabled = 0;
} }
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::MySQLError);
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::Error);
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
} }
@@ -614,7 +602,7 @@ void EQEmuLogSys::EnableConsoleLogging()
std::copy(std::begin(pre_silence_settings), std::end(pre_silence_settings), std::begin(log_settings)); std::copy(std::begin(pre_silence_settings), std::end(pre_silence_settings), std::begin(log_settings));
} }
EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings(bool silent_load) EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
{ {
InjectTablesIfNotExist(); InjectTablesIfNotExist();
@@ -656,7 +644,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings(bool silent_load)
// If we go through this whole loop and nothing is set to any debug level, there // If we go through this whole loop and nothing is set to any debug level, there
// is no point to create a file or keep anything open // is no point to create a file or keep anything open
if (log_settings[c.log_category_id].log_to_file > 0) { if (log_settings[c.log_category_id].log_to_file > 0) {
m_file_logs_enabled = true; LogSys.m_file_logs_enabled = true;
} }
db_categories.emplace_back(c.log_category_id); db_categories.emplace_back(c.log_category_id);
@@ -682,33 +670,14 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings(bool silent_load)
if (is_missing_in_database && !is_deprecated_category) { if (is_missing_in_database && !is_deprecated_category) {
LogInfo("Automatically adding new log category [{}] ({})", Logs::LogCategoryName[i], i); LogInfo("Automatically adding new log category [{}] ({})", Logs::LogCategoryName[i], i);
auto e = LogsysCategoriesRepository::NewEntity(); auto new_category = LogsysCategoriesRepository::NewEntity();
e.log_category_id = i; new_category.log_category_id = i;
e.log_category_description = Strings::Escape(Logs::LogCategoryName[i]); new_category.log_category_description = Strings::Escape(Logs::LogCategoryName[i]);
e.log_to_console = log_settings[i].log_to_console; new_category.log_to_console = log_settings[i].log_to_console;
e.log_to_gmsay = log_settings[i].log_to_gmsay; new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
e.log_to_file = log_settings[i].log_to_file; new_category.log_to_file = log_settings[i].log_to_file;
e.log_to_discord = log_settings[i].log_to_discord; new_category.log_to_discord = log_settings[i].log_to_discord;
db_categories_to_add.emplace_back(e); db_categories_to_add.emplace_back(new_category);
}
// look to see if the category name is different in the database
auto it = std::find_if(
categories.begin(),
categories.end(),
[i](const auto &c) { return c.log_category_id == i; }
);
if (it != categories.end()) {
if (it->log_category_description != Logs::LogCategoryName[i]) {
LogInfo(
"Updating log category [{}] ({}) to new name [{}]",
it->log_category_description,
i,
Logs::LogCategoryName[i]
);
it->log_category_description = Logs::LogCategoryName[i];
LogsysCategoriesRepository::ReplaceOne(*m_database, *it);
}
} }
} }
@@ -718,10 +687,6 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings(bool silent_load)
return this; return this;
} }
if (silent_load) {
SilenceConsoleLogging();
}
LogInfo("Loaded [{}] log categories", categories.size()); LogInfo("Loaded [{}] log categories", categories.size());
auto webhooks = DiscordWebhooksRepository::GetWhere(*m_database, fmt::format("id < {}", MAX_DISCORD_WEBHOOK_ID)); auto webhooks = DiscordWebhooksRepository::GetWhere(*m_database, fmt::format("id < {}", MAX_DISCORD_WEBHOOK_ID));
@@ -739,10 +704,6 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings(bool silent_load)
log_settings[Logs::Info].log_to_file = static_cast<uint8>(Logs::General); log_settings[Logs::Info].log_to_file = static_cast<uint8>(Logs::General);
log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General); log_settings[Logs::Info].log_to_console = static_cast<uint8>(Logs::General);
if (silent_load) {
SilenceConsoleLogging();
}
return this; return this;
} }
+15 -39
View File
@@ -74,7 +74,7 @@ namespace Logs {
Spawns, Spawns,
Spells, Spells,
Status, // deprecated Status, // deprecated
TCPConnection, // deprecated TCPConnection,
Tasks, Tasks,
Tradeskills, Tradeskills,
Trading, Trading,
@@ -142,16 +142,6 @@ namespace Logs {
EqTime, EqTime,
Corpses, Corpses,
XTargets, XTargets,
EvolveItem,
PositionUpdate,
KSM,
BotSettings,
BotSpellChecks,
BotSpellTypeChecks,
NpcHandin,
ZoneState,
NetClient,
NetTCP,
MaxCategoryID /* Don't Remove this */ MaxCategoryID /* Don't Remove this */
}; };
@@ -185,7 +175,7 @@ namespace Logs {
"Spawns", "Spawns",
"Spells", "Spells",
"Status (Deprecated)", "Status (Deprecated)",
"TCP Connection (Deprecated)", "TCP Connection",
"Tasks", "Tasks",
"Tradeskills", "Tradeskills",
"Trading", "Trading",
@@ -194,8 +184,8 @@ namespace Logs {
"Web Interface (Deprecated)", "Web Interface (Deprecated)",
"World Server (Deprecated)", "World Server (Deprecated)",
"Zone Server (Deprecated)", "Zone Server (Deprecated)",
"MySQL Error", "QueryErr",
"MySQL Query", "Query",
"Mercenaries", "Mercenaries",
"Quest Debug", "Quest Debug",
"Legacy Packet Logging (Deprecated)", "Legacy Packet Logging (Deprecated)",
@@ -211,15 +201,15 @@ namespace Logs {
"Traps", "Traps",
"NPC Roam Box", "NPC Roam Box",
"NPC Scaling", "NPC Scaling",
"Mob Appearance", "MobAppearance",
"Info", "Info",
"Warning", "Warning",
"Critical (Deprecated)", "Critical (Deprecated)",
"Emergency (Deprecated)", "Emergency (Deprecated)",
"Alert (Deprecated)", "Alert (Deprecated)",
"Notice (Deprecated)", "Notice (Deprecated)",
"AI Scan Close", "AI Scan",
"AI Yell For Help", "AI Yell",
"AI CastBeneficial", "AI CastBeneficial",
"AOE Cast", "AOE Cast",
"Entity Management", "Entity Management",
@@ -237,7 +227,7 @@ namespace Logs {
"DialogueWindow", "DialogueWindow",
"HTTP", "HTTP",
"Saylink", "Saylink",
"Checksum Verification", "ChecksumVer",
"CombatRecord", "CombatRecord",
"Hate", "Hate",
"Discord", "Discord",
@@ -252,20 +242,12 @@ namespace Logs {
"Zoning", "Zoning",
"EqTime", "EqTime",
"Corpses", "Corpses",
"XTargets", "XTargets"
"EvolveItem",
"PositionUpdate",
"KSM", // Kernel Samepage Merging
"Bot Settings",
"Bot Spell Checks",
"Bot Spell Type Checks",
"NpcHandin",
"ZoneState",
"Net Server <-> Client",
"Net TCP"
}; };
} }
#include "eqemu_logsys_log_aliases.h"
class Database; class Database;
constexpr uint16 MAX_DISCORD_WEBHOOK_ID = 300; constexpr uint16 MAX_DISCORD_WEBHOOK_ID = 300;
@@ -281,13 +263,7 @@ public:
*/ */
void CloseFileLogs(); void CloseFileLogs();
EQEmuLogSys *LoadLogSettingsDefaults(); EQEmuLogSys *LoadLogSettingsDefaults();
EQEmuLogSys *LoadLogDatabaseSettings(bool silent_load = false); EQEmuLogSys *LoadLogDatabaseSettings();
static EQEmuLogSys *Instance()
{
static EQEmuLogSys instance;
return &instance;
}
/** /**
* @param directory_name * @param directory_name
@@ -354,7 +330,7 @@ public:
/** /**
* Internally used memory reference for all log settings per category * Internally used memory reference for all log settings per category
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults * These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
* Database loaded via EQEmuLogSys::Instance()->SetDatabase(&database)->LoadLogDatabaseSettings(); * Database loaded via LogSys.SetDatabase(&database)->LoadLogDatabaseSettings();
*/ */
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{}; LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
@@ -438,7 +414,7 @@ private:
void InjectTablesIfNotExist(); void InjectTablesIfNotExist();
}; };
#include "eqemu_logsys_log_aliases.h" extern EQEmuLogSys LogSys;
/** /**
template<typename... Args> template<typename... Args>
@@ -460,7 +436,7 @@ void OutF(
#define OutF(ls, debug_level, log_category, file, func, line, formatStr, ...) \ #define OutF(ls, debug_level, log_category, file, func, line, formatStr, ...) \
do { \ do { \
ls->Out(debug_level, log_category, file, func, line, fmt::format(formatStr, ##__VA_ARGS__).c_str()); \ ls.Out(debug_level, log_category, file, func, line, fmt::format(formatStr, ##__VA_ARGS__).c_str()); \
} while(0) } while(0)
#endif #endif
File diff suppressed because it is too large Load Diff
@@ -714,18 +714,6 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
h.charges > 1 ? fmt::format(" Charges: {}", h.charges) : "", h.charges > 1 ? fmt::format(" Charges: {}", h.charges) : "",
h.attuned ? " (Attuned)" : "" h.attuned ? " (Attuned)" : ""
); );
for (int i = 0; i < h.augment_ids.size(); i++) {
if (!h.augment_names[i].empty()) {
const uint8 slot_id = (i + 1);
handin_items_info += fmt::format(
"Augment {}: {} ({})\n",
slot_id,
h.augment_names[i],
h.augment_ids[i]
);
}
}
} }
} }
@@ -739,18 +727,6 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
r.charges > 1 ? fmt::format(" Charges: {}", r.charges) : "", r.charges > 1 ? fmt::format(" Charges: {}", r.charges) : "",
r.attuned ? " (Attuned)" : "" r.attuned ? " (Attuned)" : ""
); );
for (int i = 0; i < r.augment_ids.size(); i++) {
if (!r.augment_names[i].empty()) {
const uint8 slot_id = (i + 1);
return_items_info += fmt::format(
"Augment {}: {} ({})\n",
slot_id,
r.augment_names[i],
r.augment_ids[i]
);
}
}
} }
} }
@@ -813,36 +789,50 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
); );
} }
std::string npc_info = fmt::format(
"{} ({})\n",
e.npc_name,
e.npc_id
);
npc_info += fmt::format(
"Is Quest Handin: {}",
e.is_quest_handin ? "Yes" : "No"
);
std::vector<DiscordField> f = {}; std::vector<DiscordField> f = {};
BuildDiscordField(&f, "NPC", npc_info);
if (!handin_items_info.empty()) { if (!handin_items_info.empty()) {
BuildDiscordField(&f, "Handin Items", handin_items_info); BuildDiscordField(
&f,
"Handin Items",
fmt::format(
"{}",
handin_items_info
)
);
} }
if (!handin_money_info.empty()) { if (!handin_money_info.empty()) {
BuildDiscordField(&f, "Handin Money", handin_money_info); BuildDiscordField(
&f,
"Handin Money",
fmt::format(
"{}",
handin_money_info
)
);
} }
if (!return_items_info.empty()) { if (!return_items_info.empty()) {
BuildDiscordField(&f, "Return Items", return_items_info); BuildDiscordField(
&f,
"Return Items",
fmt::format(
"{}",
return_items_info
)
);
} }
if (!return_money_info.empty()) { if (!return_money_info.empty()) {
BuildDiscordField(&f, "Return Money", return_money_info); BuildDiscordField(
&f,
"Return Money",
fmt::format(
"{}",
return_money_info
)
);
} }
std::vector<DiscordEmbed> embeds = {}; std::vector<DiscordEmbed> embeds = {};
@@ -1081,51 +1071,51 @@ std::string PlayerEventDiscordFormatter::FormatTradeEvent(
if (!e.character_1_give_items.empty()) { if (!e.character_1_give_items.empty()) {
for (const auto &i: e.character_1_give_items) { for (const auto &i: e.character_1_give_items) {
std::string augment_info; std::string augment_info;
if (i.augment_1_id > 0) { if (i.aug_1_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 1: {} ({})", "Augment 1: {} ({})",
i.augment_1_name, i.aug_1_item_name,
i.augment_1_id i.aug_1_item_id
); );
} }
if (i.augment_2_id > 0) { if (i.aug_2_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 2: {} ({})", "Augment 2: {} ({})",
i.augment_2_name, i.aug_2_item_name,
i.augment_2_id i.aug_2_item_id
); );
} }
if (i.augment_3_id > 0) { if (i.aug_3_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 3: {} ({})", "Augment 3: {} ({})",
i.augment_3_name, i.aug_3_item_name,
i.augment_3_id i.aug_3_item_id
); );
} }
if (i.augment_4_id > 0) { if (i.aug_4_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 4: {} ({})\n", "Augment 4: {} ({})\n",
i.augment_4_name, i.aug_4_item_name,
i.augment_4_id i.aug_4_item_id
); );
} }
if (i.augment_5_id > 0) { if (i.aug_5_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 5: {} ({})\n", "Augment 5: {} ({})\n",
i.augment_5_name, i.aug_5_item_name,
i.augment_5_id i.aug_5_item_id
); );
} }
if (i.augment_6_id > 0) { if (i.aug_6_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 6: {} ({})", "Augment 6: {} ({})",
i.augment_6_name, i.aug_6_item_name,
i.augment_6_id i.aug_6_item_id
); );
} }
@@ -1146,51 +1136,51 @@ std::string PlayerEventDiscordFormatter::FormatTradeEvent(
if (!e.character_2_give_items.empty()) { if (!e.character_2_give_items.empty()) {
for (const auto &i: e.character_2_give_items) { for (const auto &i: e.character_2_give_items) {
std::string augment_info; std::string augment_info;
if (i.augment_1_id > 0) { if (i.aug_1_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 1: {} ({})", "Augment 1: {} ({})",
i.augment_1_name, i.aug_1_item_name,
i.augment_1_id i.aug_1_item_id
); );
} }
if (i.augment_2_id > 0) { if (i.aug_2_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 2: {} ({})", "Augment 2: {} ({})",
i.augment_2_name, i.aug_2_item_name,
i.augment_2_id i.aug_2_item_id
); );
} }
if (i.augment_3_id > 0) { if (i.aug_3_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 3: {} ({})", "Augment 3: {} ({})",
i.augment_3_name, i.aug_3_item_name,
i.augment_3_id i.aug_3_item_id
); );
} }
if (i.augment_4_id > 0) { if (i.aug_4_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 4: {} ({})\n", "Augment 4: {} ({})\n",
i.augment_4_name, i.aug_4_item_name,
i.augment_4_id i.aug_4_item_id
); );
} }
if (i.augment_5_id > 0) { if (i.aug_5_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 5: {} ({})\n", "Augment 5: {} ({})\n",
i.augment_5_name, i.aug_5_item_name,
i.augment_5_id i.aug_5_item_id
); );
} }
if (i.augment_6_id > 0) { if (i.aug_6_item_id > 0) {
augment_info += fmt::format( augment_info += fmt::format(
"Augment 6: {} ({})", "Augment 6: {} ({})",
i.augment_6_name, i.aug_6_item_name,
i.augment_6_id i.aug_6_item_id
); );
} }
+20 -576
View File
@@ -1,14 +1,8 @@
#include "player_event_logs.h"
#include <cereal/archives/json.hpp> #include <cereal/archives/json.hpp>
#include "player_event_logs.h"
#include "player_event_discord_formatter.h"
#include "../platform.h" #include "../platform.h"
#include "../rulesys.h" #include "../rulesys.h"
#include "player_event_discord_formatter.h"
#include "../repositories/player_event_loot_items_repository.h"
#include "../repositories/player_event_merchant_sell_repository.h"
#include "../repositories/player_event_merchant_purchase_repository.h"
#include "../repositories/player_event_npc_handin_repository.h"
#include "../repositories/player_event_npc_handin_entries_repository.h"
const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1 hour const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1 hour
@@ -17,7 +11,6 @@ void PlayerEventLogs::Init()
{ {
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000); m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL); m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
m_database_ping_timer.SetTimer(10 * 1000); // 10 seconds
ValidateDatabaseConnection(); ValidateDatabaseConnection();
@@ -28,7 +21,6 @@ void PlayerEventLogs::Init()
m_settings[i].event_enabled = 1; m_settings[i].event_enabled = 1;
m_settings[i].retention_days = 0; m_settings[i].retention_days = 0;
m_settings[i].discord_webhook_id = 0; m_settings[i].discord_webhook_id = 0;
m_settings[i].etl_enabled = false;
} }
SetSettingsDefaults(); SetSettingsDefaults();
@@ -73,7 +65,6 @@ void PlayerEventLogs::Init()
c.event_name = PlayerEvent::EventName[i]; c.event_name = PlayerEvent::EventName[i];
c.event_enabled = m_settings[i].event_enabled; c.event_enabled = m_settings[i].event_enabled;
c.retention_days = m_settings[i].retention_days; c.retention_days = m_settings[i].retention_days;
c.etl_enabled = false;
settings_to_insert.emplace_back(c); settings_to_insert.emplace_back(c);
} }
} }
@@ -87,7 +78,6 @@ void PlayerEventLogs::Init()
// on initial boot process truncation // on initial boot process truncation
if (processing_in_world || processing_in_qs) { if (processing_in_world || processing_in_qs) {
LoadEtlIds();
ProcessRetentionTruncation(); ProcessRetentionTruncation();
} }
} }
@@ -131,328 +121,23 @@ void PlayerEventLogs::ProcessBatchQueue()
return; return;
} }
static std::map<uint32, uint32> counter{};
counter.clear();
for (auto const &e: m_record_batch_queue) {
counter[e.event_type_id]++;
}
BenchTimer benchmark; BenchTimer benchmark;
EtlQueues etl_queues{};
for (const auto &[type, count]: counter) {
if (count > 0) {
switch (type) {
case PlayerEvent::TRADE:
etl_queues.trade.reserve(count);
break;
case PlayerEvent::SPEECH:
etl_queues.speech.reserve(count);
break;
case PlayerEvent::LOOT_ITEM:
etl_queues.loot_items.reserve(count);
break;
case PlayerEvent::KILLED_NPC:
etl_queues.killed_npc.reserve(count);
break;
case PlayerEvent::NPC_HANDIN:
etl_queues.npc_handin.reserve(count);
break;
case PlayerEvent::AA_PURCHASE:
etl_queues.aa_purchase.reserve(count);
break;
case PlayerEvent::MERCHANT_SELL:
etl_queues.merchant_sell.reserve(count);
break;
case PlayerEvent::KILLED_RAID_NPC:
etl_queues.killed_raid_npc.reserve(count);
break;
case PlayerEvent::KILLED_NAMED_NPC:
etl_queues.killed_named_npc.reserve(count);
break;
case PlayerEvent::MERCHANT_PURCHASE:
etl_queues.merchant_purchase.reserve(count);
break;
default:
break;
}
}
}
// Helper to deserialize event data
auto Deserialize = [](const std::string &data, auto &out) {
if (!Strings::IsValidJson(data)) {
return;
}
// cpp exceptions are terrible, don't ever use them
try {
std::stringstream ss(data);
cereal::JSONInputArchive ar(ss);
out.serialize(ar);
}
catch (const std::exception &e) {}
};
// Helper to assign ETL table ID
auto AssignEtlId = [&](
PlayerEventLogsRepository::PlayerEventLogs& r,
PlayerEvent::EventType type
)
{
if (m_etl_settings.contains(type)) {
r.etl_table_id = m_etl_settings.at(type).next_id++;
}
};
// Define event processors
std::unordered_map<PlayerEvent::EventType, std::function<void(PlayerEventLogsRepository::PlayerEventLogs &)>> event_processors = {
{
PlayerEvent::EventType::LOOT_ITEM, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::LootItemEvent in{};
PlayerEventLootItemsRepository::PlayerEventLootItems out{};
Deserialize(r.event_data, in);
out.charges = in.charges;
out.corpse_name = in.corpse_name;
out.item_id = in.item_id;
out.item_name = in.item_name;
out.augment_1_id = in.augment_1_id;
out.augment_2_id = in.augment_2_id;
out.augment_3_id = in.augment_3_id;
out.augment_4_id = in.augment_4_id;
out.augment_5_id = in.augment_5_id;
out.augment_6_id = in.augment_6_id;
out.npc_id = in.npc_id;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::LOOT_ITEM);
etl_queues.loot_items.push_back(out);
}
},
{
PlayerEvent::EventType::MERCHANT_SELL, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::MerchantSellEvent in{};
PlayerEventMerchantSellRepository::PlayerEventMerchantSell out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.merchant_name = in.merchant_name;
out.merchant_type = in.merchant_type;
out.item_id = in.item_id;
out.item_name = in.item_name;
out.charges = in.charges;
out.cost = in.cost;
out.alternate_currency_id = in.alternate_currency_id;
out.player_money_balance = in.player_money_balance;
out.player_currency_balance = in.player_currency_balance;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::MERCHANT_SELL);
etl_queues.merchant_sell.push_back(out);
}},
{
PlayerEvent::EventType::MERCHANT_PURCHASE, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::MerchantPurchaseEvent in{};
PlayerEventMerchantPurchaseRepository::PlayerEventMerchantPurchase out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.merchant_name = in.merchant_name;
out.merchant_type = in.merchant_type;
out.item_id = in.item_id;
out.item_name = in.item_name;
out.charges = in.charges;
out.cost = in.cost;
out.alternate_currency_id = in.alternate_currency_id;
out.player_money_balance = in.player_money_balance;
out.player_currency_balance = in.player_currency_balance;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::MERCHANT_PURCHASE);
etl_queues.merchant_purchase.push_back(out);
}},
{
PlayerEvent::EventType::NPC_HANDIN, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::HandinEvent in{};
PlayerEventNpcHandinRepository::PlayerEventNpcHandin out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.npc_name = in.npc_name;
out.handin_copper = in.handin_money.copper;
out.handin_silver = in.handin_money.silver;
out.handin_gold = in.handin_money.gold;
out.handin_platinum = in.handin_money.platinum;
out.return_copper = in.return_money.copper;
out.return_silver = in.return_money.silver;
out.return_gold = in.return_money.gold;
out.return_platinum = in.return_money.platinum;
out.is_quest_handin = in.is_quest_handin;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::NPC_HANDIN);
etl_queues.npc_handin.push_back(out);
for (const auto &i: in.handin_items) {
PlayerEventNpcHandinEntriesRepository::PlayerEventNpcHandinEntries entry{};
entry.player_event_npc_handin_id = r.etl_table_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.type = 1;
etl_queues.npc_handin_entries.push_back(entry);
}
for (const auto &i: in.return_items) {
PlayerEventNpcHandinEntriesRepository::PlayerEventNpcHandinEntries entry{};
entry.player_event_npc_handin_id = r.etl_table_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.type = 2;
etl_queues.npc_handin_entries.push_back(entry);
}
}},
{
PlayerEvent::EventType::TRADE, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::TradeEvent in{};
PlayerEventTradeRepository::PlayerEventTrade out{};
Deserialize(r.event_data, in);
out.char1_id = in.character_1_id;
out.char2_id = in.character_2_id;
out.char1_copper = in.character_1_give_money.copper;
out.char1_silver = in.character_1_give_money.silver;
out.char1_gold = in.character_1_give_money.gold;
out.char1_platinum = in.character_1_give_money.platinum;
out.char2_copper = in.character_2_give_money.copper;
out.char2_silver = in.character_2_give_money.silver;
out.char2_gold = in.character_2_give_money.gold;
out.char2_platinum = in.character_2_give_money.platinum;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::TRADE);
etl_queues.trade.push_back(out);
for (const auto &i: in.character_1_give_items) {
PlayerEventTradeEntriesRepository::PlayerEventTradeEntries entry{};
entry.player_event_trade_id = r.etl_table_id;
entry.char_id = in.character_1_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.slot = i.slot;
etl_queues.trade_entries.push_back(entry);
}
for (const auto &i: in.character_2_give_items) {
PlayerEventTradeEntriesRepository::PlayerEventTradeEntries entry{};
entry.player_event_trade_id = r.etl_table_id;
entry.char_id = in.character_2_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.slot = i.slot;
etl_queues.trade_entries.push_back(entry);
}
}},
{
PlayerEvent::EventType::SPEECH, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::PlayerSpeech in{};
PlayerEventSpeechRepository::PlayerEventSpeech out{};
Deserialize(r.event_data, in);
out.from_char_id = in.from;
out.to_char_id = in.to;
out.type = in.type;
out.min_status = in.min_status;
out.message = in.message;
out.guild_id = in.guild_id;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::SPEECH);
etl_queues.speech.push_back(out);
}},
{
PlayerEvent::EventType::KILLED_NPC, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::KilledNPCEvent in{};
PlayerEventKilledNpcRepository::PlayerEventKilledNpc out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.npc_name = in.npc_name;
out.combat_time_seconds = in.combat_time_seconds;
out.total_damage_per_second_taken = in.total_damage_per_second_taken;
out.total_heal_per_second_taken = in.total_heal_per_second_taken;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::KILLED_NPC);
etl_queues.killed_npc.push_back(out);
}},
{
PlayerEvent::EventType::AA_PURCHASE, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::AAPurchasedEvent in{};
PlayerEventAaPurchaseRepository::PlayerEventAaPurchase out{};
Deserialize(r.event_data, in);
out.aa_ability_id = in.aa_id;
out.cost = in.aa_cost;
out.previous_id = in.aa_previous_id;
out.next_id = in.aa_next_id;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::AA_PURCHASE);
etl_queues.aa_purchase.push_back(out);
}},
};
// Process the batch queue
for (auto &r: m_record_batch_queue) {
if (m_settings[r.event_type_id].etl_enabled) {
auto it = event_processors.find(static_cast<PlayerEvent::EventType>(r.event_type_id));
if (it != event_processors.end()) {
it->second(r); // Call the appropriate lambda
}
else {
LogPlayerEventsDetail("Non-Implemented ETL routing [{}]", r.event_type_id);
}
}
}
// Helper to flush and clear queues
auto flush_queue = [&](auto insert_many, auto &queue) {
if (!queue.empty()) {
insert_many(*m_database, queue);
queue.clear();
}
};
// flush many // flush many
PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue); PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue);
LogPlayerEventsDetail(
// flush etl queues
flush_queue(PlayerEventLootItemsRepository::InsertMany, etl_queues.loot_items);
flush_queue(PlayerEventMerchantSellRepository::InsertMany, etl_queues.merchant_sell);
flush_queue(PlayerEventMerchantPurchaseRepository::InsertMany, etl_queues.merchant_purchase);
flush_queue(PlayerEventNpcHandinRepository::InsertMany, etl_queues.npc_handin);
flush_queue(PlayerEventNpcHandinEntriesRepository::InsertMany, etl_queues.npc_handin_entries);
flush_queue(PlayerEventTradeRepository::InsertMany, etl_queues.trade);
flush_queue(PlayerEventTradeEntriesRepository::InsertMany, etl_queues.trade_entries);
flush_queue(PlayerEventSpeechRepository::InsertMany, etl_queues.speech);
flush_queue(PlayerEventKilledNpcRepository::InsertMany, etl_queues.killed_npc);
flush_queue(PlayerEventKilledNamedNpcRepository::InsertMany, etl_queues.killed_named_npc);
flush_queue(PlayerEventKilledRaidNpcRepository::InsertMany, etl_queues.killed_raid_npc);
flush_queue(PlayerEventAaPurchaseRepository::InsertMany, etl_queues.aa_purchase);
LogPlayerEvents(
"Processing batch player event log queue of [{}] took [{}]", "Processing batch player event log queue of [{}] took [{}]",
m_record_batch_queue.size(), m_record_batch_queue.size(),
benchmark.elapsed() benchmark.elapsed()
); );
// empty // empty
m_record_batch_queue.clear(); m_record_batch_queue = {};
m_batch_queue_lock.unlock(); m_batch_queue_lock.unlock();
} }
// adds a player event to the queue // adds a player event to the queue
void PlayerEventLogs::AddToQueue(PlayerEventLogsRepository::PlayerEventLogs &log) void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &log)
{ {
m_batch_queue_lock.lock(); m_batch_queue_lock.lock();
m_record_batch_queue.emplace_back(log); m_record_batch_queue.emplace_back(log);
@@ -509,7 +194,7 @@ bool PlayerEventLogs::IsEventDiscordEnabled(int32_t event_type_id)
} }
// ensure there is a matching webhook to begin with // ensure there is a matching webhook to begin with
if (!EQEmuLogSys::Instance()->GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) { if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return true; return true;
} }
@@ -529,27 +214,13 @@ std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_typ
} }
// ensure there is a matching webhook to begin with // ensure there is a matching webhook to begin with
if (!EQEmuLogSys::Instance()->GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) { if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return EQEmuLogSys::Instance()->GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url; return LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url;
} }
return ""; return "";
} }
void PlayerEventLogs::LoadPlayerEventSettingsFromQS(
const std::vector<PlayerEventLogSettingsRepository::PlayerEventLogSettings> &settings
)
{
for (const auto &e : settings) {
if (e.id >= PlayerEvent::MAX || e.id < 0) {
continue;
}
m_settings[e.id] = e;
}
LogInfo("Applied [{}] player event log settings from QS", settings.size());
}
// GM_COMMAND | [x] Implemented Formatter // GM_COMMAND | [x] Implemented Formatter
// ZONING | [x] Implemented Formatter // ZONING | [x] Implemented Formatter
// AA_GAIN | [x] Implemented Formatter // AA_GAIN | [x] Implemented Formatter
@@ -917,7 +588,7 @@ std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::Playe
break; break;
} }
default: { default: {
LogPlayerEventsDetail( LogInfo(
"Player event [{}] ({}) Discord formatter not implemented", "Player event [{}] ({}) Discord formatter not implemented",
e.player_event_log.event_type_name, e.player_event_log.event_type_name,
e.player_event_log.event_type_id e.player_event_log.event_type_id
@@ -931,12 +602,7 @@ std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::Playe
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess // general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
void PlayerEventLogs::Process() void PlayerEventLogs::Process()
{ {
if (m_database_ping_timer.Check()) { if (m_process_batch_events_timer.Check() || m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
m_database->ping();
}
if (m_process_batch_events_timer.Check() ||
m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
ProcessBatchQueue(); ProcessBatchQueue();
} }
@@ -947,116 +613,30 @@ void PlayerEventLogs::Process()
void PlayerEventLogs::ProcessRetentionTruncation() void PlayerEventLogs::ProcessRetentionTruncation()
{ {
LogPlayerEventsDetail("Running truncation"); LogPlayerEvents("Running truncation");
// Map of repository-specific deletion functions
std::unordered_map<PlayerEvent::EventType, std::function<uint32(const std::string &)>> repository_deleters = {
{
PlayerEvent::LOOT_ITEM, [&](const std::string &condition) {
return PlayerEventLootItemsRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::MERCHANT_SELL, [&](const std::string &condition) {
return PlayerEventMerchantSellRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::MERCHANT_PURCHASE, [&](const std::string &condition) {
return PlayerEventMerchantPurchaseRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::NPC_HANDIN, [&](const std::string &condition) {
uint32 deleted_count = PlayerEventNpcHandinRepository::DeleteWhere(*m_database, condition);
deleted_count += PlayerEventNpcHandinEntriesRepository::DeleteWhere(*m_database, condition);
return deleted_count;
}},
{
PlayerEvent::TRADE, [&](const std::string &condition) {
uint32 deleted_count = PlayerEventTradeRepository::DeleteWhere(*m_database, condition);
deleted_count += PlayerEventTradeEntriesRepository::DeleteWhere(*m_database, condition);
return deleted_count;
}},
{
PlayerEvent::SPEECH, [&](const std::string &condition) {
return PlayerEventSpeechRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::KILLED_NPC, [&](const std::string &condition) {
return PlayerEventKilledNpcRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::KILLED_NAMED_NPC, [&](const std::string &condition) {
return PlayerEventKilledNamedNpcRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::KILLED_RAID_NPC, [&](const std::string &condition) {
return PlayerEventKilledRaidNpcRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::AA_PURCHASE, [&](const std::string &condition) {
return PlayerEventAaPurchaseRepository::DeleteWhere(*m_database, condition);
}}
};
// Group event types by retention interval
std::unordered_map<int, std::vector<int>> retention_groups;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) { for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
if (m_settings[i].retention_days > 0) { if (m_settings[i].retention_days > 0) {
retention_groups[m_settings[i].retention_days].push_back(i); int deleted_count = PlayerEventLogsRepository::DeleteWhere(
}
}
for (const auto &[retention_days, event_types]: retention_groups) {
std::string condition = fmt::format(
"created_at < (NOW() - INTERVAL {} DAY)",
retention_days
);
// Handle ETL deletions for each event type in the group
uint32 total_deleted_count = 0;
for (int event_type_id: event_types) {
if (m_settings[event_type_id].etl_enabled) {
auto it = repository_deleters.find(static_cast<PlayerEvent::EventType>(m_settings[event_type_id].id));
if (it != repository_deleters.end()) {
total_deleted_count += it->second(condition);
}
else {
LogError("Non-Implemented ETL Event Type [{}]", static_cast<uint32>(m_settings[event_type_id].id));
}
}
}
if (total_deleted_count > 0) {
LogInfo(
"Truncated [{}] ETL events older than [{}] days",
total_deleted_count,
retention_days
);
}
// Batch deletion for player_event_logs
std::string event_type_ids = fmt::format(
"({})",
fmt::join(event_types, ", ")
);
uint32 deleted_count = PlayerEventLogsRepository::DeleteWhere(
*m_database, *m_database,
fmt::format( fmt::format(
"event_type_id IN {} AND {}", "event_type_id = {} AND created_at < (NOW() - INTERVAL {} DAY)",
event_type_ids, i,
condition m_settings[i].retention_days
) )
); );
if (deleted_count > 0) { if (deleted_count > 0) {
LogInfo( LogInfo(
"Truncated [{}] events of types [{}] older than [{}] days", "Truncated [{}] events of type [{}] ({}) older than [{}] days",
deleted_count, deleted_count,
event_type_ids, PlayerEvent::EventName[i],
retention_days i,
m_settings[i].retention_days
); );
} }
} }
}
} }
void PlayerEventLogs::ReloadSettings() void PlayerEventLogs::ReloadSettings()
@@ -1127,144 +707,8 @@ void PlayerEventLogs::SetSettingsDefaults()
m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1; m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1;
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1; m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1; m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1;
m_settings[PlayerEvent::EVOLVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPEECH].event_enabled = 0;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) { for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT; m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
} }
} }
void PlayerEventLogs::LoadEtlIds()
{
auto e = [&](auto p) -> bool {
for (PlayerEventLogSettingsRepository::PlayerEventLogSettings const &c: m_settings) {
if (c.id == p) {
return c.etl_enabled ? true : false;
}
}
return false;
};
m_etl_settings.clear();
m_etl_settings = {
{
PlayerEvent::LOOT_ITEM,
{
.enabled = e(PlayerEvent::LOOT_ITEM),
.table_name = "player_event_loot_items",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventLootItemsRepository::TableName()))
}
},
{
PlayerEvent::MERCHANT_SELL,
{
.enabled = e(PlayerEvent::MERCHANT_SELL),
.table_name = "player_event_merchant_sell",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventMerchantSellRepository::TableName()))
}
},
{
PlayerEvent::MERCHANT_PURCHASE,
{
.enabled = e(PlayerEvent::MERCHANT_PURCHASE),
.table_name = "player_event_merchant_purchase",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventMerchantPurchaseRepository::TableName()))
}
},
{
PlayerEvent::NPC_HANDIN,
{
.enabled = e(PlayerEvent::NPC_HANDIN),
.table_name = "player_event_npc_handin",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventNpcHandinRepository::TableName()))
}
},
{
PlayerEvent::TRADE,
{
.enabled = e(PlayerEvent::TRADE),
.table_name = "player_event_trade",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventTradeRepository::TableName()))
}
},
{
PlayerEvent::SPEECH,
{
.enabled = e(PlayerEvent::SPEECH),
.table_name = "player_event_speech",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventSpeechRepository::TableName()))
}
},
{
PlayerEvent::KILLED_NPC,
{
.enabled = e(PlayerEvent::KILLED_NPC),
.table_name = "player_event_killed_npc",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventKilledNpcRepository::TableName()))
}
},
{
PlayerEvent::KILLED_NAMED_NPC,
{
.enabled = e(PlayerEvent::KILLED_NAMED_NPC),
.table_name = "player_event_killed_named_npc",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventKilledNamedNpcRepository::TableName()))
}
},
{
PlayerEvent::KILLED_RAID_NPC,
{
.enabled = e(PlayerEvent::KILLED_RAID_NPC),
.table_name = "player_event_killed_raid_npc",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventKilledRaidNpcRepository::TableName()))
}
},
{
PlayerEvent::AA_PURCHASE,
{
.enabled = e(PlayerEvent::AA_PURCHASE),
.table_name = "player_event_aa_purchase",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventAaPurchaseRepository::TableName()))
}
}
};
for (auto &e: m_etl_settings) {
LogPlayerEventsDetail(
"ETL Settings [{}] Enabled [{}] Table [{}] NextId [{}]",
PlayerEvent::EventName[e.first],
e.second.enabled,
e.second.table_name,
e.second.next_id
);
}
}
bool PlayerEventLogs::LoadDatabaseConnection()
{
const auto c = EQEmuConfig::get();
LogInfo(
"Connecting to MySQL for PlayerEvents [{}]@[{}]:[{}]",
c->DatabaseUsername.c_str(),
c->DatabaseHost.c_str(),
c->DatabasePort
);
if (!player_event_database.Connect(
c->DatabaseHost.c_str(),
c->DatabaseUsername.c_str(),
c->DatabasePassword.c_str(),
c->DatabaseDB.c_str(),
c->DatabasePort
)) {
LogError("Cannot continue without a database connection for player events.");
return false;
}
SetDatabase(&player_event_database);
return true;
}
+10 -63
View File
@@ -1,38 +1,19 @@
#ifndef EQEMU_PLAYER_EVENT_LOGS_H #ifndef EQEMU_PLAYER_EVENT_LOGS_H
#define EQEMU_PLAYER_EVENT_LOGS_H #define EQEMU_PLAYER_EVENT_LOGS_H
#include "../repositories/player_event_log_settings_repository.h"
#include "player_events.h"
#include "../servertalk.h"
#include "../repositories/player_event_logs_repository.h"
#include "../timer.h"
#include "../json/json_archive_single_line.h"
#include <cereal/archives/json.hpp> #include <cereal/archives/json.hpp>
#include <mutex> #include <mutex>
#include "../json/json_archive_single_line.h"
#include "../servertalk.h"
#include "../timer.h"
#include "../eqemu_config.h"
#include "../repositories/player_event_log_settings_repository.h"
#include "../repositories/player_event_logs_repository.h"
#include "../repositories/player_event_loot_items_repository.h"
#include "../repositories/player_event_merchant_purchase_repository.h"
#include "../repositories/player_event_merchant_sell_repository.h"
#include "../repositories/player_event_npc_handin_repository.h"
#include "../repositories/player_event_npc_handin_entries_repository.h"
#include "../repositories/player_event_trade_repository.h"
#include "../repositories/player_event_trade_entries_repository.h"
#include "../repositories/player_event_speech_repository.h"
#include "../repositories/player_event_killed_npc_repository.h"
#include "../repositories/player_event_killed_named_npc_repository.h"
#include "../repositories/player_event_killed_raid_npc_repository.h"
#include "../repositories/player_event_aa_purchase_repository.h"
class PlayerEventLogs { class PlayerEventLogs {
public: public:
Database player_event_database{};
void Init(); void Init();
bool LoadDatabaseConnection();
void ReloadSettings(); void ReloadSettings();
void LoadEtlIds();
PlayerEventLogs *SetDatabase(Database *db); PlayerEventLogs *SetDatabase(Database *db);
bool ValidateDatabaseConnection(); bool ValidateDatabaseConnection();
bool IsEventEnabled(PlayerEvent::EventType event); bool IsEventEnabled(PlayerEvent::EventType event);
@@ -40,7 +21,7 @@ public:
void Process(); void Process();
// batch queue // batch queue
void AddToQueue(PlayerEventLogsRepository::PlayerEventLogs &logs); void AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &logs);
// main event record generic function // main event record generic function
// can ingest any struct event types // can ingest any struct event types
@@ -73,42 +54,12 @@ public:
return BuildPlayerEventPacket(c); return BuildPlayerEventPacket(c);
} }
[[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings * GetSettings() const; [[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings *GetSettings() const;
bool IsEventDiscordEnabled(int32_t event_type_id); bool IsEventDiscordEnabled(int32_t event_type_id);
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id); std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
void LoadPlayerEventSettingsFromQS(const std::vector<PlayerEventLogSettingsRepository::PlayerEventLogSettings>& settings);
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e); static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
struct EtlQueues {
std::vector<PlayerEventLootItemsRepository::PlayerEventLootItems> loot_items;
std::vector<PlayerEventMerchantPurchaseRepository::PlayerEventMerchantPurchase> merchant_purchase;
std::vector<PlayerEventMerchantSellRepository::PlayerEventMerchantSell> merchant_sell;
std::vector<PlayerEventNpcHandinRepository::PlayerEventNpcHandin> npc_handin;
std::vector<PlayerEventNpcHandinEntriesRepository::PlayerEventNpcHandinEntries> npc_handin_entries;
std::vector<PlayerEventTradeRepository::PlayerEventTrade> trade;
std::vector<PlayerEventTradeEntriesRepository::PlayerEventTradeEntries> trade_entries;
std::vector<PlayerEventSpeechRepository::PlayerEventSpeech> speech;
std::vector<PlayerEventKilledNpcRepository::PlayerEventKilledNpc> killed_npc;
std::vector<PlayerEventKilledNamedNpcRepository::PlayerEventKilledNamedNpc> killed_named_npc;
std::vector<PlayerEventKilledRaidNpcRepository::PlayerEventKilledRaidNpc> killed_raid_npc;
std::vector<PlayerEventAaPurchaseRepository::PlayerEventAaPurchase> aa_purchase;
};
static PlayerEventLogs* Instance()
{
static PlayerEventLogs instance;
return &instance;
}
private: private:
struct EtlSettings {
bool enabled;
std::string table_name;
int64 next_id;
};
Database *m_database; // reference to database Database *m_database; // reference to database
PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{}; PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{};
@@ -118,10 +69,7 @@ private:
static std::unique_ptr<ServerPacket> static std::unique_ptr<ServerPacket>
BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e); BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e);
std::map<PlayerEvent::EventType, EtlSettings> m_etl_settings{};
// timers // timers
Timer m_database_ping_timer; // database ping timer
Timer m_process_batch_events_timer; // events processing timer Timer m_process_batch_events_timer; // events processing timer
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
@@ -130,9 +78,8 @@ private:
void ProcessBatchQueue(); void ProcessBatchQueue();
void ProcessRetentionTruncation(); void ProcessRetentionTruncation();
void SetSettingsDefaults(); void SetSettingsDefaults();
public:
std::map<PlayerEvent::EventType, EtlSettings> &GetEtlSettings() { return m_etl_settings;}
}; };
extern PlayerEventLogs player_event_logs;
#endif //EQEMU_PLAYER_EVENT_LOGS_H #endif //EQEMU_PLAYER_EVENT_LOGS_H
File diff suppressed because it is too large Load Diff
-326
View File
@@ -1,326 +0,0 @@
#include "evolving_items.h"
#include "item_instance.h"
#include "events/player_event_logs.h"
#include "repositories/character_evolving_items_repository.h"
EvolvingItemsManager::EvolvingItemsManager()
{
m_db = nullptr;
m_content_db = nullptr;
}
void EvolvingItemsManager::LoadEvolvingItems() const
{
auto const &results = ItemsEvolvingDetailsRepository::All(*m_content_db);
if (results.empty()) {
return;
}
std::ranges::transform(
results.begin(),
results.end(),
std::inserter(
EvolvingItemsManager::Instance()->GetEvolvingItemsCache(),
EvolvingItemsManager::Instance()->GetEvolvingItemsCache().end()
),
[](const ItemsEvolvingDetailsRepository::ItemsEvolvingDetails &x) {
return std::make_pair(x.item_id, x);
}
);
}
void EvolvingItemsManager::SetDatabase(Database *db)
{
m_db = db;
}
void EvolvingItemsManager::SetContentDatabase(Database *db)
{
m_content_db = db;
}
double EvolvingItemsManager::CalculateProgression(const uint64 current_amount, const uint32 item_id)
{
if (!EvolvingItemsManager::Instance()->GetEvolvingItemsCache().contains(item_id)) {
return 0;
}
return EvolvingItemsManager::Instance()->GetEvolvingItemsCache().at(item_id).required_amount > 0
? static_cast<double>(current_amount)
/ static_cast<double>(EvolvingItemsManager::Instance()->GetEvolvingItemsCache().at(item_id).required_amount) * 100
: 0;
}
void EvolvingItemsManager::DoLootChecks(const uint32 char_id, const uint16 slot_id, const EQ::ItemInstance &inst) const
{
if (!inst) {
return;
}
inst.SetEvolveEquipped(false);
if (inst.IsEvolving() && slot_id <= EQ::invslot::EQUIPMENT_END && slot_id >= EQ::invslot::EQUIPMENT_BEGIN) {
inst.SetEvolveEquipped(true);
}
if (!inst.IsEvolving()) {
return;
}
if (!inst.GetEvolveUniqueID()) {
auto e = CharacterEvolvingItemsRepository::NewEntity();
e.character_id = char_id;
e.item_id = inst.GetID();
e.equipped = inst.GetEvolveEquipped();
e.final_item_id = EvolvingItemsManager::Instance()->GetFinalItemID(inst);
auto r = CharacterEvolvingItemsRepository::InsertOne(*m_db, e);
e.id = r.id;
inst.SetEvolveUniqueID(e.id);
inst.SetEvolveCharID(e.character_id);
inst.SetEvolveItemID(e.item_id);
inst.SetEvolveFinalItemID(e.final_item_id);
return;
}
CharacterEvolvingItemsRepository::SetEquipped(*m_db, inst.GetEvolveUniqueID(), inst.GetEvolveEquipped());
}
uint32 EvolvingItemsManager::GetFinalItemID(const EQ::ItemInstance &inst) const
{
if (!inst) {
return 0;
}
const auto start_iterator = std::ranges::find_if(
EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cbegin(),
EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cend(),
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
return a.second.item_evo_id == inst.GetEvolveLoreID();
}
);
if (start_iterator == std::end(EvolvingItemsManager::Instance()->GetEvolvingItemsCache())) {
return 0;
}
const auto final_id = std::ranges::max_element(
start_iterator,
EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cend(),
[&](
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a,
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &b
) {
return a.second.item_evo_id == b.second.item_evo_id &&
a.second.item_evolve_level < b.second.item_evolve_level;
}
);
return final_id->first;
}
uint32 EvolvingItemsManager::GetNextEvolveItemID(const EQ::ItemInstance &inst) const
{
if (!inst) {
return 0;
}
int8 const current_level = inst.GetEvolveLvl();
const auto iterator = std::ranges::find_if(
EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cbegin(),
EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cend(),
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
return a.second.item_evo_id == inst.GetEvolveLoreID() &&
a.second.item_evolve_level == current_level + 1;
}
);
if (iterator == std::end(EvolvingItemsManager::Instance()->GetEvolvingItemsCache())) {
return 0;
}
return iterator->first;
}
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails EvolvingItemsManager::GetEvolveItemDetails(const uint64 unique_id)
{
if (GetEvolvingItemsCache().contains(unique_id)) {
return GetEvolvingItemsCache().at(unique_id);
}
return ItemsEvolvingDetailsRepository::NewEntity();
}
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> EvolvingItemsManager::GetEvolveIDItems(
const uint32 evolve_id
)
{
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> e{};
for (auto const &[key, value]: GetEvolvingItemsCache()) {
if (value.item_evo_id == evolve_id) {
e.push_back(value);
}
}
std::ranges::sort(
e.begin(),
e.end(),
[&](
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails const &a,
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails const &b
) {
return a.item_evolve_level < b.item_evolve_level;
}
);
return e;
}
uint64 EvolvingItemsManager::GetTotalEarnedXP(const EQ::ItemInstance &inst)
{
if (!inst) {
return 0;
}
uint64 xp = inst.GetEvolveCurrentAmount();
auto evolve_id_item_cache = GetEvolveIDItems(inst.GetEvolveLoreID());
auto current_level = inst.GetEvolveLvl();
for (auto const &i: evolve_id_item_cache) {
if (i.item_evolve_level < current_level) {
xp += i.required_amount;
}
}
return xp;
}
EvolveGetNextItem EvolvingItemsManager::GetNextItemByXP(const EQ::ItemInstance &inst_in, const int64 in_xp)
{
EvolveGetNextItem ets{};
if (!inst_in) {
return ets;
}
const auto evolve_items = GetEvolveIDItems(inst_in.GetEvolveLoreID());
uint32 max_transfer_level = 0;
int64 xp = in_xp;
for (auto const &e: evolve_items) {
if (e.item_evolve_level < inst_in.GetEvolveLvl()) {
continue;
}
int64 have = 0;
if (e.item_evolve_level == inst_in.GetEvolveLvl()) {
have = inst_in.GetEvolveCurrentAmount();
}
const auto required = e.required_amount;
const int64 need = required - have;
const int64 balance = xp - need;
if (balance <= 0) {
ets.new_current_amount = have + xp;
ets.new_item_id = e.item_id;
ets.from_current_amount = 0;
ets.max_transfer_level = max_transfer_level;
return ets;
}
xp = balance;
max_transfer_level += 1;
ets.new_current_amount = required;
ets.new_item_id = e.item_id;
ets.from_current_amount = balance - required;
ets.max_transfer_level = max_transfer_level;
}
return ets;
}
EvolveTransfer EvolvingItemsManager::DetermineTransferResults(
const EQ::ItemInstance &inst_from,
const EQ::ItemInstance &inst_to
)
{
EvolveTransfer ets{};
if (!inst_from || !inst_to) {
return ets;
}
auto evolving_details_inst_from = EvolvingItemsManager::Instance()->GetEvolveItemDetails(inst_from.GetID());
auto evolving_details_inst_to = EvolvingItemsManager::Instance()->GetEvolveItemDetails(inst_to.GetID());
if (!evolving_details_inst_from.id || !evolving_details_inst_to.id) {
return ets;
}
if (evolving_details_inst_from.type == evolving_details_inst_to.type) {
uint32 compatibility = 0;
uint64 xp = 0;
if (evolving_details_inst_from.sub_type == evolving_details_inst_to.sub_type) {
compatibility = 100;
}
else {
compatibility = 30;
}
xp = EvolvingItemsManager::Instance()->GetTotalEarnedXP(inst_from) * compatibility / 100;
auto results = EvolvingItemsManager::Instance()->GetNextItemByXP(inst_to, xp);
ets.item_from_id = EvolvingItemsManager::Instance()->GetFirstItemInLoreGroup(inst_from.GetEvolveLoreID());
ets.item_from_current_amount = results.from_current_amount;
ets.item_to_id = results.new_item_id;
ets.item_to_current_amount = results.new_current_amount;
ets.compatibility = compatibility;
ets.max_transfer_level = results.max_transfer_level;
}
return ets;
}
uint32 EvolvingItemsManager::GetFirstItemInLoreGroup(const uint32 lore_id)
{
for (auto const &[key, value]: GetEvolvingItemsCache()) {
if (value.item_evo_id == lore_id && value.item_evolve_level == 1) {
return key;
}
}
return 0;
}
uint32 EvolvingItemsManager::GetFirstItemInLoreGroupByItemID(const uint32 item_id)
{
for (auto const &[key, value]: GetEvolvingItemsCache()) {
if (value.item_id == item_id) {
for (auto const &[key2, value2]: GetEvolvingItemsCache()) {
if (value2.item_evo_id == value.item_evo_id && value2.item_evolve_level == 1) {
return key;
}
}
}
}
return 0;
}
void EvolvingItemsManager::LoadPlayerEvent(const EQ::ItemInstance &inst, PlayerEvent::EvolveItem &e)
{
if (!inst) {
return;
}
e.item_id = inst.GetID();
e.item_name = inst.GetItem() ? inst.GetItem()->Name : std::string();
e.level = inst.GetEvolveLvl();
e.progression = inst.GetEvolveProgression();
e.unique_id = inst.GetEvolveUniqueID();
}
-70
View File
@@ -1,70 +0,0 @@
#ifndef EVOLVING_H
#define EVOLVING_H
#include "shareddb.h"
#include "events/player_events.h"
#include "repositories/items_evolving_details_repository.h"
namespace EQ {
class ItemInstance;
}
namespace EvolvingItems {
namespace Actions {
constexpr int8 UPDATE_ITEMS = 0;
constexpr int8 TRANSFER_WINDOW_OPEN = 1;
constexpr int8 TRANSFER_WINDOW_DETAILS = 2;
constexpr int8 TRANSFER_XP = 3;
constexpr int8 FINAL_RESULT = 4;
}
namespace Types {
constexpr int8 AMOUNT_OF_EXP = 1;
constexpr int8 NUMBER_OF_KILLS = 2;
constexpr int8 SPECIFIC_MOB_RACE = 3;
constexpr int8 SPECIFIC_ZONE_ID = 4;
}
namespace SubTypes {
constexpr int8 ALL_EXP = 0;
constexpr int8 SOLO_EXP = 1;
constexpr int8 GROUP_EXP = 2;
constexpr int8 RAID_EXP = 3;
}
}
class EvolvingItemsManager
{
public:
EvolvingItemsManager();
void SetDatabase(Database *db);
void SetContentDatabase(Database *db);
void LoadEvolvingItems() const;
void DoLootChecks(uint32 char_id, uint16 slot_id, const EQ::ItemInstance &inst) const;
uint32 GetFinalItemID(const EQ::ItemInstance &inst) const;
uint32 GetNextEvolveItemID(const EQ::ItemInstance &inst) const;
uint32 GetFirstItemInLoreGroup(uint32 lore_id);
uint32 GetFirstItemInLoreGroupByItemID(uint32 item_id);
uint64 GetTotalEarnedXP(const EQ::ItemInstance &inst);
static double CalculateProgression(uint64 current_amount, uint32 item_id);
static void LoadPlayerEvent(const EQ::ItemInstance &inst, PlayerEvent::EvolveItem &e);
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails GetEvolveItemDetails(uint64 id);
EvolveTransfer DetermineTransferResults(const EQ::ItemInstance& inst_from, const EQ::ItemInstance& inst_to);
EvolveGetNextItem GetNextItemByXP(const EQ::ItemInstance &inst_in, int64 in_xp);
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails>& GetEvolvingItemsCache() { return m_evolving_items_cache; }
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> GetEvolveIDItems(uint32 evolve_id);
static EvolvingItemsManager* Instance()
{
static EvolvingItemsManager instance;
return &instance;
}
private:
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> m_evolving_items_cache;
Database * m_db;
Database * m_content_db;
};
#endif //EVOLVING_H
+101
View File
@@ -0,0 +1,101 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "expedition_lockout_timer.h"
#include "../common/strings.h"
#include "../common/rulesys.h"
#include "../common/util/uuid.h"
#include <fmt/format.h>
const char* const DZ_REPLAY_TIMER_NAME = "Replay Timer"; // see December 14, 2016 patch notes
ExpeditionLockoutTimer::ExpeditionLockoutTimer(
std::string expedition_uuid, std::string expedition_name,
std::string event_name, uint64_t expire_time, uint32_t duration
) :
m_expedition_uuid{std::move(expedition_uuid)},
m_expedition_name{std::move(expedition_name)},
m_event_name{std::move(event_name)},
m_expire_time(std::chrono::system_clock::from_time_t(expire_time)),
m_duration(duration)
{
if (m_event_name == DZ_REPLAY_TIMER_NAME)
{
m_is_replay_timer = true;
}
}
ExpeditionLockoutTimer ExpeditionLockoutTimer::CreateLockout(
const std::string& expedition_name, const std::string& event_name, uint32_t seconds, std::string uuid)
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
if (uuid.empty())
{
uuid = EQ::Util::UUID::Generate().ToString();
}
ExpeditionLockoutTimer lockout{uuid, expedition_name, event_name, 0, seconds};
lockout.Reset(); // sets expire time
return lockout;
}
uint32_t ExpeditionLockoutTimer::GetSecondsRemaining() const
{
auto now = std::chrono::system_clock::now();
if (m_expire_time > now)
{
auto remaining = m_expire_time - now;
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>(remaining).count());
}
return 0;
}
ExpeditionLockoutTimer::DaysHoursMinutes ExpeditionLockoutTimer::GetDaysHoursMinutesRemaining() const
{
auto seconds = GetSecondsRemaining();
return ExpeditionLockoutTimer::DaysHoursMinutes{
fmt::format_int(seconds / 86400).str(), // days
fmt::format_int((seconds / 3600) % 24).str(), // hours
fmt::format_int((seconds / 60) % 60).str() // minutes
};
}
bool ExpeditionLockoutTimer::IsSameLockout(const ExpeditionLockoutTimer& compare_lockout) const
{
return compare_lockout.IsSameLockout(GetExpeditionName(), GetEventName());
}
bool ExpeditionLockoutTimer::IsSameLockout(
const std::string& expedition_name, const std::string& event_name) const
{
return GetExpeditionName() == expedition_name && GetEventName() == event_name;
}
void ExpeditionLockoutTimer::AddLockoutTime(int seconds)
{
seconds = static_cast<uint32_t>(seconds * RuleR(Expedition, LockoutDurationMultiplier));
auto new_duration = std::max(0, static_cast<int>(m_duration.count()) + seconds);
auto start_time = m_expire_time - m_duration;
m_duration = std::chrono::seconds(new_duration);
m_expire_time = start_time + m_duration;
}
+76
View File
@@ -0,0 +1,76 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2020 EQEmulator Development Team (https://github.com/EQEmu/Server)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY except by those people which sell it, which
* are required to give you total support for your newly bought product;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef EXPEDITION_LOCKOUT_TIMER_H
#define EXPEDITION_LOCKOUT_TIMER_H
#include <chrono>
#include <string>
extern const char* const DZ_REPLAY_TIMER_NAME;
class ExpeditionLockoutTimer
{
public:
ExpeditionLockoutTimer() = default;
ExpeditionLockoutTimer(
std::string expedition_uuid, std::string expedition_name,
std::string event_name, uint64_t expire_time, uint32_t duration);
static ExpeditionLockoutTimer CreateLockout(
const std::string& expedition_name, const std::string& event_name,
uint32_t seconds, std::string uuid = {});
struct DaysHoursMinutes
{
std::string days;
std::string hours;
std::string mins;
};
void AddLockoutTime(int seconds);
uint32_t GetDuration() const { return static_cast<uint32_t>(m_duration.count()); }
uint64_t GetExpireTime() const { return std::chrono::system_clock::to_time_t(m_expire_time); }
uint64_t GetStartTime() const { return std::chrono::system_clock::to_time_t(m_expire_time - m_duration); }
uint32_t GetSecondsRemaining() const;
DaysHoursMinutes GetDaysHoursMinutesRemaining() const;
const std::string& GetExpeditionName() const { return m_expedition_name; }
const std::string& GetExpeditionUUID() const { return m_expedition_uuid; }
const std::string& GetEventName() const { return m_event_name; }
bool IsExpired() const { return GetSecondsRemaining() == 0; }
bool IsFromExpedition(const std::string& uuid) const { return uuid == m_expedition_uuid; }
bool IsReplayTimer() const { return m_is_replay_timer; }
bool IsSameLockout(const ExpeditionLockoutTimer& compare_lockout) const;
bool IsSameLockout(const std::string& expedition_name, const std::string& event_name) const;
void Reset() { m_expire_time = std::chrono::system_clock::now() + m_duration; }
void SetDuration(uint32_t seconds) { m_duration = std::chrono::seconds(seconds); }
void SetExpireTime(uint64_t expire_time) { m_expire_time = std::chrono::system_clock::from_time_t(expire_time); }
void SetUUID(const std::string& uuid) { m_expedition_uuid = uuid; }
private:
bool m_is_replay_timer = false;
std::string m_expedition_uuid; // expedition received in
std::string m_expedition_name;
std::string m_event_name;
std::chrono::seconds m_duration;
std::chrono::time_point<std::chrono::system_clock> m_expire_time;
};
#endif
+13 -12
View File
@@ -39,7 +39,6 @@
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
#include <sys/stat.h> #include <sys/stat.h>
#include <vector>
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -91,21 +90,23 @@ std::string File::GetCwd()
FileContentsResult File::GetContents(const std::string &file_name) FileContentsResult File::GetContents(const std::string &file_name)
{ {
std::ifstream f(file_name, std::ios::in | std::ios::binary); std::string error;
if (!f) { std::ifstream f;
return { .error = fmt::format("Couldn't open file [{}]", file_name) }; f.open(file_name);
} std::string line;
constexpr size_t CHUNK_SIZE = 4096; // Read 4KB chunks
std::string lines; std::string lines;
std::vector<char> buffer(CHUNK_SIZE); if (f.is_open()) {
while (f) {
while (f.read(buffer.data(), CHUNK_SIZE) || f.gcount() > 0) { std::getline(f, line);
lines.append(buffer.data(), f.gcount()); lines += line + "\n";
}
}
else {
error = fmt::format("Couldn't open file [{}]", file_name);
} }
return FileContentsResult{ return FileContentsResult{
.contents = lines, .contents = lines,
.error = {} .error = error,
}; };
} }
+17 -19
View File
@@ -547,54 +547,52 @@ uint32 BaseGuildManager::UpdateDbCreateGuild(std::string name, uint32 leader)
bool BaseGuildManager::UpdateDbDeleteGuild(uint32 guild_id, bool local_delete, bool db_delete) bool BaseGuildManager::UpdateDbDeleteGuild(uint32 guild_id, bool local_delete, bool db_delete)
{ {
auto const where_filter = fmt::format("guild_id = {}", guild_id);
auto const bank_items = GuildBankRepository::GetWhere(*m_db, where_filter);
if (local_delete) { if (local_delete) {
auto where_filter = fmt::format("guildid = {}", guild_id);
auto bank_items = GuildBankRepository::GetWhere(*m_db, where_filter);
if (!bank_items.empty()) { if (!bank_items.empty()) {
LogError( LogError(
"Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.",
"again.",
guild_id, guild_id,
bank_items.size() bank_items.size()
); );
LogGuilds( LogGuilds(
"Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.",
"again.",
guild_id, guild_id,
bank_items.size() bank_items.size()
); );
return false; return false;
} }
else {
auto res = m_guilds.find(guild_id); std::map<uint32, GuildInfo *>::iterator res;
res = m_guilds.find(guild_id);
if (res != m_guilds.end()) { if (res != m_guilds.end()) {
safe_delete(res->second); delete res->second;
m_guilds.erase(res); m_guilds.erase(res);
LogGuilds("Deleted guild [{}] from memory", guild_id); LogGuilds("Deleted guild [{}] from memory", guild_id);
// Does this need to be sent to world? //Does this need to be sent to world?
}
} }
} }
if (db_delete) { if (db_delete) {
auto where_filter = fmt::format("guildid = {}", guild_id);
auto bank_items = GuildBankRepository::GetWhere(*m_db, where_filter);
if (!bank_items.empty()) { if (!bank_items.empty()) {
LogError( LogError(
"Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.",
"again.",
guild_id, guild_id,
bank_items.size() bank_items.size()
); );
LogGuilds( LogGuilds(
"Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try " "Attempt to delete guild id [{}] that still has [{}] items in the bank. Please remove them and try again.",
"again.",
guild_id, guild_id,
bank_items.size() bank_items.size()
); );
return false; return false;
} }
else {
auto where_filter = fmt::format("guild_id = {}", guild_id);
GuildTributesRepository::DeleteOne(*m_db, guild_id); GuildTributesRepository::DeleteOne(*m_db, guild_id);
GuildsRepository::DeleteOne(*m_db, guild_id); GuildsRepository::DeleteOne(*m_db, guild_id);
GuildRanksRepository::DeleteWhere(*m_db, where_filter); GuildRanksRepository::DeleteWhere(*m_db, where_filter);
@@ -602,7 +600,7 @@ bool BaseGuildManager::UpdateDbDeleteGuild(uint32 guild_id, bool local_delete, b
GuildMembersRepository::DeleteWhere(*m_db, where_filter); GuildMembersRepository::DeleteWhere(*m_db, where_filter);
LogGuilds("Deleted guild [{}] from the database", guild_id); LogGuilds("Deleted guild [{}] from the database", guild_id);
} }
}
return true; return true;
} }
File diff suppressed because it is too large Load Diff
+11 -14
View File
@@ -57,8 +57,6 @@ public:
inline std::list<EQ::ItemInstance*>::const_iterator cbegin() { return m_list.cbegin(); } inline std::list<EQ::ItemInstance*>::const_iterator cbegin() { return m_list.cbegin(); }
inline std::list<EQ::ItemInstance*>::const_iterator cend() { return m_list.cend(); } inline std::list<EQ::ItemInstance*>::const_iterator cend() { return m_list.cend(); }
inline std::list<EQ::ItemInstance*>::iterator begin() { return m_list.begin(); }
inline std::list<EQ::ItemInstance*>::iterator end() { return m_list.end(); }
inline int size() { return static_cast<int>(m_list.size()); } // TODO: change to size_t inline int size() { return static_cast<int>(m_list.size()); } // TODO: change to size_t
inline bool empty() { return m_list.empty(); } inline bool empty() { return m_list.empty(); }
@@ -149,13 +147,13 @@ namespace EQ
bool HasItemEquippedByID(uint32 item_id); bool HasItemEquippedByID(uint32 item_id);
// Check how many of a specific item the player has equipped by Item ID // Check how many of a specific item the player has equipped by Item ID
uint32 CountItemEquippedByID(uint32 item_id); int CountItemEquippedByID(uint32 item_id);
// Check if player has a specific augment equipped by Item ID // Check if player has a specific augment equipped by Item ID
bool HasAugmentEquippedByID(uint32 item_id); bool HasAugmentEquippedByID(uint32 item_id);
// Check how many of a specific augment the player has equipped by Item ID // Check how many of a specific augment the player has equipped by Item ID
uint32 CountAugmentEquippedByID(uint32 item_id); int CountAugmentEquippedByID(uint32 item_id);
// Get a list of augments from a specific slot ID // Get a list of augments from a specific slot ID
std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id); std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id);
@@ -178,8 +176,8 @@ namespace EQ
// Locate an available inventory slot // Locate an available inventory slot
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false); int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = invslot::GENERAL_BEGIN, uint8 bag_start = invbag::SLOT_BEGIN); int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = invslot::GENERAL_BEGIN, uint8 bag_start = invbag::SLOT_BEGIN);
std::vector<int16> FindAllFreeSlotsThatFitItem(const EQ::ItemData *inst);
int16 FindFirstFreeSlotThatFitsItem(const EQ::ItemData *inst); int16 FindFirstFreeSlotThatFitsItem(const EQ::ItemData *inst);
int16 FindFirstFreeSlotThatFitsItemWithStacking(ItemInstance *inst) const;
// Calculate slot_id for an item within a bag // Calculate slot_id for an item within a bag
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
@@ -201,25 +199,26 @@ namespace EQ
uint8 FindBrightestLightType(); uint8 FindBrightestLightType();
void dumpEntireInventory();
void dumpWornItems();
void dumpInventory();
void dumpBankItems();
void dumpSharedBankItems();
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, const std::string& value); void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, const std::string& value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, int value); void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, float value); void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, float value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value); void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value);
std::string GetCustomItemData(int16 slot_id, const std::string& identifier); std::string GetCustomItemData(int16 slot_id, const std::string& identifier);
static const int GetItemStatValue(uint32 item_id, const std::string& identifier); static const int GetItemStatValue(uint32 item_id, const std::string& identifier);
std::map<int16, ItemInstance*>& GetWorn() { return m_worn; }
std::map<int16, ItemInstance*>& GetPersonal() { return m_inv; }
int16 HasEvolvingItem(uint64 evolve_unique_id, uint8 quantity, uint8 where);
inline int16 PushItem(int16 slot_id, ItemInstance* inst) { return _PutItem(slot_id, inst); }
protected: protected:
/////////////////////////////// ///////////////////////////////
// Protected Methods // Protected Methods
/////////////////////////////// ///////////////////////////////
int GetSlotByItemInstCollection(const std::map<int16, ItemInstance*> &collection, ItemInstance *inst); int GetSlotByItemInstCollection(const std::map<int16, ItemInstance*> &collection, ItemInstance *inst);
void dumpItemCollection(const std::map<int16, ItemInstance*> &collection);
void dumpBagContents(ItemInstance *inst, std::map<int16, ItemInstance*>::const_iterator *it);
// Retrieves item within an inventory bucket // Retrieves item within an inventory bucket
ItemInstance* _GetItem(const std::map<int16, ItemInstance*>& bucket, int16 slot_id) const; ItemInstance* _GetItem(const std::map<int16, ItemInstance*>& bucket, int16 slot_id) const;
@@ -234,8 +233,6 @@ namespace EQ
int16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity); int16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity);
int16 _HasItemByLoreGroup(std::map<int16, ItemInstance*>& bucket, uint32 loregroup); int16 _HasItemByLoreGroup(std::map<int16, ItemInstance*>& bucket, uint32 loregroup);
int16 _HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup); int16 _HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup);
int16 _HasEvolvingItem(std::map<int16, ItemInstance*>& bucket, uint64 evolve_unique_id, uint8 quantity);
int16 _HasEvolvingItem(ItemInstQueue& iqueue, uint64 evolve_unique_id, uint8 quantity);
// Player inventory // Player inventory
-81
View File
@@ -259,84 +259,3 @@ bool IpUtil::IsIPAddress(const std::string &ip_address)
} }
#include <iostream>
#ifdef _WIN32
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib") // Link against Winsock library
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
#include <iostream>
#include <string>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h> // For inet_pton
#pragma comment(lib, "ws2_32.lib") // Link against Winsock library
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> // For inet_pton
#include <unistd.h>
#endif
bool IpUtil::IsPortInUse(const std::string& ip, int port) {
bool in_use = false;
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed\n";
return true; // Assume in use on failure
}
#endif
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
#ifdef _WIN32
WSACleanup();
#endif
return true; // Assume in use on failure
}
#ifdef _WIN32
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*)&opt, sizeof(opt)); // Windows-specific
#else
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // Linux/macOS
#endif
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
// Convert IP address from string to binary format
if (inet_pton(AF_INET, ip.c_str(), &addr.sin_addr) <= 0) {
std::cerr << "Invalid IP address format: " << ip << std::endl;
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
return true; // Assume in use on failure
}
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
in_use = true; // Bind failed, port is in use
}
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
return in_use;
}
-1
View File
@@ -37,7 +37,6 @@ public:
int port int port
); );
static bool IsIPAddress(const std::string &ip_address); static bool IsIPAddress(const std::string &ip_address);
static bool IsPortInUse(const std::string& ip, int port);
}; };
+1 -1
View File
@@ -55,7 +55,7 @@ namespace EQ {
EQ_EXCEPT("IPC Mutex", "Could not create mutex."); EQ_EXCEPT("IPC Mutex", "Could not create mutex.");
} }
#else #else
std::string final_name = fmt::format("{}/{}.lock", PathManager::Instance()->GetSharedMemoryPath(), name); std::string final_name = fmt::format("{}/{}.lock", path.GetSharedMemoryPath(), name);
#ifdef __DARWIN #ifdef __DARWIN
#if __DARWIN_C_LEVEL < 200809L #if __DARWIN_C_LEVEL < 200809L
-28
View File
@@ -220,34 +220,6 @@ bool EQ::ItemData::IsType1HWeapon() const
return ((ItemType == item::ItemType1HBlunt) || (ItemType == item::ItemType1HSlash) || (ItemType == item::ItemType1HPiercing) || (ItemType == item::ItemTypeMartial)); return ((ItemType == item::ItemType1HBlunt) || (ItemType == item::ItemType1HSlash) || (ItemType == item::ItemType1HPiercing) || (ItemType == item::ItemTypeMartial));
} }
bool EQ::ItemData::IsPetUsable() const
{
if (ItemClass == item::ItemClassBag) {
return true;
}
// if it's a misc item and has slots, it's wearable
// this item type is conflated with many other item types
if (ItemClass == item::ItemTypeMisc && Slots != 0) {
return true;
}
switch (ItemType) {
case item::ItemType1HBlunt:
case item::ItemType1HSlash:
case item::ItemType1HPiercing:
case item::ItemType2HBlunt:
case item::ItemType2HSlash:
case item::ItemTypeMartial:
case item::ItemTypeShield:
case item::ItemTypeArmor:
case item::ItemTypeJewelry:
return true;
default:
return false;
}
}
bool EQ::ItemData::IsType2HWeapon() const bool EQ::ItemData::IsType2HWeapon() const
{ {
return ((ItemType == item::ItemType2HBlunt) || (ItemType == item::ItemType2HSlash) || (ItemType == item::ItemType2HPiercing)); return ((ItemType == item::ItemType2HBlunt) || (ItemType == item::ItemType2HSlash) || (ItemType == item::ItemType2HPiercing));
-1
View File
@@ -550,7 +550,6 @@ namespace EQ
bool IsType1HWeapon() const; bool IsType1HWeapon() const;
bool IsType2HWeapon() const; bool IsType2HWeapon() const;
bool IsTypeShield() const; bool IsTypeShield() const;
bool IsPetUsable() const;
bool IsQuestItem() const; bool IsQuestItem() const;
static bool CheckLoreConflict(const ItemData* l_item, const ItemData* r_item); static bool CheckLoreConflict(const ItemData* l_item, const ItemData* r_item);
+60 -85
View File
@@ -25,7 +25,6 @@
#include "rulesys.h" #include "rulesys.h"
#include "shareddb.h" #include "shareddb.h"
#include "strings.h" #include "strings.h"
#include "evolving_items.h"
//#include "../common/light_source.h" //#include "../common/light_source.h"
@@ -77,10 +76,6 @@ EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
m_color = m_item->Color; m_color = m_item->Color;
} }
if (IsEvolving()) {
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
}
m_SerialNumber = GetNextItemInstSerialNumber(); m_SerialNumber = GetNextItemInstSerialNumber();
} }
@@ -100,10 +95,6 @@ EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges
m_color = 0; m_color = 0;
} }
if (IsEvolving()) {
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
}
m_SerialNumber = GetNextItemInstSerialNumber(); m_SerialNumber = GetNextItemInstSerialNumber();
} }
@@ -155,6 +146,7 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
m_exp = copy.m_exp; m_exp = copy.m_exp;
m_evolveLvl = copy.m_evolveLvl; m_evolveLvl = copy.m_evolveLvl;
m_activated = copy.m_activated;
if (copy.m_scaledItem) { if (copy.m_scaledItem) {
m_scaledItem = new ItemData(*copy.m_scaledItem); m_scaledItem = new ItemData(*copy.m_scaledItem);
@@ -162,7 +154,12 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
m_scaledItem = nullptr; m_scaledItem = nullptr;
} }
m_evolving_details = copy.m_evolving_details; if (copy.m_evolveInfo) {
m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo);
} else {
m_evolveInfo = nullptr;
}
m_scaling = copy.m_scaling; m_scaling = copy.m_scaling;
m_ornamenticon = copy.m_ornamenticon; m_ornamenticon = copy.m_ornamenticon;
m_ornamentidfile = copy.m_ornamentidfile; m_ornamentidfile = copy.m_ornamentidfile;
@@ -177,6 +174,7 @@ EQ::ItemInstance::~ItemInstance()
Clear(); Clear();
safe_delete(m_item); safe_delete(m_item);
safe_delete(m_scaledItem); safe_delete(m_scaledItem);
safe_delete(m_evolveInfo);
} }
// Query item type // Query item type
@@ -574,7 +572,7 @@ EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const
{ {
// Not a Hero Forge item. // Not a Hero Forge item.
if (m_ornament_hero_model == 0) { if (m_ornament_hero_model == 0 || material_slot < 0) {
return 0; return 0;
} }
@@ -906,34 +904,26 @@ bool EQ::ItemInstance::IsSlotAllowed(int16 slot_id) const {
bool EQ::ItemInstance::IsDroppable(bool recurse) const bool EQ::ItemInstance::IsDroppable(bool recurse) const
{ {
if (!m_item) { if (!m_item)
return false; return false;
}
/*if (m_ornamentidfile) // not implemented /*if (m_ornamentidfile) // not implemented
return false;*/ return false;*/
if (m_attuned) { if (m_attuned)
return false; return false;
} /*if (m_item->FVNoDrop != 0) // not implemented
return false;*/
if (RuleI(World, FVNoDropFlag) == FVNoDropFlagRule::Enabled && m_item->FVNoDrop == 0) { if (m_item->NoDrop == 0)
return true;
}
if (m_item->NoDrop == 0) {
return false; return false;
}
if (recurse) { if (recurse) {
for (auto iter: m_contents) { for (auto iter : m_contents) {
if (!iter.second) { if (!iter.second)
continue; continue;
}
if (!iter.second->IsDroppable(recurse)) { if (!iter.second->IsDroppable(recurse))
return false; return false;
} }
} }
}
return true; return true;
} }
@@ -1040,6 +1030,29 @@ void EQ::ItemInstance::ScaleItem() {
m_scaledItem->CharmFileID = 0; // this stops the client from trying to scale the item itself. m_scaledItem->CharmFileID = 0; // this stops the client from trying to scale the item itself.
} }
bool EQ::ItemInstance::EvolveOnAllKills() const {
return (m_evolveInfo && m_evolveInfo->AllKills);
}
int8 EQ::ItemInstance::GetMaxEvolveLvl() const {
if (m_evolveInfo)
return m_evolveInfo->MaxLvl;
else
return 0;
}
uint32 EQ::ItemInstance::GetKillsNeeded(uint8 currentlevel) {
uint32 kills = -1; // default to -1 (max uint32 value) because this value is usually divided by, so we don't want to ever return zero.
if (m_evolveInfo)
if (currentlevel != m_evolveInfo->MaxLvl)
kills = m_evolveInfo->LvlKills[currentlevel - 1];
if (kills == 0)
kills = -1;
return kills;
}
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) { void EQ::ItemInstance::SetTimer(std::string name, uint32 time) {
Timer t(time); Timer t(time);
t.Start(time, false); t.Start(time, false);
@@ -1793,18 +1806,6 @@ std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
return augments; return augments;
} }
std::vector<std::string> EQ::ItemInstance::GetAugmentNames() const
{
std::vector<std::string> augment_names;
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) {
const auto augment = GetAugment(slot_id);
augment_names.push_back(augment ? augment->GetItem()->Name : "");
}
return augment_names;
}
int EQ::ItemInstance::GetItemRegen(bool augments) const int EQ::ItemInstance::GetItemRegen(bool augments) const
{ {
int stat = 0; int stat = 0;
@@ -1950,54 +1951,28 @@ void EQ::ItemInstance::ClearGUIDMap()
{ {
guids.clear(); guids.clear();
} }
//
bool EQ::ItemInstance::TransferOwnership(Database &db, const uint32 to_char_id) const // class EvolveInfo
{ //
if (!to_char_id || !IsEvolving()) { EvolveInfo::EvolveInfo() {
return false; // nothing here yet
}
SetEvolveCharID(to_char_id);
CharacterEvolvingItemsRepository::UpdateCharID(db, GetEvolveUniqueID(), to_char_id);
return true;
} }
uint32 EQ::ItemInstance::GetAugmentEvolveUniqueID(uint8 augment_index) const EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10) {
{ FirstItem = first;
if (!m_item || !m_item->IsClassCommon()) { MaxLvl = max;
return 0; AllKills = allkills;
} LvlKills[0] = L2;
LvlKills[1] = L3;
const auto item = GetItem(augment_index); LvlKills[2] = L4;
if (item) { LvlKills[3] = L5;
return item->GetEvolveUniqueID(); LvlKills[4] = L6;
} LvlKills[5] = L7;
LvlKills[6] = L8;
return 0; LvlKills[7] = L9;
LvlKills[8] = L10;
} }
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) const{ EvolveInfo::~EvolveInfo() {
Timer t(time);
t.Start(time, false);
m_timers[name] = t;
}
void EQ::ItemInstance::SetEvolveEquipped(const bool in) const
{
if (!IsEvolving()) {
return;
}
m_evolving_details.equipped = in;
if (in && !GetTimers().contains("evolve")) {
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
return;
}
if (in) {
GetTimers().at("evolve").SetTimer(RuleI(EvolvingItems, DelayUponEquipping));
return;
}
GetTimers().at("evolve").Disable();
} }
+46 -55
View File
@@ -23,7 +23,6 @@
#ifndef COMMON_ITEM_INSTANCE_H #ifndef COMMON_ITEM_INSTANCE_H
#define COMMON_ITEM_INSTANCE_H #define COMMON_ITEM_INSTANCE_H
#include "evolving_items.h"
class ItemParse; // Parses item packets class ItemParse; // Parses item packets
@@ -35,7 +34,6 @@ class EvolveInfo; // Stores information about an evolving item family
#include "../common/bodytypes.h" #include "../common/bodytypes.h"
#include "../common/deity.h" #include "../common/deity.h"
#include "../common/memory_buffer.h" #include "../common/memory_buffer.h"
#include "../common/repositories/character_evolving_items_repository.h"
#include <map> #include <map>
@@ -207,9 +205,13 @@ namespace EQ
bool IsDroppable(bool recurse = true) const; bool IsDroppable(bool recurse = true) const;
bool IsScaling() const { return m_scaling; } bool IsScaling() const { return m_scaling; }
bool IsEvolving() const { return (m_evolveLvl >= 1); }
uint32 GetExp() const { return m_exp; } uint32 GetExp() const { return m_exp; }
void SetExp(uint32 exp) { m_exp = exp; } void SetExp(uint32 exp) { m_exp = exp; }
void AddExp(uint32 exp) { m_exp += exp; } void AddExp(uint32 exp) { m_exp += exp; }
bool IsActivated() { return m_activated; }
void SetActivated(bool activated) { m_activated = activated; }
int8 GetEvolveLvl() const { return m_evolveLvl; }
void SetScaling(bool v) { m_scaling = v; } void SetScaling(bool v) { m_scaling = v; }
uint32 GetOrnamentationIcon() const { return m_ornamenticon; } uint32 GetOrnamentationIcon() const { return m_ornamenticon; }
void SetOrnamentIcon(uint32 ornament_icon) { m_ornamenticon = ornament_icon; } void SetOrnamentIcon(uint32 ornament_icon) { m_ornamenticon = ornament_icon; }
@@ -224,6 +226,9 @@ namespace EQ
void Initialize(SharedDatabase *db = nullptr); void Initialize(SharedDatabase *db = nullptr);
void ScaleItem(); void ScaleItem();
bool EvolveOnAllKills() const;
int8 GetMaxEvolveLvl() const;
uint32 GetKillsNeeded(uint8 currentlevel);
std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id = slot_id; s.inst = (const void*)this; std::string ser; ser.assign((char*)&s, sizeof(InternalSerializedItem_Struct)); return ser; } std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id = slot_id; s.inst = (const void*)this; std::string ser; ser.assign((char*)&s, sizeof(InternalSerializedItem_Struct)); return ser; }
void Serialize(OutBuffer& ob, int16 slot_id) const { InternalSerializedItem_Struct isi; isi.slot_id = slot_id; isi.inst = (const void*)this; ob.write((const char*)&isi, sizeof(isi)); } void Serialize(OutBuffer& ob, int16 slot_id) const { InternalSerializedItem_Struct isi; isi.slot_id = slot_id; isi.inst = (const void*)this; ob.write((const char*)&isi, sizeof(isi)); }
@@ -231,9 +236,8 @@ namespace EQ
inline int32 GetSerialNumber() const { return m_SerialNumber; } inline int32 GetSerialNumber() const { return m_SerialNumber; }
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; } inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
std::map<std::string, ::Timer>& GetTimers() const { return m_timers; } std::map<std::string, ::Timer>& GetTimers() { return m_timers; }
void SetTimer(std::string name, uint32 time); void SetTimer(std::string name, uint32 time);
void SetTimer(std::string name, uint32 time) const;
void StopTimer(std::string name); void StopTimer(std::string name);
void ClearTimers(); void ClearTimers();
@@ -305,38 +309,9 @@ namespace EQ
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const; int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
uint32 GetItemGuildFavor() const; uint32 GetItemGuildFavor() const;
std::vector<uint32> GetAugmentIDs() const; std::vector<uint32> GetAugmentIDs() const;
std::vector<std::string> GetAugmentNames() const;
static void AddGUIDToMap(uint64 existing_serial_number); static void AddGUIDToMap(uint64 existing_serial_number);
static void ClearGUIDMap(); static void ClearGUIDMap();
// evolving items stuff
CharacterEvolvingItemsRepository::CharacterEvolvingItems &GetEvolvingDetails() const { return m_evolving_details; }
int8 GetEvolveLvl() const { if (GetItem()) { return GetItem()->EvolvingLevel; } return false; }
bool IsEvolving() const { if (GetItem()) { return GetItem()->EvolvingItem; } return false; }
int8 GetMaxEvolveLvl() const { if (GetItem()) { return GetItem()->EvolvingMax; } return false; }
bool GetEvolveActivated() const { return m_evolving_details.activated ? true : false; }
bool GetEvolveEquipped() const { return m_evolving_details.equipped ? true : false; }
double GetEvolveProgression() const { return m_evolving_details.progression; }
uint64 GetEvolveUniqueID() const { return m_evolving_details.id; }
uint32 GetEvolveCharID() const { return m_evolving_details.character_id; }
uint32 GetEvolveItemID() const { return m_evolving_details.item_id; }
uint32 GetEvolveLoreID() const { if (GetItem()) { return GetItem()->EvolvingID; } return false; }
uint64 GetEvolveCurrentAmount() const { return m_evolving_details.current_amount; }
uint32 GetEvolveFinalItemID() const { return m_evolving_details.final_item_id; }
uint32 GetAugmentEvolveUniqueID(uint8 augment_index) const;
void SetEvolveEquipped(const bool in) const;
void SetEvolveActivated(const bool in) const { m_evolving_details.activated = in; }
void SetEvolveProgression(const double in) const { m_evolving_details.progression = in; }
void SetEvolveUniqueID(const uint64 in) const { m_evolving_details.id = in; }
void SetEvolveCharID(const uint32 in) const { m_evolving_details.character_id = in; }
void SetEvolveItemID(const uint32 in) const { m_evolving_details.item_id = in; }
void SetEvolveCurrentAmount(const uint64 in) const { m_evolving_details.current_amount = in; }
void SetEvolveAddToCurrentAmount(const uint64 in) const { m_evolving_details.current_amount += in; }
void SetEvolveFinalItemID(const uint32 in) const { m_evolving_details.final_item_id = in; }
bool TransferOwnership(Database& db, const uint32 to_char_id) const;
void CalculateEvolveProgression() const { m_evolving_details.progression = EvolvingItemsManager::Instance()->CalculateProgression(GetEvolveCurrentAmount(), GetID()); }
protected: protected:
////////////////////////// //////////////////////////
// Protected Members // Protected Members
@@ -348,32 +323,48 @@ namespace EQ
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; } void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
ItemInstTypes m_use_type{ItemInstNormal};// Usage type for item ItemInstTypes m_use_type {ItemInstNormal}; // Usage type for item
const ItemData * m_item{nullptr}; // Ptr to item data const ItemData* m_item {nullptr}; // Ptr to item data
int16 m_charges{0}; // # of charges for chargeable items int16 m_charges {0}; // # of charges for chargeable items
uint32 m_price{0}; // Bazaar /trader price uint32 m_price {0}; // Bazaar /trader price
uint32 m_color{0}; uint32 m_color {0};
uint32 m_merchantslot{0}; uint32 m_merchantslot {0};
int16 m_currentslot{0}; int16 m_currentslot {0};
bool m_attuned{false}; bool m_attuned {false};
int32 m_merchantcount{1};//number avaliable on the merchant, -1=unlimited int32 m_merchantcount {1}; //number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber{0}; // Unique identifier for this instance of an item. Needed for Bazaar. int32 m_SerialNumber {0}; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp{0}; uint32 m_exp {0};
int8 m_evolveLvl{0}; int8 m_evolveLvl {0};
ItemData * m_scaledItem{nullptr}; bool m_activated {false};
bool m_scaling{false}; ItemData* m_scaledItem {nullptr};
uint32 m_ornamenticon{0}; ::EvolveInfo* m_evolveInfo {nullptr};
uint32 m_ornamentidfile{0}; bool m_scaling {false};
uint32 m_new_id_file{0}; uint32 m_ornamenticon {0};
uint32 m_ornament_hero_model{0}; uint32 m_ornamentidfile {0};
uint32 m_recast_timestamp{0}; uint32 m_new_id_file {0};
int m_task_delivered_count{0}; uint32 m_ornament_hero_model {0};
mutable CharacterEvolvingItemsRepository::CharacterEvolvingItems m_evolving_details{}; uint32 m_recast_timestamp {0};
int m_task_delivered_count {0};
// Items inside of this item (augs or contents) {}; // Items inside of this item (augs or contents) {};
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9 std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9
std::map<std::string, std::string> m_custom_data {}; std::map<std::string, std::string> m_custom_data {};
mutable std::map<std::string, ::Timer> m_timers {}; std::map<std::string, ::Timer> m_timers {};
}; };
} }
class EvolveInfo {
public:
friend class EQ::ItemInstance;
//temporary
uint16 LvlKills[9];
uint32 FirstItem;
uint8 MaxLvl;
bool AllKills;
EvolveInfo();
EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10);
~EvolveInfo();
};
#endif /*COMMON_ITEM_INSTANCE_H*/ #endif /*COMMON_ITEM_INSTANCE_H*/
-1
View File
@@ -25,7 +25,6 @@ struct LootItem {
uint16 trivial_max_level; uint16 trivial_max_level;
uint16 npc_min_level; uint16 npc_min_level;
uint16 npc_max_level; uint16 npc_max_level;
uint32 lootdrop_id; // required for zone state referencing
}; };
typedef std::list<LootItem*> LootItems; typedef std::list<LootItem*> LootItems;
-220
View File
@@ -1,220 +0,0 @@
#ifndef EQEMU_KSM_HPP
#define EQEMU_KSM_HPP
#include "../eqemu_logsys.h"
#include <iostream>
#include <vector>
#include <cstring>
#ifdef _WIN32
#include <malloc.h> // For _aligned_malloc, _aligned_free
#include <windows.h>
#else
#include <sys/mman.h> // For madvise
#include <unistd.h> // For sysconf, sbrk
#endif
// Page-aligned allocator for std::vector
template <typename T>
class PageAlignedAllocator {
public:
using value_type = T;
PageAlignedAllocator() noexcept = default;
template <typename U>
PageAlignedAllocator(const PageAlignedAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
void* ptr = nullptr;
size_t size = n * sizeof(T);
#ifdef _WIN32
// Simply allocate memory without alignment
ptr = malloc(size);
if (!ptr) throw std::bad_alloc();
#else
size_t alignment = getPageSize(); // Get the system's page size
if (posix_memalign(&ptr, alignment, size) != 0) {
throw std::bad_alloc();
}
#endif
return static_cast<T*>(ptr);
}
void deallocate(T* p, std::size_t) noexcept {
free(p);
}
private:
size_t getPageSize() const
{
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
return sysInfo.dwPageSize; // Page size in bytes
#else
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
#endif
};
};
template <typename T, typename U>
bool operator==(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
return true;
}
template <typename T, typename U>
bool operator!=(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
return false;
}
// Kernel Samepage Merging (KSM) functionality
namespace KSM {
#ifdef _WIN32
// Windows-specific placeholder functions (no-op)
inline void CheckPageAlignment(void* ptr) {
}
inline void* AllocatePageAligned(size_t size) {
return memset(malloc(size), 0, size);
}
inline void MarkMemoryForKSM(void* start, size_t size) {
}
inline void AlignHeapToPageBoundary() {
}
inline void* MarkHeapStart() {
return nullptr;
}
inline size_t MeasureHeapUsage(void* start) {
return 0;
}
#else
// Linux-specific functionality
inline void CheckPageAlignment(void* ptr) {
size_t page_size = sysconf(_SC_PAGESIZE);
if (reinterpret_cast<uintptr_t>(ptr) % page_size == 0) {
LogKSMDetail("Memory is page-aligned [{}]", ptr);
} else {
LogKSMDetail("Memory is NOT page-aligned [{}]", ptr);
}
}
inline void* AllocatePageAligned(size_t size) {
size_t page_size = sysconf(_SC_PAGESIZE);
void* aligned_ptr = nullptr;
if (posix_memalign(&aligned_ptr, page_size, size) != 0) {
LogKSM("Failed to allocate page-aligned memory on Linux. page_size [{}] size [{}] bytes", page_size, size);
}
std::memset(aligned_ptr, 0, size);
return aligned_ptr;
}
inline void MarkMemoryForKSM(void* start, size_t size) {
if (madvise(start, size, MADV_MERGEABLE) == 0) {
LogKSM("Marked memory for KSM | start [{}] size [{}] bytes", start, size);
} else {
perror("madvise failed");
}
}
inline void AlignHeapToPageBoundary() {
size_t page_size = sysconf(_SC_PAGESIZE);
if (page_size == 0) {
LogKSM("Failed to retrieve page size SC_PAGESIZE [{}]", page_size);
return;
}
void* current_break = sbrk(0);
if (current_break == (void*)-1) {
LogKSM("Failed to retrieve the current program break");
return;
}
uintptr_t current_address = reinterpret_cast<uintptr_t>(current_break);
size_t misalignment = current_address % page_size;
if (misalignment != 0) {
size_t adjustment = page_size - misalignment;
if (sbrk(adjustment) == (void*)-1) {
LogKSM("Failed to align heap to page boundary. adjustment [{}] bytes", adjustment);
return;
}
}
LogKSMDetail("Heap aligned to next page boundary. Current break [{}]", sbrk(0));
}
inline void* MarkHeapStart() {
void* current_pos = sbrk(0);
AlignHeapToPageBoundary();
return current_pos;
}
inline size_t MeasureHeapUsage(void* start) {
void* current_break = sbrk(0);
return static_cast<char*>(current_break) - static_cast<char*>(start);
}
#endif
inline size_t getPageSize()
{
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
return sysInfo.dwPageSize; // Page size in bytes
#else
return static_cast<size_t>(sysconf(_SC_PAGESIZE)); // POSIX page size
#endif
};
template <typename T>
inline void PageAlignVectorAligned(std::vector<T, PageAlignedAllocator<T>>& vec) {
if (vec.empty()) {
return;
}
size_t page_size = getPageSize();
void* start = vec.data();
size_t size = vec.size() * sizeof(T);
// Check if the memory is page-aligned
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
// Allocate a new aligned vector
std::vector<T, PageAlignedAllocator<T>> aligned_vec(vec.get_allocator());
aligned_vec.reserve(vec.capacity()); // Match capacity to avoid reallocation during copy
// Copy elements from the original vector
aligned_vec.insert(aligned_vec.end(), vec.begin(), vec.end());
// Swap the aligned vector with the original vector
vec.swap(aligned_vec);
// Clear the temporary aligned vector to free its memory
aligned_vec.clear();
// Verify the new alignment
start = vec.data();
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
throw std::runtime_error("Failed to align vector memory to page boundaries.");
}
LogKSMDetail("Vector reallocated to ensure page alignment. start [{}] size [{}] bytes", start, size);
} else {
LogKSMDetail("Vector is already page-aligned. start [{}] size [{}] bytes", start, size);
}
#ifndef _WIN32
// Mark memory for KSM (only on non-Windows systems)
MarkMemoryForKSM(start, size);
#endif
}
}
#endif // EQEMU_KSM_HPP
-600
View File
@@ -1,600 +0,0 @@
#include "mysql_stmt.h"
#include "eqemu_logsys.h"
#include "mutex.h"
#include "timer.h"
#include <charconv>
namespace mysql
{
void PreparedStmt::StmtDeleter::operator()(MYSQL_STMT* stmt) noexcept
{
// The connection must be locked when closing the stmt to avoid mysql errors
// in case another thread tries to use it during the close. If the mutex is
// changed to one that throws then exceptions need to be caught here.
LockMutex lock(mutex);
mysql_stmt_close(stmt);
}
PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts)
: m_stmt(mysql_stmt_init(&mysql), { mutex }), m_query(std::move(query)), m_mutex(mutex), m_options(opts)
{
LockMutex lock(m_mutex);
if (mysql_stmt_prepare(m_stmt.get(), m_query.c_str(), static_cast<unsigned long>(m_query.size())) != 0)
{
ThrowError(fmt::format("Prepare error: {}", GetStmtError()));
}
m_params.resize(mysql_stmt_param_count(m_stmt.get()));
m_inputs.resize(m_params.size());
}
void PreparedStmt::ThrowError(const std::string& error)
{
LogMySQLError("{}", error);
throw std::runtime_error(error);
}
std::string PreparedStmt::GetStmtError()
{
auto err = mysql_stmt_errno(m_stmt.get());
auto str = mysql_stmt_error(m_stmt.get());
return fmt::format("({}) [{}] for query [{}]", err, str, m_query);
}
template <typename T>
void PreparedStmt::BindInput(size_t index, T value)
{
if (index >= m_inputs.size())
{
ThrowError(fmt::format("Cannot bind input, index {} out of range", index));
}
impl::Bind& arg = m_inputs[index];
arg.is_null = std::is_same_v<T, std::nullptr_t>;
MYSQL_BIND& bind = m_params[index];
bind.is_unsigned = std::is_unsigned_v<T>;
bind.is_null = &arg.is_null;
bind.length = &arg.length;
auto old_type = bind.buffer_type;
if constexpr (std::is_arithmetic_v<T>)
{
if (arg.buffer.size() < sizeof(T))
{
arg.buffer.resize(std::max(sizeof(T), sizeof(int64_t)));
bind.buffer = arg.buffer.data();
m_need_bind = true;
}
memcpy(arg.buffer.data(), &value, sizeof(T));
}
if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, uint8_t> || std::is_same_v<T, bool>)
{
bind.buffer_type = MYSQL_TYPE_TINY;
}
else if constexpr (std::is_same_v<T, int16_t> || std::is_same_v<T, uint16_t>)
{
bind.buffer_type = MYSQL_TYPE_SHORT;
}
else if constexpr (std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>)
{
bind.buffer_type = MYSQL_TYPE_LONG;
}
else if constexpr (std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>)
{
bind.buffer_type = MYSQL_TYPE_LONGLONG;
}
else if constexpr (std::is_same_v<T, float>)
{
bind.buffer_type = MYSQL_TYPE_FLOAT;
}
else if constexpr (std::is_same_v<T, double>)
{
bind.buffer_type = MYSQL_TYPE_DOUBLE;
}
else if constexpr (std::is_same_v<T, std::string_view>)
{
bind.buffer_type = MYSQL_TYPE_STRING;
if (arg.buffer.empty() || arg.buffer.size() < value.size())
{
arg.buffer.resize(static_cast<size_t>((value.size() + 1) * 1.5));
bind.buffer = arg.buffer.data();
bind.buffer_length = static_cast<unsigned long>(arg.buffer.size());
m_need_bind = true;
}
std::copy(value.begin(), value.end(), arg.buffer.begin());
arg.length = static_cast<unsigned long>(value.size());
}
else if constexpr (!std::is_same_v<T, std::nullptr_t>)
{
static_assert(false_v<T>, "Cannot bind unsupported type");
}
if (old_type != bind.buffer_type)
{
m_need_bind = true;
}
}
void PreparedStmt::BindInput(size_t index, const char* str)
{
BindInput(index, std::string_view(str));
}
void PreparedStmt::BindInput(size_t index, const std::string& str)
{
BindInput(index, std::string_view(str));
}
StmtResult PreparedStmt::Execute()
{
CheckArgs(0);
return DoExecute();
}
StmtResult PreparedStmt::Execute(const std::vector<param_t>& args)
{
CheckArgs(args.size());
for (size_t i = 0; i < args.size(); ++i)
{
std::visit([&](const auto& arg) { BindInput(i, arg); }, args[i]);
}
return DoExecute();
}
template <typename T>
StmtResult PreparedStmt::Execute(const std::vector<T>& args)
{
CheckArgs(args.size());
for (size_t i = 0; i < args.size(); ++i)
{
BindInput(i, args[i]);
}
return DoExecute();
}
void PreparedStmt::CheckArgs(size_t argc)
{
if (argc != m_params.size())
{
ThrowError(fmt::format("Bad arg count (got {}, expected {}) for [{}]", argc, m_params.size(), m_query));
}
}
StmtResult PreparedStmt::DoExecute()
{
BenchTimer timer;
LockMutex lock(m_mutex);
if (m_need_bind && mysql_stmt_bind_param(m_stmt.get(), m_params.data()) != 0)
{
ThrowError(fmt::format("Bind param error: {}", GetStmtError()));
}
m_need_bind = false;
if (mysql_stmt_execute(m_stmt.get()) != 0)
{
ThrowError(fmt::format("Execute error: {}", GetStmtError()));
}
my_bool attr = m_options.use_max_length;
mysql_stmt_attr_set(m_stmt.get(), STMT_ATTR_UPDATE_MAX_LENGTH, &attr);
if (m_options.buffer_results && mysql_stmt_store_result(m_stmt.get()) != 0)
{
ThrowError(fmt::format("Store result error: {}", GetStmtError()));
}
// Result buffers are bound on first execute and re-used if needed
if (m_results.empty())
{
BindResults();
}
StmtResult res(m_stmt.get(), m_results.size());
if (m_results.empty())
{
LogMySQLQuery("{} -- ({} row(s) affected) ({:.6f}s)", m_query, res.RowsAffected(), timer.elapsed());
}
else
{
LogMySQLQuery("{} -- ({} row(s) returned) ({:.6f}s)", m_query, res.RowCount(), timer.elapsed());
}
return res;
}
void PreparedStmt::BindResults()
{
MYSQL_RES* res = mysql_stmt_result_metadata(m_stmt.get());
if (!res)
{
return; // did not produce a result set
}
MYSQL_FIELD* fields = mysql_fetch_fields(res);
m_columns.resize(mysql_num_fields(res));
m_results.resize(m_columns.size());
for (int i = 0; i < static_cast<int>(m_columns.size()); ++i)
{
impl::BindColumn& col = m_columns[i].m_col;
MYSQL_BIND& bind = m_results[i];
col.index = i;
col.name = fields[i].name;
col.buffer_type = fields[i].type;
col.is_unsigned = (fields[i].flags & UNSIGNED_FLAG) != 0;
col.buffer.resize(GetResultBufferSize(fields[i]));
bind.buffer_type = col.buffer_type;
bind.buffer = col.buffer.data();
bind.buffer_length = static_cast<unsigned long>(col.buffer.size());
bind.is_unsigned = col.is_unsigned;
bind.is_null = &col.is_null;
bind.length = &col.length;
bind.error = &col.error;
}
mysql_free_result(res);
if (!m_results.empty() && mysql_stmt_bind_result(m_stmt.get(), m_results.data()) != 0)
{
ThrowError(fmt::format("Bind result error: {}", GetStmtError()));
}
}
int PreparedStmt::GetResultBufferSize(const MYSQL_FIELD& field) const
{
switch (field.type)
{
case MYSQL_TYPE_TINY:
return sizeof(int8_t);
case MYSQL_TYPE_SHORT:
return sizeof(int16_t);
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return sizeof(int32_t);
case MYSQL_TYPE_LONGLONG:
return sizeof(int64_t);
case MYSQL_TYPE_FLOAT:
return sizeof(float);
case MYSQL_TYPE_DOUBLE:
return sizeof(double);
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
return sizeof(MYSQL_TIME);
default: // if max_length is unavailable for strings buffers are resized on fetch
return field.max_length + 1; // ensure valid buffer created
}
}
StmtRow PreparedStmt::Fetch()
{
StmtRow row;
if (!m_columns.empty())
{
int rc = mysql_stmt_fetch(m_stmt.get());
if (rc == 1)
{
ThrowError(fmt::format("Fetch error: {}", GetStmtError()));
}
if (rc != MYSQL_NO_DATA)
{
if (rc == MYSQL_DATA_TRUNCATED)
{
FetchTruncated();
}
row = StmtRow(m_columns);
}
}
return row;
}
void PreparedStmt::FetchTruncated()
{
for (int i = 0; i < static_cast<int>(m_columns.size()); ++i)
{
impl::BindColumn& col = m_columns[i].m_col;
if (col.error)
{
MYSQL_BIND& bind = m_results[i];
col.buffer.resize(static_cast<size_t>(col.length * 1.5));
bind.buffer = col.buffer.data();
bind.buffer_length = static_cast<unsigned long>(col.buffer.size());
mysql_stmt_fetch_column(m_stmt.get(), &bind, i, 0);
}
}
if (mysql_stmt_bind_result(m_stmt.get(), m_results.data()) != 0)
{
ThrowError(fmt::format("Fetch rebind result error: {}", GetStmtError()));
}
}
// ---------------------------------------------------------------------------
StmtResult::StmtResult(MYSQL_STMT* stmt, size_t columns)
{
m_num_cols = static_cast<int>(columns);
m_num_rows = mysql_stmt_num_rows(stmt); // requires buffered results
m_affected = mysql_stmt_affected_rows(stmt);
m_insert_id = mysql_stmt_insert_id(stmt);
}
// ---------------------------------------------------------------------------
const StmtColumn* StmtRow::GetColumn(size_t index) const
{
return index < m_columns.size() ? &m_columns[index] : nullptr;
}
const StmtColumn* StmtRow::GetColumn(std::string_view name) const
{
auto it = std::ranges::find_if(m_columns,
[name](const StmtColumn& col) { return col.Name() == name; });
return it != m_columns.end() ? &(*it) : nullptr;
}
std::optional<std::string> StmtRow::operator[](size_t index) const
{
return GetStr(index);
}
std::optional<std::string> StmtRow::operator[](std::string_view name) const
{
return GetStr(name);
}
std::optional<std::string> StmtRow::GetStr(size_t index) const
{
const StmtColumn* col = GetColumn(index);
return col ? col->GetStr() : std::nullopt;
}
std::optional<std::string> StmtRow::GetStr(std::string_view name) const
{
const StmtColumn* col = GetColumn(name);
return col ? col->GetStr() : std::nullopt;
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtRow::Get(size_t index) const
{
const StmtColumn* col = GetColumn(index);
return col ? col->Get<T>() : std::nullopt;
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtRow::Get(std::string_view name) const
{
const StmtColumn* col = GetColumn(name);
return col ? col->Get<T>() : std::nullopt;
}
// ---------------------------------------------------------------------------
static time_t MakeTime(const MYSQL_TIME& mt)
{
// buffer mt given in mysql session time zone (assumes local)
std::tm tm{};
tm.tm_year = mt.year - 1900;
tm.tm_mon = mt.month - 1;
tm.tm_mday = mt.day;
tm.tm_hour = mt.hour;
tm.tm_min = mt.minute;
tm.tm_sec = mt.second;
tm.tm_isdst = -1;
return std::mktime(&tm);
}
static int MakeSeconds(const MYSQL_TIME& mt)
{
return (mt.neg ? -1 : 1) * static_cast<int>(mt.hour * 3600 + mt.minute * 60 + mt.second);
}
static uint64_t MakeBits(std::span<const uint8_t> data)
{
// byte stream for bits is in big endian
uint64_t bits = 0;
for (size_t i = 0; i < data.size() && i < sizeof(uint64_t); ++i)
{
bits |= static_cast<uint64_t>(data[data.size() - i - 1] & 0xff) << (i * 8);
}
return bits;
}
template <typename T>
concept has_from_chars = requires (const char* first, const char* last, T value)
{
std::from_chars(first, last, value);
};
template <typename T>
static T FromString(std::string_view sv)
{
if constexpr (std::is_same_v<T, bool>)
{
// return false for empty (zero-length) strings
return !sv.empty();
}
else if constexpr (std::is_same_v<T, float> && !has_from_chars<T>)
{
return std::strtof(std::string(sv).c_str(), nullptr);
}
else if constexpr (std::is_same_v<T, double> && !has_from_chars<T>)
{
return std::strtod(std::string(sv).c_str(), nullptr);
}
else
{
// non numbers return a zero initialized T (could return nullopt instead)
T value = {};
std::from_chars(sv.data(), sv.data() + sv.size(), value);
return value;
}
}
static std::string FormatTime(enum_field_types type, const MYSQL_TIME& mt)
{
switch (type)
{
case MYSQL_TYPE_TIME: // hhh:mm:ss '-838:59:59' to '838:59:59'
return fmt::format("{}{:02d}:{:02d}:{:02d}", mt.neg ? "-" : "", mt.hour, mt.minute, mt.second);
case MYSQL_TYPE_DATE: // YYYY-MM-DD '1000-01-01' to '9999-12-31'
return fmt::format("{}-{:02d}-{:02d}", mt.year, mt.month, mt.day);
case MYSQL_TYPE_DATETIME: // YYYY-MM-DD hh:mm:ss '1000-01-01 00:00:00' to '9999-12-31 23:59:59'
case MYSQL_TYPE_TIMESTAMP: // YYYY-MM-DD hh:mm:ss '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC
return fmt::format("{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}", mt.year, mt.month, mt.day, mt.hour, mt.minute, mt.second);
default:
return std::string();
}
}
std::optional<std::string_view> StmtColumn::GetStrView() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return std::make_optional<std::string_view>(reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length);
default:
return std::nullopt;
}
}
std::optional<std::string> StmtColumn::GetStr() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_TINY:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint8_t>()).c_str() : fmt::format_int(BitCast<int8_t>()).c_str();
case MYSQL_TYPE_SHORT:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint16_t>()).c_str() : fmt::format_int(BitCast<int16_t>()).c_str();
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint32_t>()).c_str() : fmt::format_int(BitCast<int32_t>()).c_str();
case MYSQL_TYPE_LONGLONG:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint64_t>()).c_str() : fmt::format_int(BitCast<int64_t>()).c_str();
case MYSQL_TYPE_FLOAT:
return fmt::format("{}", BitCast<float>());
case MYSQL_TYPE_DOUBLE:
return fmt::format("{}", BitCast<double>());
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
return FormatTime(m_col.buffer_type, BitCast<MYSQL_TIME>());
case MYSQL_TYPE_BIT:
return fmt::format_int(*Get<uint64_t>()).c_str();
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return std::make_optional<std::string>(reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length);
default:
return std::nullopt;
}
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtColumn::Get() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_TINY:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint8_t>()) : static_cast<T>(BitCast<int8_t>());
case MYSQL_TYPE_SHORT:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint16_t>()) : static_cast<T>(BitCast<int16_t>());
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint32_t>()) : static_cast<T>(BitCast<int32_t>());
case MYSQL_TYPE_LONGLONG:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint64_t>()) : static_cast<T>(BitCast<int64_t>());
case MYSQL_TYPE_FLOAT:
return static_cast<T>(BitCast<float>());
case MYSQL_TYPE_DOUBLE:
return static_cast<T>(BitCast<double>());
case MYSQL_TYPE_TIME: // return as total seconds
return static_cast<T>(MakeSeconds(BitCast<MYSQL_TIME>()));
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP: // return as epoch timestamp
return static_cast<T>(MakeTime(BitCast<MYSQL_TIME>()));
case MYSQL_TYPE_BIT:
return static_cast<T>(MakeBits({ m_col.buffer.data(), m_col.length }));
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return FromString<T>({ reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length });
default:
return std::nullopt;
}
}
// ---------------------------------------------------------------------------
// explicit template instantiations for supported types
template void PreparedStmt::BindInput(size_t, std::string_view);
template void PreparedStmt::BindInput(size_t, std::nullptr_t);
template StmtResult PreparedStmt::Execute(const std::vector<std::string_view>&);
template StmtResult PreparedStmt::Execute(const std::vector<std::string>&);
template StmtResult PreparedStmt::Execute(const std::vector<const char*>&);
#define INSTANTIATE(T) \
template void PreparedStmt::BindInput(size_t, T); \
template StmtResult PreparedStmt::Execute(const std::vector<T>&); \
template std::optional<T> StmtRow::Get(size_t) const; \
template std::optional<T> StmtRow::Get(std::string_view) const; \
template std::optional<T> StmtColumn::Get() const;
INSTANTIATE(bool);
INSTANTIATE(int8_t);
INSTANTIATE(uint8_t);
INSTANTIATE(int16_t);
INSTANTIATE(uint16_t);
INSTANTIATE(int32_t);
INSTANTIATE(uint32_t);
INSTANTIATE(int64_t);
INSTANTIATE(uint64_t);
INSTANTIATE(float);
INSTANTIATE(double);
} // namespace mysql
-221
View File
@@ -1,221 +0,0 @@
#pragma once
#include "mysql.h"
#include <cassert>
#include <cstring>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
class Mutex;
namespace mysql
{
// support MySQL 8.0.1+ API which removed the my_bool type
#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80001
using my_bool = bool;
#endif
template <typename>
inline constexpr bool false_v = false;
namespace impl
{
struct Bind
{
std::vector<uint8_t> buffer;
unsigned long length = 0;
my_bool is_null = false;
my_bool error = false;
};
struct BindColumn : Bind
{
int index = 0;
std::string name;
bool is_unsigned = false;
enum_field_types buffer_type = {};
};
} // namespace impl
// ---------------------------------------------------------------------------
struct StmtOptions
{
// Enable buffering (storing) entire result set after executing a statement
bool buffer_results = true;
// Enable MySQL to update max_length of fields in execute result set (requires buffering)
bool use_max_length = true;
};
// ---------------------------------------------------------------------------
// Holds ownership of bound column value buffer
class StmtColumn
{
public:
int Index() const { return m_col.index; }
bool IsNull() const { return m_col.is_null; }
bool IsUnsigned() const { return m_col.is_unsigned; }
enum_field_types Type() const { return m_col.buffer_type; }
const std::string& Name() const { return m_col.name; }
// Get view of column value buffer
std::span<const uint8_t> GetBuf() const { return { m_col.buffer.data(), m_col.length }; }
// Get view of column string value. Returns nullopt if value is NULL or not a string
std::optional<std::string_view> GetStrView() const;
// Get column value as string. Returns nullopt if value is NULL or field type unsupported
std::optional<std::string> GetStr() const;
// Get column value as numeric T. Returns nullopt if value NULL or field type unsupported
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get() const;
private:
// uses memcpy for type punning buffer data to avoid UB with strict aliasing
template <typename T>
T BitCast() const
{
T val;
assert(sizeof(T) == m_col.length);
memcpy(&val, m_col.buffer.data(), sizeof(T));
return val;
}
friend class PreparedStmt; // access to allocate and bind buffers
friend class StmtResult; // access to resize truncated buffers
impl::BindColumn m_col;
};
// ---------------------------------------------------------------------------
// Provides a non-owning view of PreparedStmt column value buffers
// Evaluates false if it does not contain a valid row
class StmtRow
{
public:
StmtRow() = default;
StmtRow(std::span<const StmtColumn> columns) : m_columns(columns) {};
explicit operator bool() const noexcept { return !m_columns.empty(); }
int ColumnCount() const { return static_cast<int>(m_columns.size()); }
const StmtColumn* GetColumn(size_t index) const;
const StmtColumn* GetColumn(std::string_view name) const;
// Get specified column value as string
// Returns nullopt if column invalid, value is NULL, or field type unsupported
std::optional<std::string> operator[](size_t index) const;
std::optional<std::string> operator[](std::string_view name) const;
std::optional<std::string> GetStr(size_t index) const;
std::optional<std::string> GetStr(std::string_view name) const;
// Get specified column value as numeric T
// Returns nullopt if column invalid, value is NULL, or field type unsupported
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get(size_t index) const;
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get(std::string_view name) const;
auto begin() const { return m_columns.begin(); }
auto end() const { return m_columns.end(); }
private:
std::span<const StmtColumn> m_columns;
};
// ---------------------------------------------------------------------------
// Result meta data for an executed prepared statement
class StmtResult
{
public:
StmtResult() = default;
StmtResult(MYSQL_STMT* stmt, size_t columns);
int ColumnCount() const { return m_num_cols; }
uint64_t RowCount() const { return m_num_rows; }
uint64_t RowsAffected() const { return m_affected; }
uint64_t LastInsertID() const { return m_insert_id; }
private:
int m_num_cols = 0;
uint64_t m_num_rows = 0;
uint64_t m_affected = 0;
uint64_t m_insert_id = 0;
};
// ---------------------------------------------------------------------------
class PreparedStmt
{
public:
// Supported argument types for execute
using param_t = std::variant<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>;
PreparedStmt() = delete;
PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts = {});
const std::string& GetQuery() const { return m_query; }
StmtOptions GetOptions() const { return m_options; }
void SetOptions(StmtOptions options) { m_options = options; }
void FreeResult() { mysql_stmt_free_result(m_stmt.get()); }
// Execute the prepared statement with specified arguments
// Throws exception on error
template <typename T>
StmtResult Execute(const std::vector<T>& args);
StmtResult Execute(const std::vector<param_t>& args);
StmtResult Execute();
// Fetch the next row into column buffers (overwrites previous row values)
// Return value evaluates false if no more rows to fetch
// Throws exception on error
StmtRow Fetch();
private:
void CheckArgs(size_t argc);
StmtResult DoExecute();
void BindResults();
void FetchTruncated();
int GetResultBufferSize(const MYSQL_FIELD& field) const;
void ThrowError(const std::string& error);
std::string GetStmtError();
// bind an input value to a query parameter by index
template <typename T>
void BindInput(size_t index, T value);
void BindInput(size_t index, const char* str);
void BindInput(size_t index, const std::string& str);
struct StmtDeleter
{
Mutex* mutex = nullptr;
void operator()(MYSQL_STMT* stmt) noexcept;
};
private:
std::unique_ptr<MYSQL_STMT, StmtDeleter> m_stmt;
std::vector<MYSQL_BIND> m_params; // input binds
std::vector<MYSQL_BIND> m_results; // result binds
std::vector<impl::Bind> m_inputs; // execute buffers (addresses bound)
std::vector<StmtColumn> m_columns; // fetch buffers (addresses bound)
std::string m_query;
StmtOptions m_options = {};
bool m_need_bind = true;
Mutex* m_mutex = nullptr; // connection mutex
};
} // namespace mysql
+111 -189
View File
@@ -1,16 +1,12 @@
#include "daybreak_connection.h" #include "daybreak_connection.h"
#include "../event/event_loop.h" #include "../event/event_loop.h"
#include "../event/task.h"
#include "../data_verification.h" #include "../data_verification.h"
#include "crc32.h" #include "crc32.h"
#include "../eqemu_logsys.h"
#include <zlib.h> #include <zlib.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <sstream>
// observed client receive window is 300 packets, 140KB
constexpr size_t MAX_CLIENT_RECV_PACKETS_PER_WINDOW = 300;
constexpr size_t MAX_CLIENT_RECV_BYTES_PER_WINDOW = 140 * 1024;
// buffer pools
SendBufferPool send_buffer_pool;
EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager() EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager()
{ {
@@ -57,22 +53,16 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop)
uv_ip4_addr("0.0.0.0", m_options.port, &recv_addr); uv_ip4_addr("0.0.0.0", m_options.port, &recv_addr);
int rc = uv_udp_bind(&m_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR); int rc = uv_udp_bind(&m_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR);
rc = uv_udp_recv_start( rc = uv_udp_recv_start(&m_socket,
&m_socket, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
[](uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
if (suggested_size > 65536) {
buf->base = new char[suggested_size]; buf->base = new char[suggested_size];
memset(buf->base, 0, suggested_size);
buf->len = suggested_size; buf->len = suggested_size;
return;
}
static thread_local char temp_buf[65536];
buf->base = temp_buf;
buf->len = 65536;
}, },
[](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
DaybreakConnectionManager *c = (DaybreakConnectionManager*)handle->data; DaybreakConnectionManager *c = (DaybreakConnectionManager*)handle->data;
if (nread < 0 || addr == nullptr) { if (nread < 0 || addr == nullptr) {
delete[] buf->base;
return; return;
} }
@@ -80,10 +70,7 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop)
uv_ip4_name((const sockaddr_in*)addr, endpoint, 16); uv_ip4_name((const sockaddr_in*)addr, endpoint, 16);
auto port = ntohs(((const sockaddr_in*)addr)->sin_port); auto port = ntohs(((const sockaddr_in*)addr)->sin_port);
c->ProcessPacket(endpoint, port, buf->base, nread); c->ProcessPacket(endpoint, port, buf->base, nread);
if (buf->len > 65536) {
delete[] buf->base; delete[] buf->base;
}
}); });
m_attached = loop; m_attached = loop;
@@ -323,7 +310,7 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
m_last_session_stats = Clock::now(); m_last_session_stats = Clock::now();
m_outgoing_budget = owner->m_options.outgoing_data_rate; m_outgoing_budget = owner->m_options.outgoing_data_rate;
LogNetClient("New session [{}] with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key)); LogNetcode("New session [{}] with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
} }
//new connection made as client //new connection made as client
@@ -355,16 +342,16 @@ EQ::Net::DaybreakConnection::~DaybreakConnection()
void EQ::Net::DaybreakConnection::Close() void EQ::Net::DaybreakConnection::Close()
{ {
if (m_status != StatusDisconnected && m_status != StatusDisconnecting) { if (m_status == StatusConnected) {
FlushBuffer(); FlushBuffer();
SendDisconnect(); SendDisconnect();
}
if (m_status != StatusDisconnecting) {
m_close_time = Clock::now(); m_close_time = Clock::now();
}
ChangeStatus(StatusDisconnecting); ChangeStatus(StatusDisconnecting);
}
else {
ChangeStatus(StatusDisconnecting);
}
} }
void EQ::Net::DaybreakConnection::QueuePacket(Packet &p) void EQ::Net::DaybreakConnection::QueuePacket(Packet &p)
@@ -647,7 +634,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
p.PutSerialize(0, reply); p.PutSerialize(0, reply);
InternalSend(p); InternalSend(p);
LogNetClient("[OP_SessionRequest] Session [{}] started with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key)); LogNetcode("[OP_SessionRequest] Session [{}] started with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
} }
break; break;
@@ -666,7 +653,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
m_max_packet_size = reply.max_packet_size; m_max_packet_size = reply.max_packet_size;
ChangeStatus(StatusConnected); ChangeStatus(StatusConnected);
LogNetClient( LogNetcode(
"[OP_SessionResponse] Session [{}] refresh with encode key [{}]", "[OP_SessionResponse] Session [{}] refresh with encode key [{}]",
m_connect_code, m_connect_code,
HostToNetwork(m_encode_key) HostToNetwork(m_encode_key)
@@ -795,7 +782,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
SendDisconnect(); SendDisconnect();
} }
LogNetClient( LogNetcode(
"[OP_SessionDisconnect] Session [{}] disconnect with encode key [{}]", "[OP_SessionDisconnect] Session [{}] disconnect with encode key [{}]",
m_connect_code, m_connect_code,
HostToNetwork(m_encode_key) HostToNetwork(m_encode_key)
@@ -865,7 +852,7 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
} }
if (p.Length() < (size_t)m_crc_bytes) { if (p.Length() < (size_t)m_crc_bytes) {
LogNetClient("Session [{}] ignored packet (crc bytes invalid on session)", m_connect_code); LogNetcode("Session [{}] ignored packet (crc bytes invalid on session)", m_connect_code);
return false; return false;
} }
@@ -1056,7 +1043,7 @@ void EQ::Net::DaybreakConnection::Decompress(Packet &p, size_t offset, size_t le
return; return;
} }
static thread_local uint8_t new_buffer[4096]; static uint8_t new_buffer[4096];
uint8_t *buffer = (uint8_t*)p.Data() + offset; uint8_t *buffer = (uint8_t*)p.Data() + offset;
uint32_t new_length = 0; uint32_t new_length = 0;
@@ -1077,7 +1064,7 @@ void EQ::Net::DaybreakConnection::Decompress(Packet &p, size_t offset, size_t le
void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t length) void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t length)
{ {
static thread_local uint8_t new_buffer[2048] = { 0 }; uint8_t new_buffer[2048] = { 0 };
uint8_t *buffer = (uint8_t*)p.Data() + offset; uint8_t *buffer = (uint8_t*)p.Data() + offset;
uint32_t new_length = 0; uint32_t new_length = 0;
bool send_uncompressed = true; bool send_uncompressed = true;
@@ -1110,97 +1097,14 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
return; return;
} }
if (m_streams[stream].sent_packets.empty()) { auto resends = 0;
return; auto now = Clock::now();
}
m_resend_packets_sent = 0;
m_resend_bytes_sent = 0;
auto now = Clock::now(); // Current time
auto s = &m_streams[stream]; auto s = &m_streams[stream];
for (auto &entry : s->sent_packets) {
// Get a reference resend delay (assume first packet represents the typical case) auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - entry.second.last_sent);
if (!s->sent_packets.empty()) { if (entry.second.times_resent == 0) {
// Check if the first packet has timed out if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
auto &first_packet = s->sent_packets.begin()->second; auto &p = entry.second.packet;
auto time_since_first_sent = std::chrono::duration_cast<std::chrono::milliseconds>(now - first_packet.first_sent).count();
if (time_since_first_sent >= m_owner->m_options.resend_timeout) {
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
auto first_sent_ms = std::chrono::duration_cast<std::chrono::milliseconds>(first_packet.first_sent.time_since_epoch()).count();
LogNetClient(
"Closing connection for m_endpoint [{}] m_port [{}] time_since_first_sent [{}] >= m_owner->m_options.resend_timeout [{}] now [{}] first_packet.first_sent [{}]",
m_endpoint,
m_port,
time_since_first_sent,
m_owner->m_options.resend_timeout,
now_ms,
first_sent_ms
);
Close();
return;
}
if (m_last_ack - now > std::chrono::milliseconds(1000)) {
LogNetClient(
"Resetting m_acked_since_last_resend flag for m_endpoint [{}] m_port [{}]",
m_endpoint,
m_port
);
m_acked_since_last_resend = true;
}
// make sure that the first_packet in the list first_sent time is within the resend_delay and now
// if it is not, then we need to resend all packets in the list
if (time_since_first_sent <= first_packet.resend_delay && !m_acked_since_last_resend) {
LogNetClientDetail(
"Not resending packets for m_endpoint [{}] m_port [{}] packets [{}] time_first_sent [{}] resend_delay [{}] m_acked_since_last_resend [{}]",
m_endpoint,
m_port,
s->sent_packets.size(),
time_since_first_sent,
first_packet.resend_delay,
m_acked_since_last_resend
);
return;
}
}
if (EQEmuLogSys::Instance()->IsLogEnabled(Logs::General, Logs::NetClient)) {
size_t total_size = 0;
for (auto &e: s->sent_packets) {
total_size += e.second.packet.Length();
}
LogNetClientDetail(
"Resending packets for m_endpoint [{}] m_port [{}] packet count [{}] total packet size [{}] m_acked_since_last_resend [{}]",
m_endpoint,
m_port,
s->sent_packets.size(),
total_size,
m_acked_since_last_resend
);
}
for (auto &e: s->sent_packets) {
if (m_resend_packets_sent >= MAX_CLIENT_RECV_PACKETS_PER_WINDOW ||
m_resend_bytes_sent >= MAX_CLIENT_RECV_BYTES_PER_WINDOW) {
LogNetClient(
"Stopping resend because we hit thresholds for m_endpoint [{}] m_port [{}] m_resend_packets_sent [{}] max [{}] in_queue [{}] m_resend_bytes_sent [{}] max [{}]",
m_endpoint,
m_port,
m_resend_packets_sent,
MAX_CLIENT_RECV_PACKETS_PER_WINDOW,
s->sent_packets.size(),
m_resend_bytes_sent,
MAX_CLIENT_RECV_BYTES_PER_WINDOW
);
break;
}
auto &sp = e.second;
auto &p = sp.packet;
if (p.Length() >= DaybreakHeader::size()) { if (p.Length() >= DaybreakHeader::size()) {
if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) { if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) {
m_stats.resent_fragments++; m_stats.resent_fragments++;
@@ -1214,26 +1118,48 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
} }
m_stats.resent_packets++; m_stats.resent_packets++;
// Resend the packet
InternalBufferedSend(p); InternalBufferedSend(p);
entry.second.last_sent = now;
m_resend_packets_sent++; entry.second.times_resent++;
m_resend_bytes_sent += p.Length(); entry.second.resend_delay = EQ::Clamp(entry.second.resend_delay * 2, m_owner->m_options.resend_delay_min, m_owner->m_options.resend_delay_max);
sp.last_sent = now; resends++;
sp.times_resent++; }
sp.resend_delay = EQ::Clamp( }
sp.resend_delay * 2, else {
m_owner->m_options.resend_delay_min, auto time_since_first_sent = std::chrono::duration_cast<std::chrono::milliseconds>(now - entry.second.first_sent);
m_owner->m_options.resend_delay_max if (time_since_first_sent.count() >= m_owner->m_options.resend_timeout) {
); Close();
return;
} }
m_acked_since_last_resend = false; if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
m_last_ack = now; auto &p = entry.second.packet;
if (p.Length() >= DaybreakHeader::size()) {
if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) {
m_stats.resent_fragments++;
}
else {
m_stats.resent_full++;
}
}
else {
m_stats.resent_full++;
}
m_stats.resent_packets++;
InternalBufferedSend(p);
entry.second.last_sent = now;
entry.second.times_resent++;
entry.second.resend_delay = EQ::Clamp(entry.second.resend_delay * 2, m_owner->m_options.resend_delay_min, m_owner->m_options.resend_delay_max);
resends++;
}
}
}
} }
void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq) void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
{ {
auto now = Clock::now(); auto now = Clock::now();
auto s = &m_streams[stream]; auto s = &m_streams[stream];
auto iter = s->sent_packets.begin(); auto iter = s->sent_packets.begin();
@@ -1254,9 +1180,6 @@ void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
++iter; ++iter;
} }
} }
m_acked_since_last_resend = true;
m_last_ack = now;
} }
void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq) void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq)
@@ -1274,9 +1197,6 @@ void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq)
s->sent_packets.erase(iter); s->sent_packets.erase(iter);
} }
m_acked_since_last_resend = true;
m_last_ack = now;
} }
void EQ::Net::DaybreakConnection::UpdateDataBudget(double budget_add) void EQ::Net::DaybreakConnection::UpdateDataBudget(double budget_add)
@@ -1373,53 +1293,46 @@ void EQ::Net::DaybreakConnection::SendKeepAlive()
InternalSend(p); InternalSend(p);
} }
void EQ::Net::DaybreakConnection::InternalSend(Packet &p) { void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
{
if (m_owner->m_options.outgoing_data_rate > 0.0) { if (m_owner->m_options.outgoing_data_rate > 0.0) {
auto new_budget = m_outgoing_budget - (p.Length() / 1024.0); auto new_budget = m_outgoing_budget - (p.Length() / 1024.0);
if (new_budget <= 0.0) { if (new_budget <= 0.0) {
m_stats.dropped_datarate_packets++; m_stats.dropped_datarate_packets++;
return; return;
} else { }
else {
m_outgoing_budget = new_budget; m_outgoing_budget = new_budget;
} }
} }
m_last_send = Clock::now(); m_last_send = Clock::now();
auto pooled_opt = send_buffer_pool.acquire(); auto send_func = [](uv_udp_send_t* req, int status) {
if (!pooled_opt) { delete[](char*)req->data;
m_stats.dropped_datarate_packets++; delete req;
return; };
}
auto [send_req, data, ctx] = *pooled_opt;
ctx->pool = &send_buffer_pool; // set pool pointer
sockaddr_in send_addr{};
uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr);
uv_buf_t send_buffers[1];
if (PacketCanBeEncoded(p)) { if (PacketCanBeEncoded(p)) {
m_stats.bytes_before_encode += p.Length(); m_stats.bytes_before_encode += p.Length();
DynamicPacket out; DynamicPacket out;
out.PutPacket(0, p); out.PutPacket(0, p);
for (auto &m_encode_passe: m_encode_passes) { for (int i = 0; i < 2; ++i) {
switch (m_encode_passe) { switch (m_encode_passes[i]) {
case EncodeCompression: case EncodeCompression:
if (out.GetInt8(0) == 0) { if (out.GetInt8(0) == 0)
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size()); Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
} else { else
Compress(out, 1, out.Length() - 1); Compress(out, 1, out.Length() - 1);
}
break; break;
case EncodeXOR: case EncodeXOR:
if (out.GetInt8(0) == 0) { if (out.GetInt8(0) == 0)
Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size()); Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size());
} else { else
Encode(out, 1, out.Length() - 1); Encode(out, 1, out.Length() - 1);
}
break; break;
default: default:
break; break;
@@ -1427,43 +1340,52 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p) {
} }
AppendCRC(out); AppendCRC(out);
uv_udp_send_t *send_req = new uv_udp_send_t;
memset(send_req, 0, sizeof(*send_req));
sockaddr_in send_addr;
uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr);
uv_buf_t send_buffers[1];
char *data = new char[out.Length()];
memcpy(data, out.Data(), out.Length()); memcpy(data, out.Data(), out.Length());
send_buffers[0] = uv_buf_init(data, out.Length()); send_buffers[0] = uv_buf_init(data, out.Length());
} else { send_req->data = send_buffers[0].base;
m_stats.sent_bytes += out.Length();
m_stats.sent_packets++;
if (m_owner->m_options.simulated_out_packet_loss && m_owner->m_options.simulated_out_packet_loss >= m_owner->m_rand.Int(0, 100)) {
delete[](char*)send_req->data;
delete send_req;
return;
}
uv_udp_send(send_req, &m_owner->m_socket, send_buffers, 1, (sockaddr*)&send_addr, send_func);
return;
}
m_stats.bytes_before_encode += p.Length();
uv_udp_send_t *send_req = new uv_udp_send_t;
sockaddr_in send_addr;
uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr);
uv_buf_t send_buffers[1];
char *data = new char[p.Length()];
memcpy(data, p.Data(), p.Length()); memcpy(data, p.Data(), p.Length());
send_buffers[0] = uv_buf_init(data, p.Length()); send_buffers[0] = uv_buf_init(data, p.Length());
} send_req->data = send_buffers[0].base;
m_stats.sent_bytes += p.Length(); m_stats.sent_bytes += p.Length();
m_stats.sent_packets++; m_stats.sent_packets++;
if (m_owner->m_options.simulated_out_packet_loss && if (m_owner->m_options.simulated_out_packet_loss && m_owner->m_options.simulated_out_packet_loss >= m_owner->m_rand.Int(0, 100)) {
m_owner->m_options.simulated_out_packet_loss >= m_owner->m_rand.Int(0, 100)) { delete[](char*)send_req->data;
send_buffer_pool.release(ctx); delete send_req;
return; return;
} }
int send_result = uv_udp_send( uv_udp_send(send_req, &m_owner->m_socket, send_buffers, 1, (sockaddr*)&send_addr, send_func);
send_req, &m_owner->m_socket, send_buffers, 1, (sockaddr *)&send_addr,
[](uv_udp_send_t *req, int status) {
auto *ctx = reinterpret_cast<EmbeddedContext *>(req->data);
if (!ctx) {
std::cerr << "Error: send_req->data is null in callback!" << std::endl;
return;
}
if (status < 0) {
std::cerr << "uv_udp_send failed: " << uv_strerror(status) << std::endl;
}
ctx->pool->release(ctx);
}
);
if (send_result < 0) {
std::cerr << "uv_udp_send() failed: " << uv_strerror(send_result) << std::endl;
send_buffer_pool.release(ctx);
}
} }
void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, bool reliable) void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, bool reliable)
-7
View File
@@ -3,7 +3,6 @@
#include "../random.h" #include "../random.h"
#include "packet.h" #include "packet.h"
#include "daybreak_structs.h" #include "daybreak_structs.h"
#include "daybreak_pooling.h"
#include <uv.h> #include <uv.h>
#include <chrono> #include <chrono>
#include <functional> #include <functional>
@@ -182,12 +181,6 @@ namespace EQ
Timestamp m_close_time; Timestamp m_close_time;
double m_outgoing_budget; double m_outgoing_budget;
// resend tracking
size_t m_resend_packets_sent = 0;
size_t m_resend_bytes_sent = 0;
bool m_acked_since_last_resend = false;
Timestamp m_last_ack;
struct DaybreakSentPacket struct DaybreakSentPacket
{ {
DynamicPacket packet; DynamicPacket packet;
-123
View File
@@ -1,123 +0,0 @@
#pragma once
#include <optional>
#include <atomic>
#include <memory>
#include <array>
#include <vector>
#include <mutex>
#include <iostream>
#include "../eqemu_logsys.h"
#include <uv.h>
constexpr size_t UDP_BUFFER_SIZE = 512;
struct EmbeddedContext {
size_t pool_index;
class SendBufferPool* pool;
};
class SendBufferPool {
public:
explicit SendBufferPool(size_t initial_capacity = 64)
: m_capacity(initial_capacity), m_head(0)
{
LogNetClient("[SendBufferPool] Initializing with capacity [{}]", (int)m_capacity);
m_pool.reserve(m_capacity);
m_locks = std::make_unique<std::atomic_bool[]>(m_capacity);
for (size_t i = 0; i < m_capacity; ++i) {
auto* req = new PooledUdpSend();
req->context.pool_index = i;
req->context.pool = this;
req->uv_req.data = &req->context;
m_pool.emplace_back(std::unique_ptr<PooledUdpSend>(req));
m_locks[i].store(false, std::memory_order_relaxed);
}
}
std::optional<std::tuple<uv_udp_send_t*, char*, EmbeddedContext*>> acquire() {
size_t cap = m_capacity.load(std::memory_order_acquire);
for (size_t i = 0; i < cap; ++i) {
size_t index = m_head.fetch_add(1, std::memory_order_relaxed) % cap;
bool expected = false;
if (m_locks[index].compare_exchange_strong(expected, true)) {
auto* req = m_pool[index].get();
LogNetClientDetail("[SendBufferPool] Acquired [{}]", index);
return std::make_tuple(&req->uv_req, req->buffer.data(), &req->context);
}
}
LogNetClient("[SendBufferPool] Growing from [{}] to [{}]", cap, cap * 2);
grow();
return acquireAfterGrowth();
}
void release(EmbeddedContext* ctx) {
if (!ctx || ctx->pool != this || ctx->pool_index >= m_capacity.load(std::memory_order_acquire)) {
LogNetClient("[SendBufferPool] Invalid context release [{}]", ctx ? ctx->pool_index : -1);
return;
}
m_locks[ctx->pool_index].store(false, std::memory_order_release);
LogNetClientDetail("[SendBufferPool] Released [{}]", ctx->pool_index);
}
private:
struct PooledUdpSend {
uv_udp_send_t uv_req;
std::array<char, UDP_BUFFER_SIZE> buffer;
EmbeddedContext context;
};
std::vector<std::unique_ptr<PooledUdpSend>> m_pool;
std::unique_ptr<std::atomic_bool[]> m_locks;
std::atomic<size_t> m_capacity;
std::atomic<size_t> m_head;
std::mutex m_grow_mutex;
void grow() {
std::lock_guard<std::mutex> lock(m_grow_mutex);
size_t old_cap = m_capacity.load(std::memory_order_acquire);
size_t new_cap = old_cap * 2;
m_pool.reserve(new_cap);
for (size_t i = old_cap; i < new_cap; ++i) {
auto* req = new PooledUdpSend();
req->context.pool_index = i;
req->context.pool = this;
req->uv_req.data = &req->context;
m_pool.emplace_back(std::unique_ptr<PooledUdpSend>(req));
}
auto new_locks = std::make_unique<std::atomic_bool[]>(new_cap);
for (size_t i = 0; i < old_cap; ++i) {
new_locks[i].store(m_locks[i].load(std::memory_order_acquire));
}
for (size_t i = old_cap; i < new_cap; ++i) {
new_locks[i].store(false, std::memory_order_relaxed);
}
m_locks = std::move(new_locks);
m_capacity.store(new_cap, std::memory_order_release);
LogNetClient("[SendBufferPool] Grew to [{}] from [{}]", new_cap, old_cap);
}
std::optional<std::tuple<uv_udp_send_t*, char*, EmbeddedContext*>> acquireAfterGrowth() {
size_t cap = m_capacity.load(std::memory_order_acquire);
for (size_t i = 0; i < cap; ++i) {
size_t index = m_head.fetch_add(1, std::memory_order_relaxed) % cap;
bool expected = false;
if (m_locks[index].compare_exchange_strong(expected, true)) {
auto* req = m_pool[index].get();
LogNetClient("[SendBufferPool] Acquired after grow [{}]", index);
return std::make_tuple(&req->uv_req, req->buffer.data(), &req->context);
}
}
return std::nullopt;
}
};
-1
View File
@@ -171,4 +171,3 @@ namespace EQ
}; };
} }
} }
+1 -1
View File
@@ -71,7 +71,7 @@ void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req)
OpcodeManager::EmuToName(p->GetOpcode()), OpcodeManager::EmuToName(p->GetOpcode()),
(*m_opcode_manager)->EmuToEQ(p->GetOpcode()), (*m_opcode_manager)->EmuToEQ(p->GetOpcode()),
p->Size(), p->Size(),
(EQEmuLogSys::Instance()->IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "") (LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "")
); );
if (m_opcode_manager && *m_opcode_manager) { if (m_opcode_manager && *m_opcode_manager) {
+3 -3
View File
@@ -62,15 +62,15 @@ void EQ::Net::ServertalkClient::Connect()
m_connecting = true; m_connecting = true;
EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) { EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
if (connection == nullptr) { if (connection == nullptr) {
LogNetTCP("Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port); LogF(Logs::General, Logs::TCPConnection, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
m_connecting = false; m_connecting = false;
return; return;
} }
LogNetTCP("Connected to {0}:{1}", m_addr, m_port); LogF(Logs::General, Logs::TCPConnection, "Connected to {0}:{1}", m_addr, m_port);
m_connection = connection; m_connection = connection;
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) { m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
LogNetTCP("Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port); LogF(Logs::General, Logs::TCPConnection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
m_connection.reset(); m_connection.reset();
}); });
@@ -23,9 +23,6 @@ namespace EQ
bool Connected() const { return m_connecting != true; } bool Connected() const { return m_connecting != true; }
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; } std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
const std::unique_ptr<EQ::Timer> &GetTimer() const { return m_timer; }
private: private:
void Connect(); void Connect();
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length); void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
@@ -58,15 +58,15 @@ void EQ::Net::ServertalkLegacyClient::Connect()
m_connecting = true; m_connecting = true;
EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) { EQ::Net::TCPConnection::Connect(m_addr, m_port, false, [this](std::shared_ptr<EQ::Net::TCPConnection> connection) {
if (connection == nullptr) { if (connection == nullptr) {
LogNetTCP("Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port); LogF(Logs::General, Logs::TCPConnection, "Error connecting to {0}:{1}, attempting to reconnect...", m_addr, m_port);
m_connecting = false; m_connecting = false;
return; return;
} }
LogNetTCP("Connected to {0}:{1}", m_addr, m_port); LogF(Logs::General, Logs::TCPConnection, "Connected to {0}:{1}", m_addr, m_port);
m_connection = connection; m_connection = connection;
m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) { m_connection->OnDisconnect([this](EQ::Net::TCPConnection *c) {
LogNetTCP("Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port); LogF(Logs::General, Logs::TCPConnection, "Connection lost to {0}:{1}, attempting to reconnect...", m_addr, m_port);
m_connection.reset(); m_connection.reset();
}); });
+6 -6
View File
@@ -25,7 +25,7 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
return; return;
if (opcode == ServerOP_UsertoWorldReq) { if (opcode == ServerOP_UsertoWorldReq) {
auto req_in = (UsertoWorldRequest*)p.Data(); auto req_in = (UsertoWorldRequest_Struct*)p.Data();
EQ::Net::DynamicPacket req; EQ::Net::DynamicPacket req;
size_t i = 0; size_t i = 0;
@@ -45,7 +45,7 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
} }
if (opcode == ServerOP_LSClientAuth) { if (opcode == ServerOP_LSClientAuth) {
auto req_in = (ClientAuth*)p.Data(); auto req_in = (ClientAuth_Struct*)p.Data();
EQ::Net::DynamicPacket req; EQ::Net::DynamicPacket req;
size_t i = 0; size_t i = 0;
@@ -54,7 +54,7 @@ void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet
req.PutData(i, req_in->key, 30); i += 30; req.PutData(i, req_in->key, 30); i += 30;
req.PutUInt8(i, req_in->lsadmin); i += 1; req.PutUInt8(i, req_in->lsadmin); i += 1;
req.PutUInt16(i, req_in->is_world_admin); i += 2; req.PutUInt16(i, req_in->is_world_admin); i += 2;
req.PutUInt32(i, req_in->ip_address); i += 4; req.PutUInt32(i, req_in->ip); i += 4;
req.PutUInt8(i, req_in->is_client_from_local_network); i += 1; req.PutUInt8(i, req_in->is_client_from_local_network); i += 1;
EQ::Net::DynamicPacket out; EQ::Net::DynamicPacket out;
@@ -123,7 +123,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
{ {
size_t current = 0; size_t current = 0;
size_t total = m_buffer.size(); size_t total = m_buffer.size();
constexpr size_t ls_info_size = sizeof(LoginserverNewWorldRequest); constexpr size_t ls_info_size = sizeof(ServerNewLSInfo_Struct);
while (current < total) { while (current < total) {
auto left = total - current; auto left = total - current;
@@ -138,7 +138,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
//this creates a small edge case where the exact size of a //this creates a small edge case where the exact size of a
//packet from the modern protocol can't be "43061256" //packet from the modern protocol can't be "43061256"
//so in send we pad it one byte if that's the case //so in send we pad it one byte if that's the case
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(LoginserverNewWorldRequest)) { if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
m_legacy_mode = true; m_legacy_mode = true;
m_identifier = "World"; m_identifier = "World";
m_parent->ConnectionIdentified(this); m_parent->ConnectionIdentified(this);
@@ -319,7 +319,7 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
size_t message_len = length; size_t message_len = length;
EQ::Net::StaticPacket packet(&data[0], message_len); EQ::Net::StaticPacket packet(&data[0], message_len);
const auto is_detail_enabled = EQEmuLogSys::Instance()->IsLogEnabled(Logs::Detail, Logs::PacketServerToServer); const auto is_detail_enabled = LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerToServer);
if (opcode != ServerOP_KeepAlive || is_detail_enabled) { if (opcode != ServerOP_KeepAlive || is_detail_enabled) {
LogPacketServerToServer( LogPacketServerToServer(
"[{:#06x}] Size [{}] {}", "[{:#06x}] Size [{}] {}",
+37 -92
View File
@@ -1,8 +1,5 @@
#include "tcp_connection.h" #include "tcp_connection.h"
#include "../event/event_loop.h" #include "../event/event_loop.h"
#include <iostream>
WriteReqPool tcp_write_pool;
void on_close_handle(uv_handle_t* handle) { void on_close_handle(uv_handle_t* handle) {
delete (uv_tcp_t *)handle; delete (uv_tcp_t *)handle;
@@ -67,37 +64,34 @@ void EQ::Net::TCPConnection::Connect(const std::string &addr, int port, bool ipv
}); });
} }
void EQ::Net::TCPConnection::Start() void EQ::Net::TCPConnection::Start() {
{ uv_read_start((uv_stream_t*)m_socket, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
uv_read_start(
(uv_stream_t *) m_socket, [](uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
if (suggested_size > 65536) {
buf->base = new char[suggested_size]; buf->base = new char[suggested_size];
buf->len = suggested_size; buf->len = suggested_size;
return; }, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
}
static thread_local char temp_buf[65536]; TCPConnection *connection = (TCPConnection*)stream->data;
buf->base = temp_buf;
buf->len = 65536;
}, [](uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
auto *connection = (TCPConnection *) stream->data;
if (nread > 0) { if (nread > 0) {
connection->Read(buf->base, nread); connection->Read(buf->base, nread);
if (buf->base) {
delete[] buf->base;
}
} }
else if (nread == UV_EOF) { else if (nread == UV_EOF) {
connection->Disconnect(); if (buf->base) {
delete[] buf->base;
}
} }
else if (nread < 0) { else if (nread < 0) {
connection->Disconnect(); connection->Disconnect();
}
if (buf->len > 65536) { if (buf->base) {
delete [] buf->base; delete[] buf->base;
} }
} }
); });
} }
void EQ::Net::TCPConnection::OnRead(std::function<void(TCPConnection*, const unsigned char*, size_t)> cb) void EQ::Net::TCPConnection::OnRead(std::function<void(TCPConnection*, const unsigned char*, size_t)> cb)
@@ -134,92 +128,43 @@ void EQ::Net::TCPConnection::Read(const char *data, size_t count)
} }
} }
void EQ::Net::TCPConnection::Write(const char* data, size_t count) { void EQ::Net::TCPConnection::Write(const char *data, size_t count)
if (!m_socket || !data || count == 0) { {
std::cerr << "TCPConnection::Write - Invalid socket or data\n"; if (!m_socket) {
return; return;
} }
if (count <= TCP_BUFFER_SIZE) { struct WriteBaton
// Fast path: use pooled request with embedded buffer {
auto req_opt = tcp_write_pool.acquire(); TCPConnection *connection;
if (!req_opt) { char *buffer;
std::cerr << "TCPConnection::Write - Out of write requests\n"; };
return;
}
TCPWriteReq* write_req = *req_opt; WriteBaton *baton = new WriteBaton;
baton->connection = this;
baton->buffer = new char[count];
// Fill buffer and set context uv_write_t *write_req = new uv_write_t;
memcpy(write_req->buffer.data(), data, count); memset(write_req, 0, sizeof(uv_write_t));
write_req->connection = this; write_req->data = baton;
write_req->magic = 0xC0FFEE; uv_buf_t send_buffers[1];
uv_buf_t buf = uv_buf_init(write_req->buffer.data(), static_cast<unsigned int>(count)); memcpy(baton->buffer, data, count);
send_buffers[0] = uv_buf_init(baton->buffer, count);
int result = uv_write( uv_write(write_req, (uv_stream_t*)m_socket, send_buffers, 1, [](uv_write_t* req, int status) {
&write_req->req, WriteBaton *baton = (WriteBaton*)req->data;
reinterpret_cast<uv_stream_t*>(m_socket), delete[] baton->buffer;
&buf,
1,
[](uv_write_t* req, int status) {
auto* full_req = reinterpret_cast<TCPWriteReq*>(req);
if (full_req->magic != 0xC0FFEE) {
std::cerr << "uv_write callback - invalid magic, skipping release\n";
return;
}
tcp_write_pool.release(full_req);
if (status < 0 && full_req->connection) {
std::cerr << "uv_write failed: " << uv_strerror(status) << std::endl;
full_req->connection->Disconnect();
}
}
);
if (result < 0) {
std::cerr << "uv_write() failed immediately: " << uv_strerror(result) << std::endl;
tcp_write_pool.release(write_req);
}
} else {
// Slow path: allocate heap buffer for large write
LogNetTCP("[TCPConnection] Large write of [{}] bytes, using heap buffer", count);
char* heap_buffer = new char[count];
memcpy(heap_buffer, data, count);
uv_write_t* write_req = new uv_write_t;
write_req->data = heap_buffer;
uv_buf_t buf = uv_buf_init(heap_buffer, static_cast<unsigned int>(count));
int result = uv_write(
write_req,
reinterpret_cast<uv_stream_t*>(m_socket),
&buf,
1,
[](uv_write_t* req, int status) {
char* data = static_cast<char*>(req->data);
delete[] data;
delete req; delete req;
if (status < 0) { if (status < 0) {
std::cerr << "uv_write (large) failed: " << uv_strerror(status) << std::endl; baton->connection->Disconnect();
} }
}
);
if (result < 0) { delete baton;
std::cerr << "uv_write() (large) failed immediately: " << uv_strerror(result) << std::endl; });
delete[] heap_buffer;
delete write_req;
}
}
} }
std::string EQ::Net::TCPConnection::LocalIP() const std::string EQ::Net::TCPConnection::LocalIP() const
{ {
sockaddr_storage addr; sockaddr_storage addr;
-1
View File
@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "tcp_connection_pooling.h"
#include <functional> #include <functional>
#include <string> #include <string>
#include <memory> #include <memory>
-125
View File
@@ -1,125 +0,0 @@
#pragma once
#include "../eqemu_logsys.h"
#include <vector>
#include <array>
#include <atomic>
#include <memory>
#include <optional>
#include <mutex>
#include <uv.h>
#include <iostream>
namespace EQ { namespace Net { class TCPConnection; } }
constexpr size_t TCP_BUFFER_SIZE = 8192;
struct TCPWriteReq {
uv_write_t req{};
std::array<char, TCP_BUFFER_SIZE> buffer{};
size_t buffer_index{};
EQ::Net::TCPConnection* connection{};
uint32_t magic = 0xC0FFEE;
};
class WriteReqPool {
public:
explicit WriteReqPool(size_t initial_capacity = 512)
: m_capacity(initial_capacity), m_head(0) {
initialize_pool(m_capacity);
}
std::optional<TCPWriteReq*> acquire() {
size_t cap = m_capacity.load(std::memory_order_acquire);
for (size_t i = 0; i < cap; ++i) {
size_t index = m_head.fetch_add(1, std::memory_order_relaxed) % cap;
bool expected = false;
if (m_locks[index].compare_exchange_strong(expected, true, std::memory_order_acquire)) {
LogNetTCPDetail("[WriteReqPool] Acquired buffer index [{}]", index);
return m_reqs[index].get();
}
}
LogNetTCP("[WriteReqPool] Growing from [{}] to [{}]", cap, cap * 2);
grow();
return acquireAfterGrow();
}
void release(TCPWriteReq* req) {
if (!req) return;
const size_t index = req->buffer_index;
const size_t cap = m_capacity.load(std::memory_order_acquire);
if (index >= cap || m_reqs[index].get() != req) {
std::cerr << "WriteReqPool::release - Invalid or stale pointer (index=" << index << ")\n";
return;
}
m_locks[index].store(false, std::memory_order_release);
LogNetTCPDetail("[WriteReqPool] Released buffer index [{}]", index);
}
private:
std::vector<std::unique_ptr<TCPWriteReq>> m_reqs;
std::unique_ptr<std::atomic_bool[]> m_locks;
std::atomic<size_t> m_capacity;
std::atomic<size_t> m_head;
std::mutex m_grow_mutex;
void initialize_pool(size_t count) {
m_reqs.reserve(count);
m_locks = std::make_unique<std::atomic_bool[]>(count);
for (size_t i = 0; i < count; ++i) {
auto req = std::make_unique<TCPWriteReq>();
req->buffer_index = i;
req->req.data = req.get(); // optional: for use in libuv callbacks
m_locks[i].store(false, std::memory_order_relaxed);
m_reqs.emplace_back(std::move(req));
}
m_capacity.store(count, std::memory_order_release);
}
void grow() {
std::lock_guard<std::mutex> lock(m_grow_mutex);
const size_t old_cap = m_capacity.load(std::memory_order_acquire);
const size_t new_cap = old_cap * 2;
m_reqs.reserve(new_cap);
for (size_t i = old_cap; i < new_cap; ++i) {
auto req = std::make_unique<TCPWriteReq>();
req->buffer_index = i;
req->req.data = req.get(); // optional
m_reqs.emplace_back(std::move(req));
}
auto new_locks = std::make_unique<std::atomic_bool[]>(new_cap);
for (size_t i = 0; i < old_cap; ++i) {
new_locks[i].store(m_locks[i].load(std::memory_order_acquire));
}
for (size_t i = old_cap; i < new_cap; ++i) {
new_locks[i].store(false, std::memory_order_relaxed);
}
m_locks = std::move(new_locks);
m_capacity.store(new_cap, std::memory_order_release);
}
std::optional<TCPWriteReq*> acquireAfterGrow() {
const size_t cap = m_capacity.load(std::memory_order_acquire);
for (size_t i = 0; i < cap; ++i) {
bool expected = false;
if (m_locks[i].compare_exchange_strong(expected, true, std::memory_order_acquire)) {
LogNetTCP("[WriteReqPool] Acquired buffer index [{}] after grow", i);
return m_reqs[i].get();
}
}
return std::nullopt;
}
};
-2
View File
@@ -197,7 +197,6 @@ IN(OP_RecipeDetails, uint32);
//there is also a complicated OP_RecipeDetails reply struct OUT //there is also a complicated OP_RecipeDetails reply struct OUT
IN(OP_RecipeAutoCombine, RecipeAutoCombine_Struct); IN(OP_RecipeAutoCombine, RecipeAutoCombine_Struct);
IN(OP_TradeSkillCombine, NewCombine_Struct); IN(OP_TradeSkillCombine, NewCombine_Struct);
IN(OP_TradeSkillRecipeInspect, TradeSkillRecipeInspect_Struct);
IN(OP_ItemName, ItemNamePacket_Struct); IN(OP_ItemName, ItemNamePacket_Struct);
IN(OP_AugmentItem, AugmentItem_Struct); IN(OP_AugmentItem, AugmentItem_Struct);
IN(OP_ClickDoor, ClickDoor_Struct); IN(OP_ClickDoor, ClickDoor_Struct);
@@ -251,7 +250,6 @@ IN(OP_TraderBuy, TraderBuy_Struct);
IN(OP_Trader, Trader_ShowItems_Struct); IN(OP_Trader, Trader_ShowItems_Struct);
IN(OP_GMFind, GMSummon_Struct); IN(OP_GMFind, GMSummon_Struct);
IN(OP_PickPocket, PickPocket_Struct); IN(OP_PickPocket, PickPocket_Struct);
IN(OP_PickZone, PickZone_Struct);
IN(OP_Bind_Wound, BindWound_Struct); IN(OP_Bind_Wound, BindWound_Struct);
INr(OP_TrackTarget); INr(OP_TrackTarget);
INr(OP_Track); INr(OP_Track);
+19 -26
View File
@@ -78,7 +78,7 @@ namespace RoF
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
@@ -117,7 +117,7 @@ namespace RoF
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@@ -1213,22 +1213,22 @@ namespace RoF
case 1: { // GuildBankItemUpdate case 1: { // GuildBankItemUpdate
auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer;
auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer;
eq->action = 0; eq->Action = 0;
OUT(unknown004); OUT(Unknown004);
eq->unknown008 = 0; eq->Unknown08 = 0;
OUT(slot_id); OUT(SlotID);
OUT(area); OUT(Area);
OUT(display); OUT(Unknown012);
OUT(item_id); OUT(ItemID);
OUT(icon_id); OUT(Icon);
OUT(quantity); OUT(Quantity);
OUT(permissions); OUT(Permissions);
OUT(allow_merge); OUT(AllowMerge);
OUT(is_useable); OUT(Useable);
OUT_str(item_name); OUT_str(ItemName);
OUT_str(donator); OUT_str(Donator);
OUT_str(who_for); OUT_str(WhoFor);
OUT(unknown226); OUT(Unknown226);
break; break;
} }
default: default:
@@ -5188,14 +5188,7 @@ namespace RoF
//sprintf(hdr.unknown000, "06e0002Y1W00"); //sprintf(hdr.unknown000, "06e0002Y1W00");
strn0cpy( snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
hdr.unknown000,
fmt::format(
"{:016}\0",
packet_type == ItemPacketInvalid ? 0 : inst->GetSerialNumber()
).c_str(),
sizeof(hdr.unknown000)
);
hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 1000) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 1000) ? 0xFFFFFFFF : inst->GetCharges()) : 1);
hdr.unknown004 = 0; hdr.unknown004 = 0;
+49 -151
View File
@@ -81,7 +81,7 @@ namespace RoF2
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
@@ -123,7 +123,7 @@ namespace RoF2
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@@ -433,9 +433,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon); VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
VARSTRUCT_SKIP_TYPE(uint32, eq); VARSTRUCT_SKIP_TYPE(uint32, eq);
} }
dest->QueuePacket(outapp.get()); dest->QueuePacket(outapp.get());
safe_delete(in);
break; break;
} }
default: { default: {
@@ -470,8 +468,8 @@ namespace RoF2
} }
auto p_size = 41 * results.size() + name_size + 14; auto p_size = 41 * results.size() + name_size + 14;
auto buffer = new char[p_size]; auto buffer = std::make_unique<char[]>(p_size);
auto bufptr = buffer; auto bufptr = buffer.get();
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0); VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, results[0].trader_zone_id); VARSTRUCT_ENCODE_TYPE(uint16, bufptr, results[0].trader_zone_id);
@@ -489,11 +487,10 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_stat); //itemstat VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_stat); //itemstat
} }
safe_delete_array(in->pBuffer); safe_delete(in->pBuffer);
in->size = p_size; in->size = p_size;
in->pBuffer = (uchar*)buffer; in->pBuffer = (uchar *) buffer.get();
dest->QueuePacket(in); dest->QueuePacket(in);
safe_delete(in);
break; break;
} }
@@ -503,22 +500,21 @@ namespace RoF2
break; break;
} }
case WelcomeMessage: { case WelcomeMessage: {
auto buffer = new char[sizeof(structs::BazaarWelcome_Struct)]; auto buffer = std::make_unique<char[]>(sizeof(structs::BazaarWelcome_Struct));
auto emu = (BazaarWelcome_Struct *) in->pBuffer; auto emu = (BazaarWelcome_Struct *) in->pBuffer;
auto eq = (structs::BazaarWelcome_Struct *) buffer; auto eq = (structs::BazaarWelcome_Struct *) buffer.get();
eq->action = structs::RoF2BazaarTraderBuyerActions::WelcomeMessage; eq->action = structs::RoF2BazaarTraderBuyerActions::WelcomeMessage;
eq->num_of_traders = emu->traders; eq->num_of_traders = emu->traders;
eq->num_of_items = emu->items; eq->num_of_items = emu->items;
safe_delete_array(in->pBuffer); safe_delete(in->pBuffer);
in->SetOpcode(OP_TraderShop); in->SetOpcode(OP_TraderShop);
in->size = sizeof(structs::BazaarWelcome_Struct); in->size = sizeof(structs::BazaarWelcome_Struct);
in->pBuffer = (uchar *)buffer; in->pBuffer = (uchar *) buffer.get();
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action); LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
dest->QueuePacket(in); dest->QueuePacket(in);
safe_delete(in);
break; break;
} }
@@ -591,17 +587,15 @@ namespace RoF2
eq->entity_id = emu->entity_id; eq->entity_id = emu->entity_id;
eq->trader_id = emu->trader_id; eq->trader_id = emu->trader_id;
eq->zone_id = emu->zone_id; eq->zone_id = emu->zone_id;
eq->zone_instance_id = emu->zone_instance_id;
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name)); strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
LogTrading( LogTrading(
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] " "(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] zone_id <green>[{}]",
"zone_id <green>[{}] zone_instance_id <green>[{}]",
eq->action, eq->action,
eq->trader_id, eq->trader_id,
eq->entity_id, eq->entity_id,
eq->zone_id, eq->zone_id
eq->zone_instance_id); );
dest->FastQueuePacket(&outapp); dest->FastQueuePacket(&outapp);
break; break;
} }
@@ -896,9 +890,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_instance_id); VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_instance_id);
VARSTRUCT_ENCODE_STRING(eq, b.buyer_name.c_str()); VARSTRUCT_ENCODE_STRING(eq, b.buyer_name.c_str());
} }
dest->QueuePacket(outapp.get()); dest->QueuePacket(outapp.get());
safe_delete(inapp);
break; break;
} }
case Barter_RemoveFromMerchantWindow: { case Barter_RemoveFromMerchantWindow: {
@@ -969,7 +961,6 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.seller_quantity); VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.seller_quantity);
dest->QueuePacket(outapp.get()); dest->QueuePacket(outapp.get());
safe_delete(inapp);
break; break;
} }
default: { default: {
@@ -1350,58 +1341,6 @@ namespace RoF2
dest->FastQueuePacket(&in, ack_req); dest->FastQueuePacket(&in, ack_req);
} }
ENCODE(OP_EvolveItem)
{
EQApplicationPacket *in = *p;
*p = nullptr;
auto action = *reinterpret_cast<uint32 *>(in->pBuffer);
switch (action) {
case EvolvingItems::Actions::TRANSFER_WINDOW_DETAILS: {
auto emu = reinterpret_cast<EvolveItemMessaging *>(in->pBuffer);
EvolveXPWindowSend e{};
EQ::Util::MemoryStreamReader ss(emu->serialized_data, in->size - sizeof(emu->action));
cereal::BinaryInputArchive ar(ss);
ar(e);
auto item_1 = static_cast<const EQ::ItemInstance *>(reinterpret_cast<EQ::InternalSerializedItem_Struct
*>(e.serialize_item_1.data())->inst);
auto item_2 = static_cast<const EQ::ItemInstance *>(reinterpret_cast<EQ::InternalSerializedItem_Struct
*>(e.serialize_item_2.data())->inst);
EQ::OutBuffer ob;
SerializeItem(ob, item_1, 0, 0, ItemPacketMerchant);
SerializeItem(ob, item_2, 0, 0, ItemPacketMerchant);
auto out = std::make_unique<EQApplicationPacket>(
OP_EvolveItem,
sizeof(EvolveXPWindowSendDetails_Struct) + ob.size()
);
auto data = reinterpret_cast<EvolveXPWindowSendDetails_Struct *>(out->pBuffer);
data->action = e.action;
data->compatibility = e.compatibility;
data->max_transfer_level = e.max_transfer_level;
data->item1_unique_id = e.item1_unique_id;
data->item2_unique_id = e.item2_unique_id;
data->item1_present = e.item1_present;
data->item2_present = e.item2_present;
memcpy(data->serialize_data, ob.str().data(), ob.size());
dest->QueuePacket(out.get());
safe_delete(in);
break;
}
default: {
dest->FastQueuePacket(&in);
break;
}
}
}
ENCODE(OP_ExpansionInfo) ENCODE(OP_ExpansionInfo)
{ {
ENCODE_LENGTH_EXACT(ExpansionInfo_Struct); ENCODE_LENGTH_EXACT(ExpansionInfo_Struct);
@@ -1743,19 +1682,22 @@ namespace RoF2
case 1: { // GuildBankItemUpdate case 1: { // GuildBankItemUpdate
auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer;
auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer;
eq->action = 0; eq->Action = 0;
OUT(display); OUT(Unknown004);
OUT(slot_id); eq->Unknown08 = 0;
OUT(area); OUT(SlotID);
OUT(item_id); OUT(Area);
OUT(icon_id); OUT(Unknown012);
OUT(quantity); OUT(ItemID);
OUT(permissions); OUT(Icon);
OUT(allow_merge); OUT(Quantity);
OUT(is_useable); OUT(Permissions);
OUT_str(item_name); OUT(AllowMerge);
OUT_str(donator); OUT(Useable);
OUT_str(who_for); OUT_str(ItemName);
OUT_str(Donator);
OUT_str(WhoFor);
OUT(Unknown226);
break; break;
} }
default: default:
@@ -1901,11 +1843,11 @@ namespace RoF2
} }
} }
safe_delete_array(in->pBuffer); auto outapp = new EQApplicationPacket(OP_GuildsList);
outapp->size = packet_size;
outapp->pBuffer = buffer;
in->pBuffer = buffer; dest->FastQueuePacket(&outapp);
in->size = packet_size;
dest->FastQueuePacket(&in);
} }
ENCODE(OP_GuildTributeDonateItem) ENCODE(OP_GuildTributeDonateItem)
@@ -2102,33 +2044,6 @@ namespace RoF2
} }
} }
ENCODE(OP_ItemPreviewRequest)
{
EQApplicationPacket* in = *p;
*p = nullptr;
uchar* in_buf = in->pBuffer;
auto int_item = (EQ::InternalSerializedItem_Struct*) in_buf;
EQ::OutBuffer buf;
EQ::OutBuffer::pos_type last_pos = buf.tellp();
SerializeItem(buf, (const EQ::ItemInstance*) int_item->inst, int_item->slot_id, 0, ItemPacketInvalid);
if (buf.tellp() == last_pos) {
LogNetcode("RoF2::ENCODE(OP_ItemPreviewRequest) Serialization failed");
safe_delete_array(in_buf);
safe_delete(in);
return;
}
in->size = buf.size();
in->pBuffer = buf.detach();
safe_delete_array(in_buf);
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_ItemVerifyReply) ENCODE(OP_ItemVerifyReply)
{ {
ENCODE_LENGTH_EXACT(ItemVerifyReply_Struct); ENCODE_LENGTH_EXACT(ItemVerifyReply_Struct);
@@ -4688,7 +4603,7 @@ namespace RoF2
Bitfields->linkdead = 0; Bitfields->linkdead = 0;
Bitfields->showhelm = emu->showhelm; Bitfields->showhelm = emu->showhelm;
Bitfields->trader = emu->trader ? 1 : 0; Bitfields->trader = emu->trader ? 1 : 0;
Bitfields->targetable = emu->NPC ? emu->untargetable : 1; Bitfields->targetable = 1;
Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0; Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
Bitfields->showname = ShowName; Bitfields->showname = ShowName;
@@ -4841,7 +4756,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // FindBits MQ2 name VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // FindBits MQ2 name
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->npc_tint_id); // NpcTintIndex VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // NpcTintIndex
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // PrimaryTintIndex VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // PrimaryTintIndex
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // SecondaryTintIndex VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // SecondaryTintIndex
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
@@ -6303,11 +6218,6 @@ namespace RoF2
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
break; break;
} }
case structs::RoF2BazaarTraderBuyerActions::FirstOpenSearch: {
__packet->SetOpcode(OP_BazaarSearch);
LogTrading("(RoF2) First time opening Bazaar Search since zoning. Action <green>[{}]", action);
break;
}
case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: { case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: {
__packet->SetOpcode(OP_BazaarSearch); __packet->SetOpcode(OP_BazaarSearch);
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action); LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
@@ -6448,18 +6358,9 @@ namespace RoF2
//sprintf(hdr.unknown000, "06e0002Y1W00"); //sprintf(hdr.unknown000, "06e0002Y1W00");
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000)); strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
hdr.stacksize = 1; hdr.stacksize =
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
if (item->ID == PARCEL_MONEY_ITEM_ID) { ? 0xFFFFFFFF : inst->GetCharges()) : 1);
hdr.stacksize = inst->GetPrice();
} else if (inst->IsStackable()) {
if (inst->GetCharges() > std::numeric_limits<int16>::max()) {
hdr.stacksize = std::numeric_limits<uint32>::max();
} else {
hdr.stacksize = inst->GetCharges();
}
}
hdr.unknown004 = 0; hdr.unknown004 = 0;
structs::InventorySlot_Struct slot_id{}; structs::InventorySlot_Struct slot_id{};
@@ -6481,11 +6382,6 @@ namespace RoF2
hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0);
hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber());
hdr.parcel_item_id = packet_type == ItemPacketParcel ? inst->GetID() : 0; hdr.parcel_item_id = packet_type == ItemPacketParcel ? inst->GetID() : 0;
if (item->EvolvingItem) {
hdr.instance_id = inst->GetEvolveUniqueID() & 0xFFFFFFFF; //lower dword
hdr.parcel_item_id = inst->GetEvolveUniqueID() >> 32; //upper dword
}
hdr.last_cast_time = inst->GetRecastTimestamp(); hdr.last_cast_time = inst->GetRecastTimestamp();
hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254)
? 0xFFFFFFFF ? 0xFFFFFFFF
@@ -6499,15 +6395,18 @@ namespace RoF2
ob.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); ob.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader));
if (item->EvolvingItem > 0) { if (item->EvolvingItem > 0) {
RoF2::structs::EvolvingItem_Struct evotop; RoF2::structs::EvolvingItem evotop;
evotop.final_item_id = inst->GetEvolveFinalItemID(); evotop.unknown001 = 0;
evotop.evolve_level = item->EvolvingLevel; evotop.unknown002 = 0;
evotop.progress = inst->GetEvolveProgression(); evotop.unknown003 = 0;
evotop.activated = inst->GetEvolveActivated(); evotop.unknown004 = 0;
evotop.evolve_max_level = item->EvolvingMax; evotop.evoLevel = item->EvolvingLevel;
evotop.progress = 0;
evotop.Activated = 1;
evotop.evomaxlevel = item->EvolvingMax;
ob.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem_Struct)); ob.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem));
} }
/** /**
@@ -6881,13 +6780,12 @@ namespace RoF2
iqbs.Heirloom = 0; iqbs.Heirloom = 0;
iqbs.Placeable = 0; iqbs.Placeable = 0;
iqbs.unknown28 = -1; iqbs.unknown28 = -1;
iqbs.unknown29 = packet_type == ItemPacketInvalid ? 0xFF : 0;
iqbs.unknown30 = -1; iqbs.unknown30 = -1;
iqbs.NoZone = 0; iqbs.NoZone = 0;
iqbs.NoGround = 0; iqbs.NoGround = 0;
iqbs.unknown37a = 0; // (guessed position) New to RoF2 iqbs.unknown37a = 0; // (guessed position) New to RoF2
iqbs.unknown38 = 0; iqbs.unknown38 = 0;
iqbs.unknown39 = packet_type == ItemPacketInvalid ? 0 : 1;; iqbs.unknown39 = 1;
ob.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); ob.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct));
+3 -38
View File
@@ -86,7 +86,7 @@ namespace RoF2
const int16 TRIBUTE_SIZE = 5; const int16 TRIBUTE_SIZE = 5;
const int16 TROPHY_TRIBUTE_SIZE = 0;//unknown const int16 TROPHY_TRIBUTE_SIZE = 0;//unknown
const int16 GUILD_TRIBUTE_SIZE = 2;//unverified const int16 GUILD_TRIBUTE_SIZE = 2;//unverified
const int16 MERCHANT_SIZE = 500; const int16 MERCHANT_SIZE = 200;
const int16 DELETED_SIZE = 0;//unknown - "Recovery Tab" const int16 DELETED_SIZE = 0;//unknown - "Recovery Tab"
const int16 CORPSE_SIZE = POSSESSIONS_SIZE; const int16 CORPSE_SIZE = POSSESSIONS_SIZE;
const int16 BAZAAR_SIZE = 200; const int16 BAZAAR_SIZE = 200;
@@ -101,8 +101,6 @@ namespace RoF2
const int16 MAIL_SIZE = 0;//unknown const int16 MAIL_SIZE = 0;//unknown
const int16 GUILD_TROPHY_TRIBUTE_SIZE = 0;//unknown const int16 GUILD_TROPHY_TRIBUTE_SIZE = 0;//unknown
const int16 KRONO_SIZE = 0;//unknown const int16 KRONO_SIZE = 0;//unknown
const int16 GUILD_BANK_MAIN_SIZE = 200;
const int16 GUILD_BANK_DEPOSIT_SIZE = 40;
const int16 OTHER_SIZE = 0;//unknown const int16 OTHER_SIZE = 0;//unknown
const int16 TRADE_NPC_SIZE = 4; // defined by implication const int16 TRADE_NPC_SIZE = 4; // defined by implication
@@ -164,30 +162,9 @@ namespace RoF2
} // namespace enum_ } // namespace enum_
using namespace enum_; using namespace enum_;
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_INVALID = IINVALID; const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL; const int16 SLOT_BEGIN = INULL;
const int16 BANK_BEGIN = 2000;
const int16 BANK_END = (BANK_BEGIN + invtype::BANK_SIZE) - 1;
const int16 SHARED_BANK_BEGIN = 2500;
const int16 SHARED_BANK_END = (SHARED_BANK_BEGIN + invtype::SHARED_BANK_SIZE) - 1;
const int16 TRADE_BEGIN = 3000;
const int16 TRADE_END = (TRADE_BEGIN + invtype::TRADE_SIZE) - 1;
const int16 TRADE_NPC_END = (TRADE_BEGIN + invtype::TRADE_NPC_SIZE) - 1; // defined by implication
const int16 WORLD_BEGIN = 4000;
const int16 WORLD_END = (WORLD_BEGIN + invtype::WORLD_SIZE) - 1;
const int16 TRIBUTE_BEGIN = 400;
const int16 TRIBUTE_END = (TRIBUTE_BEGIN + invtype::TRIBUTE_SIZE) - 1;
const int16 GUILD_TRIBUTE_BEGIN = 450;
const int16 GUILD_TRIBUTE_END = (GUILD_TRIBUTE_BEGIN + invtype::GUILD_TRIBUTE_SIZE) - 1;
const int16 POSSESSIONS_BEGIN = slotCharm; const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor; const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1; const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
@@ -222,21 +199,10 @@ namespace RoF2
namespace invbag { namespace invbag {
inline EQ::versions::ClientVersion GetInvBagRef() { return EQ::versions::ClientVersion::RoF2; } inline EQ::versions::ClientVersion GetInvBagRef() { return EQ::versions::ClientVersion::RoF2; }
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_INVALID = IINVALID; const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL; const int16 SLOT_BEGIN = INULL;
const int16 SLOT_COUNT = 200; const int16 SLOT_END = 9; //254;
const int16 SLOT_END = SLOT_COUNT - 1; const int16 SLOT_COUNT = 10; //255; // server Size will be 255..unsure what actual client is (test)
const int16 GENERAL_BAGS_BEGIN = 251;
const int16 CURSOR_BAG_BEGIN = 351;
const int16 BANK_BAGS_BEGIN = 2031;
const int16 SHARED_BANK_BAGS_BEGIN = 2531;
const int16 TRADE_BAGS_BEGIN = 3031;
const char* GetInvBagIndexName(int16 bag_index); const char* GetInvBagIndexName(int16 bag_index);
@@ -306,7 +272,6 @@ namespace RoF2
const size_t SAY_LINK_BODY_SIZE = 56; const size_t SAY_LINK_BODY_SIZE = 56;
const uint32 MAX_GUILD_ID = 50000; const uint32 MAX_GUILD_ID = 50000;
const uint32 MAX_BAZAAR_TRADERS = 600;
} /*constants*/ } /*constants*/
-2
View File
@@ -70,7 +70,6 @@ E(OP_DzMemberListName)
E(OP_DzMemberListStatus) E(OP_DzMemberListStatus)
E(OP_DzSetLeaderName) E(OP_DzSetLeaderName)
E(OP_Emote) E(OP_Emote)
E(OP_EvolveItem)
E(OP_ExpansionInfo) E(OP_ExpansionInfo)
E(OP_FormattedMessage) E(OP_FormattedMessage)
E(OP_GMLastName) E(OP_GMLastName)
@@ -92,7 +91,6 @@ E(OP_InspectBuffs)
E(OP_InspectRequest) E(OP_InspectRequest)
E(OP_ItemLinkResponse) E(OP_ItemLinkResponse)
E(OP_ItemPacket) E(OP_ItemPacket)
E(OP_ItemPreviewRequest)
E(OP_ItemVerifyReply) E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate) E(OP_LeadershipExpUpdate)
E(OP_LogServer) E(OP_LogServer)
+40 -67
View File
@@ -1965,39 +1965,41 @@ struct GuildBankWithdrawItem_Struct
struct GuildBankItemUpdate_Struct struct GuildBankItemUpdate_Struct
{ {
void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown016, uint32 inItemID, uint32 inIcon, uint32 inQuantity, void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity,
uint32 inPermissions, uint32 inAllowMerge, bool inUseable) uint32 inPermissions, uint32 inAllowMerge, bool inUseable)
{ {
action = inAction; Action = inAction;
slot_id = inSlotID; Unknown004 = inUnknown004;
area = inArea; SlotID = inSlotID;
display = inUnknown016; Area = inArea;
item_id = inItemID; Unknown012 = inUnknown012;
icon_id = inIcon; ItemID = inItemID;
quantity = inQuantity; Icon = inIcon;
permissions = inPermissions; Quantity = inQuantity;
allow_merge = inAllowMerge; Permissions = inPermissions;
is_useable = inUseable; AllowMerge = inAllowMerge;
item_name[0] = '\0'; Useable = inUseable;
donator[0] = '\0'; ItemName[0] = '\0';
who_for[0] = '\0'; Donator[0] = '\0';
WhoFor[0] = '\0';
}; };
/*000*/ uint32 action; /*000*/ uint32 Action;
/*004*/ uint32 not_used004; //disassemble of client did not use this /*004*/ uint32 Unknown004;
/*008*/ uint32 not_used008; //disassemble of client did not use this /*008*/ uint32 Unknown08;
/*012*/ uint16 slot_id; /*012*/ uint16 SlotID;
/*014*/ uint16 area; /*014*/ uint16 Area;
/*016*/ uint32 display; /*016*/ uint32 Unknown012;
/*020*/ uint32 item_id; /*020*/ uint32 ItemID;
/*024*/ uint32 icon_id; /*024*/ uint32 Icon;
/*028*/ uint32 quantity; /*028*/ uint32 Quantity;
/*032*/ uint32 permissions; /*032*/ uint32 Permissions;
/*036*/ uint8 allow_merge; /*036*/ uint8 AllowMerge;
/*037*/ uint8 is_useable; // Used in conjunction with the Public-if-useable permission. /*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission.
/*038*/ char item_name[64]; /*038*/ char ItemName[64];
/*102*/ char donator[64]; /*102*/ char Donator[64];
/*166*/ char who_for[64]; /*166*/ char WhoFor[64];
/*230*/ uint16 Unknown226;
}; };
struct GuildBankClear_Struct struct GuildBankClear_Struct
@@ -3117,8 +3119,7 @@ enum RoF2BazaarTraderBuyerActions {
BazaarInspect = 18, BazaarInspect = 18,
ClickTrader = 28, ClickTrader = 28,
ItemMove = 19, ItemMove = 19,
ReconcileItems = 20, ReconcileItems = 20
FirstOpenSearch = 26
}; };
enum RoF2BuyerActions { enum RoF2BuyerActions {
@@ -3933,11 +3934,6 @@ struct NewCombine_Struct
/*24*/ /*24*/
}; };
struct TradeSkillRecipeInspect_Struct {
uint32 recipe_id;
uint32 padding[17];
};
//client requesting favorite recipies //client requesting favorite recipies
struct TradeskillFavorites_Struct { struct TradeskillFavorites_Struct {
@@ -4749,12 +4745,15 @@ struct ItemSerializationHeader
uint8 isEvolving; uint8 isEvolving;
}; };
struct EvolvingItem_Struct { struct EvolvingItem {
uint32 final_item_id; uint8 unknown001;
int32 evolve_level; uint8 unknown002;
uint8 unknown003;
uint8 unknown004;
int32 evoLevel;
double progress; double progress;
uint8 activated; uint8 Activated;
int32 evolve_max_level; int32 evomaxlevel;
uint8 unknown005[4]; uint8 unknown005[4];
}; };
@@ -5428,32 +5427,6 @@ struct Parcel_Struct
}; };
}; /*structs*/ }; /*structs*/
struct EvolveItemToggle_Struct {
uint32 action;
uint32 unknown_004;
uint64 unique_id;
uint32 percentage;
uint32 activated;
};
struct EvolveXPWindowReceive_Struct {
uint32 action;
uint32 unknown_004;
uint64 item1_unique_id;
uint64 item2_unique_id;
};
struct EvolveXPWindowSendDetails_Struct {
/*000*/ uint32 action;
/*004*/ uint64 item1_unique_id;
/*012*/ uint64 item2_unique_id;
/*020*/ uint32 compatibility;
/*024*/ uint32 max_transfer_level;
/*028*/ uint8 item1_present;
/*029*/ uint8 item2_present;
/*030*/ char serialize_data[];
};
}; /*RoF2*/ }; /*RoF2*/
#endif /*COMMON_ROF2_STRUCTS_H*/ #endif /*COMMON_ROF2_STRUCTS_H*/
+30 -30
View File
@@ -1946,38 +1946,38 @@ struct GuildBankItemUpdate_Struct
void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity,
uint32 inPermissions, uint32 inAllowMerge, bool inUseable) uint32 inPermissions, uint32 inAllowMerge, bool inUseable)
{ {
action = inAction; Action = inAction;
unknown004 = inUnknown004; Unknown004 = inUnknown004;
slot_id = inSlotID; SlotID = inSlotID;
area = inArea; Area = inArea;
display = inUnknown012; Unknown012 = inUnknown012;
item_id = inItemID; ItemID = inItemID;
icon_id = inIcon; Icon = inIcon;
quantity = inQuantity; Quantity = inQuantity;
permissions = inPermissions; Permissions = inPermissions;
allow_merge = inAllowMerge; AllowMerge = inAllowMerge;
is_useable = inUseable; Useable = inUseable;
item_name[0] = '\0'; ItemName[0] = '\0';
donator[0] = '\0'; Donator[0] = '\0';
who_for[0] = '\0'; WhoFor[0] = '\0';
}; };
/*000*/ uint32 action; /*000*/ uint32 Action;
/*004*/ uint32 unknown004; /*004*/ uint32 Unknown004;
/*008*/ uint32 unknown008; /*008*/ uint32 Unknown08;
/*012*/ uint16 slot_id; /*012*/ uint16 SlotID;
/*014*/ uint16 area; /*014*/ uint16 Area;
/*016*/ uint32 display; /*016*/ uint32 Unknown012;
/*020*/ uint32 item_id; /*020*/ uint32 ItemID;
/*024*/ uint32 icon_id; /*024*/ uint32 Icon;
/*028*/ uint32 quantity; /*028*/ uint32 Quantity;
/*032*/ uint32 permissions; /*032*/ uint32 Permissions;
/*036*/ uint8 allow_merge; /*036*/ uint8 AllowMerge;
/*037*/ uint8 is_useable; // Used in conjunction with the Public-if-useable permission. /*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission.
/*038*/ char item_name[64]; /*038*/ char ItemName[64];
/*102*/ char donator[64]; /*102*/ char Donator[64];
/*166*/ char who_for[64]; /*166*/ char WhoFor[64];
/*230*/ uint16 unknown226; /*230*/ uint16 Unknown226;
}; };
struct GuildBankClear_Struct struct GuildBankClear_Struct
+13 -13
View File
@@ -72,7 +72,7 @@ namespace SoD
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@@ -113,7 +113,7 @@ namespace SoD
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@@ -3966,12 +3966,12 @@ namespace SoD
SoDSlot = serverSlot - 2; SoDSlot = serverSlot - 2;
} }
else if (serverSlot <= EQ::invbag::GENERAL_BAGS_END && serverSlot >= EQ::invbag::GENERAL_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::GENERAL_BAGS_8_END && serverSlot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
SoDSlot = serverSlot - (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));; SoDSlot = serverSlot + 11;
} }
else if (serverSlot <= EQ::invbag::CURSOR_BAG_END && serverSlot >= EQ::invbag::CURSOR_BAG_BEGIN) { else if (serverSlot <= EQ::invbag::CURSOR_BAG_END && serverSlot >= EQ::invbag::CURSOR_BAG_BEGIN) {
SoDSlot = serverSlot - (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN); SoDSlot = serverSlot - 9;
} }
else if (serverSlot <= EQ::invslot::TRIBUTE_END && serverSlot >= EQ::invslot::TRIBUTE_BEGIN) { else if (serverSlot <= EQ::invslot::TRIBUTE_END && serverSlot >= EQ::invslot::TRIBUTE_BEGIN) {
@@ -3991,7 +3991,7 @@ namespace SoD
} }
else if (serverSlot <= EQ::invbag::BANK_BAGS_END && serverSlot >= EQ::invbag::BANK_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::BANK_BAGS_END && serverSlot >= EQ::invbag::BANK_BAGS_BEGIN) {
SoDSlot = serverSlot - (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));; SoDSlot = serverSlot + 1;
} }
else if (serverSlot <= EQ::invslot::SHARED_BANK_END && serverSlot >= EQ::invslot::SHARED_BANK_BEGIN) { else if (serverSlot <= EQ::invslot::SHARED_BANK_END && serverSlot >= EQ::invslot::SHARED_BANK_BEGIN) {
@@ -3999,7 +3999,7 @@ namespace SoD
} }
else if (serverSlot <= EQ::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
SoDSlot = serverSlot - (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::SHARED_BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); SoDSlot = serverSlot + 1;
} }
else if (serverSlot <= EQ::invslot::TRADE_END && serverSlot >= EQ::invslot::TRADE_BEGIN) { else if (serverSlot <= EQ::invslot::TRADE_END && serverSlot >= EQ::invslot::TRADE_BEGIN) {
@@ -4007,7 +4007,7 @@ namespace SoD
} }
else if (serverSlot <= EQ::invbag::TRADE_BAGS_END && serverSlot >= EQ::invbag::TRADE_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::TRADE_BAGS_END && serverSlot >= EQ::invbag::TRADE_BAGS_BEGIN) {
SoDSlot = serverSlot - (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::TRADE_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); SoDSlot = serverSlot;
} }
else if (serverSlot <= EQ::invslot::WORLD_END && serverSlot >= EQ::invslot::WORLD_BEGIN) { else if (serverSlot <= EQ::invslot::WORLD_END && serverSlot >= EQ::invslot::WORLD_BEGIN) {
@@ -4049,11 +4049,11 @@ namespace SoD
} }
else if (sod_slot <= invbag::GENERAL_BAGS_END && sod_slot >= invbag::GENERAL_BAGS_BEGIN) { else if (sod_slot <= invbag::GENERAL_BAGS_END && sod_slot >= invbag::GENERAL_BAGS_BEGIN) {
server_slot = sod_slot + (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = sod_slot - 11;
} }
else if (sod_slot <= invbag::CURSOR_BAG_END && sod_slot >= invbag::CURSOR_BAG_BEGIN) { else if (sod_slot <= invbag::CURSOR_BAG_END && sod_slot >= invbag::CURSOR_BAG_BEGIN) {
server_slot = sod_slot + (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN); server_slot = sod_slot + 9;
} }
else if (sod_slot <= invslot::TRIBUTE_END && sod_slot >= invslot::TRIBUTE_BEGIN) { else if (sod_slot <= invslot::TRIBUTE_END && sod_slot >= invslot::TRIBUTE_BEGIN) {
@@ -4073,7 +4073,7 @@ namespace SoD
} }
else if (sod_slot <= invbag::BANK_BAGS_END && sod_slot >= invbag::BANK_BAGS_BEGIN) { else if (sod_slot <= invbag::BANK_BAGS_END && sod_slot >= invbag::BANK_BAGS_BEGIN) {
server_slot = sod_slot + (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::BANK_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = sod_slot - 1;
} }
else if (sod_slot <= invslot::SHARED_BANK_END && sod_slot >= invslot::SHARED_BANK_BEGIN) { else if (sod_slot <= invslot::SHARED_BANK_END && sod_slot >= invslot::SHARED_BANK_BEGIN) {
@@ -4081,7 +4081,7 @@ namespace SoD
} }
else if (sod_slot <= invbag::SHARED_BANK_BAGS_END && sod_slot >= invbag::SHARED_BANK_BAGS_BEGIN) { else if (sod_slot <= invbag::SHARED_BANK_BAGS_END && sod_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
server_slot = sod_slot + (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::SHARED_BANK_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = sod_slot - 1;
} }
else if (sod_slot <= invslot::TRADE_END && sod_slot >= invslot::TRADE_BEGIN) { else if (sod_slot <= invslot::TRADE_END && sod_slot >= invslot::TRADE_BEGIN) {
@@ -4089,7 +4089,7 @@ namespace SoD
} }
else if (sod_slot <= invbag::TRADE_BAGS_END && sod_slot >= invbag::TRADE_BAGS_BEGIN) { else if (sod_slot <= invbag::TRADE_BAGS_END && sod_slot >= invbag::TRADE_BAGS_BEGIN) {
server_slot = sod_slot + (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::TRADE_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = sod_slot;
} }
else if (sod_slot <= invslot::WORLD_END && sod_slot >= invslot::WORLD_BEGIN) { else if (sod_slot <= invslot::WORLD_END && sod_slot >= invslot::WORLD_BEGIN) {
+13 -13
View File
@@ -71,7 +71,7 @@ namespace SoF
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@@ -110,7 +110,7 @@ namespace SoF
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@@ -3355,12 +3355,12 @@ namespace SoF
sof_slot = server_slot - 2; sof_slot = server_slot - 2;
} }
else if (server_slot <= EQ::invbag::GENERAL_BAGS_END && server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::GENERAL_BAGS_8_END && server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
sof_slot = server_slot - (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));; sof_slot = server_slot + 11;
} }
else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) { else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) {
sof_slot = server_slot - (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN); sof_slot = server_slot - 9;
} }
else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) { else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) {
@@ -3380,7 +3380,7 @@ namespace SoF
} }
else if (server_slot <= EQ::invbag::BANK_BAGS_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::BANK_BAGS_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) {
sof_slot = server_slot - (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); sof_slot = server_slot + 1;
} }
else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) { else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) {
@@ -3388,7 +3388,7 @@ namespace SoF
} }
else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END && server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END && server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
sof_slot = server_slot - (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::SHARED_BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); sof_slot = server_slot + 1;
} }
else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) { else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) {
@@ -3396,7 +3396,7 @@ namespace SoF
} }
else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) {
sof_slot = server_slot - (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::TRADE_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); sof_slot = server_slot;
} }
else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) { else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) {
@@ -3442,11 +3442,11 @@ namespace SoF
} }
else if (sof_slot <= invbag::GENERAL_BAGS_END && sof_slot >= invbag::GENERAL_BAGS_BEGIN) { else if (sof_slot <= invbag::GENERAL_BAGS_END && sof_slot >= invbag::GENERAL_BAGS_BEGIN) {
server_slot = sof_slot + (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT));; server_slot = sof_slot - 11;
} }
else if (sof_slot <= invbag::CURSOR_BAG_END && sof_slot >= invbag::CURSOR_BAG_BEGIN) { else if (sof_slot <= invbag::CURSOR_BAG_END && sof_slot >= invbag::CURSOR_BAG_BEGIN) {
server_slot = sof_slot + (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN); server_slot = sof_slot + 9;
} }
else if (sof_slot <= invslot::TRIBUTE_END && sof_slot >= invslot::TRIBUTE_BEGIN) { else if (sof_slot <= invslot::TRIBUTE_END && sof_slot >= invslot::TRIBUTE_BEGIN) {
@@ -3466,7 +3466,7 @@ namespace SoF
} }
else if (sof_slot <= invbag::BANK_BAGS_END && sof_slot >= invbag::BANK_BAGS_BEGIN) { else if (sof_slot <= invbag::BANK_BAGS_END && sof_slot >= invbag::BANK_BAGS_BEGIN) {
server_slot = sof_slot + (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));; server_slot = sof_slot - 1;
} }
else if (sof_slot <= invslot::SHARED_BANK_END && sof_slot >= invslot::SHARED_BANK_BEGIN) { else if (sof_slot <= invslot::SHARED_BANK_END && sof_slot >= invslot::SHARED_BANK_BEGIN) {
@@ -3474,7 +3474,7 @@ namespace SoF
} }
else if (sof_slot <= invbag::SHARED_BANK_BAGS_END && sof_slot >= invbag::SHARED_BANK_BAGS_BEGIN) { else if (sof_slot <= invbag::SHARED_BANK_BAGS_END && sof_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
server_slot = sof_slot + (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::SHARED_BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));; server_slot = sof_slot - 1;
} }
else if (sof_slot <= invslot::TRADE_END && sof_slot >= invslot::TRADE_BEGIN) { else if (sof_slot <= invslot::TRADE_END && sof_slot >= invslot::TRADE_BEGIN) {
@@ -3482,7 +3482,7 @@ namespace SoF
} }
else if (sof_slot <= invbag::TRADE_BAGS_END && sof_slot >= invbag::TRADE_BAGS_BEGIN) { else if (sof_slot <= invbag::TRADE_BAGS_END && sof_slot >= invbag::TRADE_BAGS_BEGIN) {
server_slot = sof_slot + (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::TRADE_BAGS_BEGIN) / invbag::SLOT_COUNT));; server_slot = sof_slot;
} }
else if (sof_slot <= invslot::WORLD_END && sof_slot >= invslot::WORLD_BEGIN) { else if (sof_slot <= invslot::WORLD_END && sof_slot >= invslot::WORLD_BEGIN) {
+14 -14
View File
@@ -73,7 +73,7 @@ namespace Titanium
auto Config = EQEmuConfig::get(); auto Config = EQEmuConfig::get();
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@@ -114,7 +114,7 @@ namespace Titanium
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@@ -3596,12 +3596,12 @@ namespace Titanium
else if (server_slot == (EQ::invslot::POSSESSIONS_COUNT + EQ::invslot::slotAmmo)) { else if (server_slot == (EQ::invslot::POSSESSIONS_COUNT + EQ::invslot::slotAmmo)) {
titanium_slot = server_slot - 4; titanium_slot = server_slot - 4;
} }
else if (server_slot <= EQ::invbag::GENERAL_BAGS_END && else if (server_slot <= EQ::invbag::GENERAL_BAGS_8_END &&
server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) { server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
titanium_slot = server_slot - (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) { else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) {
titanium_slot = server_slot - (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN); titanium_slot = server_slot - 20;
} }
else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) { else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
@@ -3616,21 +3616,21 @@ namespace Titanium
else if (server_slot <= EQ::invslot::BANK_END && server_slot >= EQ::invslot::BANK_BEGIN) { else if (server_slot <= EQ::invslot::BANK_END && server_slot >= EQ::invslot::BANK_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invbag::BANK_BAGS_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::BANK_BAGS_16_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) {
titanium_slot = server_slot - (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) { else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END && else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END &&
server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) { server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
titanium_slot = server_slot - (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::SHARED_BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) { else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) {
titanium_slot = server_slot - (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::TRADE_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) { else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
@@ -3687,10 +3687,10 @@ namespace Titanium
server_slot = titanium_slot + 4; server_slot = titanium_slot + 4;
} }
else if (titanium_slot <= invbag::GENERAL_BAGS_END && titanium_slot >= invbag::GENERAL_BAGS_BEGIN) { else if (titanium_slot <= invbag::GENERAL_BAGS_END && titanium_slot >= invbag::GENERAL_BAGS_BEGIN) {
server_slot = titanium_slot + (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = titanium_slot;
} }
else if (titanium_slot <= invbag::CURSOR_BAG_END && titanium_slot >= invbag::CURSOR_BAG_BEGIN) { else if (titanium_slot <= invbag::CURSOR_BAG_END && titanium_slot >= invbag::CURSOR_BAG_BEGIN) {
server_slot = titanium_slot + (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN); server_slot = titanium_slot + 20;
} }
else if (titanium_slot <= invslot::TRIBUTE_END && titanium_slot >= invslot::TRIBUTE_BEGIN) { else if (titanium_slot <= invslot::TRIBUTE_END && titanium_slot >= invslot::TRIBUTE_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;
@@ -3705,19 +3705,19 @@ namespace Titanium
server_slot = titanium_slot; server_slot = titanium_slot;
} }
else if (titanium_slot <= invbag::BANK_BAGS_END && titanium_slot >= invbag::BANK_BAGS_BEGIN) { else if (titanium_slot <= invbag::BANK_BAGS_END && titanium_slot >= invbag::BANK_BAGS_BEGIN) {
server_slot = titanium_slot + (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::BANK_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = titanium_slot;
} }
else if (titanium_slot <= invslot::SHARED_BANK_END && titanium_slot >= invslot::SHARED_BANK_BEGIN) { else if (titanium_slot <= invslot::SHARED_BANK_END && titanium_slot >= invslot::SHARED_BANK_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;
} }
else if (titanium_slot <= invbag::SHARED_BANK_BAGS_END && titanium_slot >= invbag::SHARED_BANK_BAGS_BEGIN) { else if (titanium_slot <= invbag::SHARED_BANK_BAGS_END && titanium_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
server_slot = titanium_slot + (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::SHARED_BANK_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = titanium_slot;
} }
else if (titanium_slot <= invslot::TRADE_END && titanium_slot >= invslot::TRADE_BEGIN) { else if (titanium_slot <= invslot::TRADE_END && titanium_slot >= invslot::TRADE_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;
} }
else if (titanium_slot <= invbag::TRADE_BAGS_END && titanium_slot >= invbag::TRADE_BAGS_BEGIN) { else if (titanium_slot <= invbag::TRADE_BAGS_END && titanium_slot >= invbag::TRADE_BAGS_BEGIN) {
server_slot = titanium_slot + (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::TRADE_BAGS_BEGIN) / invbag::SLOT_COUNT)); server_slot = titanium_slot;
} }
else if (titanium_slot <= invslot::WORLD_END && titanium_slot >= invslot::WORLD_BEGIN) { else if (titanium_slot <= invslot::WORLD_END && titanium_slot >= invslot::WORLD_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;
+6 -6
View File
@@ -2463,25 +2463,25 @@ struct WhoAllReturnStruct {
struct BeginTrader_Struct { struct BeginTrader_Struct {
uint32 action; uint32 action;
uint32 unknown04; uint32 unknown04;
uint64 serial_number[EQ::invtype::BAZAAR_SIZE]; uint64 serial_number[80];
uint32 cost[EQ::invtype::BAZAAR_SIZE]; uint32 cost[80];
}; };
struct Trader_Struct { struct Trader_Struct {
uint32 action; uint32 action;
uint32 unknown004; uint32 unknown004;
uint64 item_id[EQ::invtype::BAZAAR_SIZE]; uint64 item_id[80];
uint32 item_cost[EQ::invtype::BAZAAR_SIZE]; uint32 item_cost[80];
}; };
struct ClickTrader_Struct { struct ClickTrader_Struct {
uint32 code; uint32 code;
uint32 unknown[161];//damn soe this is totally pointless :/ but at least your finally using memset! Good job :) -LE uint32 unknown[161];//damn soe this is totally pointless :/ but at least your finally using memset! Good job :) -LE
uint32 itemcost[EQ::invtype::BAZAAR_SIZE]; uint32 itemcost[80];
}; };
struct GetItems_Struct{ struct GetItems_Struct{
uint32 items[EQ::invtype::BAZAAR_SIZE]; uint32 items[80];
}; };
struct BecomeTrader_Struct { struct BecomeTrader_Struct {
+13 -13
View File
@@ -76,7 +76,7 @@ namespace UF
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@@ -117,7 +117,7 @@ namespace UF
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@@ -4908,12 +4908,12 @@ namespace UF
UFSlot = serverSlot - 2; UFSlot = serverSlot - 2;
} }
else if (serverSlot <= EQ::invbag::GENERAL_BAGS_END && serverSlot >= EQ::invbag::GENERAL_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::GENERAL_BAGS_8_END && serverSlot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
UFSlot = serverSlot - (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN)/*3748*/ - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); // + 11; UFSlot = serverSlot + 11;
} }
else if (serverSlot <= EQ::invbag::CURSOR_BAG_END && serverSlot >= EQ::invbag::CURSOR_BAG_BEGIN) { else if (serverSlot <= EQ::invbag::CURSOR_BAG_END && serverSlot >= EQ::invbag::CURSOR_BAG_BEGIN) {
UFSlot = serverSlot - (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN)/*5668*/; // - 9; UFSlot = serverSlot - 9;
} }
else if (serverSlot <= EQ::invslot::TRIBUTE_END && serverSlot >= EQ::invslot::TRIBUTE_BEGIN) { else if (serverSlot <= EQ::invslot::TRIBUTE_END && serverSlot >= EQ::invslot::TRIBUTE_BEGIN) {
@@ -4933,7 +4933,7 @@ namespace UF
} }
else if (serverSlot <= EQ::invbag::BANK_BAGS_END && serverSlot >= EQ::invbag::BANK_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::BANK_BAGS_END && serverSlot >= EQ::invbag::BANK_BAGS_BEGIN) {
UFSlot = serverSlot - (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); // + 1; UFSlot = serverSlot + 1;
} }
else if (serverSlot <= EQ::invslot::SHARED_BANK_END && serverSlot >= EQ::invslot::SHARED_BANK_BEGIN) { else if (serverSlot <= EQ::invslot::SHARED_BANK_END && serverSlot >= EQ::invslot::SHARED_BANK_BEGIN) {
@@ -4941,7 +4941,7 @@ namespace UF
} }
else if (serverSlot <= EQ::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
UFSlot = serverSlot - (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::SHARED_BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); // + 1; UFSlot = serverSlot + 1;
} }
else if (serverSlot <= EQ::invslot::TRADE_END && serverSlot >= EQ::invslot::TRADE_BEGIN) { else if (serverSlot <= EQ::invslot::TRADE_END && serverSlot >= EQ::invslot::TRADE_BEGIN) {
@@ -4949,7 +4949,7 @@ namespace UF
} }
else if (serverSlot <= EQ::invbag::TRADE_BAGS_END && serverSlot >= EQ::invbag::TRADE_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::TRADE_BAGS_END && serverSlot >= EQ::invbag::TRADE_BAGS_BEGIN) {
UFSlot = serverSlot - (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::TRADE_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT)); // + 0; UFSlot = serverSlot;
} }
else if (serverSlot <= EQ::invslot::WORLD_END && serverSlot >= EQ::invslot::WORLD_BEGIN) { else if (serverSlot <= EQ::invslot::WORLD_END && serverSlot >= EQ::invslot::WORLD_BEGIN) {
@@ -4991,11 +4991,11 @@ namespace UF
} }
else if (ufSlot <= invbag::GENERAL_BAGS_END && ufSlot >= invbag::GENERAL_BAGS_BEGIN) { else if (ufSlot <= invbag::GENERAL_BAGS_END && ufSlot >= invbag::GENERAL_BAGS_BEGIN) {
ServerSlot = ufSlot + (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN)/*3748*/ + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((ufSlot - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT)); // - 11; ServerSlot = ufSlot - 11;
} }
else if (ufSlot <= invbag::CURSOR_BAG_END && ufSlot >= invbag::CURSOR_BAG_BEGIN) { else if (ufSlot <= invbag::CURSOR_BAG_END && ufSlot >= invbag::CURSOR_BAG_BEGIN) {
ServerSlot = ufSlot + (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN)/*5668*/; // + 9; ServerSlot = ufSlot + 9;
} }
else if (ufSlot <= invslot::TRIBUTE_END && ufSlot >= invslot::TRIBUTE_BEGIN) { else if (ufSlot <= invslot::TRIBUTE_END && ufSlot >= invslot::TRIBUTE_BEGIN) {
@@ -5015,7 +5015,7 @@ namespace UF
} }
else if (ufSlot <= invbag::BANK_BAGS_END && ufSlot >= invbag::BANK_BAGS_BEGIN) { else if (ufSlot <= invbag::BANK_BAGS_END && ufSlot >= invbag::BANK_BAGS_BEGIN) {
ServerSlot = ufSlot + (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((ufSlot - invbag::BANK_BAGS_BEGIN) / invbag::SLOT_COUNT)); // - 1; ServerSlot = ufSlot - 1;
} }
else if (ufSlot <= invslot::SHARED_BANK_END && ufSlot >= invslot::SHARED_BANK_BEGIN) { else if (ufSlot <= invslot::SHARED_BANK_END && ufSlot >= invslot::SHARED_BANK_BEGIN) {
@@ -5023,7 +5023,7 @@ namespace UF
} }
else if (ufSlot <= invbag::SHARED_BANK_BAGS_END && ufSlot >= invbag::SHARED_BANK_BAGS_BEGIN) { else if (ufSlot <= invbag::SHARED_BANK_BAGS_END && ufSlot >= invbag::SHARED_BANK_BAGS_BEGIN) {
ServerSlot = ufSlot + (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((ufSlot - invbag::SHARED_BANK_BAGS_BEGIN) / invbag::SLOT_COUNT)); // - 1; ServerSlot = ufSlot - 1;
} }
else if (ufSlot <= invslot::TRADE_END && ufSlot >= invslot::TRADE_BEGIN) { else if (ufSlot <= invslot::TRADE_END && ufSlot >= invslot::TRADE_BEGIN) {
@@ -5031,7 +5031,7 @@ namespace UF
} }
else if (ufSlot <= invbag::TRADE_BAGS_END && ufSlot >= invbag::TRADE_BAGS_BEGIN) { else if (ufSlot <= invbag::TRADE_BAGS_END && ufSlot >= invbag::TRADE_BAGS_BEGIN) {
ServerSlot = ufSlot + (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((ufSlot - invbag::TRADE_BAGS_BEGIN) / invbag::SLOT_COUNT)); // - 0; ServerSlot = ufSlot;
} }
else if (ufSlot <= invslot::WORLD_END && ufSlot >= invslot::WORLD_BEGIN) { else if (ufSlot <= invslot::WORLD_END && ufSlot >= invslot::WORLD_BEGIN) {
+70 -88
View File
@@ -5,19 +5,31 @@
#include "strings.h" #include "strings.h"
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
void PathManager::Init() inline std::string striptrailingslash(const std::string &file_path)
{
if (file_path.back() == '/' || file_path.back() == '\\') {
return file_path.substr(0, file_path.length() - 1);
}
return file_path;
}
void PathManager::LoadPaths()
{ {
m_server_path = File::FindEqemuConfigPath(); m_server_path = File::FindEqemuConfigPath();
if (!m_server_path.empty()) {
std::filesystem::current_path(m_server_path);
}
if (m_server_path.empty()) { if (m_server_path.empty()) {
LogInfo("Failed to load server path"); LogInfo("Failed to load server path");
return; return;
} }
std::filesystem::current_path(m_server_path); LogInfo("server [{}]", m_server_path);
if (!EQEmuConfig::LoadConfig()) { if (!EQEmuConfig::LoadConfig()) {
LogError("Failed to load eqemu config"); LogError("Failed to load eqemu config");
@@ -26,85 +38,60 @@ void PathManager::Init()
const auto c = EQEmuConfig::get(); const auto c = EQEmuConfig::get();
auto resolve_path = [&](const std::string& dir, const std::vector<std::string>& fallback_dirs = {}) -> std::string { // maps
// relative if (File::Exists(fs::path{m_server_path + "/" + c->MapDir}.string())) {
if (File::Exists((fs::path{m_server_path} / dir).string())) { m_maps_path = fs::relative(fs::path{m_server_path + "/" + c->MapDir}).string();
return fs::relative(fs::path{m_server_path} / dir).lexically_normal().string(); }
else if (File::Exists(fs::path{m_server_path + "/maps"}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/maps"}).string();
}
else if (File::Exists(fs::path{m_server_path + "/Maps"}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/Maps"}).string();
} }
// absolute // quests
if (File::Exists(fs::path{dir}.string())) { if (File::Exists(fs::path{m_server_path + "/" + c->QuestDir}.string())) {
return fs::absolute(fs::path{dir}).string(); m_quests_path = fs::relative(fs::path{m_server_path + "/" + c->QuestDir}).string();
} }
// fallback search options if specified // plugins
for (const auto& fallback : fallback_dirs) { if (File::Exists(fs::path{m_server_path + "/" + c->PluginDir}.string())) {
if (File::Exists((fs::path{m_server_path} / fallback).string())) { m_plugins_path = fs::relative(fs::path{m_server_path + "/" + c->PluginDir}).string();
return fs::relative(fs::path{m_server_path} / fallback).lexically_normal().string();
}
} }
// if all else fails, just set it to the config value // lua_modules
return dir; if (File::Exists(fs::path{m_server_path + "/" + c->LuaModuleDir}.string())) {
}; m_lua_modules_path = fs::relative(fs::path{m_server_path + "/" + c->LuaModuleDir}).string();
auto load_many_paths_fallback = [&](const std::vector<std::string>& dirs, const std::string& fallback, std::vector<std::string>& target) {
target.clear();
if (!dirs.empty()) {
for (const auto& path : dirs) {
target.push_back(resolve_path(path));
}
} else {
target.push_back(resolve_path(fallback));
}
};
load_many_paths_fallback(c->GetQuestDirectories(), c->QuestDir, m_quests_paths);
load_many_paths_fallback(c->GetPluginsDirectories(), c->PluginDir, m_plugin_paths);
load_many_paths_fallback(c->GetLuaModuleDirectories(), c->LuaModuleDir, m_lua_module_paths);
// resolve all paths
m_maps_path = resolve_path(c->MapDir, {"maps", "Maps"});
m_lua_mods_path = resolve_path("mods");
m_patch_path = resolve_path(c->PatchDir);
m_opcode_path = resolve_path(c->OpcodeDir);
m_shared_memory_path = resolve_path(c->SharedMemDir);
m_log_path = resolve_path(c->LogDir, {"logs"});
// Log all paths in a loop
std::vector<std::pair<std::string, std::string>> paths = {
{"server", m_server_path},
{"logs", m_log_path},
{"maps", m_maps_path},
{"lua mods", m_lua_mods_path},
{"patches", m_patch_path},
{"opcode", m_opcode_path},
{"shared_memory", m_shared_memory_path}
};
constexpr int name_width = 15;
constexpr int path_width = 0;
constexpr int break_length = 70;
LogInfo("Loading server paths");
LogInfo("{}", Strings::Repeat("-", break_length));
for (const auto& [name, in_path] : paths) {
if (!in_path.empty()) {
LogInfo("{:>{}} > [{:<{}}]", name, name_width, in_path, path_width);
}
} }
auto log_paths = [&](const std::string& label, const std::vector<std::string>& paths) { // lua mods
if (!paths.empty()) { if (File::Exists(fs::path{ m_server_path + "/mods" }.string())) {
LogInfo("{:>{}} > [{:<{}}]", label, name_width - 1, Strings::Join(paths, ";"), path_width); m_lua_mods_path = fs::relative(fs::path{ m_server_path + "/mods" }).string();
} }
};
log_paths("quests", m_quests_paths); // patches
log_paths("plugins", m_plugin_paths); if (File::Exists(fs::path{m_server_path + "/" + c->PatchDir}.string())) {
log_paths("lua_modules", m_lua_module_paths); m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
}
LogInfo("{}", Strings::Repeat("-", break_length)); // shared_memory_path
if (File::Exists(fs::path{m_server_path + "/" + c->SharedMemDir}.string())) {
m_shared_memory_path = fs::relative(fs::path{ m_server_path + "/" + c->SharedMemDir }).string();
}
// logging path
if (File::Exists(fs::path{m_server_path + "/" + c->LogDir}.string())) {
m_log_path = fs::relative(fs::path{m_server_path + "/" + c->LogDir}).string();
}
LogInfo("logs path [{}]", m_log_path);
LogInfo("lua mods path [{}]", m_lua_mods_path);
LogInfo("lua_modules path [{}]", m_lua_modules_path);
LogInfo("maps path [{}]", m_maps_path);
LogInfo("patches path [{}]", m_patch_path);
LogInfo("plugins path [{}]", m_plugins_path);
LogInfo("quests path [{}]", m_quests_path);
LogInfo("shared_memory path [{}]", m_shared_memory_path);
} }
const std::string &PathManager::GetServerPath() const const std::string &PathManager::GetServerPath() const
@@ -117,26 +104,21 @@ const std::string &PathManager::GetMapsPath() const
return m_maps_path; return m_maps_path;
} }
const std::string &PathManager::GetQuestsPath() const
{
return m_quests_path;
}
const std::string &PathManager::GetPluginsPath() const
{
return m_plugins_path;
}
const std::string &PathManager::GetSharedMemoryPath() const const std::string &PathManager::GetSharedMemoryPath() const
{ {
return m_shared_memory_path; return m_shared_memory_path;
} }
std::vector<std::string> PathManager::GetQuestPaths() const
{
return m_quests_paths;
}
std::vector<std::string> PathManager::GetPluginPaths() const
{
return m_plugin_paths;
}
std::vector<std::string> PathManager::GetLuaModulePaths() const
{
return m_lua_module_paths;
}
const std::string &PathManager::GetLogPath() const const std::string &PathManager::GetLogPath() const
{ {
return m_log_path; return m_log_path;
@@ -147,9 +129,9 @@ const std::string &PathManager::GetPatchPath() const
return m_patch_path; return m_patch_path;
} }
const std::string &PathManager::GetOpcodePath() const const std::string &PathManager::GetLuaModulesPath() const
{ {
return m_opcode_path; return m_lua_modules_path;
} }
const std::string &PathManager::GetLuaModsPath() const const std::string &PathManager::GetLuaModsPath() const
+7 -19
View File
@@ -3,45 +3,33 @@
#include <string> #include <string>
#include <vector>
class PathManager { class PathManager {
public: public:
void Init(); void LoadPaths();
static PathManager *Instance()
{
static PathManager instance;
return &instance;
}
[[nodiscard]] const std::string &GetLogPath() const; [[nodiscard]] const std::string &GetLogPath() const;
[[nodiscard]] const std::string &GetLuaModsPath() const; [[nodiscard]] const std::string &GetLuaModsPath() const;
[[nodiscard]] const std::string &GetLuaModulesPath() const; [[nodiscard]] const std::string &GetLuaModulesPath() const;
[[nodiscard]] const std::string &GetMapsPath() const; [[nodiscard]] const std::string &GetMapsPath() const;
[[nodiscard]] const std::string &GetPatchPath() const; [[nodiscard]] const std::string &GetPatchPath() const;
[[nodiscard]] const std::string &GetOpcodePath() const; [[nodiscard]] const std::string &GetPluginsPath() const;
[[nodiscard]] const std::string &GetQuestsPath() const;
[[nodiscard]] const std::string &GetServerPath() const; [[nodiscard]] const std::string &GetServerPath() const;
[[nodiscard]] const std::string &GetSharedMemoryPath() const; [[nodiscard]] const std::string &GetSharedMemoryPath() const;
[[nodiscard]] std::vector<std::string> GetQuestPaths() const;
[[nodiscard]] std::vector<std::string> GetPluginPaths() const;
[[nodiscard]] std::vector<std::string> GetLuaModulePaths() const;
private: private:
std::string m_log_path; std::string m_log_path;
std::string m_lua_mods_path; std::string m_lua_mods_path;
std::string m_lua_modules_path;
std::string m_maps_path; std::string m_maps_path;
std::string m_patch_path; std::string m_patch_path;
std::string m_opcode_path; std::string m_plugins_path;
std::string m_quests_path; std::string m_quests_path;
std::vector<std::string> m_quests_paths;
std::vector<std::string> m_plugin_paths;
std::vector<std::string> m_lua_module_paths;
private:
std::string m_server_path; std::string m_server_path;
std::string m_shared_memory_path; std::string m_shared_memory_path;
}; };
extern PathManager path;
#endif //EQEMU_PATH_MANAGER_H #endif //EQEMU_PATH_MANAGER_H
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include "../types.h"
#include "../database.h"
#include "../strings.h"
#include "../eqemu_logsys.h"
#include "../eqemu_logsys_log_aliases.h"
#include "../features.h"
#include "../global_define.h"
+34
View File
@@ -0,0 +1,34 @@
// types
#include <limits>
#include <string>
#include <cctype>
#include <sstream>
// containers
#include <iterator>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <list>
#include <vector>
// utilities
#include <iostream>
#include <cassert>
#include <cmath>
#include <memory>
#include <functional>
#include <algorithm>
#include <utility>
#include <tuple>
#include <fstream>
#include <cstdio>
// fmt
#include <fmt/format.h>
// lua
#include "lua.hpp"
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
-14
View File
@@ -1,14 +0,0 @@
#pragma once
// Lightweight, widely used
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <memory>
#include <limits>
#include <cstdint>
#include <cassert>
// fmt
#include <fmt/format.h>
-1
View File
@@ -1,7 +1,6 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include "process.h" #include "process.h"
#include <fmt/format.h>
std::string Process::execute(const std::string &cmd) std::string Process::execute(const std::string &cmd)
{ {

Some files were not shown because too many files have changed in this diff Show More