Compare commits

..

57 Commits

Author SHA1 Message Date
Xackery 0c6ec2117a Added WorldUDP Port 2022-12-30 08:28:06 -08:00
Kinglykrab 2218f46b5b [Commands] Cleanup #dbspawn2 Command. (#2493)
* [Commands] Cleanup #dbspawn2 Command.

Add some descriptive messages so that you get some feedback from the command.

* Update dbspawn2.cpp
2022-10-29 21:22:24 -04:00
Kinglykrab 53dcd14534 [Commands] Cleanup #emotesearch and #emoteview Command. (#2494)
* [Commands] Cleanup #emoteview Command.

Cleanup command messages and logic.

Add constants for Emote Events and Emote Types and replace all the old constants with the new constants.

* Update emoteview.cpp

* Cleanup #emotesearch Command.
2022-10-29 21:22:17 -04:00
Kinglykrab dcbc9a358f [Commands] Cleanup #modifynpcstat Command. (#2499)
* [Commands] Cleanup #modifynpcstat Command.

Cleanup messages and logic,

Add map and loop through it to display all stats, can add to this in the future if we add more stuff modifiable by this command.

* Delete settings.json

* Update modifynpcstat.cpp

* Update modifynpcstat.cpp

* Update questmgr.h
2022-10-29 21:22:07 -04:00
Kinglykrab b512447448 [Bots] Add give/remove saylinks to ^itemuse. (#2503)
Adds shortcut saylinks for giving items to bots or removing items from them.
2022-10-29 21:22:01 -04:00
hg 444a4f6744 [Tasks] Add pre-task update event (#2512)
This adds the player EVENT_TASK_BEFORE_UPDATE event which will allow
quests to prevent a source controlled task update by returning non-zero.
2022-10-29 20:46:08 -04:00
hg 43ec9dc815 [Tasks] Let task completion event block task rewards (#2511)
Returning non-zero from EVENT_TASK_COMPLETE will prevent task rewards
and completion emote. This is necessary for a DoN mission which scripts
a mission failure but still gives the lockout.
2022-10-29 20:46:00 -04:00
hg 9e836a9780 [Feature] Add player /inspect quest event (#2508)
Returning non-zero from EVENT_INSPECT will prevent default message
2022-10-29 19:49:48 -04:00
hg 3bc5d4b125 [Quest API] Add ResetAlternateAdvancementRank() to Perl/Lua. (#2510)
Exports Client::ResetAlternateAdvancementRank
2022-10-29 19:49:23 -04:00
hg 9f033df196 [Cleanup] Send eqstr message in AddAAPoints (#2507)
This api is only used by quests
2022-10-29 19:48:27 -04:00
hg 16ee25224d [Feature] Add special ability to block /open (#2506)
This adds the IMMUNE_OPEN (53) special ability to prevent /open on
LDON_TREASURE classes.
2022-10-29 19:48:14 -04:00
hg 56510e6383 [Quest API] Add Corpse::AddItem overloads for Lua (#2509)
Perl already has these
2022-10-29 19:48:03 -04:00
Aeadoin bf43bda1e2 [Bots] Cleanup Bot Spell Functions, reduce reliance on NPC Functions/Attributes (#2495)
* [Bots] Initial Cleanup of Functions, moved Bot Casting out of mob_ai.cpp

* Moved Bots off NPC AI_Spells Struct, and AI_Spells private attribute.

* Formatting Fixes, fixed LogAI entries, Added LogAIModerate Alias

* Add Constants.

* Added Bot DB Struct, fixed some potential casting issues

* Formatting

* Formatting
2022-10-29 16:38:15 -04:00
hg 5708164511 [Tasks] Add method to filter shared task offers (#2497) 2022-10-29 16:38:04 -04:00
Kinglykrab 7abb02655d [Rules] Add Toggle for Warrior Shielding (#2496)
This adds a toggle to disable the Warrior shielding ability. This will not stop the client-side message from sending when you do not have a target, but it will keep the ability from doing anything.
2022-10-22 14:59:52 -05:00
Akkadius cb08c02537 [Hotfix] Fix path load ordering for CLI commands 2022-10-15 22:26:12 -05:00
Chris Miles dea94ce63d [Zoning] Revert #2424 (#2492) 2022-10-15 20:48:15 -05:00
Chris Miles bd302b8394 [Logs] Have #reload logs also reload UCS logging (#2491) 2022-10-15 17:06:36 -05:00
Coreidan 221140c3c5 [Doors] Fix Neriak PoK Stone (#2486)
* [Doors] Fix Neriak PoK Stone

This augments the recent zone version heading changes where the doors for Neriak need to be corrected. The client version mask was incorrect and the locations were incorrect for the client.  Tested in my sandbox.

* [Doors] Change Misty PoK Stone Destination To Old Zone

Code fix #2482 changed Misty PoK Stone destination to the new misty zone.  This needed to be changed back to the old zone.  Zone destination was modified along with destination coordinates.

Co-authored-by: chrisjezorek <chris@jezoreksolutions.com>
2022-10-15 15:18:12 -05:00
Chris Miles 7092183103 [Crash] Stability Fixes (#2489)
* Input sanitation for #zone

* Update zone.cpp

* Update clientlist.cpp

* Test

* Test

* Remove logging, revert /who all code

* Remove log

* Update clientlist.cpp
2022-10-15 15:17:50 -05:00
Chris Miles bbbebdd346 [Crash] Pointer validation in mob iteration loops (#2490) 2022-10-15 15:10:11 -05:00
Akkadius 05723ad1e8 [Hotfix] Return weather_type_map 2022-10-14 17:57:55 -05:00
Chris Miles 4c7a625d7c [Doors] Fix Misty PoK Stone (#2482) 2022-10-13 21:03:15 -05:00
Aeadoin 1b82e6b283 [Feature] Add Hate Override for Heals (#2485)
* [Feature] Add Hate Override for Heals

* Formatting

Co-authored-by: Akkadius <akkadius1@gmail.com>
2022-10-13 21:02:59 -05:00
Kinglykrab 0240a9cc76 [Quest API] Add IsRaining() and IsSnowing() to Perl/Lua. (#2477)
* [Quest API] Add IsRaining() and IsSnowing() to Perl/Lua.

- Add quest::IsRaining() to Perl.
- Add quest::IsSnowing() to Perl.
- Add eq.is_raining() to Lua.
- Add eq.is_snowing() to Lua.

This will allow server operators to tell if a zone is currently raining, snowing, or neither.

* Remove unnecessary quest manager stuff.

* Added constants and cleaned up #weather command

* Revert "Added constants and cleaned up #weather command"

This reverts commit 2ec85304b7.

* Revert "Revert "Added constants and cleaned up #weather command""

This reverts commit 76f4e411b6.

* Delete settings.json

* Update zone.cpp
2022-10-13 20:59:55 -05:00
Aeadoin eb02525d36 [Feature] Add Support for "Show Mine Only" Filters (#2484)
* [Feature] Add Support for "Show Mine Only" Filters

* Added "Show Mine Only" support for HoTs

* remove this-> as it's implied.
2022-10-12 20:39:53 -05:00
Michael d7097e84ff [Feature] AA Cap Limit (#2423)
* [Feature] AA Cap Limit

Will force unused AA points to the cap if they exceed the cap. Will also force AA Percentage to 0%. NOTE: The variable, UnusedAAPointCap, should NOT be lowered once implemented without first checking the DB for how many Unused AAs people have.  The next time they gain any EXP, it WILL drop them to cap.  Also, PCs should be given warning prior to this patch going to Live, to ensure they have a chance to spend any AAs above the cap, else they will lose them.

* Fix formatting on strings

* Fixes

* Change ConvertArray to fmt

* Fix formating and >= 0 aa_cap per review
2022-10-12 20:14:44 -05:00
Aeadoin 3de65d46b4 [Bug Fix] Fixed Spell Logic for Bot Nukes (#2481) 2022-10-12 20:14:14 -05:00
Kinglykrab 303b35a755 [Commands] Cleanup #setlanguage Command. (#2464)
* [Commands] Cleanup #setlanguage Command.

Cleanup #setlanguage command and remove unnecessary variables.

* Tabs not spaces.

* newline
2022-10-12 20:13:25 -05:00
Aeadoin a9e218acfa [Feature] Soft Delete Bots on Character Soft Delete (#2467)
* [Feature] Soft Delete Bots on Character SoftDelete

* Moved Bot Soft Delete logic to be inline with SoftDeletes rule.

* Update from feedback

Co-authored-by: Akkadius <akkadius1@gmail.com>
2022-10-12 20:12:29 -05:00
Aeadoin 0f2da56b04 [Feature] Spell Ranks will now work with AllowSpellMemorizeFromItem Rule (#2475)
* Figured out Popup Windows

* SendPopupToClient, and response works

* Added Popup logic

* Didn't use WriteSpellInfoSection function

* Misc fixes, DB String ID 11004  now referenced as a constant

* Remove use of "this"

* Added "else" statement to return if "AllowSpellMemorizeFromItem" rule is not used
2022-10-12 19:53:21 -05:00
Kinglykrab f3f8a50d3c [Bug Fix] Allow Songs to be scribed from scrolls (#2460)
* [Bug Fix] Allow Songs to be scribed from scrolls

Songs weren't capable of being scribed from scrolls because we didn't check for `Song: ` in the name.

Converted old logic to substrings, can probably do it cleaner, but it's better than it was.

Removed extraneous `initiator->IsClient()` calls as `initiator` is **always** a client.

* Fix substr logic.
2022-10-11 21:29:54 -05:00
Chris Miles bc72641eef [Zoning] Fix zone race condition (#2479)
* Testing

* Separate auto shutdown fix

* Revert for PR

* Invalidate lock in places where zoning is cancelled
2022-10-11 20:23:27 -05:00
Chris Miles 18bfee5616 [Zone Shutdown] Fix for resetting shutdown timer (#2480) 2022-10-11 20:23:12 -05:00
Chris Miles 6c8930eacd [Logging] Fix zoning log typo (#2478) 2022-10-11 18:01:24 -04:00
Chris Miles e18d4a81c5 [Zoning] Possible zoning under world fix (#2424) 2022-10-10 22:55:49 -05:00
Alex 77c3841a49 [Process Management] Change all executables to use the default event loop run (#2471)
* Loginserver change to event loop run.

* eqlaunch, loginserver, queryserv, world
2022-10-10 22:55:39 -05:00
Michael Cook (mackal) 832bffa811 Fix Client::QuestReward overload SummonItem call (#2472)
The overload that took the packet struct wasn't calling SummonItem with
-1 charges, resulting it chargeless items if they had any
2022-10-05 16:23:03 -04:00
Aeadoin 267472fc91 [Bug Fix] Touch Of Vinitras was ignoring pet DT rule (#2469) 2022-10-03 19:35:52 -04:00
Chris Miles 44f760d177 [Crash] Fix reload crashes (#2462) 2022-09-30 07:54:05 -05:00
Michael Cook (mackal) 50fc4d68aa eqlaunch wasn't loading paths (#2461) 2022-09-29 14:23:20 -04:00
Akkadius ee167bbc64 [Hotfix] Fix lua mod load path 2022-09-29 12:06:01 -05:00
Chris Miles b20d0b84f6 [Logging] Remove loginserver unhandled error (#2458) 2022-09-28 22:20:20 -05:00
Kinglykrab 267d73ca27 [Tasks] Use zone currencies instead of hard-coded enum. (#2459) 2022-09-28 22:20:07 -05:00
Chris Miles c1626da40d [Crash] Websocket Crash fix race when fetching log categories (#2456)
* [Crash] Websocket crash fix race

* Refine check
2022-09-28 21:29:04 -05:00
Aeadoin 554b41d424 [Feature] Change Lifetap Emotes to be filterable. (#2454) 2022-09-28 21:03:26 -05:00
Chris Miles 714fb032e9 [Crash] Fix spawn race condition shown by #repop (#2455)
* Troubleshooting

* Debugging

* Debugging

* Debugging

* Debugging

* Remove debug line

* Revert back to GetRawNPCTypeName
2022-09-28 21:03:05 -05:00
Chris Miles 74dfc1ae3c [Database] Add fallback migration for logsys columns (#2457) 2022-09-28 21:02:51 -05:00
Akkadius 6b1e3d94f8 [Hotfix] Force collation on conversion script 2022-09-28 14:15:16 -05:00
Chris Miles f357361474 [Logging] Add stack trace in code paths that shouldn't occur (#2453)
* [Logging] Add stack trace in code paths that shouldn't occur

* Update zone_store.cpp

* Windows workaround
2022-09-28 13:32:39 -05:00
Chris Miles f8e7576ae7 [File Paths] Implement Path Manager (#2440)
* Push up branch for testing

* Path manager

* Tweaks

* Changes

* More path work

* Update paths for eqemu_server.pl

* More path work

* Import and export client files

* Path remove

* More path work

* Update eqemu_config.h

* Fix tests

* Tests disable temp

* Update eqemu_config.h

* Update .drone.yml

* Hook tests back up

* Update main.cpp

* Platform tests

* Fix include

* Use std::filesystem on windows

* Fix IPCMutex name on windows

* std::filesystem changes

* Update path_manager.cpp

* Explicit string cast

* Explicit string cast

* Update path_manager.cpp

* Windows fixes

* Mapped files

* Relative fixes

* Use relative paths off of cwd

* Update Debian image to Debian 11 (updates GCC)

Co-authored-by: hg <4683435+hgtw@users.noreply.github.com>
2022-09-28 04:08:59 -05:00
Chris Miles 19791195e5 [Logging] Netcode Logging Unify (#2443)
* [Logging] Unify netcode logging

* More tweaks, generator

* Exclude OP_SpecialMesg at callback level

* Consolidate packet loggers

* Log at EQStream level instead of proxy

* Fix C->S

* Server to server logging

* C-S for Loginserver

* Hook UCS for C->S

* Update eqemu_logsys.h

* World C->S logging

* Translate opcodes through patch system for client to server

* Additional logging requests

* Add detailed opcode translation logging

* vStringFormat resiliency

* Translate loginserver C->S

* Simplify out message string (reduce copies) and ignore legacy formats

* Update eqemu_logsys.cpp

* Log file format

* Handle deprecated categories
2022-09-28 03:42:09 -05:00
Chris Miles 9d766bf5dc [World CLI] Refactor world CLI to be easier to reason about (#2441) 2022-09-28 03:04:09 -05:00
Chris Miles 7ac8fe17e5 [Library] Bump httplib to 0.11.2 (#2442) 2022-09-28 03:03:23 -05:00
Kinglykrab 959a17daea [Quest API] Add GetGMStatus() to Perl/Lua. (#2448)
* [Quest API] Add GetGMStatus() to Perl/Lua.

- Add $client->GetGMStatus() to Perl.
- Add client:GetGMStatus() to Lua.
- Fix client:Admin() using Lua_Safe_Call_Bool().

This is just a more descriptive form of $client->Admin() in Perl and client:Admin() in Lua.

* Update lua_client.cpp

* Update perl_client.cpp
2022-09-28 03:03:07 -05:00
Kinglykrab 90406e0328 [Quest API] Add Merchant Events to Perl/Lua. (#2452)
- Add EVENT_ALT_CURRENCY_MERCHANT_BUY to Perl/Lua.
- Add EVENT_ALT_CURRENCY_MERCHANT_SELL to Perl/Lua.
- Add EVENT_MERCHANT_BUY to Perl/Lua.
- Add EVENT_MERCHANT_SELL to Perl/Lua.

This will allow server operators to track or do specific stuff based on if a person buys X item from Y NPC or whatever.
2022-09-28 03:02:42 -05:00
hg e883703b2f [Tasks] Schema simplification (#2449)
* Combine task_activity item and npc fields

This will make tooling easier.

While denormalizing goallists may not be ideal, it decouples tasks from
rewards which share the table and removes a redundant column in favor
of a using the delimited string which better matches live packet data.

* [Tasks] Deprecate goallists table, migrate reward goal lists, simplify logic

* Update 2022_09_25_task_concat_matchlists.sql

* Update 2022_09_25_task_concat_matchlists.sql

* Tweaks

* Fix reward column name in conversion script

* Task reward stacking

* Update task_client_state.cpp

* Implement stack counts

* Fix reward item instance memory leak

* Validate reward item instance

* Fix item reward message

* Fix findtask

Co-authored-by: Akkadius <akkadius1@gmail.com>
2022-09-28 02:31:05 -05:00
169 changed files with 11859 additions and 5443 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ volumes:
steps:
- name: server-build
# Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
image: akkadius/eqemu-server:latest
image: akkadius/eqemu-server:v11
commands:
- sudo chown eqemu:eqemu /drone/src/ * -R
- sudo chown eqemu:eqemu /home/eqemu/.ccache/ * -R
+13 -4
View File
@@ -28,10 +28,12 @@
#include "../../common/strings.h"
#include "../../common/content/world_content_service.h"
#include "../../common/zone_store.h"
#include "../../common/path_manager.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
void ExportSpells(SharedDatabase *db);
void ExportSkillCaps(SharedDatabase *db);
@@ -44,6 +46,8 @@ int main(int argc, char **argv)
LogSys.LoadLogSettingsDefaults();
set_exception_handler();
path.LoadPaths();
LogInfo("Client Files Export Utility");
if (!EQEmuConfig::LoadConfig()) {
LogError("Unable to load configuration file");
@@ -86,6 +90,7 @@ int main(int argc, char **argv)
}
LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings()
->StartFileLogs();
@@ -126,7 +131,8 @@ void ExportSpells(SharedDatabase *db)
{
LogInfo("Exporting Spells");
FILE *f = fopen("export/spells_us.txt", "w");
std::string file = fmt::format("{}/export/spells_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
LogError("Unable to open export/spells_us.txt to write, skipping.");
return;
@@ -208,7 +214,8 @@ void ExportSkillCaps(SharedDatabase *db)
{
LogInfo("Exporting Skill Caps");
FILE *f = fopen("export/SkillCaps.txt", "w");
std::string file = fmt::format("{}/export/SkillCaps.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
return;
@@ -238,7 +245,8 @@ void ExportBaseData(SharedDatabase *db)
{
LogInfo("Exporting Base Data");
FILE *f = fopen("export/BaseData.txt", "w");
std::string file = fmt::format("{}/export/BaseData.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
LogError("Unable to open export/BaseData.txt to write, skipping.");
return;
@@ -271,7 +279,8 @@ void ExportDBStrings(SharedDatabase *db)
{
LogInfo("Exporting DB Strings");
FILE *f = fopen("export/dbstr_us.txt", "w");
std::string file = fmt::format("{}/export/dbstr_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
return;
+17 -8
View File
@@ -26,10 +26,12 @@
#include "../../common/strings.h"
#include "../../common/content/world_content_service.h"
#include "../../common/zone_store.h"
#include "../../common/path_manager.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db);
@@ -41,6 +43,8 @@ int main(int argc, char **argv) {
LogSys.LoadLogSettingsDefaults();
set_exception_handler();
path.LoadPaths();
LogInfo("Client Files Import Utility");
if(!EQEmuConfig::LoadConfig()) {
LogError("Unable to load configuration file.");
@@ -83,6 +87,7 @@ int main(int argc, char **argv) {
}
LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings()
->StartFileLogs();
@@ -127,9 +132,10 @@ bool IsStringField(int i) {
void ImportSpells(SharedDatabase *db) {
LogInfo("Importing Spells");
FILE *f = fopen("import/spells_us.txt", "r");
std::string file = fmt::format("{}/import/spells_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "r");
if(!f) {
LogError("Unable to open import/spells_us.txt to read, skipping.");
LogError("Unable to open {} to read, skipping.", file);
return;
}
@@ -216,9 +222,10 @@ void ImportSpells(SharedDatabase *db) {
void ImportSkillCaps(SharedDatabase *db) {
LogInfo("Importing Skill Caps");
FILE *f = fopen("import/SkillCaps.txt", "r");
std::string file = fmt::format("{}/import/SkillCaps.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "r");
if(!f) {
LogError("Unable to open import/SkillCaps.txt to read, skipping.");
LogError("Unable to open {} to read, skipping.", file);
return;
}
@@ -251,9 +258,10 @@ void ImportSkillCaps(SharedDatabase *db) {
void ImportBaseData(SharedDatabase *db) {
LogInfo("Importing Base Data");
FILE *f = fopen("import/BaseData.txt", "r");
std::string file = fmt::format("{}/import/BaseData.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "r");
if(!f) {
LogError("Unable to open import/BaseData.txt to read, skipping.");
LogError("Unable to open {} to read, skipping.", file);
return;
}
@@ -296,9 +304,10 @@ void ImportBaseData(SharedDatabase *db) {
void ImportDBStrings(SharedDatabase *db) {
LogInfo("Importing DB Strings");
FILE *f = fopen("import/dbstr_us.txt", "r");
std::string file = fmt::format("{}/import/dbstr_us.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "r");
if(!f) {
LogError("Unable to open import/dbstr_us.txt to read, skipping.");
LogError("Unable to open {} to read, skipping.", file);
return;
}
+5 -2
View File
@@ -37,7 +37,7 @@ SET(common_sources
extprofile.cpp
discord_manager.cpp
faction.cpp
file_util.cpp
file.cpp
guild_base.cpp
guilds.cpp
inventory_profile.cpp
@@ -61,6 +61,7 @@ SET(common_sources
packet_dump.cpp
packet_dump_file.cpp
packet_functions.cpp
path_manager.cpp
perl_eqdb.cpp
perl_eqdb_res.cpp
proc_launcher.cpp
@@ -529,7 +530,7 @@ SET(common_headers
expedition_lockout_timer.h
extprofile.h
faction.h
file_util.h
file.h
features.h
fixed_memory_hash_set.h
fixed_memory_variable_hash_set.h
@@ -565,6 +566,7 @@ SET(common_headers
packet_dump.h
packet_dump_file.h
packet_functions.h
path_manager.cpp
platform.h
proc_launcher.h
profanity_manager.h
@@ -648,6 +650,7 @@ SET(common_headers
patches/uf_limits.h
patches/uf_ops.h
patches/uf_structs.h
stacktrace/backward.hpp
StackWalker/StackWalker.h
util/memory_stream.h
util/directory.h
+49 -33
View File
@@ -376,9 +376,10 @@ bool Database::ReserveName(uint32 account_id, char* name) {
* @param character_name
* @return
*/
bool Database::DeleteCharacter(char *character_name) {
bool Database::DeleteCharacter(char *character_name)
{
uint32 character_id = 0;
if(!character_name || !strlen(character_name)) {
if (!character_name || !strlen(character_name)) {
LogInfo("DeleteCharacter: request to delete without a name (empty char slot)");
return false;
}
@@ -390,45 +391,60 @@ bool Database::DeleteCharacter(char *character_name) {
}
if (character_id <= 0) {
LogError("DeleteCharacter | Invalid Character ID [{}]", character_name);
LogError("[DeleteCharacter] Invalid Character ID [{}]", character_name);
return false;
}
std::string delete_type = "hard-deleted";
if (RuleB(Character, SoftDeletes)) {
delete_type = "soft-deleted";
std::string query = fmt::format(
SQL(
UPDATE
character_data
SET
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64),
deleted_at = NOW()
WHERE
id = '{}'
),
character_id
);
QueryDatabase(query);
return true;
}
LogInfo("DeleteCharacter | Character [{}] ({}) is being [{}]", character_name, character_id, delete_type);
for (const auto& iter : DatabaseSchema::GetCharacterTables()) {
std::string table_name = iter.first;
std::string character_id_column_name = iter.second;
QueryDatabase(fmt::format("DELETE FROM {} WHERE {} = {}", table_name, character_id_column_name, character_id));
}
#ifdef BOTS
query = StringFormat("DELETE FROM `guild_members` WHERE `char_id` = '%d' AND GetMobTypeById(%i) = 'C'", character_id); // note: only use of GetMobTypeById()
QueryDatabase(query);
#endif
std::string delete_type = "hard-deleted";
if (RuleB(Character, SoftDeletes)) {
delete_type = "soft-deleted";
query = fmt::format(
SQL(
UPDATE
character_data
SET
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64),
deleted_at = NOW()
WHERE
id = '{}'
),
character_id
);
QueryDatabase(query);
#ifdef BOTS
query = fmt::format(
SQL(
UPDATE
bot_data
SET
name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64)
WHERE
owner_id = '{}'
),
character_id
);
QueryDatabase(query);
LogInfo("[DeleteCharacter] character_name [{}] ({}) bots are being [{}]", character_name, character_id, delete_type);
#endif
return true;
}
for (const auto &iter: DatabaseSchema::GetCharacterTables()) {
std::string table_name = iter.first;
std::string character_id_column_name = iter.second;
QueryDatabase(fmt::format("DELETE FROM {} WHERE {} = {}", table_name, character_id_column_name, character_id));
}
LogInfo("[DeleteCharacter] character_name [{}] ({}) is being [{}]", character_name, character_id, delete_type);
return true;
}
+3 -3
View File
@@ -26,7 +26,7 @@
#include "../strings.h"
#include "../eqemu_config.h"
#include "../database_schema.h"
#include "../file_util.h"
#include "../file.h"
#include <ctime>
@@ -383,8 +383,8 @@ void DatabaseDumpService::Dump()
pipe_file
);
if (!FileUtil::exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
FileUtil::mkdir(GetSetDumpPath());
if (!File::Exists(GetSetDumpPath()) && !IsDumpOutputToConsole()) {
File::Makedir(GetSetDumpPath());
}
if (IsDumpDropTableSyntaxOnly()) {
+4 -1
View File
@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "database.h"
#include "extprofile.h"
#include "path_manager.h"
#include <iomanip>
#include <iostream>
@@ -476,7 +477,9 @@ bool Database::CheckDatabaseConversions() {
CheckDatabaseConvertCorpseDeblob();
/* Run EQEmu Server script (Checks for database updates) */
system("perl eqemu_server.pl ran_from_world");
const std::string file = fmt::format("{}/eqemu_server.pl", path.GetServerPath());
system(fmt::format("perl {} ran_from_world", file).c_str());
return true;
}
+66
View File
@@ -513,3 +513,69 @@ std::string EQ::constants::GetObjectTypeName(int object_type)
return std::string();
}
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
{
static const std::map<uint8, std::string> weather_type_map = {
{WeatherTypes::None, "None"},
{WeatherTypes::Raining, "Raining"},
{WeatherTypes::Snowing, "Snowing"}
};
return weather_type_map;
}
std::string EQ::constants::GetWeatherTypeName(uint8 weather_type)
{
if (EQ::ValueWithin(weather_type, WeatherTypes::None, WeatherTypes::Snowing)) {
return EQ::constants::GetWeatherTypeMap().find(weather_type)->second;
}
return std::string();
}
const std::map<uint8, std::string> &EQ::constants::GetEmoteEventTypeMap()
{
static const std::map<uint8, std::string> emote_event_type_map = {
{ EmoteEventTypes::LeaveCombat, "Leave Combat" },
{ EmoteEventTypes::EnterCombat, "Enter Combat" },
{ EmoteEventTypes::OnDeath, "On Death" },
{ EmoteEventTypes::AfterDeath, "After Death" },
{ EmoteEventTypes::Hailed, "Hailed" },
{ EmoteEventTypes::KilledPC, "Killed PC" },
{ EmoteEventTypes::KilledNPC, "Killed NPC" },
{ EmoteEventTypes::OnSpawn, "On Spawn" },
{ EmoteEventTypes::OnDespawn, "On Despawn" }
};
return emote_event_type_map;
}
std::string EQ::constants::GetEmoteEventTypeName(uint8 emote_event_type)
{
if (EQ::ValueWithin(emote_event_type, EmoteEventTypes::LeaveCombat, EmoteEventTypes::OnDespawn)) {
return EQ::constants::GetEmoteEventTypeMap().find(emote_event_type)->second;
}
return std::string();
}
const std::map<uint8, std::string> &EQ::constants::GetEmoteTypeMap()
{
static const std::map<uint8, std::string> emote_type_map = {
{ EmoteTypes::Emote, "Emote" },
{ EmoteTypes::Shout, "Shout" },
{ EmoteTypes::Proximity, "Proximity" }
};
return emote_type_map;
}
std::string EQ::constants::GetEmoteTypeName(uint8 emote_type)
{
if (EQ::ValueWithin(emote_type, EmoteTypes::Emote, EmoteTypes::Proximity)) {
return EQ::constants::GetEmoteTypeMap().find(emote_type)->second;
}
return std::string();
}
+52
View File
@@ -217,6 +217,25 @@ namespace EQ
stanceBurnAE
};
enum BotSpellIDs : int {
Warrior = 3001,
Cleric,
Paladin,
Ranger,
Shadowknight,
Druid,
Monk,
Bard,
Rogue,
Shaman,
Necromancer,
Wizard,
Magician,
Enchanter,
Beastlord,
Berserker
};
enum GravityBehavior : int8 {
Ground,
Flying,
@@ -312,6 +331,30 @@ namespace EQ
NoDeposit
};
enum WeatherTypes : uint8 {
None,
Raining,
Snowing
};
enum EmoteEventTypes : uint8 {
LeaveCombat,
EnterCombat,
OnDeath,
AfterDeath,
Hailed,
KilledPC,
KilledNPC,
OnSpawn,
OnDespawn
};
enum EmoteTypes : uint8 {
Emote,
Shout,
Proximity
};
const char *GetStanceName(StanceType stance_type);
int ConvertStanceTypeToIndex(StanceType stance_type);
@@ -345,6 +388,15 @@ namespace EQ
extern const std::map<int, std::string>& GetObjectTypeMap();
std::string GetObjectTypeName(int object_type);
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
std::string GetWeatherTypeName(uint8 weather_type);
extern const std::map<uint8, std::string>& GetEmoteEventTypeMap();
std::string GetEmoteEventTypeName(uint8 emote_event_type);
extern const std::map<uint8, std::string>& GetEmoteTypeMap();
std::string GetEmoteTypeName(uint8 emote_type);
const int STANCE_TYPE_FIRST = stancePassive;
const int STANCE_TYPE_LAST = stanceBurnAE;
const int STANCE_TYPE_COUNT = stanceBurnAE;
+1 -1
View File
@@ -718,7 +718,7 @@ typedef enum {
FilterPetMisses = 21, //0=show, 1=hide
FilterFocusEffects = 22, //0=show, 1=hide
FilterPetSpells = 23, //0=show, 1=hide
FilterHealOverTime = 24, //0=show, 1=hide
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide
FilterUnknown25 = 25,
FilterUnknown26 = 26,
FilterUnknown27 = 27,
+11 -6
View File
@@ -218,13 +218,13 @@ class EQStream : public EQStreamInterface {
void init(bool resetSession=true);
public:
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
EQStream() { init(); remote_ip = 0; remote_port = 0; State = UNESTABLISHED;
StreamType = UnknownStream; compressed = true; encoded = false; app_opcode_size = 2;
bytes_sent = 0; bytes_recv = 0; create_time = Timer::GetTimeSeconds(); sessionAttempts = 0;
streamactive = false; }
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
EQStream(sockaddr_in addr) { init(); remote_ip = addr.sin_addr.s_addr;
remote_port = addr.sin_port; State = UNESTABLISHED; StreamType = UnknownStream;
compressed = true; encoded = false; app_opcode_size = 2; bytes_sent = 0; bytes_recv = 0;
create_time = Timer::GetTimeSeconds(); }
virtual ~EQStream() { RemoveData(); SetState(CLOSED); }
void SetMaxLen(uint32 length) { MaxLen=length; }
@@ -243,6 +243,11 @@ class EQStream : public EQStreamInterface {
virtual void SetOpcodeManager(OpcodeManager **opm) { OpMgr = opm; }
virtual OpcodeManager* GetOpcodeManager() const
{
return (*OpMgr);
};
void CheckTimeout(uint32 now, uint32 timeout=30);
bool HasOutgoingData();
void Process(const unsigned char *data, const uint32 length);
+2 -1
View File
@@ -30,7 +30,7 @@ struct EQStreamManagerInterfaceOptions
//World seems to support both compression and xor zone supports one or the others.
//Enforce one or the other in the convienence construct
//Login I had trouble getting to recognize compression at all
//Login I had trouble getting to recognize compression at all
//but that might be because it was still a bit buggy when i was testing that.
if (compressed) {
daybreak_options.encode_passes[0] = EQ::Net::EncodeCompression;
@@ -100,6 +100,7 @@ public:
virtual MatchState CheckSignature(const Signature *sig) { return MatchFailed; }
virtual EQStreamState GetState() = 0;
virtual void SetOpcodeManager(OpcodeManager **opm) = 0;
virtual OpcodeManager* GetOpcodeManager() const = 0;
virtual const EQ::versions::ClientVersion ClientVersion() const { return EQ::versions::ClientVersion::Unknown; }
virtual Stats GetStats() const = 0;
virtual void ResetStats() = 0;
+6 -5
View File
@@ -38,12 +38,8 @@ void EQStreamProxy::SetOpcodeManager(OpcodeManager **opm)
}
void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
if(p == nullptr)
if (p == nullptr) {
return;
if (p->GetOpcode() != OP_SpecialMesg) {
Log(Logs::General, Logs::PacketServerClient, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
Log(Logs::General, Logs::PacketServerClientWithDump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
}
EQApplicationPacket *newp = p->Copy();
@@ -112,3 +108,8 @@ bool EQStreamProxy::CheckState(EQStreamState state) {
return false;
}
OpcodeManager *EQStreamProxy::GetOpcodeManager() const
{
return (*m_opcodes);
}
+3 -1
View File
@@ -34,13 +34,15 @@ public:
virtual Stats GetStats() const;
virtual void ResetStats();
virtual EQStreamManagerInterface* GetManager() const;
virtual OpcodeManager* GetOpcodeManager() const;
protected:
std::shared_ptr<EQStreamInterface> const m_stream; //we own this stream object.
const StructStrategy *const m_structs; //we do not own this object.
//this is a pointer to a pointer to make it less likely that a packet will
//reference an invalid opcode manager when they are being reloaded.
OpcodeManager **const m_opcodes; //we do not own this object.
OpcodeManager **const m_opcodes;
//we do not own this object.
};
#endif /*EQSTREAMPROXY_H_*/
+5
View File
@@ -86,6 +86,7 @@ void EQEmuConfig::parse_config()
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
WorldUDPPort = atoi(_root["server"]["world"]["udp"].get("port", "9000").asString().c_str());
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
@@ -217,6 +218,9 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const
if (var_name == "WorldTCPPort") {
return (itoa(WorldTCPPort));
}
if (var_name == "WorldUDPPort") {
return (itoa(WorldUDPPort));
}
if (var_name == "WorldIP") {
return (WorldIP);
}
@@ -348,6 +352,7 @@ void EQEmuConfig::Dump() const
std::cout << "LoginLegacy = " << LoginLegacy << std::endl;
std::cout << "Locked = " << Locked << std::endl;
std::cout << "WorldTCPPort = " << WorldTCPPort << std::endl;
std::cout << "WorldUDPPort = " << WorldUDPPort << std::endl;
std::cout << "WorldIP = " << WorldIP << std::endl;
std::cout << "TelnetTCPPort = " << TelnetTCPPort << std::endl;
std::cout << "TelnetIP = " << TelnetIP << std::endl;
+16 -5
View File
@@ -20,7 +20,9 @@
#include "json/json.h"
#include "linked_list.h"
#include "path_manager.h"
#include <fstream>
#include <fmt/format.h>
struct LoginConfig {
std::string LoginHost;
@@ -49,6 +51,7 @@ class EQEmuConfig
LinkedList<LoginConfig*> loginlist;
bool Locked;
uint16 WorldTCPPort;
uint16 WorldUDPPort;
std::string WorldIP;
uint16 TelnetTCPPort;
std::string TelnetIP;
@@ -152,23 +155,31 @@ class EQEmuConfig
}
// Load the config
static bool LoadConfig()
static bool LoadConfig(const std::string& path = "")
{
if (_config != nullptr) {
return true;
}
_config = new EQEmuConfig;
return parseFile();
return parseFile(path);
}
// Load config file and parse data
static bool parseFile() {
static bool parseFile(const std::string& file_path = ".")
{
if (_config == nullptr) {
return LoadConfig();
return LoadConfig(file_path);
}
std::ifstream fconfig(EQEmuConfig::ConfigFile, std::ifstream::binary);
std::string file = fmt::format(
"{}/{}",
(file_path.empty() ? path.GetServerPath() : file_path),
EQEmuConfig::ConfigFile
);
std::ifstream fconfig(file, std::ifstream::binary);
try {
fconfig >> _config->_root;
_config->parse_config();
+109 -80
View File
@@ -212,21 +212,6 @@ bool EQEmuLogSys::IsRfc5424LogCategory(uint16 log_category)
);
}
/**
* @param log_category
* @param in_message
* @return
*/
std::string EQEmuLogSys::FormatOutMessageString(
uint16 log_category,
const std::string &in_message
)
{
std::string return_string = "[" + GetPlatformName() + "] ";
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
}
/**
* @param debug_level
* @param log_category
@@ -423,24 +408,10 @@ void EQEmuLogSys::Out(
...
)
{
bool log_to_console = log_settings[log_category].log_to_console > 0 &&
log_settings[log_category].log_to_console >= debug_level;
bool log_to_file = log_settings[log_category].log_to_file > 0 &&
log_settings[log_category].log_to_file >= debug_level;
bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0 &&
log_settings[log_category].log_to_gmsay >= debug_level &&
log_category != Logs::LogCategory::Netcode &&
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
bool log_to_discord = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
log_settings[log_category].log_to_discord > 0 &&
log_settings[log_category].log_to_discord >= debug_level &&
log_settings[log_category].discord_webhook_id > 0 &&
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
auto l = GetLogsEnabled(debug_level, log_category);
// bail out if nothing to log
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay && !log_to_discord;
if (nothing_to_log) {
if (!l.log_enabled) {
return;
}
@@ -449,23 +420,39 @@ void EQEmuLogSys::Out(
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
}
va_list args;
va_start(args, message);
std::string output_message = vStringFormat(message, args);
va_end(args);
// remove this when we remove all legacy logs
bool ignore_log_legacy_format = (
log_category == Logs::Netcode ||
log_category == Logs::PacketServerClient ||
log_category == Logs::PacketClientServer ||
log_category == Logs::PacketServerToServer
);
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
if (log_to_console) {
EQEmuLogSys::ProcessConsoleMessage(log_category, output_debug_message);
// remove this when we remove all legacy logs
std::string output_message = message;
if (!ignore_log_legacy_format) {
va_list args;
va_start(args, message);
output_message = vStringFormat(message, args);
va_end(args);
}
if (log_to_gmsay) {
if (l.log_to_console_enabled) {
EQEmuLogSys::ProcessConsoleMessage(
log_category,
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
);
}
if (l.log_to_gmsay_enabled) {
m_on_log_gmsay_hook(log_category, output_message);
}
if (log_to_file) {
EQEmuLogSys::ProcessLogWrite(log_category, output_debug_message);
if (l.log_to_file_enabled) {
EQEmuLogSys::ProcessLogWrite(
log_category,
fmt::format("[{}] [{}] {}", GetPlatformName(), Logs::LogCategoryName[log_category], prefix + output_message)
);
}
if (log_to_discord && m_on_log_discord_hook) {
if (l.log_to_discord_enabled && m_on_log_discord_hook) {
m_on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message);
}
}
@@ -479,7 +466,7 @@ void EQEmuLogSys::SetCurrentTimeStamp(char *time_stamp)
struct tm *time_info;
time(&raw_time);
time_info = localtime(&raw_time);
strftime(time_stamp, 80, "[%m-%d-%Y :: %H:%M:%S]", time_info);
strftime(time_stamp, 80, "[%m-%d-%Y %H:%M:%S]", time_info);
}
/**
@@ -534,37 +521,29 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
return;
}
LogInfo("Starting File Log [logs/{}_{}.log]", m_platform_file_name.c_str(), getpid());
LogInfo("Starting File Log [{}/zone/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid());
/**
* Make directory if not exists
*/
EQEmuLogSys::MakeDirectory("logs/zone");
// Make directory if not exists
EQEmuLogSys::MakeDirectory(fmt::format("{}/zone", GetLogPath()));
/**
* Open file pointer
*/
// Open file pointer
process_log.open(
StringFormat("logs/zone/%s_%i.log", m_platform_file_name.c_str(), getpid()),
fmt::format("{}/zone/{}_{}.log", GetLogPath(), m_platform_file_name, getpid()),
std::ios_base::app | std::ios_base::out
);
}
else {
/**
* All other processes
*/
// All other processes
if (m_platform_file_name.empty()) {
return;
}
LogInfo("Starting File Log [logs/{}_{}.log]", m_platform_file_name.c_str(), getpid());
LogInfo("Starting File Log [{}/{}_{}.log]", GetLogPath(), m_platform_file_name.c_str(), getpid());
/**
* Open file pointer
*/
// Open file pointer
process_log.open(
StringFormat("logs/%s_%i.log", m_platform_file_name.c_str(), getpid()),
fmt::format("{}/{}_{}.log", GetLogPath(), m_platform_file_name.c_str(), getpid()),
std::ios_base::app | std::ios_base::out
);
}
@@ -642,10 +621,19 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
// Auto inject categories that don't exist in the database...
for (int i = Logs::AA; i != Logs::MaxCategoryID; i++) {
if (std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end()) {
bool is_missing_in_database = std::find(db_categories.begin(), db_categories.end(), i) == db_categories.end();
bool is_deprecated_category = Strings::Contains(fmt::format("{}", Logs::LogCategoryName[i]), "Deprecated");
if (!is_missing_in_database && is_deprecated_category) {
LogInfo("Logging category [{}] ({}) is now deprecated, deleting from database", Logs::LogCategoryName[i], i);
LogsysCategoriesRepository::DeleteOne(*m_database, i);
}
if (is_missing_in_database && !is_deprecated_category) {
LogInfo(
"Automatically adding new log category [{0}]",
Logs::LogCategoryName[i]
"Automatically adding new log category [{}] ({})",
Logs::LogCategoryName[i],
i
);
auto new_category = LogsysCategoriesRepository::NewEntity();
@@ -696,13 +684,13 @@ void EQEmuLogSys::InjectTablesIfNotExist()
CREATE TABLE discord_webhooks
(
id INT auto_increment primary key NULL,
webhook_name varchar(100) NULL,
webhook_url varchar(255) NULL,
created_at DATETIME NULL,
deleted_at DATETIME NULL
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
webhook_name varchar(100) NULL,
webhook_url varchar(255) NULL,
created_at DATETIME NULL,
deleted_at DATETIME NULL
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;
)
);
}
@@ -713,15 +701,15 @@ void EQEmuLogSys::InjectTablesIfNotExist()
m_database->QueryDatabase(
SQL(
CREATE TABLE `logsys_categories` (
`log_category_id` int(11) NOT NULL,
`log_category_description` varchar(150) DEFAULT NULL,
`log_to_console` smallint(11) DEFAULT 0,
`log_to_file` smallint(11) DEFAULT 0,
`log_to_gmsay` smallint(11) DEFAULT 0,
`log_to_discord` smallint(11) DEFAULT 0,
`discord_webhook_id` int(11) DEFAULT 0,
PRIMARY KEY (`log_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
`log_category_id` int(11) NOT NULL,
`log_category_description` varchar(150) DEFAULT NULL,
`log_to_console` smallint(11) DEFAULT 0,
`log_to_file` smallint(11) DEFAULT 0,
`log_to_gmsay` smallint(11) DEFAULT 0,
`log_to_discord` smallint(11) DEFAULT 0,
`discord_webhook_id` int(11) DEFAULT 0,
PRIMARY KEY (`log_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
)
);
}
@@ -732,3 +720,44 @@ const EQEmuLogSys::DiscordWebhooks *EQEmuLogSys::GetDiscordWebhooks() const
return m_discord_webhooks;
}
EQEmuLogSys::LogEnabled EQEmuLogSys::GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
{
auto e = LogEnabled{};
e.log_to_console_enabled = log_settings[log_category].log_to_console > 0 &&
log_settings[log_category].log_to_console >= debug_level;
e.log_to_file_enabled = log_settings[log_category].log_to_file > 0 &&
log_settings[log_category].log_to_file >= debug_level;
e.log_to_gmsay_enabled = log_settings[log_category].log_to_gmsay > 0 &&
log_settings[log_category].log_to_gmsay >= debug_level &&
log_category != Logs::LogCategory::Netcode &&
(EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone ||
EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformWorld);
e.log_to_discord_enabled = EQEmuLogSys::m_log_platform == EQEmuExePlatform::ExePlatformZone &&
log_settings[log_category].log_to_discord > 0 &&
log_settings[log_category].log_to_discord >= debug_level &&
log_settings[log_category].discord_webhook_id > 0 &&
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
e.log_enabled =
e.log_to_console_enabled || e.log_to_file_enabled || e.log_to_gmsay_enabled || e.log_to_discord_enabled;
return e;
}
bool EQEmuLogSys::IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category)
{
return GetLogsEnabled(debug_level, log_category).log_enabled;
}
const std::string &EQEmuLogSys::GetLogPath() const
{
return m_log_path;
}
EQEmuLogSys * EQEmuLogSys::SetLogPath(const std::string &log_path)
{
EQEmuLogSys::m_log_path = log_path;
return this;
}
+31 -11
View File
@@ -54,7 +54,7 @@ namespace Logs {
AI,
Aggro,
Attack,
PacketClientServer,
DeprecatedCS,
Combat,
Commands,
Crash,
@@ -88,10 +88,10 @@ namespace Logs {
MySQLQuery,
Mercenaries,
QuestDebug,
PacketServerClient,
PacketClientServerUnhandled,
PacketServerClientWithDump,
PacketClientServerWithDump,
DeprecatedSC,
DeprecatedCSU,
DeprecatedSCD,
DeprecatedCSD,
Loginserver,
ClientLogin,
HeadlessClient,
@@ -132,6 +132,9 @@ namespace Logs {
Hate,
Discord,
Faction,
PacketServerClient,
PacketClientServer,
PacketServerToServer,
MaxCategoryID /* Don't Remove this */
};
@@ -144,7 +147,7 @@ namespace Logs {
"AI",
"Aggro",
"Attack",
"Packet :: Client -> Server",
"Deprecated",
"Combat",
"Commands",
"Crash",
@@ -178,10 +181,10 @@ namespace Logs {
"MySQL Query",
"Mercenaries",
"Quest Debug",
"Packet :: Server -> Client",
"Packet :: Client -> Server Unhandled",
"Packet :: Server -> Client (Dump)",
"Packet :: Client -> Server (Dump)",
"Deprecated",
"Deprecated",
"Deprecated",
"Deprecated",
"Login Server",
"Client Login",
"Headless Client",
@@ -222,6 +225,9 @@ namespace Logs {
"Hate",
"Discord",
"Faction",
"Packet-S->C",
"Packet-C->S",
"Packet-S->S"
};
}
@@ -313,6 +319,17 @@ public:
*/
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
struct LogEnabled {
bool log_to_file_enabled;
bool log_to_console_enabled;
bool log_to_gmsay_enabled;
bool log_to_discord_enabled;
bool log_enabled;
};
LogEnabled GetLogsEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
bool IsLogEnabled(const Logs::DebugLevel &debug_level, const uint16 &log_category);
struct DiscordWebhooks {
int id;
std::string webhook_name;
@@ -349,6 +366,9 @@ public:
// database
EQEmuLogSys *SetDatabase(Database *db);
[[nodiscard]] const std::string &GetLogPath() const;
EQEmuLogSys * SetLogPath(const std::string &log_path);
private:
// reference to database
@@ -360,8 +380,8 @@ private:
bool m_file_logs_enabled = false;
int m_log_platform = 0;
std::string m_platform_file_name;
std::string m_log_path;
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
File diff suppressed because it is too large Load Diff
+30 -20
View File
@@ -19,7 +19,7 @@
*/
#include <fstream>
#include "file_util.h"
#include "file.h"
#ifdef _WINDOWS
#include <direct.h>
@@ -35,38 +35,48 @@
#endif
#include <fmt/format.h>
#include <filesystem>
namespace fs = std::filesystem;
/**
* @param name
* @return
*/
bool FileUtil::exists(const std::string &name)
bool File::Exists(const std::string &name)
{
std::ifstream f(name.c_str());
return f.good();
return fs::exists(fs::path{name});
}
/**
* @param directory_name
*/
void FileUtil::mkdir(const std::string& directory_name)
void File::Makedir(const std::string &directory_name)
{
fs::create_directory(directory_name);
fs::permissions(directory_name, fs::perms::owner_all);
}
#ifdef _WINDOWS
struct _stat st;
if (_stat(directory_name.c_str(), &st) == 0) // exists
return;
_mkdir(directory_name.c_str());
#else
struct stat st{};
if (stat(directory_name.c_str(), &st) == 0) { // exists
return;
std::string File::FindEqemuConfigPath()
{
if (File::Exists(fs::path{File::GetCwd() + "/eqemu_config.json"}.string())) {
return File::GetCwd();
}
::mkdir(directory_name.c_str(), 0755);
#endif
else if (File::Exists(fs::path{File::GetCwd() + "/../eqemu_config.json"}.string())) {
return canonical(fs::path{File::GetCwd() + "/../"}).string();
}
else if (File::Exists(fs::path{File::GetCwd() + "/login.json"}.string())) {
return File::GetCwd();
}
else if (File::Exists(fs::path{File::GetCwd() + "/../login.json"}.string())) {
return canonical(fs::path{File::GetCwd() + "/../"}).string();
}
return {};
}
bool file_exists(const std::string& name) {
std::ifstream f(name.c_str());
return f.good();
std::string File::GetCwd()
{
return fs::current_path().string();
}
+12 -7
View File
@@ -18,16 +18,21 @@
*
*/
#ifndef EQEMU_FILE_UTIL_H
#define EQEMU_FILE_UTIL_H
#ifndef EQEMU_FILE_H
#define EQEMU_FILE_H
#include <filesystem>
class FileUtil {
namespace fs = std::filesystem;
class File {
public:
static bool exists(const std::string &name);
static void mkdir(const std::string& directory_name);
static bool Exists(const std::string &name);
static void Makedir(const std::string& directory_name);
static std::string FindEqemuConfigPath();
static std::string GetCwd();
};
bool file_exists(const std::string& name);
bool Exists(const std::string& name);
#endif //EQEMU_FILE_UTIL_H
#endif //EQEMU_FILE_H
+2836 -2113
View File
File diff suppressed because it is too large Load Diff
+4 -6
View File
@@ -30,6 +30,7 @@
#include "types.h"
#include "eqemu_exception.h"
#include "eqemu_config.h"
#include "path_manager.h"
namespace EQ {
struct IPCMutex::Implementation {
@@ -40,12 +41,11 @@ namespace EQ {
#endif
};
IPCMutex::IPCMutex(std::string name) : locked_(false) {
IPCMutex::IPCMutex(const std::string& name) : locked_(false) {
imp_ = new Implementation;
#ifdef _WINDOWS
auto Config = EQEmuConfig::get();
std::string final_name = Config->SharedMemDir + "EQEmuMutex_";
final_name += name;
std::string final_name = fmt::format("{}/EQEmuMutex_{}", Config->SharedMemDir, name);
imp_->mut_ = CreateMutex(nullptr,
FALSE,
@@ -55,9 +55,7 @@ namespace EQ {
EQ_EXCEPT("IPC Mutex", "Could not create mutex.");
}
#else
auto Config = EQEmuConfig::get();
std::string final_name = Config->SharedMemDir + name;
final_name += ".lock";
std::string final_name = fmt::format("{}/{}.lock", path.GetSharedMemoryPath(), name);
#ifdef __DARWIN
#if __DARWIN_C_LEVEL < 200809L
+1 -1
View File
@@ -37,7 +37,7 @@ namespace EQ {
Creates a named binary semaphore, basically a semaphore that is init S <- 1
\param name The name of this mutex.
*/
IPCMutex(std::string name);
IPCMutex(const std::string& name);
//! Destructor
~IPCMutex();
+3
View File
@@ -33,6 +33,9 @@
#include <sys/stat.h>
#endif
#include <filesystem>
namespace fs = std::filesystem;
namespace EQ {
struct MemoryMappedFile::Implementation {
+23 -5
View File
@@ -3,6 +3,7 @@
#include "../event/task.h"
#include "../data_verification.h"
#include "crc32.h"
#include "../eqemu_logsys.h"
#include <zlib.h>
#include <fmt/format.h>
#include <sstream>
@@ -308,6 +309,8 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
m_combined[1] = OP_Combined;
m_last_session_stats = Clock::now();
m_outgoing_budget = owner->m_options.outgoing_data_rate;
LogNetcode("New session [{}] with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
}
//new connection made as client
@@ -466,7 +469,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
for (int i = 1; i >= 0; --i) {
switch (m_encode_passes[i]) {
case EncodeXOR:
if (temp.GetInt8(0) == 0)
if (temp.GetInt8(0) == 0)
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size());
else
Decode(temp, 1, temp.Length() - 1);
@@ -630,6 +633,8 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
DynamicPacket p;
p.PutSerialize(0, reply);
InternalSend(p);
LogNetcode("[OP_SessionRequest] Session [{}] started with encode key [{}]", m_connect_code, HostToNetwork(m_encode_key));
}
break;
@@ -647,6 +652,12 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2;
m_max_packet_size = reply.max_packet_size;
ChangeStatus(StatusConnected);
LogNetcode(
"[OP_SessionResponse] Session [{}] refresh with encode key [{}]",
m_connect_code,
HostToNetwork(m_encode_key)
);
}
}
break;
@@ -771,6 +782,12 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
SendDisconnect();
}
LogNetcode(
"[OP_SessionDisconnect] Session [{}] disconnect with encode key [{}]",
m_connect_code,
HostToNetwork(m_encode_key)
);
ChangeStatus(StatusDisconnecting);
break;
}
@@ -835,6 +852,7 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
}
if (p.Length() < (size_t)m_crc_bytes) {
LogNetcode("Session [{}] ignored packet (crc bytes invalid on session)", m_connect_code);
return false;
}
@@ -1078,7 +1096,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
if (m_status == DbProtocolStatus::StatusDisconnected) {
return;
}
auto resends = 0;
auto now = Clock::now();
auto s = &m_streams[stream];
@@ -1113,7 +1131,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
Close();
return;
}
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
auto &p = entry.second.packet;
if (p.Length() >= DaybreakHeader::size()) {
@@ -1406,8 +1424,8 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
sent.first_sent = Clock::now();
sent.times_resent = 0;
sent.resend_delay = EQ::Clamp(
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
m_owner->m_options.resend_delay_min,
static_cast<size_t>((m_rolling_ping * m_owner->m_options.resend_delay_factor) + m_owner->m_options.resend_delay_ms),
m_owner->m_options.resend_delay_min,
m_owner->m_options.resend_delay_max);
stream->sent_packets.insert(std::make_pair(stream->sequence_out, sent));
stream->sequence_out++;
+9
View File
@@ -65,6 +65,15 @@ EQ::Net::EQStream::~EQStream()
}
void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req) {
LogPacketServerClient(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(p->GetOpcode()),
(*m_opcode_manager)->EmuToEQ(p->GetOpcode()),
p->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "")
);
if (m_opcode_manager && *m_opcode_manager) {
uint16 opcode = 0;
if (p->GetOpcodeBypass() != 0) {
+4
View File
@@ -57,6 +57,10 @@ namespace EQ
virtual void SetOpcodeManager(OpcodeManager **opm) {
m_opcode_manager = opm;
}
virtual OpcodeManager * GetOpcodeManager() const
{
return (*m_opcode_manager);
};
virtual Stats GetStats() const;
virtual void ResetStats();
+11 -1
View File
@@ -135,7 +135,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
auto leg_opcode = *(uint16_t*)&m_buffer[current];
auto leg_size = *(uint16_t*)&m_buffer[current + 2] - 4;
//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"
//so in send we pad it one byte if that's the case
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
@@ -319,6 +319,16 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
size_t message_len = length;
EQ::Net::StaticPacket packet(&data[0], message_len);
const auto is_detail_enabled = LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerToServer);
if (opcode != ServerOP_KeepAlive || is_detail_enabled) {
LogPacketServerToServer(
"[{:#06x}] Size [{}] {}",
opcode,
packet.Length(),
(is_detail_enabled ? "\n" + packet.ToString() : "")
);
}
auto cb = m_message_callbacks.find(opcode);
if (cb != m_message_callbacks.end()) {
cb->second(opcode, packet);
+3
View File
@@ -184,6 +184,9 @@ uint16 RegularOpcodeManager::EmuToEQ(const EmuOpcode emu_op) {
MOpcodes.lock();
res = emu_to_eq[emu_op];
MOpcodes.unlock();
LogNetcodeDetail("[Opcode Manager] Translate emu [{}] ({:#06x}) eq [{:#06x}]", OpcodeNames[emu_op], emu_op, res);
#ifdef DEBUG_TRANSLATE
fprintf(stderr, "M Translate Emu %s (%d) to EQ 0x%.4x\n", OpcodeNames[emu_op], emu_op, res);
#endif
+4 -12
View File
@@ -32,6 +32,7 @@
#include "../inventory_profile.h"
#include "rof_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include <iostream>
#include <sstream>
@@ -75,12 +76,8 @@ namespace RoF
{
//create our opcode manager if we havent already
if (opcodes == nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager();
@@ -118,12 +115,7 @@ namespace RoF
//we need to go to every stream and replace it's manager.
if (opcodes != nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return;
+5 -12
View File
@@ -32,6 +32,7 @@
#include "../inventory_profile.h"
#include "rof2_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include <iostream>
#include <sstream>
@@ -76,12 +77,9 @@ namespace RoF2
{
//create our opcode manager if we havent already
if (opcodes == nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager();
@@ -122,12 +120,7 @@ namespace RoF2
//we need to go to every stream and replace it's manager.
if (opcodes != nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return;
+3 -12
View File
@@ -32,6 +32,7 @@
#include "../item_instance.h"
#include "sod_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include <iostream>
#include <sstream>
@@ -69,12 +70,7 @@ namespace SoD
{
//create our opcode manager if we havent already
if (opcodes == nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager();
@@ -115,12 +111,7 @@ namespace SoD
//we need to go to every stream and replace it's manager.
if (opcodes != nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return;
+3 -12
View File
@@ -32,6 +32,7 @@
#include "../item_instance.h"
#include "sof_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include <iostream>
#include <sstream>
@@ -69,12 +70,7 @@ namespace SoF
{
//create our opcode manager if we havent already
if (opcodes == nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager();
@@ -113,12 +109,7 @@ namespace SoF
//we need to go to every stream and replace it's manager.
if (opcodes != nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return;
+3 -11
View File
@@ -32,6 +32,7 @@
#include "../strings.h"
#include "../item_instance.h"
#include "titanium_structs.h"
#include "../path_manager.h"
#include <sstream>
@@ -69,11 +70,7 @@ namespace Titanium
auto Config = EQEmuConfig::get();
//create our opcode manager if we havent already
if (opcodes == nullptr) {
//TODO: get this file name from the config file
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager();
@@ -114,12 +111,7 @@ namespace Titanium
//we need to go to every stream and replace it's manager.
if (opcodes != nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return;
+3 -12
View File
@@ -32,6 +32,7 @@
#include "../item_instance.h"
#include "uf_structs.h"
#include "../rulesys.h"
#include "../path_manager.h"
#include <iostream>
#include <sstream>
@@ -69,12 +70,7 @@ namespace UF
{
//create our opcode manager if we havent already
if (opcodes == nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
//load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager();
@@ -115,12 +111,7 @@ namespace UF
//we need to go to every stream and replace it's manager.
if (opcodes != nullptr) {
//TODO: get this file name from the config file
auto Config = EQEmuConfig::get();
std::string opfile = Config->PatchDir;
opfile += "patch_";
opfile += name;
opfile += ".conf";
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return;
+133
View File
@@ -0,0 +1,133 @@
#include "path_manager.h"
#include "file.h"
#include "eqemu_logsys.h"
#include "eqemu_config.h"
#include "strings.h"
#include <filesystem>
namespace fs = std::filesystem;
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();
std::filesystem::current_path(m_server_path);
LogInfo("[PathManager] server [{}]", m_server_path);
if (!EQEmuConfig::LoadConfig()) {
LogError("[PathManager] Failed to load eqemu config");
return;
}
const auto c = EQEmuConfig::get();
// maps
if (File::Exists(fs::path{m_server_path + "/" + c->MapDir}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/" + c->MapDir}).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();
}
// quests
if (File::Exists(fs::path{m_server_path + "/" + c->QuestDir}.string())) {
m_quests_path = fs::relative(fs::path{m_server_path + "/" + c->QuestDir}).string();
}
// plugins
if (File::Exists(fs::path{m_server_path + "/" + c->PluginDir}.string())) {
m_plugins_path = fs::relative(fs::path{m_server_path + "/" + c->PluginDir}).string();
}
// lua_modules
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();
}
// lua mods
if (File::Exists(fs::path{ m_server_path + "/mods" }.string())) {
m_lua_mods_path = fs::relative(fs::path{ m_server_path + "/mods" }).string();
}
// patches
if (File::Exists(fs::path{m_server_path + "/" + c->PatchDir}.string())) {
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
}
// 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("[PathManager] logs [{}]", m_log_path);
LogInfo("[PathManager] lua mods [{}]", m_lua_mods_path);
LogInfo("[PathManager] lua_modules [{}]", m_lua_modules_path);
LogInfo("[PathManager] maps [{}]", m_maps_path);
LogInfo("[PathManager] patches [{}]", m_patch_path);
LogInfo("[PathManager] plugins [{}]", m_plugins_path);
LogInfo("[PathManager] quests [{}]", m_quests_path);
LogInfo("[PathManager] shared_memory [{}]", m_shared_memory_path);
}
const std::string &PathManager::GetServerPath() const
{
return m_server_path;
}
const std::string &PathManager::GetMapsPath() const
{
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
{
return m_shared_memory_path;
}
const std::string &PathManager::GetLogPath() const
{
return m_log_path;
}
const std::string &PathManager::GetPatchPath() const
{
return m_patch_path;
}
const std::string &PathManager::GetLuaModulesPath() const
{
return m_lua_modules_path;
}
const std::string &PathManager::GetLuaModsPath() const
{
return m_lua_mods_path;
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef EQEMU_PATH_MANAGER_H
#define EQEMU_PATH_MANAGER_H
#include <string>
class PathManager {
public:
void LoadPaths();
[[nodiscard]] const std::string &GetLogPath() const;
[[nodiscard]] const std::string &GetLuaModsPath() const;
[[nodiscard]] const std::string &GetLuaModulesPath() const;
[[nodiscard]] const std::string &GetMapsPath() const;
[[nodiscard]] const std::string &GetPatchPath() const;
[[nodiscard]] const std::string &GetPluginsPath() const;
[[nodiscard]] const std::string &GetQuestsPath() const;
[[nodiscard]] const std::string &GetServerPath() const;
[[nodiscard]] const std::string &GetSharedMemoryPath() const;
private:
std::string m_log_path;
std::string m_lua_mods_path;
std::string m_lua_modules_path;
std::string m_maps_path;
std::string m_patch_path;
std::string m_plugins_path;
std::string m_quests_path;
std::string m_server_path;
std::string m_shared_memory_path;
};
extern PathManager path;
#endif //EQEMU_PATH_MANAGER_H
+2
View File
@@ -67,6 +67,8 @@ std::string GetPlatformName()
return "Launch";
case EQEmuExePlatform::ExePlatformHC:
return "HC";
case EQEmuExePlatform::ExePlatformTests:
return "Tests";
default:
return "";
}
+2 -1
View File
@@ -36,7 +36,8 @@ enum EQEmuExePlatform
ExePlatformSharedMemory,
ExePlatformClientImport,
ExePlatformClientExport,
ExePlatformHC
ExePlatformHC,
ExePlatformTests
};
void RegisterExecutablePlatform(EQEmuExePlatform p);
+1
View File
@@ -17,6 +17,7 @@
*/
#include "rulesys.h"
#include "eqemu_logsys.h"
#include "database.h"
#include "strings.h"
#include <cstdlib>
+2
View File
@@ -491,6 +491,7 @@ RULE_INT(Combat, FrontalStunImmunityRaces, 512, "Bitmask for Races than have fro
RULE_BOOL(Combat, NPCsUseFrontalStunImmunityRaces, true, "Enable or disable NPCs using frontal stun immunity Races from Combat:FrontalStunImmunityRaces, true by default.")
RULE_BOOL(Combat, AssassinateOnlyHumanoids, true, "Enable or disable Assassinate only being allowed on Humanoids, true by default.")
RULE_BOOL(Combat, HeadshotOnlyHumanoids, true, "Enable or disable Headshot only being allowed on Humanoids, true by default.")
RULE_BOOL(Combat, EnableWarriorShielding, true, "Enable or disable Warrior Shielding Ability (/shield), true by default.")
RULE_CATEGORY_END()
RULE_CATEGORY(NPC)
@@ -686,6 +687,7 @@ RULE_REAL(AA, ModernAAScalingStartPercent, 1000, "1000% or 10x AA experience at
RULE_INT(AA, ModernAAScalingAAMinimum, 0, "The minimum number of earned AA before AA experience scaling begins")
RULE_INT(AA, ModernAAScalingAALimit, 4000, "The number of earned AA when AA experience scaling ends")
RULE_BOOL(AA, SoundForAAEarned, false, "Play sound when AA point earned")
RULE_INT(AA, UnusedAAPointCap, -1, "Cap for Unused AA Points. Default: -1. NOTE: DO NOT LOWER THIS WITHOUT KNOWING WHAT YOU ARE DOING. MAY RESULT IN PLAYERS LOSING AAs.")
RULE_CATEGORY_END()
RULE_CATEGORY(Console)
+10 -8
View File
@@ -41,6 +41,7 @@
#include "repositories/criteria/content_filter_criteria.h"
#include "repositories/account_repository.h"
#include "repositories/faction_association_repository.h"
#include "path_manager.h"
namespace ItemField
{
@@ -940,7 +941,7 @@ bool SharedDatabase::LoadItems(const std::string &prefix) {
const auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("items");
mutex.Lock();
std::string file_name = Config->SharedMemDir + prefix + std::string("items");
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("items"));
LogInfo("[Shared Memory] Attempting to load file [{}]", file_name);
items_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
items_hash = std::make_unique<EQ::FixedMemoryHashSet<EQ::ItemData>>(static_cast<uint8*>(items_mmf->Get()), items_mmf->Size());
@@ -1436,7 +1437,7 @@ bool SharedDatabase::LoadNPCFactionLists(const std::string &prefix) {
const auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("faction");
mutex.Lock();
std::string file_name = Config->SharedMemDir + prefix + std::string("faction");
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("faction"));
LogInfo("[Shared Memory] Attempting to load file [{}]", file_name);
faction_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
faction_hash = std::make_unique<EQ::FixedMemoryHashSet<NPCFactionList>>(static_cast<uint8*>(faction_mmf->Get()), faction_mmf->Size());
@@ -1509,7 +1510,7 @@ bool SharedDatabase::LoadFactionAssociation(const std::string &prefix)
auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("factionassociations");
mutex.Lock();
std::string file_name = Config->SharedMemDir + prefix + std::string("factionassociations");
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("factionassociations"));
faction_associations_mmf = std::unique_ptr<EQ::MemoryMappedFile>(new EQ::MemoryMappedFile(file_name));
faction_associations_hash = std::unique_ptr<EQ::FixedMemoryHashSet<FactionAssociations>>(
new EQ::FixedMemoryHashSet<FactionAssociations>(reinterpret_cast<uint8 *>(faction_associations_mmf->Get()),
@@ -1704,7 +1705,7 @@ bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
const auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("skill_caps");
mutex.Lock();
std::string file_name = Config->SharedMemDir + prefix + std::string("skill_caps");
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("skill_caps"));
LogInfo("[Shared Memory] Attempting to load file [{}]", file_name);
skill_caps_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
mutex.Unlock();
@@ -1863,7 +1864,7 @@ bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const
EQ::IPCMutex mutex("spells");
mutex.Lock();
std::string file_name = Config->SharedMemDir + prefix + std::string("spells");
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("spells"));
spells_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
LogInfo("[Shared Memory] Attempting to load file [{}]", file_name);
*records = *static_cast<uint32*>(spells_mmf->Get());
@@ -2077,7 +2078,7 @@ bool SharedDatabase::LoadBaseData(const std::string &prefix) {
EQ::IPCMutex mutex("base_data");
mutex.Lock();
std::string file_name = Config->SharedMemDir + prefix + std::string("base_data");
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("base_data"));
base_data_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
mutex.Unlock();
} catch(std::exception& ex) {
@@ -2398,12 +2399,13 @@ bool SharedDatabase::LoadLoot(const std::string &prefix) {
const auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("loot");
mutex.Lock();
std::string file_name_lt = Config->SharedMemDir + prefix + std::string("loot_table");
std::string file_name_lt = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("loot_table"));
loot_table_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name_lt);
loot_table_hash = std::make_unique<EQ::FixedMemoryVariableHashSet<LootTable_Struct>>(
static_cast<uint8*>(loot_table_mmf->Get()),
loot_table_mmf->Size());
std::string file_name_ld = Config->SharedMemDir + prefix + std::string("loot_drop");
std::string file_name_ld = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("loot_drop"));
loot_drop_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name_ld);
loot_drop_hash = std::make_unique<EQ::FixedMemoryVariableHashSet<LootDrop_Struct>>(
static_cast<uint8*>(loot_drop_mmf->Get()),
File diff suppressed because it is too large Load Diff
+1 -15
View File
@@ -49,20 +49,6 @@ enum class TaskTimerType
Request
};
// live alt currency types, may not match current server alternate currency ids
enum class AltCurrencyType
{
RadiantCrystal = 4,
EbonCrystal = 5,
MarkOfValor = 31,
CommemorativeCoin = 33,
PieceOfEight = 37,
RemnantOfTranquility = 38,
SathirTradeGem = 41,
BathezidTradeGem = 43,
FroststoneDucat = 48,
};
struct ActivityInformation {
int req_activity_id;
int step;
@@ -216,7 +202,7 @@ struct TaskInformation {
int faction_amount{}; // faction hit value
TaskMethodType reward_method;
int reward_points;
AltCurrencyType reward_point_type;
int32_t reward_point_type;
int activity_count{};
uint8_t min_level{};
uint8_t max_level{};
+1 -1
View File
@@ -34,7 +34,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9208
#define CURRENT_BINARY_DATABASE_VERSION 9212
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9029
+12 -12
View File
@@ -20,6 +20,7 @@
#include "zone_store.h"
#include "../common/content/world_content_service.h"
#include "stacktrace/backward.hpp"
ZoneStore::ZoneStore() = default;
ZoneStore::~ZoneStore() = default;
@@ -81,12 +82,6 @@ const char *ZoneStore::GetZoneName(uint32 zone_id, bool error_unknown)
return "UNKNOWN";
}
LogInfo(
"[GetZoneName] Failed to get zone name by zone_id [{}] error_unknown [{}]",
zone_id,
(error_unknown ? "true" : "false")
);
return nullptr;
}
@@ -107,12 +102,6 @@ const char *ZoneStore::GetZoneLongName(uint32 zone_id, bool error_unknown)
return "UNKNOWN";
}
LogInfo(
"[GetZoneLongName] Failed to get zone long name by zone_id [{}] error_unknown [{}]",
zone_id,
(error_unknown ? "true" : "false")
);
return nullptr;
}
@@ -185,6 +174,17 @@ ZoneRepository::Zone *ZoneStore::GetZone(const char *in_zone_name)
return nullptr;
}
ZoneRepository::Zone *ZoneStore::GetZone(std::string in_zone_name)
{
for (auto &z: m_zones) {
if (z.short_name == in_zone_name) {
return &z;
}
}
return nullptr;
}
const std::vector<ZoneRepository::Zone> &ZoneStore::GetZones() const
{
return m_zones;
+1
View File
@@ -35,6 +35,7 @@ public:
ZoneRepository::Zone *GetZone(uint32 zone_id, int version = 0);
ZoneRepository::Zone *GetZone(const char *in_zone_name);
ZoneRepository::Zone *GetZone(std::string in_zone_name);
uint32 GetZoneID(const char *in_zone_name);
uint32 GetZoneID(std::string zone_name);
std::string GetZoneName(uint32 zone_id);
+20 -8
View File
@@ -21,6 +21,7 @@
#include "../common/proc_launcher.h"
#include "../common/eqemu_config.h"
#include "../common/servertalk.h"
#include "../common/path_manager.h"
#include "../common/platform.h"
#include "../common/crash.h"
#include "../common/unix.h"
@@ -33,6 +34,7 @@
#include <time.h>
EQEmuLogSys LogSys;
PathManager path;
bool RunLoops = false;
@@ -43,6 +45,8 @@ int main(int argc, char *argv[]) {
LogSys.LoadLogSettingsDefaults();
set_exception_handler();
path.LoadPaths();
std::string launcher_name;
if(argc == 2) {
launcher_name = argv[1];
@@ -101,11 +105,17 @@ int main(int argc, char *argv[]) {
Log(Logs::Detail, Logs::Launcher, "Starting main loop...");
ProcLauncher *launch = ProcLauncher::get();
RunLoops = true;
while(RunLoops) {
auto loop_fn = [&](EQ::Timer* t) {
//Advance the timer to our current point in time
Timer::SetCurrentTime();
if (!RunLoops) {
EQ::EventLoop::Get().Shutdown();
return;
}
/*
* Let the process manager look for dead children
*/
@@ -116,29 +126,31 @@ int main(int argc, char *argv[]) {
*/
zone = zones.begin();
zend = zones.end();
for(; zone != zend; ++zone) {
if(!zone->second->Process())
for (; zone != zend; ++zone) {
if (!zone->second->Process())
to_remove.insert(zone->first);
}
/*
* Kill off any zones which have stopped
*/
while(!to_remove.empty()) {
while (!to_remove.empty()) {
std::string rem = *to_remove.begin();
to_remove.erase(rem);
zone = zones.find(rem);
if(zone == zones.end()) {
if (zone == zones.end()) {
//wtf...
continue;
}
delete zone->second;
zones.erase(rem);
}
};
EQ::EventLoop::Get().Process();
Sleep(5);
}
EQ::Timer process_timer(loop_fn);
process_timer.Start(32, true);
EQ::EventLoop::Get().Run();
//try to be semi-nice about this... without waiting too long
zone = zones.begin();
+34 -54
View File
@@ -26,13 +26,13 @@ bool Client::Process()
{
EQApplicationPacket *app = m_connection->PopPacket();
while (app) {
if (server.options.IsTraceOn()) {
LogDebug("Application packet received from client (size {0})", app->Size());
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(app);
}
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
m_connection->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
if (m_client_status == cs_failed_to_login) {
delete app;
@@ -42,9 +42,7 @@ bool Client::Process()
switch (app->GetOpcode()) {
case OP_SessionReady: {
if (server.options.IsTraceOn()) {
LogInfo("Session ready received from client");
}
LogInfo("Session ready received from client account {}", GetClientDescription());
Handle_SessionReady((const char *) app->pBuffer, app->Size());
break;
}
@@ -54,9 +52,7 @@ bool Client::Process()
break;
}
if (server.options.IsTraceOn()) {
LogInfo("Login received from client");
}
LogInfo("Login received from client {}", GetClientDescription());
Handle_Login((const char *) app->pBuffer, app->Size());
break;
@@ -67,9 +63,7 @@ bool Client::Process()
break;
}
if (server.options.IsTraceOn()) {
LogDebug("Server list request received from client");
}
LogInfo("Server list request received from client {}", GetClientDescription());
SendServerListPacket(*(uint32_t *) app->pBuffer);
break;
@@ -83,13 +77,6 @@ bool Client::Process()
Handle_Play((const char *) app->pBuffer);
break;
}
default: {
if (LogSys.log_settings[Logs::PacketClientServerUnhandled].is_category_enabled == 1) {
char dump[64];
app->build_header_dump(dump);
LogError("Recieved unhandled application packet from the client: [{}]", dump);
}
}
}
delete app;
@@ -128,10 +115,6 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
buf->base_reply.success = true;
buf->base_reply.error_str_id = 0x65; // 101 "No Error"
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
m_connection->QueuePacket(outapp);
delete outapp;
}
@@ -290,14 +273,12 @@ void Client::Handle_Play(const char *data)
auto server_id_in = (unsigned int) play->server_number;
auto sequence_in = (unsigned int) play->base_header.sequence;
if (server.options.IsTraceOn()) {
LogInfo(
"Play received from client [{0}] server number {1} sequence {2}",
GetAccountName(),
server_id_in,
sequence_in
);
}
LogInfo(
"[Handle_Play] Play received from client [{}] server number [{}] sequence [{}]",
GetAccountName(),
server_id_in,
sequence_in
);
m_play_server_id = (unsigned int) play->server_number;
m_play_sequence_id = sequence_in;
@@ -310,21 +291,14 @@ void Client::Handle_Play(const char *data)
*/
void Client::SendServerListPacket(uint32 seq)
{
auto outapp = server.server_manager->CreateServerListPacket(this, seq);
auto app = server.server_manager->CreateServerListPacket(this, seq);
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp.get());
}
m_connection->QueuePacket(outapp.get());
m_connection->QueuePacket(app.get());
}
void Client::SendPlayResponse(EQApplicationPacket *outapp)
{
if (server.options.IsTraceOn()) {
LogDebug("Sending play response for {0}", GetAccountName());
// server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size);
}
LogInfo("Sending play response for {}", GetClientDescription());
m_connection->QueuePacket(outapp);
}
@@ -422,10 +396,6 @@ void Client::DoFailedLogin()
outapp.WriteData(&base_header, sizeof(base_header));
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(&outapp);
}
m_connection->QueuePacket(&outapp);
m_client_status = cs_failed_to_login;
}
@@ -576,10 +546,6 @@ void Client::DoSuccessfulLogin(
outapp->WriteData(&base_header, sizeof(base_header));
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp.get());
}
m_connection->QueuePacket(outapp.get());
m_client_status = cs_logged_in;
@@ -596,7 +562,7 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
if (server.options.IsDisplayExpansions()) {
int32_t expansion = server.options.GetMaxExpansions();
int32_t owned_expansion = (expansion << 1) | 1;
@@ -839,3 +805,17 @@ bool Client::ProcessHealthCheck(std::string username)
return false;
}
std::string Client::GetClientDescription()
{
in_addr in{};
in.s_addr = GetConnection()->GetRemoteIP();
std::string client_ip = inet_ntoa(in);
return fmt::format(
"account_name [{}] account_id ({}) ip_address [{}]",
GetAccountName(),
GetAccountID(),
client_ip
);
}
+7 -1
View File
@@ -51,7 +51,7 @@ public:
* @param size
*/
void Handle_Login(const char *data, unsigned int size);
/**
* Sends the expansion data packet
*
@@ -111,6 +111,12 @@ public:
*/
std::string GetAccountName() const { return m_account_name; }
/**
* Returns a description for the client for logging
* @return std::string
*/
std::string GetClientDescription();
/**
* Gets the key generated at login for this client
*
+20 -10
View File
@@ -6,6 +6,7 @@ extern bool run_server;
#include "../common/eqemu_logsys.h"
#include "../common/misc.h"
#include "../common/path_manager.h"
ClientManager::ClientManager()
{
@@ -15,13 +16,18 @@ ClientManager::ClientManager()
titanium_stream = new EQ::Net::EQStreamManager(titanium_opts);
titanium_ops = new RegularOpcodeManager;
if (!titanium_ops->LoadOpcodes(
std::string opcodes_path = fmt::format(
"{}/{}",
path.GetServerPath(),
server.config.GetVariableString(
"client_configuration",
"titanium_opcodes",
"login_opcodes.conf"
).c_str())) {
)
);
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
server.config.GetVariableString("client_configuration", "titanium_opcodes", "login_opcodes.conf")
@@ -49,14 +55,18 @@ ClientManager::ClientManager()
EQStreamManagerInterfaceOptions sod_opts(sod_port, false, false);
sod_stream = new EQ::Net::EQStreamManager(sod_opts);
sod_ops = new RegularOpcodeManager;
if (
!sod_ops->LoadOpcodes(
server.config.GetVariableString(
"client_configuration",
"sod_opcodes",
"login_opcodes.conf"
).c_str()
)) {
opcodes_path = fmt::format(
"{}/{}",
path.GetServerPath(),
server.config.GetVariableString(
"client_configuration",
"sod_opcodes",
"login_opcodes.conf"
)
);
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
server.config.GetVariableString("client_configuration", "sod_opcodes", "login_opcodes.conf").c_str()
+35 -23
View File
@@ -11,6 +11,7 @@
#include "loginserver_webserver.h"
#include "loginserver_command_handler.h"
#include "../common/strings.h"
#include "../common/path_manager.h"
#include <time.h>
#include <stdlib.h>
#include <string>
@@ -20,6 +21,7 @@
LoginServer server;
EQEmuLogSys LogSys;
bool run_server = true;
PathManager path;
void ResolveAddresses();
void CatchSignal(int sig_num)
@@ -42,18 +44,11 @@ void LoadDatabaseConnection()
void LoadServerConfig()
{
server.config = EQ::JsonConfigFile::Load("login.json");
server.config = EQ::JsonConfigFile::Load(
fmt::format("{}/login.json", path.GetServerPath())
);
LogInfo("Config System Init");
/**
* Logging
*/
server.options.Trace(server.config.GetVariableBool("logging", "trace", false));
server.options.WorldTrace(server.config.GetVariableBool("logging", "world_trace", false));
server.options.DumpInPackets(server.config.GetVariableBool("logging", "dump_packets_in", false));
server.options.DumpOutPackets(server.config.GetVariableBool("logging", "dump_packets_out", false));
/**
* Worldservers
*/
@@ -63,7 +58,7 @@ void LoadServerConfig()
"reject_duplicate_servers",
false
)
);
);
server.options.SetShowPlayerCount(server.config.GetVariableBool("worldservers", "show_player_count", false));
server.options.AllowUnregistered(
server.config.GetVariableBool(
@@ -90,8 +85,18 @@ void LoadServerConfig()
/**
* Expansion Display Settings
*/
server.options.DisplayExpansions(server.config.GetVariableBool("client_configuration", "display_expansions", false)); //disable by default
server.options.MaxExpansions(server.config.GetVariableInt("client_configuration", "max_expansions_mask", 67108863)); //enable display of all expansions
server.options.DisplayExpansions(
server.config.GetVariableBool(
"client_configuration",
"display_expansions",
false
)); //disable by default
server.options.MaxExpansions(
server.config.GetVariableInt(
"client_configuration",
"max_expansions_mask",
67108863
)); //enable display of all expansions
/**
* Account
@@ -171,6 +176,8 @@ int main(int argc, char **argv)
LogSys.LoadLogSettingsDefaults();
}
path.LoadPaths();
/**
* Command handler
*/
@@ -181,7 +188,7 @@ int main(int argc, char **argv)
LoadDatabaseConnection();
LogSys.LoadLogSettingsDefaults();
LogSys.log_settings[Logs::Debug].log_to_console = static_cast<uint8>(Logs::General);
LogSys.log_settings[Logs::Debug].log_to_console = static_cast<uint8>(Logs::General);
LogSys.log_settings[Logs::Debug].is_category_enabled = 1;
LoginserverCommandHandler::CommandHandler(argc, argv);
@@ -196,6 +203,7 @@ int main(int argc, char **argv)
if (argc == 1) {
LogSys.SetDatabase(server.db)
->SetLogPath("logs")
->LoadLogDatabaseSettings()
->StartFileLogs();
}
@@ -258,10 +266,6 @@ int main(int argc, char **argv)
web_api_thread.detach();
}
LogInfo("[Config] [Logging] IsTraceOn [{0}]", server.options.IsTraceOn());
LogInfo("[Config] [Logging] IsWorldTraceOn [{0}]", server.options.IsWorldTraceOn());
LogInfo("[Config] [Logging] IsDumpInPacketsOn [{0}]", server.options.IsDumpInPacketsOn());
LogInfo("[Config] [Logging] IsDumpOutPacketsOn [{0}]", server.options.IsDumpOutPacketsOn());
LogInfo("[Config] [Account] CanAutoCreateAccounts [{0}]", server.options.CanAutoCreateAccounts());
LogInfo("[Config] [Client_Configuration] DisplayExpansions [{0}]", server.options.IsDisplayExpansions());
LogInfo("[Config] [Client_Configuration] MaxExpansions [{0}]", server.options.GetMaxExpansions());
@@ -285,13 +289,21 @@ int main(int argc, char **argv)
LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed());
LogInfo("[Config] [Security] IsUpdatingInsecurePasswords [{0}]", server.options.IsUpdatingInsecurePasswords());
while (run_server) {
auto loop_fn = [&](EQ::Timer* t) {
Timer::SetCurrentTime();
server.client_manager->Process();
EQ::EventLoop::Get().Process();
Sleep(5);
}
if (!run_server) {
EQ::EventLoop::Get().Shutdown();
return;
}
server.client_manager->Process();
};
EQ::Timer process_timer(loop_fn);
process_timer.Start(32, true);
EQ::EventLoop::Get().Run();
LogInfo("Server Shutdown");
-47
View File
@@ -13,9 +13,6 @@ public:
*/
Options() :
allow_unregistered(true),
trace(false),
dump_in_packets(false),
dump_out_packets(false),
display_expansions(false),
max_expansions_mask(0),
encryption_mode(5),
@@ -42,46 +39,6 @@ public:
*/
inline bool IsUnregisteredAllowed() const { return allow_unregistered; }
/**
* Sets trace.
*/
inline void Trace(bool b) { trace = b; }
/**
* Returns the value of trace.
*/
inline bool IsTraceOn() const { return trace; }
/**
* Sets trace.
*/
inline void WorldTrace(bool b) { world_trace = b; }
/**
* Returns the value of trace.
*/
inline bool IsWorldTraceOn() const { return world_trace; }
/**
* Sets dump_in_packets.
*/
inline void DumpInPackets(bool b) { dump_in_packets = b; }
/**
* Returns the value of dump_in_packets.
*/
inline bool IsDumpInPacketsOn() const { return dump_in_packets; }
/**
* Sets dump_out_packets.
*/
inline void DumpOutPackets(bool b) { dump_out_packets = b; }
/**
* Returns the value of dump_out_packets.
*/
inline bool IsDumpOutPacketsOn() const { return dump_out_packets; }
/**
* Sets encryption_mode.
*/
@@ -148,10 +105,6 @@ public:
private:
bool allow_unregistered;
bool trace;
bool world_trace;
bool dump_in_packets;
bool dump_out_packets;
bool display_expansions;
bool reject_duplicate_servers;
bool world_dev_test_servers_list_bottom;
+10 -8
View File
@@ -180,21 +180,23 @@ void ServerManager::SendUserToWorldRequest(
EQ::Net::DynamicPacket outapp;
outapp.Resize(sizeof(UsertoWorldRequest_Struct));
auto *user_to_world_request = (UsertoWorldRequest_Struct *) outapp.Data();
user_to_world_request->worldid = server_id;
user_to_world_request->lsaccountid = client_account_id;
strncpy(user_to_world_request->login, &client_loginserver[0], 64);
auto *r = (UsertoWorldRequest_Struct *) outapp.Data();
r->worldid = server_id;
r->lsaccountid = client_account_id;
strncpy(r->login, &client_loginserver[0], 64);
(*iter)->GetConnection()->Send(ServerOP_UsertoWorldReq, outapp);
found = true;
if (server.options.IsDumpInPacketsOn()) {
LogInfo("{0}", outapp.ToString());
}
LogNetcode(
"[UsertoWorldRequest] [Size: {}]\n{}",
outapp.Length(),
outapp.ToString()
);
}
++iter;
}
if (!found && server.options.IsTraceOn()) {
if (!found) {
LogError("Client requested a user to world but supplied an invalid id of {0}", server_id);
}
}
+98 -154
View File
@@ -79,17 +79,12 @@ void WorldServer::Reset()
*/
void WorldServer::ProcessNewLSInfo(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: [{0}], (size {1})",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessNewLSInfo] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(ServerNewLSInfo_Struct)) {
LogError(
@@ -129,18 +124,13 @@ void WorldServer::ProcessNewLSInfo(uint16_t opcode, const EQ::Net::Packet &packe
*/
void WorldServer::ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &packet)
{
Log(
Logs::Detail,
Logs::Netcode,
"Application packet received from server: 0x%.4X, (size %u)",
LogNetcode(
"[ProcessLSStatus] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length()
packet.Length(),
packet.ToString()
);
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
if (packet.Length() < sizeof(ServerLSStatus_Struct)) {
LogError(
"Received application packet from server that had opcode ServerOP_LSStatus, but was too small. Discarded to avoid buffer overrun"
@@ -151,15 +141,13 @@ void WorldServer::ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &packet
auto *ls_status = (ServerLSStatus_Struct *) packet.Data();
if (server.options.IsWorldTraceOn()) {
LogDebug(
"World Server Status Update Received | Server [{0}] Status [{1}] Players [{2}] Zones [{3}]",
GetServerLongName(),
ls_status->status,
ls_status->num_players,
ls_status->num_zones
);
}
LogDebug(
"World Server Status Update Received | Server [{0}] Status [{1}] Players [{2}] Zones [{3}]",
GetServerLongName(),
ls_status->status,
ls_status->num_players,
ls_status->num_zones
);
Handle_LSStatus(ls_status);
}
@@ -170,17 +158,12 @@ void WorldServer::ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &packet
*/
void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: [{0}], (size {1})",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessUserToWorldResponseLegacy] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(UsertoWorldResponseLegacy_Struct)) {
LogError(
@@ -191,19 +174,11 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
return;
}
//I don't use world trace for this and here is why:
//Because this is a part of the client login procedure it makes tracking client errors
//While keeping world server spam with multiple servers connected almost impossible.
if (server.options.IsTraceOn()) {
LogDebug("User-To-World Response received");
}
auto *r = (UsertoWorldResponseLegacy_Struct *) packet.Data();
LogDebug("Trying to find client with user id of [{0}]", r->lsaccountid);
Client *client = server.client_manager->GetClient(r->lsaccountid, "eqemu");
if (client) {
LogDebug(
"Found client with user id of [{0}] and account name of [{1}]",
r->lsaccountid,
@@ -254,21 +229,13 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
break;
}
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Sending play response: allowed [{0}] sequence [{1}] server number [{2}] message [{3}]",
per->base_reply.success,
per->base_header.sequence,
per->server_number,
per->base_reply.error_str_id
);
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
}
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
LogDebug(
"Sending play response: allowed [{0}] sequence [{1}] server number [{2}] message [{3}]",
per->base_reply.success,
per->base_header.sequence,
per->server_number,
per->base_reply.error_str_id
);
client->SendPlayResponse(outapp);
delete outapp;
@@ -287,17 +254,12 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne
*/
void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: 0x%.4X, (size %u)",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessUserToWorldResponse] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(UsertoWorldResponse_Struct)) {
LogError(
@@ -308,25 +270,18 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
return;
}
//I don't use world trace for this and here is why:
//Because this is a part of the client login procedure it makes tracking client errors
//While keeping world server spam with multiple servers connected almost impossible.
if (server.options.IsTraceOn()) {
LogDebug("User-To-World Response received");
}
auto user_to_world_response = (UsertoWorldResponse_Struct *) packet.Data();
LogDebug("Trying to find client with user id of [{0}]", user_to_world_response->lsaccountid);
Client *client = server.client_manager->GetClient(
Client *c = server.client_manager->GetClient(
user_to_world_response->lsaccountid,
user_to_world_response->login
);
if (client) {
if (c) {
LogDebug("Found client with user id of [{0}] and account name of {1}",
user_to_world_response->lsaccountid,
client->GetAccountName().c_str()
c->GetAccountName().c_str()
);
auto *outapp = new EQApplicationPacket(
@@ -334,69 +289,62 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
sizeof(PlayEverquestResponse_Struct)
);
auto *per = (PlayEverquestResponse_Struct *) outapp->pBuffer;
per->base_header.sequence = client->GetPlaySequence();
per->server_number = client->GetPlayServerID();
auto *r = (PlayEverquestResponse_Struct *) outapp->pBuffer;
r->base_header.sequence = c->GetPlaySequence();
r->server_number = c->GetPlayServerID();
LogDebug(
"Found sequence and play of [{0}] [{1}]",
client->GetPlaySequence(),
client->GetPlayServerID()
c->GetPlaySequence(),
c->GetPlayServerID()
);
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
if (user_to_world_response->response > 0) {
per->base_reply.success = true;
r->base_reply.success = true;
SendClientAuth(
client->GetConnection()->GetRemoteAddr(),
client->GetAccountName(),
client->GetKey(),
client->GetAccountID(),
client->GetLoginServerName()
c->GetConnection()->GetRemoteAddr(),
c->GetAccountName(),
c->GetKey(),
c->GetAccountID(),
c->GetLoginServerName()
);
}
switch (user_to_world_response->response) {
case UserToWorldStatusSuccess:
per->base_reply.error_str_id = LS::ErrStr::ERROR_NONE;
r->base_reply.error_str_id = LS::ErrStr::ERROR_NONE;
break;
case UserToWorldStatusWorldUnavail:
per->base_reply.error_str_id = LS::ErrStr::ERROR_SERVER_UNAVAILABLE;
r->base_reply.error_str_id = LS::ErrStr::ERROR_SERVER_UNAVAILABLE;
break;
case UserToWorldStatusSuspended:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_SUSPENDED;
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_SUSPENDED;
break;
case UserToWorldStatusBanned:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_BANNED;
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACCOUNT_BANNED;
break;
case UserToWorldStatusWorldAtCapacity:
per->base_reply.error_str_id = LS::ErrStr::ERROR_WORLD_MAX_CAPACITY;
r->base_reply.error_str_id = LS::ErrStr::ERROR_WORLD_MAX_CAPACITY;
break;
case UserToWorldStatusAlreadyOnline:
per->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER;
r->base_reply.error_str_id = LS::ErrStr::ERROR_ACTIVE_CHARACTER;
break;
default:
per->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN;
r->base_reply.error_str_id = LS::ErrStr::ERROR_UNKNOWN;
break;
}
if (server.options.IsTraceOn()) {
LogDebug(
"Sending play response with following data, allowed [{0}], sequence {1}, server number {2}, message {3}",
per->base_reply.success,
per->base_header.sequence,
per->server_number,
per->base_reply.error_str_id
);
LogDebug("[Size: [{0}]] {1}", outapp->size, DumpPacketToString(outapp));
}
LogDebug(
"Sending play response with following data, allowed [{0}], sequence {1}, server number {2}, message {3}",
r->base_reply.success,
r->base_header.sequence,
r->server_number,
r->base_reply.error_str_id
);
if (server.options.IsDumpOutPacketsOn()) {
DumpPacket(outapp);
}
client->SendPlayResponse(outapp);
c->SendPlayResponse(outapp);
delete outapp;
}
else {
@@ -413,17 +361,12 @@ void WorldServer::ProcessUserToWorldResponse(uint16_t opcode, const EQ::Net::Pac
*/
void WorldServer::ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet &packet)
{
if (server.options.IsWorldTraceOn()) {
LogDebug(
"Application packet received from server: [{0}], (size {1})",
opcode,
packet.Length()
);
}
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(opcode, packet);
}
LogNetcode(
"[ProcessLSAccountUpdate] Application packet received from server [{:#04x}] [Size: {}]\n{}",
opcode,
packet.Length(),
packet.ToString()
);
if (packet.Length() < sizeof(ServerLSAccountUpdate_Struct)) {
LogError(
@@ -434,9 +377,7 @@ void WorldServer::ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet
return;
}
if (server.options.IsWorldTraceOn()) {
LogDebug("ServerOP_LSAccountUpdate packet received from [{0}]", m_short_name);
}
LogDebug("ServerOP_LSAccountUpdate packet received from [{0}]", m_short_name);
auto *loginserver_update = (ServerLSAccountUpdate_Struct *) packet.Data();
if (IsServerTrusted()) {
@@ -607,34 +548,34 @@ void WorldServer::SendClientAuth(
)
{
EQ::Net::DynamicPacket outapp;
ClientAuth_Struct client_auth{};
ClientAuth_Struct a{};
client_auth.loginserver_account_id = account_id;
a.loginserver_account_id = account_id;
strncpy(client_auth.account_name, account.c_str(), 30);
strncpy(client_auth.key, key.c_str(), 30);
strncpy(a.account_name, account.c_str(), 30);
strncpy(a.key, key.c_str(), 30);
client_auth.lsadmin = 0;
client_auth.is_world_admin = 0;
client_auth.ip = inet_addr(ip.c_str());
strncpy(client_auth.loginserver_name, &loginserver_name[0], 64);
a.lsadmin = 0;
a.is_world_admin = 0;
a.ip = inet_addr(ip.c_str());
strncpy(a.loginserver_name, &loginserver_name[0], 64);
const std::string &client_address(ip);
std::string world_address(m_connection->Handle()->RemoteIP());
if (client_address == world_address) {
client_auth.is_client_from_local_network = 1;
a.is_client_from_local_network = 1;
}
else if (IpUtil::IsIpInPrivateRfc1918(client_address)) {
LogInfo("Client is authenticating from a local address [{0}]", client_address);
client_auth.is_client_from_local_network = 1;
a.is_client_from_local_network = 1;
}
else {
client_auth.is_client_from_local_network = 0;
a.is_client_from_local_network = 0;
}
struct in_addr ip_addr{};
ip_addr.s_addr = client_auth.ip;
ip_addr.s_addr = a.ip;
LogInfo(
"Client authentication response: world_address [{0}] client_address [{1}]",
@@ -645,22 +586,25 @@ void WorldServer::SendClientAuth(
LogInfo(
"Sending Client Authentication Response ls_account_id [{0}] ls_name [{1}] name [{2}] key [{3}] ls_admin [{4}] "
"world_admin [{5}] ip [{6}] local [{7}]",
client_auth.loginserver_account_id,
client_auth.loginserver_name,
client_auth.account_name,
client_auth.key,
client_auth.lsadmin,
client_auth.is_world_admin,
a.loginserver_account_id,
a.loginserver_name,
a.account_name,
a.key,
a.lsadmin,
a.is_world_admin,
inet_ntoa(ip_addr),
client_auth.is_client_from_local_network
a.is_client_from_local_network
);
outapp.PutSerialize(0, client_auth);
outapp.PutSerialize(0, a);
m_connection->Send(ServerOP_LSClientAuth, outapp);
if (server.options.IsDumpInPacketsOn()) {
DumpPacket(ServerOP_LSClientAuth, outapp);
}
LogNetcode(
"[ServerOP_LSClientAuth] Sending [{:#04x}] [Size: {}]\n{}",
ServerOP_LSClientAuth,
outapp.Length(),
outapp.ToString()
);
}
constexpr static int MAX_ACCOUNT_NAME_LENGTH = 30;
+18 -4
View File
@@ -31,6 +31,7 @@
#include "queryservconfig.h"
#include "lfguild.h"
#include "worldserver.h"
#include "../common/path_manager.h"
#include <list>
#include <signal.h>
#include <thread>
@@ -43,6 +44,7 @@ std::string WorldShortName;
const queryservconfig *Config;
WorldServer *worldserver = 0;
EQEmuLogSys LogSys;
PathManager path;
void CatchSignal(int sig_num)
{
@@ -56,6 +58,8 @@ int main()
set_exception_handler();
Timer LFGuildExpireTimer(60000);
path.LoadPaths();
LogInfo("Starting EQEmu QueryServ");
if (!queryservconfig::LoadConfig()) {
LogInfo("Loading server configuration failed");
@@ -80,6 +84,7 @@ int main()
}
LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings()
->StartFileLogs();
@@ -99,15 +104,24 @@ int main()
/* Load Looking For Guild Manager */
lfguildmanager.LoadDatabase();
while (RunLoops) {
auto loop_fn = [&](EQ::Timer* t) {
Timer::SetCurrentTime();
if (!RunLoops) {
EQ::EventLoop::Get().Shutdown();
return;
}
if (LFGuildExpireTimer.Check()) {
lfguildmanager.ExpireEntries();
}
};
EQ::Timer process_timer(loop_fn);
process_timer.Start(32, true);
EQ::EventLoop::Get().Run();
EQ::EventLoop::Get().Process();
Sleep(5);
}
LogSys.CloseFileLogs();
}
+2 -2
View File
@@ -40,13 +40,13 @@ public:
}
// Load the config
static bool LoadConfig() {
static bool LoadConfig(const std::string& path = "") {
if (_chat_config != nullptr)
delete _chat_config;
_chat_config=new queryservconfig;
_config=_chat_config;
return _config->parseFile();
return _config->parseFile(path);
}
};
+5
View File
@@ -36,10 +36,12 @@
#include "base_data.h"
#include "../common/content/world_content_service.h"
#include "../common/zone_store.h"
#include "../common/path_manager.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
#ifdef _WINDOWS
#include <direct.h>
@@ -83,6 +85,8 @@ int main(int argc, char **argv)
LogSys.LoadLogSettingsDefaults();
set_exception_handler();
path.LoadPaths();
LogInfo("Shared Memory Loader Program");
if (!EQEmuConfig::LoadConfig()) {
LogError("Unable to load configuration file");
@@ -124,6 +128,7 @@ int main(int argc, char **argv)
}
LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings()
->StartFileLogs();
+1 -1
View File
@@ -21,7 +21,7 @@ SET(tests_headers
ADD_EXECUTABLE(tests ${tests_sources} ${tests_headers})
TARGET_LINK_LIBRARIES(tests common cppunit fmt)
TARGET_LINK_LIBRARIES(tests common cppunit fmt ${SERVER_LIBS})
INSTALL(TARGETS tests RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
+14 -6
View File
@@ -20,6 +20,8 @@
#include <iostream>
#include <fstream>
#include <memory>
#include "../common/platform.h"
#include "../common/path_manager.h"
#include "memory_mapped_file_test.h"
#include "ipc_mutex_test.h"
#include "fixed_memory_test.h"
@@ -30,17 +32,23 @@
#include "data_verification_test.h"
#include "skills_util_test.h"
#include "task_state_test.h"
#include "../common/eqemu_config.h"
const EQEmuConfig *Config;
EQEmuLogSys LogSys;
PathManager path;
int main()
{
RegisterExecutablePlatform(ExePlatformClientImport);
LogSys.LoadLogSettingsDefaults();
path.LoadPaths();
int main() {
auto ConfigLoadResult = EQEmuConfig::LoadConfig();
Config = EQEmuConfig::get();
Config = EQEmuConfig::get();
try {
std::ofstream outfile("test_output.txt");
std::ofstream outfile("test_output.txt");
std::unique_ptr<Test::Output> output(new Test::TextOutput(Test::TextOutput::Verbose, outfile));
Test::Suite tests;
Test::Suite tests;
tests.add(new MemoryMappedFileTest());
tests.add(new IPCMutexTest());
tests.add(new FixedMemoryHashTest());
@@ -52,7 +60,7 @@ int main() {
tests.add(new SkillsUtilsTest());
tests.add(new TaskStateTest());
tests.run(*output, true);
} catch(...) {
} catch (...) {
return -1;
}
return 0;
+14 -2
View File
@@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "clientlist.h"
#include "database.h"
#include "chatchannel.h"
#include "../common/path_manager.h"
#include <list>
#include <vector>
@@ -478,8 +479,11 @@ Clientlist::Clientlist(int ChatPort) {
const ucsconfig *Config = ucsconfig::get();
LogInfo("Loading [{}]", Config->MailOpCodesFile.c_str());
if (!ChatOpMgr->LoadOpcodes(Config->MailOpCodesFile.c_str()))
std::string opcodes_file = fmt::format("{}/{}", path.GetServerPath(), Config->MailOpCodesFile);
LogInfo("Loading [{}]", opcodes_file);
if (!ChatOpMgr->LoadOpcodes(opcodes_file.c_str()))
exit(1);
chatsf->OnNewConnection([this](std::shared_ptr<EQ::Net::EQStream> stream) {
@@ -615,6 +619,14 @@ void Clientlist::Process()
while (KeyValid && !(*it)->GetForceDisconnect() && (app = (*it)->ClientStream->PopPacket())) {
EmuOpcode opcode = app->GetOpcode();
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
(*it)->ClientStream->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
switch (opcode) {
case OP_MailLogin: {
char *PacketBuffer = (char *)app->pBuffer + 1;
+5
View File
@@ -38,6 +38,7 @@
#include "../common/net/tcp_server.h"
#include "../common/net/servertalk_client_connection.h"
#include "../common/discord_manager.h"
#include "../common/path_manager.h"
ChatChannelList *ChannelList;
Clientlist *g_Clientlist;
@@ -45,6 +46,7 @@ EQEmuLogSys LogSys;
Database database;
WorldServer *worldserver = nullptr;
DiscordManager discord_manager;
PathManager path;
const ucsconfig *Config;
@@ -101,6 +103,8 @@ int main() {
LogSys.LoadLogSettingsDefaults();
set_exception_handler();
path.LoadPaths();
// Check every minute for unused channels we can delete
//
Timer ChannelListProcessTimer(60000);
@@ -132,6 +136,7 @@ int main() {
}
LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings()
->StartFileLogs();
+2 -2
View File
@@ -40,13 +40,13 @@ public:
}
// Load the config
static bool LoadConfig() {
static bool LoadConfig(const std::string& path = "") {
if (_chat_config != nullptr)
delete _chat_config;
_chat_config=new ucsconfig;
_config=_chat_config;
return _config->parseFile();
return _config->parseFile(path);
}
};
+4
View File
@@ -74,6 +74,10 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
{
break;
}
case ServerOP_ReloadLogs: {
LogSys.LoadLogDatabaseSettings();
break;
}
case ServerOP_DiscordWebhookMessage: {
auto *q = (DiscordWebhookMessage_Struct *) p.Data();
+7 -17
View File
@@ -50,6 +50,11 @@ if ($Config{osname} =~ /Win|MS/i) {
$OS = "Windows";
}
if (-e "../eqemu_config.json") {
print "[Info] Config is up one level, let's set current directory up one level...\n";
chdir("../");
}
#############################################
# internet check
#############################################
@@ -83,6 +88,8 @@ if (-d "bin") {
$bin_dir = "bin/";
}
my $world_path = get_world_path();
#############################################
# run routines
#############################################
@@ -540,14 +547,6 @@ sub do_installer_routines
print `"$path" --host $host --user $root_user --password="$root_password" -N -B -e "FLUSH PRIVILEGES"`;
}
my $world_path = "world";
if (-e "bin/world") {
$world_path = "bin/world";
}
elsif (-e "bin/world.exe") {
$world_path = "bin/world.exe";
}
#::: Get Binary DB version
if ($OS eq "Windows") {
@db_version = split(': ', `"$world_path" db_version`);
@@ -592,15 +591,6 @@ sub check_for_input
sub check_for_world_bootup_database_update
{
my $world_path = "world";
if (-e "bin/world") {
$world_path = "bin/world";
}
elsif (-e "bin/world.exe") {
$world_path = "bin/world.exe";
}
$binary_database_version = 0;
$local_database_version = 0;
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
my $filename = './common/eqemu_logsys.h';
open(my $fh, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";
my $contents = "";
while (my $row = <$fh>) {
chomp $row;
$contents .= $row . "\n";
}
my @enum = split('enum LogCategory \{', $contents);
if (scalar(@enum) > 0) {
# print $enum[1];
my @second_split = split('};', $enum[1]);
if (scalar(@second_split) > 0) {
my $categories = $second_split[0];
$categories =~ s/^\s+//;
$categories =~ s/\s+$//;
$categories =~ s/ //g;
$categories =~ s/ //g;
$categories =~ s/\n//g;
$categories =~ s/None=0,//g;
$categories =~ s/,MaxCategoryID//g;
$categories =~ s/\/\*//g;
$categories =~ s/\*\///g;
$categories =~ s/Don'tRemovethis//g;
my @cats = split(',', $categories);
foreach my $cat (@cats) {
print "#define Log" . $cat . "(message, ...) do {\\
if (LogSys.IsLogEnabled(Logs::General, Logs::" . $cat . "))\\
OutF(LogSys, Logs::General, Logs::" . $cat . ", __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\\
} while (0)
#define Log" . $cat . "Detail(message, ...) do {\\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::" . $cat . "))\\
OutF(LogSys, Logs::Detail, Logs::" . $cat . ", __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\\
} while (0)
";
# print "$cat\n";
}
}
}
close $fh;
-241
View File
@@ -1,241 +0,0 @@
#!/usr/bin/perl
# Author: Akkadius
# @file: lua-doc-parser.pl
# @description: Script meant to parse the source code to build the LUA API list
use File::Find;
use Data::Dumper;
sub usage() {
print "Usage:\n";
print " --client - Prints methods for just client class methods\n";
print " --mob - Prints methods for just mob class methods\n";
print " --npc - Prints methods for just npc class methods\n";
print " --entity - Prints methods for just entity class methods\n";
print " --entity_list - Prints methods for just entity_list class methods\n";
print " --door - Prints methods for just door class methods\n";
print " --object - Prints methods for just object class methods\n";
print " --group - Prints methods for just group class methods\n";
print " --raid - Prints methods for just raid class methods\n";
print " --item - Prints methods for just item class methods\n";
print " --iteminst - Prints methods for just iteminst class methods\n";
print " --inventory - Prints methods for just inventory class methods\n";
print " --corpse - Prints methods for just corpse class methods\n";
print " --hate_entry - Prints methods for just hate_entry class methods\n";
print " --quest - Prints methods for just quest class methods\n";
print " --spell - Prints methods for just spell class methods\n";
print " --spawn - Prints methods for just spawn class methods\n";
print " --packet - Prints methods for just packet class methods\n";
print " --stat_bonuses - Prints methods for just stat_bonuses class methods\n";
print " --all - Prints methods for all classes\n";
exit(1);
}
if($#ARGV < 0) {
usage();
}
#::: Open File
my $filename = 'lua-api.md';
open(my $fh, '>', $filename) or die "Could not open file '$filename' $!";
my $export = $ARGV[0];
$export=~s/--//g;
my $export_file_search = $export;
if ($export eq "quest") {
$export_file_search = "lua_general";
}
my @files;
my $start_dir = "zone/";
find(
sub { push @files, $File::Find::name unless -d; },
$start_dir
);
for my $file (@files) {
#::: Skip non lua.cpp files
if($file!~/lua_/i || $file!~/cpp/i){
next;
}
#::: If we are specifying a specific class type, skip everything else
if ($export ne "all" && $export ne "") {
if ($file!~/$export_file_search\.cpp/i) {
next;
}
}
@methods = ();
$split_key = "";
$object_prefix = "";
#::: Client Export
if ($export=~/all|client/i && $file=~/_client/i) {
$split_key = "Client::";
$object_prefix = "client:";
}
#::: Mob Export
if ($export=~/all|mob/i && $file=~/_mob/i) {
$split_key = "Mob::";
$object_prefix = "mob:";
}
#::: NPC Export
if ($export=~/all|npc/i && $file=~/_npc/i) {
$split_key = "NPC::";
$object_prefix = "npc:";
}
#::: Object Export
if ($export=~/all|object/i && $file=~/_object/i) {
$split_key = "Object::";
$object_prefix = "object:";
}
#::: Door Export
if ($export=~/all|door/i && $file=~/_door/i) {
$split_key = "Door::";
$object_prefix = "door:";
}
#::: Entity Export
if ($export=~/all|entity/i && $file=~/_entity/i) {
$split_key = "Entity::";
$object_prefix = "entity:";
}
#::: Entity List Export
if ($export=~/all|entity_list/i && $file=~/_entity_list/i) {
$split_key = "EntityList::";
$object_prefix = "entity_list:";
}
#::: Group
if ($export=~/all|group/i && $file=~/_group/i) {
$split_key = "Group::";
$object_prefix = "group:";
}
#::: Raid
if ($export=~/all|raid/i && $file=~/_raid/i) {
$split_key = "Raid::";
$object_prefix = "raid:";
}
#::: Corpse
if ($export=~/all|corpse/i && $file=~/_corpse/i) {
$split_key = "Corpse::";
$object_prefix = "corpse:";
}
#::: Hateentry
if ($export=~/all|hate_entry/i && $file=~/_hate_entry/i) {
$split_key = "HateEntry::";
$object_prefix = "hate_entry:";
}
#::: Spell
if ($export=~/all|spell/i && $file=~/_spell/i) {
$split_key = "Spell::";
$object_prefix = "spell:";
}
#::: Spawn
if ($export=~/all|spawn/i && $file=~/_spawn/i) {
$split_key = "Spawn::";
$object_prefix = "spawn:";
}
#::: StatBonuses
if ($export=~/all|stat_bonuses/i && $file=~/stat_bonuses/i) {
$split_key = "StatBonuses::";
$object_prefix = "statbonuses:";
}
#::: Item
if ($export=~/all|item/i && $file=~/_item/i) {
$split_key = "Item::";
$object_prefix = "item:";
}
#::: ItemInst
if ($export=~/all|iteminst/i && $file=~/_iteminst/i) {
$split_key = "ItemInst::";
$object_prefix = "iteminst:";
}
#::: Inventory
if ($export=~/all|inventory/i && $file=~/_inventory/i) {
$split_key = "Inventory::";
$object_prefix = "inventory:";
}
#::: Packet
if ($export=~/all|packet/i && $file=~/_packet/i) {
$split_key = "Packet::";
$object_prefix = "packet:";
}
#::: Quest
if ($export=~/all|quest/i && $file=~/lua_general/i) {
$split_key = " lua_";
$object_prefix = "eq.";
}
#::: Open File
print "\nOpening '" . $file . "'\n";
if ($split_key eq "") {
next;
}
open (FILE, $file);
while (<FILE>) {
chomp;
$line = $_;
@data = split(" ", $line);
if ((lc(substr($data[1], 0, 4)) eq "lua_") && $line!~/luabind/i && $line!~/return |#ifdef|struct /i) {
#::: Get return type
$return_type = trim($data[0]);
@method_split = split($split_key, $line);
@method_end = split("{", $method_split[1]);
$method = $object_prefix . trim($method_end[0]) . "; -- " . $return_type . "\n";
push @methods, $method;
}
}
#::: Header
$header = $split_key;
$header =~s/:://g;
print $fh "# " . $header . "\n";
print $fh "```lua\n";
@methods = sort @methods;
foreach $method (@methods) {
print $fh $method;
print $method;
}
print $fh "```\n\n";
}
close $fh;
#::: Trim Whitespaces
sub trim {
my $string = $_[0];
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
-179
View File
@@ -1,179 +0,0 @@
#!/usr/bin/perl
# Author: Akkadius
# @file: perl-doc-parser.pl
# @description: Script meant to parse the source code to build the Perl API list
use File::Find;
use Data::Dumper;
sub usage() {
print "Usage:\n";
print " --client - Prints methods for just client class methods\n";
print " --mob - Prints methods for just mob class methods\n";
print " --npc - Prints methods for just npc class methods\n";
print " --entity - Prints methods for just entity class methods\n";
print " --door - Prints methods for just door class methods\n";
print " --object - Prints methods for just object class methods\n";
print " --group - Prints methods for just group class methods\n";
print " --raid - Prints methods for just raid class methods\n";
print " --questitem - Prints methods for just questitem class methods\n";
print " --corpse - Prints methods for just corpse class methods\n";
print " --hateentry - Prints methods for just hateentry class methods\n";
print " --quest - Prints methods for just quest class methods\n";
print " --all - Prints methods for all classes\n";
exit(1);
}
if($#ARGV < 0) {
usage();
}
my $export = $ARGV[0];
$export=~s/--//g;
my $export_file_search = $export;
if ($export eq "quest") {
$export_file_search = "embparser_api";
}
my @files;
my $start_dir = "zone/";
find(
sub { push @files, $File::Find::name unless -d; },
$start_dir
);
for my $file (@files) {
#::: Skip non Perl files
if($file!~/perl_|embparser_api/i){
next;
}
#::: If we are specifying a specific class type, skip everything else
if ($export ne "all" && $export ne "") {
if ($file!~/$export_file_search/i) {
next;
}
}
@methods = ();
$split_key = "";
$object_prefix = "";
#::: Open File
print "\nOpening '" . $file . "'\n";
open (FILE, $file);
while (<FILE>) {
chomp;
$line = $_;
if ($line=~/Perl_croak/i && $line=~/Usa/i && $line=~/::/i && $line!~/::new/i) {
#::: Client export
if ($export=~/all|client/i && $line=~/Client::/i) {
$split_key = "Client::";
$object_prefix = "\$client->";
}
#::: Mob export
if ($export=~/all|mob/i && $line=~/Mob::/i) {
$split_key = "Mob::";
$object_prefix = "\$mob->";
}
#::: NPC export
if ($export=~/all|npc/i && $line=~/NPC::/i) {
$split_key = "NPC::";
$object_prefix = "\$npc->";
}
#::: Corpse export
if ($export=~/all|corpse/i && $line=~/Corpse::/i) {
$split_key = "Corpse::";
$object_prefix = "\$corpse->";
}
#::: Entity export
if ($export=~/all|entity/i && $line=~/EntityList::/i) {
$split_key = "EntityList::";
$object_prefix = "\$entity_list->";
}
#::: Doors export
if ($export=~/all|door/i && $line=~/Doors::/i) {
$split_key = "Doors::";
$object_prefix = "\$door->";
}
#::: Object export
if ($export=~/all|object/i && $line=~/Object::/i) {
$split_key = "Object::";
$object_prefix = "\$object->";
}
#::: Group export
if ($export=~/all|group/i && $line=~/Group::/i) {
$split_key = "Group::";
$object_prefix = "\$group->";
}
#::: Raid export
if ($export=~/all|raid/i && $line=~/Raid::/i) {
$split_key = "Raid::";
$object_prefix = "\$raid->";
}
#::: Hateentry export
if ($export=~/all|hateentry/i && $line=~/HateEntry::/i) {
$split_key = "HateEntry::";
$object_prefix = "\$hate_entry->";
}
#::: Questitem export
if ($export=~/all|questitem/i && $line=~/QuestItem::/i) {
$split_key = "QuestItem::";
$object_prefix = "\$quest_item->";
}
#::: Quest:: exports
if ($export=~/all|quest/i && $line=~/quest::/i) {
$split_key = "quest::";
$object_prefix = "\quest::";
}
#::: Split on croak usage
@data = split($split_key, $line);
$usage = trim($data[1]);
#::: Split out param borders and get method name
@params_begin = split('\(', $usage);
$method_name = trim($params_begin[0]);
#::: Get params string built
@params_end = split('\)', $params_begin[1]);
$params_string = trim($params_end[0]);
$params_string =~s/THIS\,//g;
$params_string =~s/THIS//g;
$params_string = trim($params_string);
$method = $object_prefix . $method_name . "(" . lc($params_string) . ")\n";
push @methods, $method;
}
}
@methods = sort @methods;
foreach $method (@methods) {
print $method;
}
}
#::: Trim Whitespaces
sub trim {
my $string = $_[0];
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
+4
View File
@@ -462,6 +462,10 @@
9206|2022_09_03_fix_door_destination_headings.sql|SELECT * FROM db_version WHERE version >= 9206|empty|
9207|2022_09_03_fix_zone_point_heading_data.sql|SELECT * FROM db_version WHERE version >= 9207|empty|
9208|2022_09_25_task_concat_matchlists.sql|SHOW COLUMNS FROM `task_activities` LIKE 'npc_id'|not_empty|
9209|2022_09_28_discord_webhooks.sql|SHOW COLUMNS FROM `logsys_categories` LIKE 'log_to_discord'|empty|
9210|2022_10_11_fix_misty_pok_stone.sql|select * from doors where id = 2040 and `name` = 'POKRVPORT500' and client_version_mask = 4294967232|empty|
9211|2022_10_14_fix_neriak_pok_stone.sql|select * from doors where id = 2057 and `name` = 'POKNRKPORT500' and client_version_mask = 4294967232|empty|
9212|2022_10_14_fix_misty_pok_stone.sql|select * from doors where id = 2040 and `name` = 'POKRVPORT500' and dest_zone = 'misty'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not
@@ -1,4 +1,5 @@
SET SESSION group_concat_max_len = 1048576;
SET collation_connection = latin1_swedish_ci;
-- backup original(s)
CREATE TABLE `goallists_backup_9_25_2022` LIKE `goallists`;
@@ -0,0 +1,4 @@
ALTER TABLE logsys_categories
ADD log_to_discord smallint(11) default 0 AFTER log_to_gmsay;
ALTER TABLE logsys_categories
ADD discord_webhook_id int(11) default 0 AFTER log_to_discord;
@@ -0,0 +1,2 @@
REPLACE INTO `doors` (`id`, `doorid`, `zone`, `version`, `name`, `pos_y`, `pos_x`, `pos_z`, `heading`, `opentype`, `guild`, `lockpick`, `keyitem`, `nokeyring`, `triggerdoor`, `triggertype`, `disable_timer`, `doorisopen`, `door_param`, `dest_zone`, `dest_instance`, `dest_x`, `dest_y`, `dest_z`, `dest_heading`, `invert_state`, `incline`, `size`, `buffer`, `client_version_mask`, `is_ldon_door`, `dz_switch_id`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (2040, 37, 'PoKnowledge', 0, 'POKRVPORT500', 908.668, 1228.06, -156.248, 384, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'mistythicket', 0, -209, -324, 8, 253, 0, 0, 100, -559.555, 4294967232, 0, 0, -1, -1, NULL, NULL);
REPLACE INTO `doors` (`id`, `doorid`, `zone`, `version`, `name`, `pos_y`, `pos_x`, `pos_z`, `heading`, `opentype`, `guild`, `lockpick`, `keyitem`, `nokeyring`, `triggerdoor`, `triggertype`, `disable_timer`, `doorisopen`, `door_param`, `dest_zone`, `dest_instance`, `dest_x`, `dest_y`, `dest_z`, `dest_heading`, `invert_state`, `incline`, `size`, `buffer`, `client_version_mask`, `is_ldon_door`, `dz_switch_id`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (36669, 158, 'PoKnowledge', 0, 'POKRVPORT500', 908.668, 1228.06, -156.248, 384, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'misty', 0, -1262.71, -546, 8, 2, 0, 0, 100, -559.555, 63, 0, 0, -1, -1, NULL, NULL);
@@ -0,0 +1 @@
REPLACE INTO `doors` (`id`, `doorid`, `zone`, `version`, `name`, `pos_y`, `pos_x`, `pos_z`, `heading`, `opentype`, `guild`, `lockpick`, `keyitem`, `nokeyring`, `triggerdoor`, `triggertype`, `disable_timer`, `doorisopen`, `door_param`, `dest_zone`, `dest_instance`, `dest_x`, `dest_y`, `dest_z`, `dest_heading`, `invert_state`, `incline`, `size`, `buffer`, `client_version_mask`, `is_ldon_door`, `dz_switch_id`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (2040, 37, 'PoKnowledge', 0, 'POKRVPORT500', 908.668, 1228.06, -156.248, 384, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'misty', 0, -1262.71, -546, 8, 2, 0, 0, 100, -559.555, 4294967232, 0, 0, -1, -1, NULL, NULL);
@@ -0,0 +1,2 @@
REPLACE INTO `doors` (`id`, `doorid`, `zone`, `version`, `name`, `pos_y`, `pos_x`, `pos_z`, `heading`, `opentype`, `guild`, `lockpick`, `keyitem`, `nokeyring`, `triggerdoor`, `triggertype`, `disable_timer`, `doorisopen`, `door_param`, `dest_zone`, `dest_instance`, `dest_x`, `dest_y`, `dest_z`, `dest_heading`, `invert_state`, `incline`, `size`, `buffer`, `client_version_mask`, `is_ldon_door`, `dz_switch_id`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (2057, 20, 'PoKnowledge', 0, 'POKNRKPORT500', -909.187, 131.793, -156.148, 256, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'nektulos', 1, -840, -809, 9, 999, 0, 0, 100, 733.98, 4294967232, 0, 0, -1, -1, NULL, NULL);
REPLACE INTO `doors` (`id`, `doorid`, `zone`, `version`, `name`, `pos_y`, `pos_x`, `pos_z`, `heading`, `opentype`, `guild`, `lockpick`, `keyitem`, `nokeyring`, `triggerdoor`, `triggertype`, `disable_timer`, `doorisopen`, `door_param`, `dest_zone`, `dest_instance`, `dest_x`, `dest_y`, `dest_z`, `dest_heading`, `invert_state`, `incline`, `size`, `buffer`, `client_version_mask`, `is_ldon_door`, `dz_switch_id`, `min_expansion`, `max_expansion`, `content_flags`, `content_flags_disabled`) VALUES (17151, 157, 'PoKnowledge', 0, 'POKNRKPORT500', -909.187, 131.793, -156.148, 256, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'nektulos', 0, -840, -809, 9, 999, 0, 0, 100, 733.98, 3, 0, 0, -1, -1, NULL, NULL);
+70 -70
View File
@@ -1,78 +1,78 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
SET(world_sources
adventure.cpp
adventure_manager.cpp
client.cpp
cliententry.cpp
clientlist.cpp
console.cpp
dynamic_zone.cpp
dynamic_zone_manager.cpp
eql_config.cpp
eqemu_api_world_data_service.cpp
expedition_database.cpp
expedition_message.cpp
launcher_link.cpp
launcher_list.cpp
lfplist.cpp
login_server.cpp
login_server_list.cpp
main.cpp
queryserv.cpp
shared_task_manager.cpp
shared_task_world_messaging.cpp
ucs.cpp
web_interface.cpp
web_interface_eqw.cpp
wguild_mgr.cpp
world_event_scheduler.cpp
world_config.cpp
world_console_connection.cpp
world_server_command_handler.cpp
worlddb.cpp
world_boot.cpp
zonelist.cpp
zoneserver.cpp
)
adventure.cpp
adventure_manager.cpp
client.cpp
cliententry.cpp
clientlist.cpp
console.cpp
dynamic_zone.cpp
dynamic_zone_manager.cpp
eql_config.cpp
eqemu_api_world_data_service.cpp
expedition_database.cpp
expedition_message.cpp
launcher_link.cpp
launcher_list.cpp
lfplist.cpp
login_server.cpp
login_server_list.cpp
main.cpp
queryserv.cpp
shared_task_manager.cpp
shared_task_world_messaging.cpp
ucs.cpp
web_interface.cpp
web_interface_eqw.cpp
wguild_mgr.cpp
world_event_scheduler.cpp
world_config.cpp
world_console_connection.cpp
world_server_cli.cpp
worlddb.cpp
world_boot.cpp
zonelist.cpp
zoneserver.cpp
)
SET(world_headers
adventure.h
adventure_manager.h
adventure_template.h
client.h
cliententry.h
clientlist.h
console.h
dynamic_zone.h
dynamic_zone_manager.h
eql_config.h
eqemu_api_world_data_service.h
expedition_database.h
expedition_message.h
launcher_link.h
launcher_list.h
lfplist.h
login_server.h
login_server_list.h
queryserv.h
shared_task_manager.h
shared_task_world_messaging.h
sof_char_create_data.h
ucs.h
web_interface.h
web_interface_eqw.h
wguild_mgr.h
world_config.h
world_console_connection.h
world_tcp_connection.h
world_server_command_handler.h
worlddb.h
world_boot.h
world_event_scheduler.h
zonelist.h
zoneserver.h
)
adventure.h
adventure_manager.h
adventure_template.h
client.h
cliententry.h
clientlist.h
console.h
dynamic_zone.h
dynamic_zone_manager.h
eql_config.h
eqemu_api_world_data_service.h
expedition_database.h
expedition_message.h
launcher_link.h
launcher_list.h
lfplist.h
login_server.h
login_server_list.h
queryserv.h
shared_task_manager.h
shared_task_world_messaging.h
sof_char_create_data.h
ucs.h
web_interface.h
web_interface_eqw.h
wguild_mgr.h
world_config.h
world_console_connection.h
world_tcp_connection.h
world_server_cli.h
worlddb.h
world_boot.h
world_event_scheduler.h
zonelist.h
zoneserver.h
)
ADD_EXECUTABLE(world ${world_sources} ${world_headers})
+37
View File
@@ -0,0 +1,37 @@
#include "../../common/eqemu_logsys_log_aliases.h"
#include "../worlddb.h"
void WorldserverCLI::CopyCharacter(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Copies a character into a destination account";
std::vector<std::string> arguments = {
"source_character_name",
"destination_character_name",
"destination_account_name"
};
std::vector<std::string> options = {};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
std::string source_character_name = cmd(2).str();
std::string destination_character_name = cmd(3).str();
std::string destination_account_name = cmd(4).str();
LogInfo(
"Attempting to copy character [{}] to [{}] via account [{}]",
source_character_name,
destination_character_name,
destination_account_name
);
database.CopyCharacter(
source_character_name,
destination_character_name,
destination_account_name
);
}
+60
View File
@@ -0,0 +1,60 @@
#include "../../common/database/database_dump_service.h"
void WorldserverCLI::DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Dumps server database tables";
std::vector<std::string> arguments = {};
std::vector<std::string> options = {
"--all",
"--content-tables",
"--login-tables",
"--player-tables",
"--bot-tables",
"--state-tables",
"--system-tables",
"--query-serv-tables",
"--table-structure-only",
"--table-lock",
"--dump-path=",
"--dump-output-to-console",
"--drop-table-syntax-only",
"--compress"
};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
auto s = new DatabaseDumpService();
bool dump_all = cmd[{"-a", "--all"}];
if (!cmd("--dump-path").str().empty()) {
s->SetDumpPath(cmd("--dump-path").str());
}
/**
* Set Option
*/
s->SetDumpContentTables(cmd[{"--content-tables"}] || dump_all);
s->SetDumpLoginServerTables(cmd[{"--login-tables"}] || dump_all);
s->SetDumpPlayerTables(cmd[{"--player-tables"}] || dump_all);
s->SetDumpBotTables(cmd[{"--bot-tables"}] || dump_all);
s->SetDumpStateTables(cmd[{"--state-tables"}] || dump_all);
s->SetDumpSystemTables(cmd[{"--system-tables"}] || dump_all);
s->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}] || dump_all);
s->SetDumpAllTables(dump_all);
s->SetDumpWithNoData(cmd[{"--table-structure-only"}]);
s->SetDumpTableLock(cmd[{"--table-lock"}]);
s->SetDumpWithCompression(cmd[{"--compress"}]);
s->SetDumpOutputToConsole(cmd[{"--dump-output-to-console"}]);
s->SetDumpDropTableSyntaxOnly(cmd[{"--drop-table-syntax-only"}]);
/**
* Dump
*/
s->Dump();
}
+68
View File
@@ -0,0 +1,68 @@
#include "../../common/database_schema.h"
#include "../../common/json/json.h"
void WorldserverCLI::DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Displays server database schema";
if (cmd[{"-h", "--help"}]) {
return;
}
Json::Value player_tables_json;
std::vector<std::string> player_tables = DatabaseSchema::GetPlayerTables();
for (const auto &table: player_tables) {
player_tables_json.append(table);
}
Json::Value content_tables_json;
std::vector<std::string> content_tables = DatabaseSchema::GetContentTables();
for (const auto &table: content_tables) {
content_tables_json.append(table);
}
Json::Value server_tables_json;
std::vector<std::string> server_tables = DatabaseSchema::GetServerTables();
for (const auto &table: server_tables) {
server_tables_json.append(table);
}
Json::Value login_tables_json;
std::vector<std::string> login_tables = DatabaseSchema::GetLoginTables();
for (const auto &table: login_tables) {
login_tables_json.append(table);
}
Json::Value state_tables_json;
std::vector<std::string> state_tables = DatabaseSchema::GetStateTables();
for (const auto &table: state_tables) {
state_tables_json.append(table);
}
Json::Value version_tables_json;
std::vector<std::string> version_tables = DatabaseSchema::GetVersionTables();
for (const auto &table: version_tables) {
version_tables_json.append(table);
}
Json::Value bot_tables_json;
std::vector<std::string> bot_tables = DatabaseSchema::GetBotTables();
for (const auto &table: bot_tables) {
bot_tables_json.append(table);
}
Json::Value schema;
schema["content_tables"] = content_tables_json;
schema["login_tables"] = login_tables_json;
schema["player_tables"] = player_tables_json;
schema["server_tables"] = server_tables_json;
schema["state_tables"] = state_tables_json;
schema["version_tables"] = version_tables_json;
schema["bot_tables"] = bot_tables_json;
std::stringstream payload;
payload << schema;
std::cout << payload.str() << std::endl;
}
+24
View File
@@ -0,0 +1,24 @@
#include "../worlddb.h"
void WorldserverCLI::DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Sets account status by account name";
std::vector<std::string> arguments = {
"{name}",
"{status}"
};
std::vector<std::string> options = {};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
database.SetAccountStatus(
cmd(2).str(),
std::stoi(cmd(3).str())
);
}
+21
View File
@@ -0,0 +1,21 @@
#include "../../common/version.h"
#include "../../common/json/json.h"
void WorldserverCLI::DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Shows database version";
if (cmd[{"-h", "--help"}]) {
return;
}
Json::Value database_version;
database_version["database_version"] = CURRENT_BINARY_DATABASE_VERSION;
database_version["bots_database_version"] = CURRENT_BINARY_BOTS_DATABASE_VERSION;
std::stringstream payload;
payload << database_version;
std::cout << payload.str() << std::endl;
}
+21
View File
@@ -0,0 +1,21 @@
#include "../../common/zone_store.h"
void WorldserverCLI::TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Test command";
if (cmd[{"-h", "--help"}]) {
return;
}
zone_store.LoadZones(database);
const char* zonename = ZoneName(0);
if (zonename == 0) {
LogInfo("Zone name is 0");
}
if (zonename == nullptr) {
LogInfo("Zone name is nullptr");
}
}
+44
View File
@@ -0,0 +1,44 @@
#include "../../common/rulesys.h"
#include "../../common/repositories/content_flags_repository.h"
#include "../../common/content/world_content_service.h"
#include "../../common/repositories/criteria/content_filter_criteria.h"
#include "../worlddb.h"
void WorldserverCLI::ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Expansion test command";
if (cmd[{"-h", "--help"}]) {
return;
}
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
LogInfo("No rule set configured, using default rules");
}
content_service.SetCurrentExpansion(RuleI(Expansion, CurrentExpansion));
std::vector<ContentFlagsRepository::ContentFlags> flags = {};
auto f = ContentFlagsRepository::NewEntity();
f.enabled = 1;
std::vector<std::string> flag_names = {
"hateplane_enabled",
"patch_nerf_7077",
};
for (auto &name: flag_names) {
f.flag_name = name;
flags.push_back(f);
}
content_service.SetContentFlags(flags);
LogInfo(
"Current expansion is [{}] ({}) is Velious Enabled [{}] Criteria [{}]",
content_service.GetCurrentExpansion(),
content_service.GetCurrentExpansionName(),
content_service.IsTheScarsOfVeliousEnabled() ? "true" : "false",
ContentFilterCriteria::apply()
);
}
+100
View File
@@ -0,0 +1,100 @@
#include "../../common/repositories/instance_list_repository.h"
#include "../worlddb.h"
void WorldserverCLI::TestRepository(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Test command";
if (cmd[{"-h", "--help"}]) {
return;
}
/**
* Insert one
*/
auto e = InstanceListRepository::NewEntity();
e.zone = 999;
e.version = 1;
e.is_global = 1;
e.start_time = 0;
e.duration = 0;
e.never_expires = 1;
auto inserted = InstanceListRepository::InsertOne(database, e);
LogInfo("Inserted ID is [{}] zone [{}]", inserted.id, inserted.zone);
/**
* Find one
*/
auto f = InstanceListRepository::FindOne(database, inserted.id);
LogInfo("Found ID is [{}] zone [{}]", f.id, f.zone);
/**
* Update one
*/
LogInfo("Updating instance id [{}] zone [{}]", f.id, f.zone);
int update_instance_list_count = InstanceListRepository::UpdateOne(database, f);
f.zone = 777;
LogInfo(
"Updated instance id [{}] zone [{}] affected [{}]",
f.id,
f.zone,
update_instance_list_count
);
/**
* Delete one
*/
int deleted = InstanceListRepository::DeleteOne(database, f.id);
LogInfo("Deleting one instance [{}] deleted count [{}]", f.id, deleted);
/**
* Insert many
*/
std::vector<InstanceListRepository::InstanceList> instance_lists;
auto b = InstanceListRepository::NewEntity();
b.zone = 999;
b.version = 1;
b.is_global = 1;
b.start_time = 0;
b.duration = 0;
b.never_expires = 1;
for (int i = 0; i < 10; i++) {
instance_lists.push_back(b);
}
/**
* Insert Many
*/
int inserted_count = InstanceListRepository::InsertMany(database, instance_lists);
LogInfo("Bulk insertion test, inserted [{}]", inserted_count);
for (auto &entry: InstanceListRepository::GetWhere(database, fmt::format("zone = {}", 999))) {
LogInfo("Iterating through entry id [{}] zone [{}]", entry.id, entry.zone);
}
LogInfo("[Max ID] {}", InstanceListRepository::GetMaxId(database));
LogInfo("[Count] {}", InstanceListRepository::Count(database));
LogInfo("[Count Where] {}", InstanceListRepository::Count(database, "zone = 999"));
LogInfo("[Count Where] {}", InstanceListRepository::Count(database, "zone = 777"));
/**
* Delete where
*/
int deleted_count = InstanceListRepository::DeleteWhere(database, fmt::format("zone = {}", 999));
LogInfo("Bulk deletion test, deleted [{}]", deleted_count);
}
+21
View File
@@ -0,0 +1,21 @@
#include "../../common/repositories/zone_repository.h"
void WorldserverCLI::TestRepository2(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Test command";
if (cmd[{"-h", "--help"}]) {
return;
}
auto zones = ZoneRepository::GetWhere(content_db, "short_name = 'anguish'");
for (auto &zone: zones) {
LogInfo(
"Zone [{}] long_name [{}] id [{}]",
zone.short_name,
zone.long_name,
zone.id
);
}
}
+24
View File
@@ -0,0 +1,24 @@
#include "../../common/json/json.h"
#include "../../common/version.h"
void WorldserverCLI::Version(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Shows server version";
if (cmd[{"-h", "--help"}]) {
return;
}
Json::Value j;
j["bots_database_version"] = CURRENT_BINARY_BOTS_DATABASE_VERSION;
j["compile_date"] = COMPILE_DATE;
j["compile_time"] = COMPILE_TIME;
j["database_version"] = CURRENT_BINARY_DATABASE_VERSION;
j["server_version"] = CURRENT_VERSION;
std::stringstream payload;
payload << j;
std::cout << payload.str() << std::endl;
}
+8 -1
View File
@@ -35,6 +35,7 @@
#include "../common/emu_versions.h"
#include "../common/random.h"
#include "../common/shareddb.h"
#include "../common/opcodemgr.h"
#include "client.h"
#include "worlddb.h"
@@ -1009,7 +1010,13 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
EmuOpcode opcode = app->GetOpcode();
LogNetcode("Received EQApplicationPacket [{:#04x}]", opcode);
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
eqs->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
if (!eqs->CheckState(ESTABLISHED)) {
LogInfo("Client disconnected (net inactive on send)");
+1 -1
View File
@@ -686,8 +686,8 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S
int idx=-1;
while(iterator.MoreElements()) {
cle = iterator.GetData();
const char* tmpZone = ZoneName(cle->zone());
if (
(cle->Online() >= CLE_Status::Zoning) &&
(!cle->GetGM() || cle->Anon() != 1 || admin >= cle->Admin()) &&
+1 -2
View File
@@ -490,7 +490,7 @@ bool LoginServer::Connect()
[this](EQ::Net::ServertalkClient *client) {
if (client) {
LogInfo(
"Connected to Loginserver: [{0}:{1}]",
"Connected to Loginserver [{0}:{1}]",
m_loginserver_address,
m_loginserver_port
);
@@ -499,7 +499,6 @@ bool LoginServer::Connect()
zoneserver_list.SendLSZones();
m_statusupdate_timer = std::make_unique<EQ::Timer>(
LoginServer_StatusUpdateInterval, true, [this](EQ::Timer *t) {
SendStatus();
}
+22 -8
View File
@@ -88,13 +88,15 @@ union semun {
#include "dynamic_zone_manager.h"
#include "expedition_database.h"
#include "world_server_command_handler.h"
#include "world_server_cli.h"
#include "../common/content/world_content_service.h"
#include "../common/repositories/character_task_timers_repository.h"
#include "../common/zone_store.h"
#include "world_event_scheduler.h"
#include "shared_task_manager.h"
#include "world_boot.h"
#include "../common/path_manager.h"
ZoneStore zone_store;
ClientList client_list;
@@ -115,6 +117,7 @@ const WorldConfig *Config;
EQEmuLogSys LogSys;
WorldContentService content_service;
WebInterfaceList web_interface;
PathManager path;
void CatchSignal(int sig_num);
@@ -142,6 +145,8 @@ int main(int argc, char **argv)
return 0;
}
path.LoadPaths();
if (!WorldBoot::LoadServerConfig()) {
return 0;
}
@@ -332,8 +337,8 @@ int main(int argc, char **argv)
);
WorldBoot::CheckForPossibleConfigurationIssues();
EQStreamManagerInterfaceOptions opts(9000, false, false);
EQStreamManagerInterfaceOptions opts(Config->WorldUDPPort, false, false);
opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);
@@ -366,8 +371,14 @@ int main(int argc, char **argv)
}
);
while (RunLoops) {
auto loop_fn = [&](EQ::Timer* t) {
Timer::SetCurrentTime();
if (!RunLoops) {
EQ::EventLoop::Get().Shutdown();
return;
}
eqs = nullptr;
//give the stream identifier a chance to do its work....
@@ -376,7 +387,7 @@ int main(int argc, char **argv)
//check the stream identifier for any now-identified streams
while ((eqsi = stream_identifier.PopIdentified())) {
//now that we know what patch they are running, start up their client object
struct in_addr in{};
struct in_addr in {};
in.s_addr = eqsi->GetRemoteIP();
if (RuleB(World, UseBannedIPsTable)) { //Lieka: Check to see if we have the responsibility for blocking IPs.
LogInfo("Checking inbound connection [{}] against BannedIPs table", inet_ntoa(in));
@@ -442,10 +453,13 @@ int main(int argc, char **argv)
);
UpdateWindowTitle(window_title);
}
};
EQ::Timer process_timer(loop_fn);
process_timer.Start(32, true);
EQ::EventLoop::Get().Run();
EQ::EventLoop::Get().Process();
Sleep(5);
}
LogInfo("World main loop completed");
LogInfo("Shutting down zone connections (if any)");
zoneserver_list.KillAll();
+19 -8
View File
@@ -18,19 +18,25 @@
#include "world_boot.h"
#include "world_config.h"
#include "world_event_scheduler.h"
#include "world_server_command_handler.h"
#include "world_server_cli.h"
#include "../common/zone_store.h"
#include "worlddb.h"
#include "zonelist.h"
#include "zoneserver.h"
#include "../common/ip_util.h"
#include "../common/zone_store.h"
#include "../common/path_manager.h"
extern ZSList zoneserver_list;
extern WorldConfig Config;
void WorldBoot::GMSayHookCallBackProcessWorld(uint16 log_category, std::string message)
{
// we don't want to loop up with chat messages
if (message.find("OP_SpecialMesg") != std::string::npos) {
return;
}
// Cut messages down to 4000 max to prevent client crash
if (!message.empty()) {
message = message.substr(0, 4000);
@@ -84,10 +90,11 @@ bool WorldBoot::HandleCommandInput(int argc, char **argv)
// command handler
if (argc > 1) {
LogSys.SilenceConsoleLogging();
path.LoadPaths();
WorldConfig::LoadConfig();
LoadDatabaseConnections();
LogSys.EnableConsoleLogging();
WorldserverCommandHandler::CommandHandler(argc, argv);
WorldserverCLI::CommandHandler(argc, argv);
}
return false;
@@ -164,14 +171,14 @@ int get_file_size(const std::string &filename) // path to file
void WorldBoot::CheckForServerScript(bool force_download)
{
const std::string file = "eqemu_server.pl";
const std::string file = fmt::format("{}/eqemu_server.pl", path.GetServerPath());
std::ifstream f(file);
/* Fetch EQEmu Server script */
if (!f || get_file_size(file) < 100 || force_download) {
if (force_download) {
std::remove("eqemu_server.pl");
std::remove(fmt::format("{}/eqemu_server.pl", path.GetServerPath()).c_str());
} /* Delete local before fetch */
std::cout << "Pulling down EQEmu Server Maintenance Script (eqemu_server.pl)..." << std::endl;
@@ -194,13 +201,15 @@ void WorldBoot::CheckForServerScript(bool force_download)
if (auto res = r.Get(u.get_path().c_str())) {
if (res->status == 200) {
// write file
std::ofstream out("eqemu_server.pl");
std::string script = fmt::format("{}/eqemu_server.pl", path.GetServerPath());
std::ofstream out(script);
out << res->body;
out.close();
#ifdef _WIN32
#else
system("chmod 755 eqemu_server.pl");
system("chmod +x eqemu_server.pl");
system(fmt::format("chmod 755 {}", script).c_str());
system(fmt::format("chmod +x {}", script).c_str());
#endif
}
}
@@ -211,7 +220,8 @@ void WorldBoot::CheckForXMLConfigUpgrade()
{
if (!std::ifstream("eqemu_config.json") && std::ifstream("eqemu_config.xml")) {
CheckForServerScript(true);
if (system("perl eqemu_server.pl convert_xml")) {}
std::string command = fmt::format("perl {}/eqemu_server.pl convert_xml", path.GetServerPath());
if (system(command.c_str())) {}
}
else {
CheckForServerScript();
@@ -286,6 +296,7 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
// logging system init
auto logging = LogSys.SetDatabase(&database)
->SetLogPath(path.GetLogPath())
->LoadLogDatabaseSettings();
if (RuleB(Logging, WorldGMSayLogging)) {
+2 -2
View File
@@ -46,13 +46,13 @@ public:
}
// Load the config
static bool LoadConfig() {
static bool LoadConfig(const std::string& path = "") {
if (_world_config != nullptr)
delete _world_config;
_world_config=new WorldConfig;
_config=_world_config;
return _config->parseFile();
return _config->parseFile(path);
}
// Accessors for the static private object
+45
View File
@@ -0,0 +1,45 @@
#include "world_server_cli.h"
/**
* @param argc
* @param argv
*/
void WorldserverCLI::CommandHandler(int argc, char **argv)
{
if (argc == 1) { return; }
argh::parser cmd;
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
EQEmuCommand::DisplayDebug(cmd);
/**
* Declare command mapping
*/
auto function_map = EQEmuCommand::function_map;
/**
* Register commands
*/
function_map["world:version"] = &WorldserverCLI::Version;
function_map["character:copy-character"] = &WorldserverCLI::CopyCharacter;
function_map["database:version"] = &WorldserverCLI::DatabaseVersion;
function_map["database:set-account-status"] = &WorldserverCLI::DatabaseSetAccountStatus;
function_map["database:schema"] = &WorldserverCLI::DatabaseGetSchema;
function_map["database:dump"] = &WorldserverCLI::DatabaseDump;
function_map["test:test"] = &WorldserverCLI::TestCommand;
function_map["test:expansion"] = &WorldserverCLI::ExpansionTestCommand;
function_map["test:repository"] = &WorldserverCLI::TestRepository;
function_map["test:repository2"] = &WorldserverCLI::TestRepository2;
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
}
#include "cli/copy_character.cpp"
#include "cli/database_dump.cpp"
#include "cli/database_get_schema.cpp"
#include "cli/database_set_account_status.cpp"
#include "cli/database_version.cpp"
#include "cli/test.cpp"
#include "cli/test_expansion.cpp"
#include "cli/test_repository.cpp"
#include "cli/test_repository_2.cpp"
#include "cli/version.cpp"
+23
View File
@@ -0,0 +1,23 @@
#include "iostream"
#include "../common/cli/eqemu_command_handler.h"
#ifndef EQEMU_WORLD_SERVER_COMMAND_HANDLER_H
#define EQEMU_WORLD_SERVER_COMMAND_HANDLER_H
class WorldserverCLI {
public:
static void CommandHandler(int argc, char **argv);
static void Version(int argc, char **argv, argh::parser &cmd, std::string &description);
static void CopyCharacter(int argc, char **argv, argh::parser &cmd, std::string &description);
static void DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description);
static void DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description);
static void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
static void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
static void TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
static void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
static void TestRepository(int argc, char **argv, argh::parser &cmd, std::string &description);
static void TestRepository2(int argc, char **argv, argh::parser &cmd, std::string &description);
};
#endif //EQEMU_WORLD_SERVER_COMMAND_HANDLER_H
-523
View File
@@ -1,523 +0,0 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "world_server_command_handler.h"
#include "../common/eqemu_logsys.h"
#include "../common/discord/discord.h"
#include "../common/json/json.h"
#include "../common/version.h"
#include "worlddb.h"
#include "../common/database_schema.h"
#include "../common/database/database_dump_service.h"
#include "../common/content/world_content_service.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include "../common/rulesys.h"
#include "../common/repositories/instance_list_repository.h"
#include "../common/repositories/zone_repository.h"
#include "../zone/queryserv.h"
namespace WorldserverCommandHandler {
/**
* @param argc
* @param argv
*/
void CommandHandler(int argc, char **argv)
{
if (argc == 1) { return; }
argh::parser cmd;
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
EQEmuCommand::DisplayDebug(cmd);
/**
* Declare command mapping
*/
auto function_map = EQEmuCommand::function_map;
/**
* Register commands
*/
function_map["world:version"] = &WorldserverCommandHandler::Version;
function_map["character:copy-character"] = &WorldserverCommandHandler::CopyCharacter;
function_map["database:version"] = &WorldserverCommandHandler::DatabaseVersion;
function_map["database:set-account-status"] = &WorldserverCommandHandler::DatabaseSetAccountStatus;
function_map["database:schema"] = &WorldserverCommandHandler::DatabaseGetSchema;
function_map["database:dump"] = &WorldserverCommandHandler::DatabaseDump;
function_map["test:test"] = &WorldserverCommandHandler::TestCommand;
function_map["test:expansion"] = &WorldserverCommandHandler::ExpansionTestCommand;
function_map["test:repository"] = &WorldserverCommandHandler::TestRepository;
function_map["test:repository2"] = &WorldserverCommandHandler::TestRepository2;
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Shows database version";
if (cmd[{"-h", "--help"}]) {
return;
}
Json::Value database_version;
database_version["database_version"] = CURRENT_BINARY_DATABASE_VERSION;
database_version["bots_database_version"] = CURRENT_BINARY_BOTS_DATABASE_VERSION;
std::stringstream payload;
payload << database_version;
std::cout << payload.str() << std::endl;
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void Version(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Shows server version";
if (cmd[{"-h", "--help"}]) {
return;
}
Json::Value database_version;
database_version["bots_database_version"] = CURRENT_BINARY_BOTS_DATABASE_VERSION;
database_version["compile_date"] = COMPILE_DATE;
database_version["compile_time"] = COMPILE_TIME;
database_version["database_version"] = CURRENT_BINARY_DATABASE_VERSION;
database_version["server_version"] = CURRENT_VERSION;
std::stringstream payload;
payload << database_version;
std::cout << payload.str() << std::endl;
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Sets account status by account name";
std::vector<std::string> arguments = {
"{name}",
"{status}"
};
std::vector<std::string> options = {};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
database.SetAccountStatus(
cmd(2).str(),
std::stoi(cmd(3).str())
);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Displays server database schema";
if (cmd[{"-h", "--help"}]) {
return;
}
Json::Value player_tables_json;
std::vector<std::string> player_tables = DatabaseSchema::GetPlayerTables();
for (const auto &table: player_tables) {
player_tables_json.append(table);
}
Json::Value content_tables_json;
std::vector<std::string> content_tables = DatabaseSchema::GetContentTables();
for (const auto &table: content_tables) {
content_tables_json.append(table);
}
Json::Value server_tables_json;
std::vector<std::string> server_tables = DatabaseSchema::GetServerTables();
for (const auto &table: server_tables) {
server_tables_json.append(table);
}
Json::Value login_tables_json;
std::vector<std::string> login_tables = DatabaseSchema::GetLoginTables();
for (const auto &table: login_tables) {
login_tables_json.append(table);
}
Json::Value state_tables_json;
std::vector<std::string> state_tables = DatabaseSchema::GetStateTables();
for (const auto &table: state_tables) {
state_tables_json.append(table);
}
Json::Value version_tables_json;
std::vector<std::string> version_tables = DatabaseSchema::GetVersionTables();
for (const auto &table: version_tables) {
version_tables_json.append(table);
}
Json::Value bot_tables_json;
std::vector<std::string> bot_tables = DatabaseSchema::GetBotTables();
for (const auto &table: bot_tables) {
bot_tables_json.append(table);
}
Json::Value schema;
schema["content_tables"] = content_tables_json;
schema["login_tables"] = login_tables_json;
schema["player_tables"] = player_tables_json;
schema["server_tables"] = server_tables_json;
schema["state_tables"] = state_tables_json;
schema["version_tables"] = version_tables_json;
schema["bot_tables"] = bot_tables_json;
std::stringstream payload;
payload << schema;
std::cout << payload.str() << std::endl;
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Dumps server database tables";
std::vector<std::string> arguments = {};
std::vector<std::string> options = {
"--all",
"--content-tables",
"--login-tables",
"--player-tables",
"--bot-tables",
"--state-tables",
"--system-tables",
"--query-serv-tables",
"--table-structure-only",
"--table-lock",
"--dump-path=",
"--dump-output-to-console",
"--drop-table-syntax-only",
"--compress"
};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
auto database_dump_service = new DatabaseDumpService();
bool dump_all = cmd[{"-a", "--all"}];
if (!cmd("--dump-path").str().empty()) {
database_dump_service->SetDumpPath(cmd("--dump-path").str());
}
/**
* Set Option
*/
database_dump_service->SetDumpContentTables(cmd[{"--content-tables"}] || dump_all);
database_dump_service->SetDumpLoginServerTables(cmd[{"--login-tables"}] || dump_all);
database_dump_service->SetDumpPlayerTables(cmd[{"--player-tables"}] || dump_all);
database_dump_service->SetDumpBotTables(cmd[{"--bot-tables"}] || dump_all);
database_dump_service->SetDumpStateTables(cmd[{"--state-tables"}] || dump_all);
database_dump_service->SetDumpSystemTables(cmd[{"--system-tables"}] || dump_all);
database_dump_service->SetDumpQueryServerTables(cmd[{"--query-serv-tables"}] || dump_all);
database_dump_service->SetDumpAllTables(dump_all);
database_dump_service->SetDumpWithNoData(cmd[{"--table-structure-only"}]);
database_dump_service->SetDumpTableLock(cmd[{"--table-lock"}]);
database_dump_service->SetDumpWithCompression(cmd[{"--compress"}]);
database_dump_service->SetDumpOutputToConsole(cmd[{"--dump-output-to-console"}]);
database_dump_service->SetDumpDropTableSyntaxOnly(cmd[{"--drop-table-syntax-only"}]);
/**
* Dump
*/
database_dump_service->Dump();
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Test command";
if (cmd[{"-h", "--help"}]) {
return;
}
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Expansion test command";
if (cmd[{"-h", "--help"}]) {
return;
}
if (!RuleManager::Instance()->LoadRules(&database, "default", false)) {
LogInfo("No rule set configured, using default rules");
}
content_service.SetCurrentExpansion(RuleI(Expansion, CurrentExpansion));
std::vector<ContentFlagsRepository::ContentFlags> flags = {};
auto f = ContentFlagsRepository::NewEntity();
f.enabled = 1;
std::vector<std::string> flag_names = {
"hateplane_enabled",
"patch_nerf_7077",
};
for (auto &name: flag_names) {
f.flag_name = name;
flags.push_back(f);
}
content_service.SetContentFlags(flags);
LogInfo(
"Current expansion is [{}] ({}) is Velious Enabled [{}] Criteria [{}]",
content_service.GetCurrentExpansion(),
content_service.GetCurrentExpansionName(),
content_service.IsTheScarsOfVeliousEnabled() ? "true" : "false",
ContentFilterCriteria::apply()
);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void TestRepository(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Test command";
if (cmd[{"-h", "--help"}]) {
return;
}
/**
* Insert one
*/
auto instance_list_entry = InstanceListRepository::NewEntity();
instance_list_entry.zone = 999;
instance_list_entry.version = 1;
instance_list_entry.is_global = 1;
instance_list_entry.start_time = 0;
instance_list_entry.duration = 0;
instance_list_entry.never_expires = 1;
auto instance_list_inserted = InstanceListRepository::InsertOne(database, instance_list_entry);
LogInfo("Inserted ID is [{}] zone [{}]", instance_list_inserted.id, instance_list_inserted.zone);
/**
* Find one
*/
auto found_instance_list = InstanceListRepository::FindOne(database, instance_list_inserted.id);
LogInfo("Found ID is [{}] zone [{}]", found_instance_list.id, found_instance_list.zone);
/**
* Update one
*/
LogInfo("Updating instance id [{}] zone [{}]", found_instance_list.id, found_instance_list.zone);
int update_instance_list_count = InstanceListRepository::UpdateOne(database, found_instance_list);
found_instance_list.zone = 777;
LogInfo(
"Updated instance id [{}] zone [{}] affected [{}]",
found_instance_list.id,
found_instance_list.zone,
update_instance_list_count
);
/**
* Delete one
*/
int deleted = InstanceListRepository::DeleteOne(database, found_instance_list.id);
LogInfo("Deleting one instance [{}] deleted count [{}]", found_instance_list.id, deleted);
/**
* Insert many
*/
std::vector<InstanceListRepository::InstanceList> instance_lists;
auto instance_list_entry_bulk = InstanceListRepository::NewEntity();
instance_list_entry_bulk.zone = 999;
instance_list_entry_bulk.version = 1;
instance_list_entry_bulk.is_global = 1;
instance_list_entry_bulk.start_time = 0;
instance_list_entry_bulk.duration = 0;
instance_list_entry_bulk.never_expires = 1;
for (int i = 0; i < 10; i++) {
instance_lists.push_back(instance_list_entry_bulk);
}
/**
* Insert Many
*/
int inserted_count = InstanceListRepository::InsertMany(database, instance_lists);
LogInfo("Bulk insertion test, inserted [{}]", inserted_count);
for (auto &entry: InstanceListRepository::GetWhere(database, fmt::format("zone = {}", 999))) {
LogInfo("Iterating through entry id [{}] zone [{}]", entry.id, entry.zone);
}
LogInfo("[Max ID] {}", InstanceListRepository::GetMaxId(database));
LogInfo("[Count] {}", InstanceListRepository::Count(database));
LogInfo("[Count Where] {}", InstanceListRepository::Count(database, "zone = 999"));
LogInfo("[Count Where] {}", InstanceListRepository::Count(database, "zone = 777"));
/**
* Delete where
*/
int deleted_count = InstanceListRepository::DeleteWhere(database, fmt::format("zone = {}", 999));
LogInfo("Bulk deletion test, deleted [{}]", deleted_count);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void TestRepository2(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Test command";
if (cmd[{"-h", "--help"}]) {
return;
}
auto zones = ZoneRepository::GetWhere(content_db, "short_name = 'anguish'");
for (auto &zone: zones) {
LogInfo(
"Zone [{}] long_name [{}] id [{}]",
zone.short_name,
zone.long_name,
zone.id
);
}
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CopyCharacter(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Copies a character into a destination account";
std::vector<std::string> arguments = {
"source_character_name",
"destination_character_name",
"destination_account_name"
};
std::vector<std::string> options = {};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
std::string source_character_name = cmd(2).str();
std::string destination_character_name = cmd(3).str();
std::string destination_account_name = cmd(4).str();
LogInfo(
"Attempting to copy character [{}] to [{}] via account [{}]",
source_character_name,
destination_character_name,
destination_account_name
);
database.CopyCharacter(
source_character_name,
destination_character_name,
destination_account_name
);
}
}
-42
View File
@@ -1,42 +0,0 @@
/**
* EQEmulator: Everquest Server Emulator
* Copyright (C) 2001-2019 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 "iostream"
#include "../common/cli/eqemu_command_handler.h"
#ifndef EQEMU_WORLD_SERVER_COMMAND_HANDLER_H
#define EQEMU_WORLD_SERVER_COMMAND_HANDLER_H
namespace WorldserverCommandHandler {
void CommandHandler(int argc, char **argv);
void Version(int argc, char **argv, argh::parser &cmd, std::string &description);
void CopyCharacter(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseVersion(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseSetAccountStatus(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description);
void DatabaseDump(int argc, char **argv, argh::parser &cmd, std::string &description);
void TestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
void ExpansionTestCommand(int argc, char **argv, argh::parser &cmd, std::string &description);
void TestRepository(int argc, char **argv, argh::parser &cmd, std::string &description);
void TestRepository2(int argc, char **argv, argh::parser &cmd, std::string &description);
};
#endif //EQEMU_WORLD_SERVER_COMMAND_HANDLER_H
+4 -3
View File
@@ -94,7 +94,7 @@ ZoneServer::~ZoneServer() {
}
}
bool ZoneServer::SetZone(uint32 in_zone_id, uint32 in_instance_id, bool is_static_zone) {
bool ZoneServer::SetZone(uint32 in_zone_id, uint32 in_instance_id, bool in_is_static_zone) {
is_booting_up = false;
std::string zone_short_name = ZoneName(in_zone_id, true);
@@ -114,7 +114,7 @@ bool ZoneServer::SetZone(uint32 in_zone_id, uint32 in_instance_id, bool is_stati
) :
""
),
is_static_zone ? " (Static)" : ""
in_is_static_zone ? " (Static)" : ""
);
}
@@ -130,7 +130,7 @@ bool ZoneServer::SetZone(uint32 in_zone_id, uint32 in_instance_id, bool is_stati
LSSleepUpdate(GetPrevZoneID());
}
is_static_zone = is_static_zone;
is_static_zone = in_is_static_zone;
strn0cpy(zone_name, zone_short_name.c_str(), sizeof(zone_name));
strn0cpy(long_name, zone_long_name.c_str(), sizeof(long_name));
@@ -1354,6 +1354,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
case ServerOP_ReloadLogs: {
zoneserver_list.SendPacket(pack);
UCSLink.SendPacket(pack);
LogSys.LoadLogDatabaseSettings();
break;
}
+1 -1
View File
@@ -40,7 +40,7 @@ public:
void SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...);
void SendEmoteMessageRaw(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message);
void SendKeepAlive();
bool SetZone(uint32 in_zone_id, uint32 in_instance_id = 0, bool is_static_zone = false);
bool SetZone(uint32 in_zone_id, uint32 in_instance_id = 0, bool in_is_static_zone = false);
void TriggerBootup(uint32 in_zone_id = 0, uint32 in_instance_id = 0, const char* admin_name = 0, bool is_static_zone = false);
void Disconnect() { auto handle = tcpc->Handle(); if (handle) { handle->Disconnect(); } }
void IncomingClient(Client* client);
+12 -4
View File
@@ -1372,11 +1372,19 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib
break;
}
}
if (GetOwner() && IsPet())
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
if (!ignore_default_buff && IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id))
if (GetOwner() && IsPet()) {
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
}
if (!ignore_default_buff && IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
AggroAmount = IsBardSong(spell_id) ? 2 : 9;
}
// overrides the hate (ex. Healing Splash), can be negative (but function will return 0).
if (spells[spell_id].hate_added != 0) {
AggroAmount = spells[spell_id].hate_added;
}
if (AggroAmount > 0) {
int HateMod = RuleI(Aggro, SpellAggroMod);
@@ -1385,7 +1393,7 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib
AggroAmount = (AggroAmount * HateMod) / 100;
}
return std::max(0, AggroAmount);
return std::max(0, AggroAmount + spells[spell_id].bonus_hate); //Bonus Hate from spells like Aurora of Morrow
}
void Mob::AddFeignMemory(Mob* attacker) {
+1 -1
View File
@@ -829,7 +829,7 @@ Json::Value ApiGetZoneAttributes(EQ::Net::WebsocketServerConnection *connection,
Json::Value ApiGetLogsysCategories(EQ::Net::WebsocketServerConnection *connection, Json::Value params)
{
if (zone->GetZoneID() == 0) {
if (!zone || (zone && zone->GetZoneID() == 0)) {
throw EQ::Net::WebsocketException("Zone must be loaded to invoke this call");
}

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