From 9052f8f420bcf4c9dcb666830826de1ca1511665 Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Mon, 20 Jan 2025 17:38:20 +0000 Subject: [PATCH 1/7] CMake: Move Tracy definitions up a level --- CMakeLists.txt | 7 +++++++ ext/CMakeLists.txt | 9 --------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c0b88ab13d..03a4afa4d6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,13 @@ add_definitions( # For external libs set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE) +# Tracy flags +option(TRACY_ENABLE "Enable Tracy profiling." OFF) +if(ENABLE_TRACY OR TRACY_ENABLED OR TRACY) # Also handle close flags + set(TRACY_ENABLE ON) +endif() +message(STATUS "TRACY_ENABLE: ${TRACY_ENABLE}") + add_subdirectory(ext) include(ClangTidy) diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 895556ef20b..4c74a891c27 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -6,15 +6,6 @@ add_subdirectory(concurrentqueue) add_subdirectory(sol) -option(TRACY_ENABLE "Enable Tracy profiling." OFF) - -# Also handle close flags: -if(ENABLE_TRACY OR TRACY_ENABLED OR TRACY) - set(TRACY_ENABLE ON) -endif() - -message(STATUS "TRACY_ENABLE: ${TRACY_ENABLE}") - # CPM Modules if(TRACY_ENABLE) # Tracy version tag, without the leading 'v' From d73756ac52aa3eb6c4d07df43f5bcfb036f352dd Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Mon, 20 Jan 2025 17:39:03 +0000 Subject: [PATCH 2/7] Core: Clean up some queries in fishingcontest --- src/map/fishingcontest.cpp | 49 ++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/map/fishingcontest.cpp b/src/map/fishingcontest.cpp index 9fab6eff7e0..d43083e5ab5 100644 --- a/src/map/fishingcontest.cpp +++ b/src/map/fishingcontest.cpp @@ -201,10 +201,11 @@ namespace fishingcontest // Set the rank value if (rankGroup > 0) { - std::string Query = "INSERT INTO char_fishing_contest_history (charid, contest_rank_{}) " - "VALUES ({}, 1) ON DUPLICATE KEY UPDATE contest_rank_{} = contest_rank_{} + 1"; - auto rset = db::query(fmt::format(Query, rankGroup, charID, rankGroup, rankGroup)); + const auto query = fmt::format("INSERT INTO char_fishing_contest_history (charid, contest_rank_{}) \ + VALUES ({}, 1) ON DUPLICATE KEY UPDATE contest_rank_{} = contest_rank_{} + 1", + rankGroup, charID, rankGroup, rankGroup); + auto rset = db::query(query); if (!rset) { ShowWarning("Unable to update player [%s] fishing reward history.", entry.name); @@ -418,25 +419,24 @@ namespace fishingcontest } // Update the DB with the current contest entries - std::string Query = "REPLACE INTO `fishing_contest_entries` " - "(charid, mjob, sjob, mlevel, slevel, race, allegiance, fishRank, score, submitTime, contestRank, share) " - "SELECT charid, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} " - "FROM chars WHERE charname = '{}'"; - - auto rset = db::query(fmt::format(Query, - entry->mjob, - entry->sjob, - entry->mlvl, - entry->slvl, - entry->race, - entry->allegiance, - entry->fishRank, - entry->score, - entry->submitTime, - entry->contestRank, - entry->share, - entry->name)); - + const auto query = fmt::format("REPLACE INTO `fishing_contest_entries` \ + (charid, mjob, sjob, mlevel, slevel, race, allegiance, fishRank, score, submitTime, contestRank, share) \ + SELECT charid, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} \ + FROM chars WHERE charname = '{}'", + entry->mjob, + entry->sjob, + entry->mlvl, + entry->slvl, + entry->race, + entry->allegiance, + entry->fishRank, + entry->score, + entry->submitTime, + entry->contestRank, + entry->share, + entry->name); + + const auto rset = db::query(query); if (!rset) { ShowDebug("Error writing fishing contest data to database."); @@ -493,10 +493,7 @@ namespace fishingcontest if (PEntry != nullptr) { // Remove from the database - const char* Query = "DELETE FROM `fishing_contest_entries` \ - WHERE `charid` = {}"; - auto rset = db::query(fmt::format(Query, PChar->id)); - + const auto rset = db::preparedStmt("DELETE FROM fishing_contest_entries WHERE charid = ?", PChar->id); if (!rset) { ShowError("Failed to remove entry from fishing entry database."); From d44130befe33fc64b037ffe99622bcf022d7a993 Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Mon, 20 Jan 2025 14:40:16 +0000 Subject: [PATCH 3/7] Core: Give a blank automaton a default name ("Automaton") --- .github/workflows/build.yml | 5 ++++- src/map/utils/puppetutils.cpp | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d69b852f5af..f0796ac1c1e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -398,7 +398,7 @@ jobs: name: windows_modules_executables path: | xi_connect.exe - xi_map.exe + xi_map_tracy.exe xi_search.exe xi_world.exe @@ -727,6 +727,9 @@ jobs: - uses: zach2good/setup-mariadb@v1 with: database: xidb + - name: Rename exe + run: | + mv xi_map_tracy.exe xi_map.exe - name: Copy settings run: | cp settings/default/* settings/ diff --git a/src/map/utils/puppetutils.cpp b/src/map/utils/puppetutils.cpp index 9d5f4909b6f..6baae384bb1 100644 --- a/src/map/utils/puppetutils.cpp +++ b/src/map/utils/puppetutils.cpp @@ -89,6 +89,7 @@ namespace puppetutils PChar->PAutomaton->saveModifiers(); PChar->PAutomaton->name = rset->get("name"); + automaton_equip_t tempEquip; db::extractFromBlob(rset, "equipped_attachments", tempEquip); @@ -99,6 +100,8 @@ namespace puppetutils tempEquip.Frame < FRAME_HARLEQUIN || tempEquip.Frame > FRAME_STORMWAKER) { + PChar->PAutomaton->name = "Automaton"; + PChar->PAutomaton->setHead(HEAD_HARLEQUIN); tempEquip.Head = HEAD_HARLEQUIN; PChar->PAutomaton->setFrame(FRAME_HARLEQUIN); From 3ea0f921f5d7267b5dfe6ee00abcf60022a52dc0 Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Mon, 20 Jan 2025 17:45:20 +0000 Subject: [PATCH 4/7] Core: Add const auto to set() method in settings --- src/common/settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/settings.h b/src/common/settings.h index 1eb096ca234..89197e2ca7b 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -163,7 +163,7 @@ namespace settings // // TODO: Gracefully convert like-types into types for the variant // TODO: Publish back up into Lua - void set(std::string name, auto value) + void set(const auto& name, const auto& value) { const auto key = to_upper(name); settingsMap[key] = SettingsVariant_t(value); From 9cd921c3c0aef499a4e169d53eed3fdc37ff062c Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Mon, 20 Jan 2025 10:49:40 +0000 Subject: [PATCH 5/7] Core: Extend CTaskMgr to accept lambdas --- src/common/socket.cpp | 4 +-- src/common/taskmgr.cpp | 9 +++---- src/common/taskmgr.h | 55 +++++++++++++++++++++++--------------- src/map/map.cpp | 10 +++---- src/map/zone.cpp | 20 ++++++++------ src/world/world_server.cpp | 4 +-- 6 files changed, 57 insertions(+), 45 deletions(-) diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 02075b3c100..7d0a4fcf19d 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -1071,8 +1071,8 @@ void socket_init_tcp() server_clock::now() + 1s, nullptr, CTaskMgr::TASK_INTERVAL, - connect_check_clear, - 5min); + 5min, + connect_check_clear); } void socket_final_tcp() diff --git a/src/common/taskmgr.cpp b/src/common/taskmgr.cpp index d45e732f691..14facfa20b3 100644 --- a/src/common/taskmgr.cpp +++ b/src/common/taskmgr.cpp @@ -38,15 +38,10 @@ CTaskMgr::~CTaskMgr() } } -CTaskMgr::CTask* CTaskMgr::AddTask(std::string const& InitName, time_point InitTick, std::any InitData, TASKTYPE InitType, TaskFunc_t InitFunc, duration InitInterval) -{ - TracyZoneScoped; - return AddTask(new CTask(InitName, InitTick, std::move(InitData), InitType, InitFunc, InitInterval)); -} - CTaskMgr::CTask* CTaskMgr::AddTask(CTask* PTask) { TracyZoneScoped; + m_TaskList.push(PTask); return PTask; } @@ -54,6 +49,7 @@ CTaskMgr::CTask* CTaskMgr::AddTask(CTask* PTask) void CTaskMgr::RemoveTask(std::string const& TaskName) { TracyZoneScoped; + // m_TaskList is a priority_queue, so we can't directly pull members out of it. // // Tasks are compared using their m_tick values, so we can safely remove all the tasks @@ -91,6 +87,7 @@ void CTaskMgr::RemoveTask(std::string const& TaskName) duration CTaskMgr::DoTimer(time_point tick) { TracyZoneScoped; + duration diff = 1s; while (!m_TaskList.empty()) diff --git a/src/common/taskmgr.h b/src/common/taskmgr.h index 2a102d3fc98..b30fe908271 100644 --- a/src/common/taskmgr.h +++ b/src/common/taskmgr.h @@ -43,7 +43,7 @@ class CTaskMgr : public Singleton { public: class CTask; - ~CTaskMgr(); + enum TASKTYPE { TASK_INTERVAL, @@ -51,16 +51,46 @@ class CTaskMgr : public Singleton TASK_REMOVE, TASK_INVALID }; - typedef int32 (*TaskFunc_t)(time_point tick, CTask*); // TODO: Get rid of C-style function pointers and add storage for lambdas + + using TaskFunc_t = std::function; typedef std::priority_queue, greater_equal> TaskList_t; + class CTask + { + public: + template + CTask(std::string const& name, time_point tick, std::any data, TASKTYPE type, duration interval, F&& func) + : m_name(name) + , m_type(type) + , m_tick(tick) + , m_interval(interval) + , m_data(data) + , m_func(std::forward(func)) + { + } + + std::string m_name; + TASKTYPE m_type; + time_point m_tick; + duration m_interval; + std::any m_data; + TaskFunc_t m_func; + }; + + ~CTaskMgr(); + TaskList_t& getTaskList() { return m_TaskList; }; CTask* AddTask(CTask*); - CTask* AddTask(std::string const& InitName, time_point InitTick, std::any InitData, TASKTYPE InitType, TaskFunc_t InitFunc, duration InitInterval = 1s); + + template + CTask* AddTask(std::string const& InitName, time_point InitTick, std::any InitData, TASKTYPE InitType, duration InitInterval, F&& InitFunc) + { + return AddTask(new CTask(InitName, InitTick, InitData, InitType, InitInterval, std::forward(InitFunc))); + } duration DoTimer(time_point tick); void RemoveTask(std::string const& TaskName); @@ -72,25 +102,6 @@ class CTaskMgr : public Singleton TaskList_t m_TaskList; }; -class CTaskMgr::CTask -{ -public: - CTask(std::string const& InitName, time_point InitTick, std::any InitData, TASKTYPE InitType, TaskFunc_t InitFunc, duration InitInterval = 1s) - : m_name(InitName) - , m_type(InitType) - , m_tick(InitTick) - , m_interval(InitInterval) - , m_data(InitData) - , m_func(InitFunc){}; - - std::string m_name; - TASKTYPE m_type; - time_point m_tick; - duration m_interval; - std::any m_data; - TaskFunc_t m_func; -}; - inline bool operator<(const CTaskMgr::CTask& a, const CTaskMgr::CTask& b) { return a.m_tick < b.m_tick; diff --git a/src/map/map.cpp b/src/map/map.cpp index 7e9b8c3c9d0..706bda98301 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -1,4 +1,4 @@ -/* +/* =========================================================================== Copyright (c) 2010-2015 Darkstar Dev Teams @@ -324,10 +324,10 @@ int32 do_init(int32 argc, char** argv) CTransportHandler::getInstance()->InitializeTransport(); - CTaskMgr::getInstance()->AddTask("time_server", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, time_server, 2400ms); - CTaskMgr::getInstance()->AddTask("map_cleanup", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, map_cleanup, 5s); - CTaskMgr::getInstance()->AddTask("garbage_collect", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, map_garbage_collect, 15min); - CTaskMgr::getInstance()->AddTask("persist_server_vars", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, serverutils::PersistVolatileServerVars, 1min); + CTaskMgr::getInstance()->AddTask("time_server", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, 2400ms, time_server); + CTaskMgr::getInstance()->AddTask("map_cleanup", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, 5s, map_cleanup); + CTaskMgr::getInstance()->AddTask("garbage_collect", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, 15min, map_garbage_collect); + CTaskMgr::getInstance()->AddTask("persist_server_vars", server_clock::now(), nullptr, CTaskMgr::TASK_INTERVAL, 1min, serverutils::PersistVolatileServerVars); ShowInfo("do_init: Removing expired database variables"); uint32 currentTimestamp = CVanaTime::getInstance()->getSysTime(); diff --git a/src/map/zone.cpp b/src/map/zone.cpp index 40ebae43b7d..b242b938e4f 100644 --- a/src/map/zone.cpp +++ b/src/map/zone.cpp @@ -720,8 +720,13 @@ void CZone::UpdateWeather() SetWeather((WEATHER)Weather); luautils::OnZoneWeatherChange(GetID(), Weather); - CTaskMgr::getInstance()->AddTask(new CTaskMgr::CTask("zone_update_weather", server_clock::now() + std::chrono::seconds(WeatherNextUpdate), this, - CTaskMgr::TASK_ONCE, zone_update_weather)); + // clang-format off + CTaskMgr::getInstance()->AddTask("zone_update_weather", server_clock::now() + std::chrono::seconds(WeatherNextUpdate), this, CTaskMgr::TASK_ONCE, 1s, + [](time_point tick, CTaskMgr::CTask* PTask) + { + return zone_update_weather(tick, PTask); + }); + // clang-format on } /************************************************************************ @@ -1017,13 +1022,12 @@ void CZone::ForEachNpc(std::function const& func) void CZone::createZoneTimers() { TracyZoneScoped; - ZoneTimer = - CTaskMgr::getInstance()->AddTask(m_zoneName, server_clock::now(), this, CTaskMgr::TASK_INTERVAL, zone_server, - std::chrono::milliseconds(static_cast(server_tick_interval))); - ZoneTimerTriggerAreas = - CTaskMgr::getInstance()->AddTask(m_zoneName + "TriggerAreas", server_clock::now(), this, CTaskMgr::TASK_INTERVAL, zone_trigger_area, - std::chrono::milliseconds(static_cast(server_trigger_area_interval))); + const auto tickInterval = std::chrono::milliseconds(static_cast(server_tick_interval)); + const auto triggerAreaInterval = std::chrono::milliseconds(static_cast(server_trigger_area_interval)); + + ZoneTimer = CTaskMgr::getInstance()->AddTask(m_zoneName, server_clock::now(), this, CTaskMgr::TASK_INTERVAL, tickInterval, zone_server); + ZoneTimerTriggerAreas = CTaskMgr::getInstance()->AddTask(m_zoneName + "TriggerAreas", server_clock::now(), this, CTaskMgr::TASK_INTERVAL, triggerAreaInterval, zone_trigger_area); } void CZone::CharZoneIn(CCharEntity* PChar) diff --git a/src/world/world_server.cpp b/src/world/world_server.cpp index b4db49a404d..978986b82c0 100644 --- a/src/world/world_server.cpp +++ b/src/world/world_server.cpp @@ -83,10 +83,10 @@ WorldServer::WorldServer(int argc, char** argv) , colonizationSystem(std::make_unique()) { // Tasks - CTaskMgr::getInstance()->AddTask("time_server", server_clock::now(), this, CTaskMgr::TASK_INTERVAL, time_server, 2400ms); + CTaskMgr::getInstance()->AddTask("time_server", server_clock::now(), this, CTaskMgr::TASK_INTERVAL, 2400ms, time_server); // TODO: Make this more reactive than a polling job - CTaskMgr::getInstance()->AddTask("forward_queued_messages_to_handlers", server_clock::now(), this, CTaskMgr::TASK_INTERVAL, forward_queued_messages_to_handlers, 250ms); + CTaskMgr::getInstance()->AddTask("forward_queued_messages_to_handlers", server_clock::now(), this, CTaskMgr::TASK_INTERVAL, 250ms, forward_queued_messages_to_handlers); } WorldServer::~WorldServer() = default; From 1f5ccc9e2a6dd6eba357a0d4ee6070152e01d70c Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Mon, 20 Jan 2025 17:39:35 +0000 Subject: [PATCH 6/7] dbtool: Fail when encountering an error during db_query --- tools/dbtool.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tools/dbtool.py b/tools/dbtool.py index 93c42b15ce4..7abab95aad6 100644 --- a/tools/dbtool.py +++ b/tools/dbtool.py @@ -252,11 +252,20 @@ def load_into_dict(filename, settings): # Redirect errors through this to hide annoying password warning -def fetch_errors(result): +def fetch_errors(query, result): for line in result.stderr.splitlines(): # Safe to ignore this warning - if "Using a password on the command line interface can be insecure" not in line: + if "Using a password on the command line interface can be insecure" in line: + continue + + # If the output line begins with ERROR, print it in red and exit + if line.startswith("ERROR"): + print_red("Encountered error while executing SQL query:") + print_red(query) + print_red("Error:") print_red(line) + print_red("Exiting...") + exit(-1) def db_query(query): @@ -273,7 +282,7 @@ def db_query(query): capture_output=True, text=True, ) - fetch_errors(result) + fetch_errors(query, result) return result @@ -497,6 +506,8 @@ def connect(): ).lower() == "y" ): + query = f"CREATE DATABASE {database} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" + result = subprocess.run( [ f"{mysql_bin}mysql{exe}", @@ -504,12 +515,12 @@ def connect(): f"-P{str(port)}", f"-u{login}", f"-p{password}", - f"-e CREATE DATABASE {database} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + f"-e {query}", ], capture_output=True, text=True, ) - fetch_errors(result) + fetch_errors(query, result) setup_db() connect() else: @@ -573,7 +584,7 @@ def backup_db(silent=False, lite=False): stderr=subprocess.PIPE, text=True, ) - fetch_errors(result) + fetch_errors("Dumping database", result) print_green("Database saved!") time.sleep(0.5) @@ -1261,6 +1272,8 @@ def main(): return elif "setup" == arg1: if len(sys.argv) > 2 and str(sys.argv[2]) == database: + query = f"CREATE DATABASE {database} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" + result = subprocess.run( [ f"{mysql_bin}mysql{exe}", @@ -1268,12 +1281,12 @@ def main(): f"-P{str(port)}", f"-u{login}", f"-p{password}", - f"-e CREATE DATABASE {database} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + f"-e {query}", ], capture_output=True, text=True, ) - fetch_errors(result) + fetch_errors(query, result) setup_db() return elif "dump" == arg1: From f11c06775b60a5d5ec3c3c76fa9e083b40243525 Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Mon, 20 Jan 2025 18:50:30 +0000 Subject: [PATCH 7/7] CI: Don't try to make new database --- .github/workflows/build.yml | 12 ++++++------ tools/dbtool.py | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f0796ac1c1e..d2be54f6ea7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -454,7 +454,7 @@ jobs: - name: Import SQL files shell: bash run: | - python3 ./tools/dbtool.py setup xidb + python3 ./tools/dbtool.py setup - name: Copy settings run: | cp settings/default/* settings/ @@ -623,7 +623,7 @@ jobs: - name: Import SQL files shell: bash run: | - python3 ./tools/dbtool.py setup xidb + python3 ./tools/dbtool.py setup - name: Assign odd zones a different port run: | mysql xidb -h 127.0.0.1 -uroot -proot -e "UPDATE xidb.zone_settings SET zoneport = 54231 WHERE zoneid % 2 = 0;" @@ -690,7 +690,7 @@ jobs: path: . - uses: zach2good/setup-mariadb@v1 with: - database: xidb + database: xidb - name: Copy settings run: | cp settings/default/* settings/ @@ -702,7 +702,7 @@ jobs: - name: Import SQL files shell: bash run: | - python3 ./tools/dbtool.py setup xidb + python3 ./tools/dbtool.py setup - name: Startup checks uses: nick-invision/retry@v3 with: @@ -726,7 +726,7 @@ jobs: path: . - uses: zach2good/setup-mariadb@v1 with: - database: xidb + database: xidb - name: Rename exe run: | mv xi_map_tracy.exe xi_map.exe @@ -751,7 +751,7 @@ jobs: - name: Import SQL files shell: bash run: | - python3 ./tools/dbtool.py setup xidb + python3 ./tools/dbtool.py setup - name: Startup checks uses: nick-invision/retry@v3 with: diff --git a/tools/dbtool.py b/tools/dbtool.py index 7abab95aad6..4cb0bece54b 100644 --- a/tools/dbtool.py +++ b/tools/dbtool.py @@ -1288,6 +1288,8 @@ def main(): ) fetch_errors(query, result) setup_db() + else: + setup_db() return elif "dump" == arg1: if len(sys.argv) > 2: