From 46f085eb4ba5a3c956eb9b0eaecb6fced5e39e3c Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Tue, 6 Dec 2022 04:39:09 -0800 Subject: [PATCH 01/63] Resolve warnings and change init order Initialize dConfig first, before logger so we know whether or not to log to console Initialize namespace Game variables to nullptr so they are a known value if accessed before initialization. Removed unused Game variables Replaced config with a pointer instead of referencing something on the stack. Assign return values to system calls to silence warnings. Tested that the server still compiles, runs and allows me to load into the game. --- dAuthServer/AuthServer.cpp | 38 +++++++------- dChatServer/ChatServer.cpp | 46 ++++++++--------- dCommon/Game.h | 2 - dMasterServer/InstanceManager.cpp | 4 +- dMasterServer/MasterServer.cpp | 34 ++++++------- dWorldServer/WorldServer.cpp | 71 ++++++++++++--------------- tests/dGameTests/GameDependencies.cpp | 1 - 7 files changed, 92 insertions(+), 104 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index a9f02f53..4999b62e 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -22,9 +22,9 @@ #include "Game.h" namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; } dLogger* SetupLogger(); @@ -37,22 +37,22 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig("authconfig.ini"); + Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("AuthServer", "Starting Auth server..."); Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__); - //Read our config: - dConfig config("authconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -61,7 +61,7 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; - return 0; + return EXIT_FAILURE; } //Find out the master's IP: @@ -80,10 +80,10 @@ int main(int argc, char** argv) { //It's safe to pass 'localhost' here, as the IP is only used as the external IP. int maxClients = 50; int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); @@ -145,8 +145,8 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index e3c6d6e9..2c36b222 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -20,11 +20,11 @@ #include "Game.h" namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; - dChatFilter* chatFilter; - AssetManager* assetManager; + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; + dChatFilter* chatFilter = nullptr; + AssetManager* assetManager = nullptr; } //RakNet includes: @@ -42,19 +42,19 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig("chatconfig.ini"); + Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("ChatServer", "Starting Chat server..."); Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__); - //Read our config: - dConfig config("chatconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - try { - std::string clientPathStr = config.GetValue("client_location"); + std::string clientPathStr = Game::config->GetValue("client_location"); if (clientPathStr.empty()) clientPathStr = "./res"; std::filesystem::path clientPath = std::filesystem::path(clientPathStr); if (clientPath.is_relative()) { @@ -69,10 +69,10 @@ int main(int argc, char** argv) { } //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -81,7 +81,7 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; - return 0; + return EXIT_FAILURE; } //Find out the master's IP: @@ -100,12 +100,12 @@ int main(int argc, char** argv) { //It's safe to pass 'localhost' here, as the IP is only used as the external IP. int maxClients = 50; int ourPort = 1501; - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); @@ -167,8 +167,8 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } diff --git a/dCommon/Game.h b/dCommon/Game.h index 1c4bbc85..38cadb70 100644 --- a/dCommon/Game.h +++ b/dCommon/Game.h @@ -5,7 +5,6 @@ class dServer; class dLogger; class InstanceManager; -class dpWorld; class dChatFilter; class dConfig; class RakPeerInterface; @@ -16,7 +15,6 @@ namespace Game { extern dLogger* logger; extern dServer* server; extern InstanceManager* im; - extern dpWorld* physicsWorld; extern dChatFilter* chatFilter; extern dConfig* config; extern std::mt19937 randomEngine; diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 83378dbb..a1983dd4 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -74,7 +74,7 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); m_Instances.push_back(instance); @@ -322,7 +322,7 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); m_Instances.push_back(instance); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 4acb9b26..a4aa270a 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -43,11 +43,11 @@ #include "FdbToSqlite.h" namespace Game { - dLogger* logger; - dServer* server; - InstanceManager* im; - dConfig* config; - AssetManager* assetManager; + dLogger* logger = nullptr; + dServer* server = nullptr; + InstanceManager* im = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; } //namespace Game bool shutdownSequenceStarted = false; @@ -79,14 +79,14 @@ int main(int argc, char** argv) { Game::logger = SetupLogger(); if (!Game::logger) return EXIT_FAILURE; - Game::logger->Log("MasterServer", "Starting Master server..."); - Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); - Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__); - Game::config = new dConfig("masterconfig.ini"); Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("MasterServer", "Starting Master server..."); + Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); + Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__); + //Connect to the MySQL Database std::string mysql_host = Game::config->GetValue("mysql_host"); std::string mysql_database = Game::config->GetValue("mysql_database"); @@ -732,28 +732,28 @@ void HandlePacket(Packet* packet) { void StartChatServer() { #ifdef __APPLE__ //macOS doesn't need sudo to run on ports < 1024 - system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); #elif _WIN32 - system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { - system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } else { - system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } #endif } void StartAuthServer() { #ifdef __APPLE__ - system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); #elif _WIN32 - system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { - system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } else { - system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } #endif } diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index acd38ad3..5887597d 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -61,17 +61,14 @@ #include "ZCompression.h" namespace Game { - dLogger* logger; - dServer* server; - dZoneManager* zoneManager; - dpWorld* physicsWorld; - dChatFilter* chatFilter; - dConfig* config; + dLogger* logger = nullptr; + dServer* server = nullptr; + dpWorld* physicsWorld = nullptr; + dChatFilter* chatFilter = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; + RakPeerInterface* chatServer = nullptr; std::mt19937 randomEngine; - - AssetManager* assetManager; - - RakPeerInterface* chatServer; SystemAddress chatSysAddr; } @@ -127,26 +124,21 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(zoneID, instanceID); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig("worldconfig.ini"); + Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); - Game::logger->SetLogToConsole(true); //We want this info to always be logged. Game::logger->Log("WorldServer", "Starting World server..."); Game::logger->Log("WorldServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("WorldServer", "Compiled on: %s", __TIMESTAMP__); -#ifndef _DEBUG - Game::logger->SetLogToConsole(false); //By default, turn it back off if not in debug. -#endif - - //Read our config: - dConfig config("worldconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - if (config.GetValue("disable_chat") == "1") chatDisabled = true; + if (Game::config->GetValue("disable_chat") == "1") chatDisabled = true; try { - std::string clientPathStr = config.GetValue("client_location"); + std::string clientPathStr = Game::config->GetValue("client_location"); if (clientPathStr.empty()) clientPathStr = "./res"; std::filesystem::path clientPath = std::filesystem::path(clientPathStr); if (clientPath.is_relative()) { @@ -166,28 +158,28 @@ int main(int argc, char** argv) { Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); - return -1; + return EXIT_FAILURE; } CDClientManager::Instance()->Initialize(); //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); - Diagnostics::SetProduceMemoryDump(config.GetValue("generate_dump") == "1"); + Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1"); - if (!config.GetValue("dump_folder").empty()) { - Diagnostics::SetOutDirectory(config.GetValue("dump_folder")); + if (!Game::config->GetValue("dump_folder").empty()) { + Diagnostics::SetOutDirectory(Game::config->GetValue("dump_folder")); } try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); } catch (sql::SQLException& ex) { Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s", ex.what()); - return 0; + return EXIT_FAILURE; } //Find out the master's IP: @@ -206,13 +198,13 @@ int main(int argc, char** argv) { ObjectIDManager::Instance()->Initialize(); UserManager::Instance()->Initialize(); LootGenerator::Instance(); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, zoneID); //Connect to the chat server: int chatPort = 1501; - if (config.GetValue("chat_server_port") != "") chatPort = std::atoi(config.GetValue("chat_server_port").c_str()); + if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); Game::chatServer = RakNetworkFactory::GetRakPeerInterface(); @@ -1279,16 +1271,15 @@ void WorldShutdownSequence() { } void FinalizeShutdown() { - //Delete our objects here: - if (Game::zoneManager) delete Game::zoneManager; - Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)", Game::server->GetZoneID(), instanceID); + //Delete our objects here: Metrics::Clear(); Database::Destroy("WorldServer"); - delete Game::chatFilter; - delete Game::server; - delete Game::logger; + if (Game::chatFilter) delete Game::chatFilter; + if (Game::server) delete Game::server; + if (Game::logger) delete Game::logger; + if (Game::config) delete Game::config; worldShutdownSequenceComplete = true; diff --git a/tests/dGameTests/GameDependencies.cpp b/tests/dGameTests/GameDependencies.cpp index 5ac3339a..7b0a8412 100644 --- a/tests/dGameTests/GameDependencies.cpp +++ b/tests/dGameTests/GameDependencies.cpp @@ -4,7 +4,6 @@ namespace Game { dLogger* logger; dServer* server; dZoneManager* zoneManager; - dpWorld* physicsWorld; dChatFilter* chatFilter; dConfig* config; std::mt19937 randomEngine; From a14e16237b8d20a1b43fc5770169c5d3ca4b5ad1 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Tue, 6 Dec 2022 19:30:43 -0800 Subject: [PATCH 02/63] Only start Master of config files exist Also default the logging to console to on on the off chance the files exist but are wrong / corrupted. --- dAuthServer/AuthServer.cpp | 4 ++-- dChatServer/ChatServer.cpp | 4 ++-- dMasterServer/MasterServer.cpp | 29 +++++++++++++++++++++++++++-- dWorldServer/WorldServer.cpp | 4 ++-- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 4999b62e..aefc822b 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -40,8 +40,8 @@ int main(int argc, char** argv) { if (!Game::logger) return EXIT_FAILURE; //Read our config: - Game::config = new dConfig("authconfig.ini"); - Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); Game::logger->Log("AuthServer", "Starting Auth server..."); diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 2c36b222..043e7869 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -45,8 +45,8 @@ int main(int argc, char** argv) { if (!Game::logger) return EXIT_FAILURE; //Read our config: - Game::config = new dConfig("chatconfig.ini"); - Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); Game::logger->Log("ChatServer", "Starting Chat server..."); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index a4aa270a..4c18566e 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -79,8 +79,33 @@ int main(int argc, char** argv) { Game::logger = SetupLogger(); if (!Game::logger) return EXIT_FAILURE; - Game::config = new dConfig("masterconfig.ini"); - Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "authconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find authconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "chatconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find chatconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "masterconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find masterconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find sharedconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "worldconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find worldconfig.ini"); + return EXIT_FAILURE; + } + + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "masterconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); Game::logger->Log("MasterServer", "Starting Master server..."); diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 5887597d..68ec0e57 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -127,8 +127,8 @@ int main(int argc, char** argv) { if (!Game::logger) return EXIT_FAILURE; //Read our config: - Game::config = new dConfig("worldconfig.ini"); - Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "worldconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); Game::logger->Log("WorldServer", "Starting World server..."); From 435761f64bdf75edf717ed6a12b966624c16447c Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 15 Dec 2022 04:02:38 -0800 Subject: [PATCH 03/63] Improve shutdown --- dAuthServer/AuthServer.cpp | 41 ++++++------ dChatServer/ChatServer.cpp | 49 ++++++++------- dCommon/Game.h | 3 + dMasterServer/InstanceManager.cpp | 6 +- dMasterServer/MasterServer.cpp | 88 ++++++++++---------------- dNet/dServer.cpp | 8 ++- dNet/dServer.h | 20 +++++- dWorldServer/WorldServer.cpp | 91 +++++++++++++++------------ tests/dGameTests/GameDependencies.cpp | 1 + 9 files changed, 160 insertions(+), 147 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index aefc822b..4fffc5d0 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -22,9 +22,10 @@ #include "Game.h" namespace Game { - dLogger* logger = nullptr; - dServer* server = nullptr; - dConfig* config = nullptr; + dLogger* logger; + dServer* server; + dConfig* config; + bool shouldShutdown = false; } dLogger* SetupLogger(); @@ -37,22 +38,22 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return EXIT_FAILURE; - - //Read our config: - Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string()); - Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); - Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); - + if (!Game::logger) return 0; Game::logger->Log("AuthServer", "Starting Auth server..."); Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__); + //Read our config: + dConfig config("authconfig.ini"); + Game::config = &config; + Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); + Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); + //Connect to the MySQL Database - std::string mysql_host = Game::config->GetValue("mysql_host"); - std::string mysql_database = Game::config->GetValue("mysql_database"); - std::string mysql_username = Game::config->GetValue("mysql_username"); - std::string mysql_password = Game::config->GetValue("mysql_password"); + std::string mysql_host = config.GetValue("mysql_host"); + std::string mysql_database = config.GetValue("mysql_database"); + std::string mysql_username = config.GetValue("mysql_username"); + std::string mysql_password = config.GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -61,7 +62,7 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; - return EXIT_FAILURE; + return 0; } //Find out the master's IP: @@ -80,10 +81,10 @@ int main(int argc, char** argv) { //It's safe to pass 'localhost' here, as the IP is only used as the external IP. int maxClients = 50; int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. - if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); - if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); + if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); + if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); - Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, Game::shouldShutdown); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); @@ -92,7 +93,7 @@ int main(int argc, char** argv) { int framesSinceMasterDisconnect = 0; int framesSinceLastSQLPing = 0; - while (true) { + while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; @@ -145,8 +146,8 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; - delete Game::config; + exit(EXIT_SUCCESS); return EXIT_SUCCESS; } diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 043e7869..d2eb7fc7 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -20,11 +20,12 @@ #include "Game.h" namespace Game { - dLogger* logger = nullptr; - dServer* server = nullptr; - dConfig* config = nullptr; - dChatFilter* chatFilter = nullptr; - AssetManager* assetManager = nullptr; + dLogger* logger; + dServer* server; + dConfig* config; + dChatFilter* chatFilter; + AssetManager* assetManager; + bool shouldShutdown = false; } //RakNet includes: @@ -42,19 +43,19 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return EXIT_FAILURE; - - //Read our config: - Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string()); - Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); - Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); - + if (!Game::logger) return 0; Game::logger->Log("ChatServer", "Starting Chat server..."); Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__); + //Read our config: + dConfig config("chatconfig.ini"); + Game::config = &config; + Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); + Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); + try { - std::string clientPathStr = Game::config->GetValue("client_location"); + std::string clientPathStr = config.GetValue("client_location"); if (clientPathStr.empty()) clientPathStr = "./res"; std::filesystem::path clientPath = std::filesystem::path(clientPathStr); if (clientPath.is_relative()) { @@ -69,10 +70,10 @@ int main(int argc, char** argv) { } //Connect to the MySQL Database - std::string mysql_host = Game::config->GetValue("mysql_host"); - std::string mysql_database = Game::config->GetValue("mysql_database"); - std::string mysql_username = Game::config->GetValue("mysql_username"); - std::string mysql_password = Game::config->GetValue("mysql_password"); + std::string mysql_host = config.GetValue("mysql_host"); + std::string mysql_database = config.GetValue("mysql_database"); + std::string mysql_username = config.GetValue("mysql_username"); + std::string mysql_password = config.GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -81,7 +82,7 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; - return EXIT_FAILURE; + return 0; } //Find out the master's IP: @@ -100,12 +101,12 @@ int main(int argc, char** argv) { //It's safe to pass 'localhost' here, as the IP is only used as the external IP. int maxClients = 50; int ourPort = 1501; - if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); - if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); + if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); + if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); - Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config); + Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, Game::shouldShutdown); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); @@ -114,7 +115,7 @@ int main(int argc, char** argv) { int framesSinceMasterDisconnect = 0; int framesSinceLastSQLPing = 0; - while (true) { + while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; @@ -167,8 +168,8 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; - delete Game::config; + exit(EXIT_SUCCESS); return EXIT_SUCCESS; } diff --git a/dCommon/Game.h b/dCommon/Game.h index 38cadb70..cbddafec 100644 --- a/dCommon/Game.h +++ b/dCommon/Game.h @@ -5,6 +5,7 @@ class dServer; class dLogger; class InstanceManager; +class dpWorld; class dChatFilter; class dConfig; class RakPeerInterface; @@ -15,10 +16,12 @@ namespace Game { extern dLogger* logger; extern dServer* server; extern InstanceManager* im; + extern dpWorld* physicsWorld; extern dChatFilter* chatFilter; extern dConfig* config; extern std::mt19937 randomEngine; extern RakPeerInterface* chatServer; extern AssetManager* assetManager; extern SystemAddress chatSysAddr; + extern bool shouldShutdown; } diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index a1983dd4..327a18b9 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -74,7 +74,7 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW cmd.append("&"); //Sends our next process to the background on Linux #endif - auto ret = system(cmd.c_str()); + system(cmd.c_str()); m_Instances.push_back(instance); @@ -322,7 +322,7 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon cmd.append("&"); //Sends our next process to the background on Linux #endif - auto ret = system(cmd.c_str()); + system(cmd.c_str()); m_Instances.push_back(instance); @@ -391,5 +391,5 @@ void Instance::Shutdown() { Game::server->Send(&bitStream, this->m_SysAddr, false); - Game::logger->Log("Instance", "Triggered world shutdown"); + Game::logger->Log("Instance", "Triggered world shutdown for zone/clone/instance %i/%i/%i", GetMapID(), GetCloneID(), GetInstanceID()); } diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 4c18566e..2f54243a 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -43,11 +43,12 @@ #include "FdbToSqlite.h" namespace Game { - dLogger* logger = nullptr; - dServer* server = nullptr; - InstanceManager* im = nullptr; - dConfig* config = nullptr; - AssetManager* assetManager = nullptr; + dLogger* logger; + dServer* server; + InstanceManager* im; + dConfig* config; + AssetManager* assetManager; + bool shouldShutdown = false; } //namespace Game bool shutdownSequenceStarted = false; @@ -58,7 +59,6 @@ void StartAuthServer(); void StartChatServer(); void HandlePacket(Packet* packet); std::map activeSessions; -bool shouldShutdown = false; SystemAddress chatServerMasterPeerSysAddr; int main(int argc, char** argv) { @@ -79,39 +79,14 @@ int main(int argc, char** argv) { Game::logger = SetupLogger(); if (!Game::logger) return EXIT_FAILURE; - if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "authconfig.ini")) { - Game::logger->Log("MasterServer", "Couldnt find authconfig.ini"); - return EXIT_FAILURE; - } - - if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "chatconfig.ini")) { - Game::logger->Log("MasterServer", "Couldnt find chatconfig.ini"); - return EXIT_FAILURE; - } - - if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "masterconfig.ini")) { - Game::logger->Log("MasterServer", "Couldnt find masterconfig.ini"); - return EXIT_FAILURE; - } - - if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini")) { - Game::logger->Log("MasterServer", "Couldnt find sharedconfig.ini"); - return EXIT_FAILURE; - } - - if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "worldconfig.ini")) { - Game::logger->Log("MasterServer", "Couldnt find worldconfig.ini"); - return EXIT_FAILURE; - } - - Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "masterconfig.ini").string()); - Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); - Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); - Game::logger->Log("MasterServer", "Starting Master server..."); Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__); + Game::config = new dConfig("masterconfig.ini"); + Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + //Connect to the MySQL Database std::string mysql_host = Game::config->GetValue("mysql_host"); std::string mysql_database = Game::config->GetValue("mysql_database"); @@ -241,7 +216,7 @@ int main(int argc, char** argv) { if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port")); - Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config); + Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, Game::shouldShutdown); //Query for the database for a server labeled "master" auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); @@ -328,7 +303,7 @@ int main(int argc, char** argv) { framesSinceLastSQLPing++; //10m shutdown for universe kill command - if (shouldShutdown) { + if (Game::shouldShutdown) { if (framesSinceKillUniverseCommand >= 40000) { //Break main loop and exit break; @@ -406,7 +381,7 @@ void HandlePacket(Packet* packet) { Game::im->RemoveInstance(instance); //Delete the old } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) { StartChatServer(); } } @@ -422,7 +397,7 @@ void HandlePacket(Packet* packet) { //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) { StartChatServer(); } } @@ -744,7 +719,7 @@ void HandlePacket(Packet* packet) { case MSG_MASTER_SHUTDOWN_UNIVERSE: { Game::logger->Log("MasterServer", "Received shutdown universe command, shutting down in 10 minutes."); - shouldShutdown = true; + Game::shouldShutdown = true; break; } @@ -757,28 +732,28 @@ void HandlePacket(Packet* packet) { void StartChatServer() { #ifdef __APPLE__ //macOS doesn't need sudo to run on ports < 1024 - auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); #elif _WIN32 - auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); + system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { - auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } else { - auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } #endif } void StartAuthServer() { #ifdef __APPLE__ - auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); #elif _WIN32 - auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); + system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { - auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } else { - auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } #endif } @@ -790,14 +765,11 @@ void ShutdownSequence() { shutdownSequenceStarted = true; - if (Game::im) { - for (auto* instance : Game::im->GetInstances()) { - if (instance == nullptr) { - continue; - } - - instance->Shutdown(); - } + { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN); + Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::logger->Log("MasterServer", "Triggered master shutdown"); } auto* objIdManager = ObjectIDManager::TryInstance(); @@ -813,6 +785,10 @@ void ShutdownSequence() { exit(EXIT_SUCCESS); } + for (auto instance : Game::im->GetInstances()) { + instance->SetIsShuttingDown(true); + } + Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); while (true) { diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 481667b8..3a5ef822 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -36,7 +36,7 @@ public: } } ReceiveDownloadCompleteCB; -dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, unsigned int zoneID) { +dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool& shouldShutdown, unsigned int zoneID) { mIP = ip; mPort = port; mZoneID = zoneID; @@ -52,6 +52,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect mReplicaManager = nullptr; mServerType = serverType; mConfig = config; + mShouldShutdown = &shouldShutdown; //Attempt to start our server here: mIsOkay = Startup(); @@ -124,8 +125,11 @@ Packet* dServer::ReceiveFromMaster() { ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet); break; } + case MSG_MASTER_SHUTDOWN: + *mShouldShutdown = true; + break; - //When we handle these packets in World instead dServer, we just return the packet's pointer. + //When we handle these packets in World instead dServer, we just return the packet's pointer. default: return packet; diff --git a/dNet/dServer.h b/dNet/dServer.h index 0fbdecce..608b3b83 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -18,7 +18,20 @@ class dServer { public: // Default constructor should only used for testing! dServer() {}; - dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, unsigned int zoneID = 0); + dServer( + const std::string& ip, + int port, + int instanceID, + int maxConnections, + bool isInternal, + bool useEncryption, + dLogger* logger, + const std::string masterIP, + int masterPort, + ServerType serverType, + dConfig* config, + bool& shouldShutdown, + unsigned int zoneID = 0); ~dServer(); Packet* ReceiveFromMaster(); @@ -64,6 +77,11 @@ private: RakPeerInterface* mPeer = nullptr; ReplicaManager* mReplicaManager = nullptr; NetworkIDManager* mNetIDManager = nullptr; + + /** + * Whether or not to shut down the server. Pointer to Game::shouldShutdown. + */ + bool* mShouldShutdown = nullptr; SocketDescriptor mSocketDescriptor; std::string mIP; int mPort; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 68ec0e57..2fdb373b 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -61,20 +61,23 @@ #include "ZCompression.h" namespace Game { - dLogger* logger = nullptr; - dServer* server = nullptr; - dpWorld* physicsWorld = nullptr; - dChatFilter* chatFilter = nullptr; - dConfig* config = nullptr; - AssetManager* assetManager = nullptr; - RakPeerInterface* chatServer = nullptr; + dLogger* logger; + dServer* server; + dZoneManager* zoneManager; + dpWorld* physicsWorld; + dChatFilter* chatFilter; + dConfig* config; std::mt19937 randomEngine; + + AssetManager* assetManager; + + RakPeerInterface* chatServer; SystemAddress chatSysAddr; -} + bool shouldShutdown = false; +} // namespace Game bool chatDisabled = false; bool chatConnected = false; -bool worldShutdownSequenceStarted = false; bool worldShutdownSequenceComplete = false; void WorldShutdownSequence(); void WorldShutdownProcess(uint32_t zoneId); @@ -124,21 +127,26 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(zoneID, instanceID); - if (!Game::logger) return EXIT_FAILURE; - - //Read our config: - Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "worldconfig.ini").string()); - Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); - Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + if (!Game::logger) return 0; + Game::logger->SetLogToConsole(true); //We want this info to always be logged. Game::logger->Log("WorldServer", "Starting World server..."); Game::logger->Log("WorldServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("WorldServer", "Compiled on: %s", __TIMESTAMP__); - if (Game::config->GetValue("disable_chat") == "1") chatDisabled = true; +#ifndef _DEBUG + Game::logger->SetLogToConsole(false); //By default, turn it back off if not in debug. +#endif + + //Read our config: + dConfig config("worldconfig.ini"); + Game::config = &config; + Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); + Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); + if (config.GetValue("disable_chat") == "1") chatDisabled = true; try { - std::string clientPathStr = Game::config->GetValue("client_location"); + std::string clientPathStr = config.GetValue("client_location"); if (clientPathStr.empty()) clientPathStr = "./res"; std::filesystem::path clientPath = std::filesystem::path(clientPathStr); if (clientPath.is_relative()) { @@ -158,28 +166,28 @@ int main(int argc, char** argv) { Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); - return EXIT_FAILURE; + return -1; } CDClientManager::Instance()->Initialize(); //Connect to the MySQL Database - std::string mysql_host = Game::config->GetValue("mysql_host"); - std::string mysql_database = Game::config->GetValue("mysql_database"); - std::string mysql_username = Game::config->GetValue("mysql_username"); - std::string mysql_password = Game::config->GetValue("mysql_password"); + std::string mysql_host = config.GetValue("mysql_host"); + std::string mysql_database = config.GetValue("mysql_database"); + std::string mysql_username = config.GetValue("mysql_username"); + std::string mysql_password = config.GetValue("mysql_password"); - Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1"); + Diagnostics::SetProduceMemoryDump(config.GetValue("generate_dump") == "1"); - if (!Game::config->GetValue("dump_folder").empty()) { - Diagnostics::SetOutDirectory(Game::config->GetValue("dump_folder")); + if (!config.GetValue("dump_folder").empty()) { + Diagnostics::SetOutDirectory(config.GetValue("dump_folder")); } try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); } catch (sql::SQLException& ex) { Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s", ex.what()); - return EXIT_FAILURE; + return 0; } //Find out the master's IP: @@ -198,13 +206,13 @@ int main(int argc, char** argv) { ObjectIDManager::Instance()->Initialize(); UserManager::Instance()->Initialize(); LootGenerator::Instance(); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); - Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, zoneID); + Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, Game::shouldShutdown, zoneID); //Connect to the chat server: int chatPort = 1501; - if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); + if (config.GetValue("chat_server_port") != "") chatPort = std::atoi(config.GetValue("chat_server_port").c_str()); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); Game::chatServer = RakNetworkFactory::GetRakPeerInterface(); @@ -315,9 +323,9 @@ int main(int argc, char** argv) { framesSinceMasterDisconnect++; int framesToWaitForMaster = ready ? 10 : 200; - if (framesSinceMasterDisconnect >= framesToWaitForMaster && !worldShutdownSequenceStarted) { + if (framesSinceMasterDisconnect >= framesToWaitForMaster && !Game::shouldShutdown) { Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", framesToWaitForMaster); - worldShutdownSequenceStarted = true; + Game::shouldShutdown = true; } } else framesSinceMasterDisconnect = 0; @@ -413,7 +421,7 @@ int main(int argc, char** argv) { //If we haven't had any players for a while, time out and shut down: if (framesSinceLastUser == (cloneID != 0 ? 4000 : 40000)) { - worldShutdownSequenceStarted = true; + Game::shouldShutdown = true; } } else { framesSinceLastUser = 0; @@ -470,7 +478,7 @@ int main(int argc, char** argv) { } } - if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete) { + if (Game::shouldShutdown && !worldShutdownSequenceComplete) { WorldShutdownProcess(zoneID); break; } @@ -789,7 +797,7 @@ void HandlePacket(Packet* packet) { } case MSG_MASTER_SHUTDOWN: { - worldShutdownSequenceStarted = true; + Game::shouldShutdown = true; Game::logger->Log("WorldServer", "Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); break; } @@ -1259,11 +1267,11 @@ void WorldShutdownProcess(uint32_t zoneId) { } void WorldShutdownSequence() { - if (worldShutdownSequenceStarted || worldShutdownSequenceComplete) { + if (Game::shouldShutdown || worldShutdownSequenceComplete) { return; } - worldShutdownSequenceStarted = true; + Game::shouldShutdown = true; Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!", Game::server->GetZoneID(), instanceID); WorldShutdownProcess(Game::server->GetZoneID()); @@ -1271,15 +1279,16 @@ void WorldShutdownSequence() { } void FinalizeShutdown() { + //Delete our objects here: + if (Game::zoneManager) delete Game::zoneManager; + Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)", Game::server->GetZoneID(), instanceID); - //Delete our objects here: Metrics::Clear(); Database::Destroy("WorldServer"); - if (Game::chatFilter) delete Game::chatFilter; - if (Game::server) delete Game::server; - if (Game::logger) delete Game::logger; - if (Game::config) delete Game::config; + delete Game::chatFilter; + delete Game::server; + delete Game::logger; worldShutdownSequenceComplete = true; diff --git a/tests/dGameTests/GameDependencies.cpp b/tests/dGameTests/GameDependencies.cpp index 7b0a8412..5ac3339a 100644 --- a/tests/dGameTests/GameDependencies.cpp +++ b/tests/dGameTests/GameDependencies.cpp @@ -4,6 +4,7 @@ namespace Game { dLogger* logger; dServer* server; dZoneManager* zoneManager; + dpWorld* physicsWorld; dChatFilter* chatFilter; dConfig* config; std::mt19937 randomEngine; From 1afe71756332574988eea8fcc4f5979450c0faa4 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 15 Dec 2022 05:46:03 -0800 Subject: [PATCH 04/63] Properly exit Properly exit based on the path taken to shutdown master. Tested that shutting down through sigint or sigterm returns -1 Tested that a segfault exits the program properly Need to test that players who are trying to connect while master is shutting down are not able to spawn more child worlds. --- dAuthServer/AuthServer.cpp | 2 +- dChatServer/ChatServer.cpp | 2 +- dMasterServer/InstanceManager.cpp | 2 +- dMasterServer/MasterServer.cpp | 82 ++++++++++++++++++++++--------- dNet/dServer.cpp | 4 +- dNet/dServer.h | 2 +- dWorldServer/WorldServer.cpp | 2 +- 7 files changed, 65 insertions(+), 31 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 4fffc5d0..092b7fa4 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -84,7 +84,7 @@ int main(int argc, char** argv) { if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); - Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, Game::shouldShutdown); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index d2eb7fc7..ace5e287 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -104,7 +104,7 @@ int main(int argc, char** argv) { if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, Game::shouldShutdown); + Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 327a18b9..de64c4ba 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -150,7 +150,7 @@ void InstanceManager::RemoveInstance(Instance* instance) { if (m_Instances[i] == instance) { instance->SetShutdownComplete(true); - RedirectPendingRequests(instance); + if (!Game::shouldShutdown) RedirectPendingRequests(instance); delete m_Instances[i]; diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 2f54243a..388654f5 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -52,13 +52,14 @@ namespace Game { } //namespace Game bool shutdownSequenceStarted = false; -void ShutdownSequence(); -int FinalizeShutdown(); +void ShutdownSequence(int signal = -1); +int FinalizeShutdown(int signal = -1); dLogger* SetupLogger(); void StartAuthServer(); void StartChatServer(); void HandlePacket(Packet* packet); std::map activeSessions; +SystemAddress authServerMasterPeerSysAddr; SystemAddress chatServerMasterPeerSysAddr; int main(int argc, char** argv) { @@ -71,9 +72,9 @@ int main(int argc, char** argv) { #endif //Triggers the shutdown sequence at application exit - std::atexit(ShutdownSequence); - signal(SIGINT, [](int) { ShutdownSequence(); }); - signal(SIGTERM, [](int) { ShutdownSequence(); }); + std::atexit([]() { ShutdownSequence(); }); + signal(SIGINT, [](int signal) { ShutdownSequence(EXIT_FAILURE); }); + signal(SIGTERM, [](int signal) { ShutdownSequence(EXIT_FAILURE); }); //Create all the objects we need to run our service: Game::logger = SetupLogger(); @@ -216,7 +217,7 @@ int main(int argc, char** argv) { if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port")); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, Game::shouldShutdown); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::shouldShutdown); //Query for the database for a server labeled "master" auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); @@ -253,8 +254,8 @@ int main(int argc, char** argv) { if (Game::config->GetValue("prestart_servers") != "" && Game::config->GetValue("prestart_servers") == "1") { StartChatServer(); - Game::im->GetInstance(0, false, 0)->SetIsReady(true); - Game::im->GetInstance(1000, false, 0)->SetIsReady(true); + Game::im->GetInstance(0, false, 0); + Game::im->GetInstance(1000, false, 0); StartAuthServer(); } @@ -350,9 +351,7 @@ int main(int argc, char** argv) { t += std::chrono::milliseconds(highFrameRate); std::this_thread::sleep_until(t); } - FinalizeShutdown(); - exit(EXIT_SUCCESS); - return EXIT_SUCCESS; + return FinalizeShutdown(EXIT_SUCCESS); } dLogger* SetupLogger() { @@ -381,9 +380,15 @@ void HandlePacket(Packet* packet) { Game::im->RemoveInstance(instance); //Delete the old } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr) { + chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; StartChatServer(); } + + if (packet->systemAddress == authServerMasterPeerSysAddr) { + authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; + StartAuthServer(); + } } if (packet->data[0] == ID_CONNECTION_LOST) { @@ -397,9 +402,15 @@ void HandlePacket(Packet* packet) { //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr) { + chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; StartChatServer(); } + + if (packet->systemAddress == authServerMasterPeerSysAddr) { + authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; + StartAuthServer(); + } } if (packet->data[1] == MASTER) { @@ -495,6 +506,14 @@ void HandlePacket(Packet* packet) { chatServerMasterPeerSysAddr = copy; } + if (theirServerType == ServerType::Auth) { + SystemAddress copy; + copy.binaryAddress = packet->systemAddress.binaryAddress; + copy.port = packet->systemAddress.port; + + authServerMasterPeerSysAddr = copy; + } + Game::logger->Log("MasterServer", "Received server info, instance: %i port: %i", theirInstanceID, theirPort); break; @@ -726,10 +745,14 @@ void HandlePacket(Packet* packet) { default: Game::logger->Log("MasterServer", "Unknown master packet ID from server: %i", packet->data[3]); } + } } -} void StartChatServer() { + if (Game::shouldShutdown) { + Game::logger->Log("MasterServer", "Currently shutting down. Chat will not be restarted."); + return; + } #ifdef __APPLE__ //macOS doesn't need sudo to run on ports < 1024 system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); @@ -742,9 +765,13 @@ void StartChatServer() { system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } #endif -} + } void StartAuthServer() { + if (Game::shouldShutdown) { + Game::logger->Log("MasterServer", "Currently shutting down. Auth will not be restarted."); + return; + } #ifdef __APPLE__ system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); #elif _WIN32 @@ -758,12 +785,13 @@ void StartAuthServer() { #endif } -void ShutdownSequence() { +void ShutdownSequence(int signal) { if (shutdownSequenceStarted) { return; } shutdownSequenceStarted = true; + Game::shouldShutdown = true; { CBITSTREAM; @@ -782,7 +810,14 @@ void ShutdownSequence() { auto ticks = 0; if (!Game::im) { - exit(EXIT_SUCCESS); + FinalizeShutdown(EXIT_FAILURE); + } + + // A server might not be finished spinning up yet, remove all of those here. + for (auto instance : Game::im->GetInstances()) { + if (!instance->GetIsReady()) { + Game::im->RemoveInstance(instance); + } } for (auto instance : Game::im->GetInstances()) { @@ -792,7 +827,6 @@ void ShutdownSequence() { Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); while (true) { - auto packet = Game::server->Receive(); if (packet) { HandlePacket(packet); @@ -811,8 +845,8 @@ void ShutdownSequence() { done = false; } } - - if (done) { + + if (done && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) { Game::logger->Log("MasterServer", "Finished shutting down MasterServer!"); break; } @@ -828,10 +862,10 @@ void ShutdownSequence() { } } - FinalizeShutdown(); + FinalizeShutdown(signal); } -int FinalizeShutdown() { +int FinalizeShutdown(int signal) { //Delete our objects here: Database::Destroy("MasterServer"); if (Game::config) delete Game::config; @@ -839,6 +873,6 @@ int FinalizeShutdown() { if (Game::server) delete Game::server; if (Game::logger) delete Game::logger; - exit(EXIT_SUCCESS); - return EXIT_SUCCESS; + if (signal != EXIT_SUCCESS) exit(signal); + return signal; } diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 3a5ef822..f41b9699 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -36,7 +36,7 @@ public: } } ReceiveDownloadCompleteCB; -dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool& shouldShutdown, unsigned int zoneID) { +dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool* shouldShutdown, unsigned int zoneID) { mIP = ip; mPort = port; mZoneID = zoneID; @@ -52,7 +52,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect mReplicaManager = nullptr; mServerType = serverType; mConfig = config; - mShouldShutdown = &shouldShutdown; + mShouldShutdown = shouldShutdown; //Attempt to start our server here: mIsOkay = Startup(); diff --git a/dNet/dServer.h b/dNet/dServer.h index 608b3b83..af4c8322 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -30,7 +30,7 @@ public: int masterPort, ServerType serverType, dConfig* config, - bool& shouldShutdown, + bool* shouldShutdown, unsigned int zoneID = 0); ~dServer(); diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 2fdb373b..abb2c19f 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -208,7 +208,7 @@ int main(int argc, char** argv) { LootGenerator::Instance(); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); - Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, Game::shouldShutdown, zoneID); + Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::shouldShutdown, zoneID); //Connect to the chat server: int chatPort = 1501; From b7341c8106bf030813a408ebeae74e92ef212d1e Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 15 Dec 2022 06:13:49 -0800 Subject: [PATCH 05/63] Resolve warnings, change config init order and remove unused Game variables for all servers (#877) * Resolve warnings and change init order Initialize dConfig first, before logger so we know whether or not to log to console Initialize namespace Game variables to nullptr so they are a known value if accessed before initialization. Removed unused Game variables Replaced config with a pointer instead of referencing something on the stack. Assign return values to system calls to silence warnings. Tested that the server still compiles, runs and allows me to load into the game. * Only start Master of config files exist Also default the logging to console to on on the off chance the files exist but are wrong / corrupted. --- dAuthServer/AuthServer.cpp | 38 +++++++------- dChatServer/ChatServer.cpp | 46 ++++++++--------- dCommon/Game.h | 2 - dMasterServer/InstanceManager.cpp | 4 +- dMasterServer/MasterServer.cpp | 59 +++++++++++++++------- dWorldServer/WorldServer.cpp | 71 ++++++++++++--------------- tests/dGameTests/GameDependencies.cpp | 1 - 7 files changed, 117 insertions(+), 104 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index a9f02f53..aefc822b 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -22,9 +22,9 @@ #include "Game.h" namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; } dLogger* SetupLogger(); @@ -37,22 +37,22 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("AuthServer", "Starting Auth server..."); Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__); - //Read our config: - dConfig config("authconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -61,7 +61,7 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; - return 0; + return EXIT_FAILURE; } //Find out the master's IP: @@ -80,10 +80,10 @@ int main(int argc, char** argv) { //It's safe to pass 'localhost' here, as the IP is only used as the external IP. int maxClients = 50; int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); @@ -145,8 +145,8 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index e3c6d6e9..043e7869 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -20,11 +20,11 @@ #include "Game.h" namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; - dChatFilter* chatFilter; - AssetManager* assetManager; + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; + dChatFilter* chatFilter = nullptr; + AssetManager* assetManager = nullptr; } //RakNet includes: @@ -42,19 +42,19 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("ChatServer", "Starting Chat server..."); Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__); - //Read our config: - dConfig config("chatconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - try { - std::string clientPathStr = config.GetValue("client_location"); + std::string clientPathStr = Game::config->GetValue("client_location"); if (clientPathStr.empty()) clientPathStr = "./res"; std::filesystem::path clientPath = std::filesystem::path(clientPathStr); if (clientPath.is_relative()) { @@ -69,10 +69,10 @@ int main(int argc, char** argv) { } //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -81,7 +81,7 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; - return 0; + return EXIT_FAILURE; } //Find out the master's IP: @@ -100,12 +100,12 @@ int main(int argc, char** argv) { //It's safe to pass 'localhost' here, as the IP is only used as the external IP. int maxClients = 50; int ourPort = 1501; - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); @@ -167,8 +167,8 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } diff --git a/dCommon/Game.h b/dCommon/Game.h index 1c4bbc85..38cadb70 100644 --- a/dCommon/Game.h +++ b/dCommon/Game.h @@ -5,7 +5,6 @@ class dServer; class dLogger; class InstanceManager; -class dpWorld; class dChatFilter; class dConfig; class RakPeerInterface; @@ -16,7 +15,6 @@ namespace Game { extern dLogger* logger; extern dServer* server; extern InstanceManager* im; - extern dpWorld* physicsWorld; extern dChatFilter* chatFilter; extern dConfig* config; extern std::mt19937 randomEngine; diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 83378dbb..a1983dd4 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -74,7 +74,7 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); m_Instances.push_back(instance); @@ -322,7 +322,7 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); m_Instances.push_back(instance); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 4acb9b26..4c18566e 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -43,11 +43,11 @@ #include "FdbToSqlite.h" namespace Game { - dLogger* logger; - dServer* server; - InstanceManager* im; - dConfig* config; - AssetManager* assetManager; + dLogger* logger = nullptr; + dServer* server = nullptr; + InstanceManager* im = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; } //namespace Game bool shutdownSequenceStarted = false; @@ -79,14 +79,39 @@ int main(int argc, char** argv) { Game::logger = SetupLogger(); if (!Game::logger) return EXIT_FAILURE; + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "authconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find authconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "chatconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find chatconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "masterconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find masterconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find sharedconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "worldconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find worldconfig.ini"); + return EXIT_FAILURE; + } + + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "masterconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("MasterServer", "Starting Master server..."); Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__); - Game::config = new dConfig("masterconfig.ini"); - Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); - //Connect to the MySQL Database std::string mysql_host = Game::config->GetValue("mysql_host"); std::string mysql_database = Game::config->GetValue("mysql_database"); @@ -732,28 +757,28 @@ void HandlePacket(Packet* packet) { void StartChatServer() { #ifdef __APPLE__ //macOS doesn't need sudo to run on ports < 1024 - system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); #elif _WIN32 - system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { - system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } else { - system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } #endif } void StartAuthServer() { #ifdef __APPLE__ - system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); #elif _WIN32 - system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { - system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } else { - system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } #endif } diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index acd38ad3..68ec0e57 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -61,17 +61,14 @@ #include "ZCompression.h" namespace Game { - dLogger* logger; - dServer* server; - dZoneManager* zoneManager; - dpWorld* physicsWorld; - dChatFilter* chatFilter; - dConfig* config; + dLogger* logger = nullptr; + dServer* server = nullptr; + dpWorld* physicsWorld = nullptr; + dChatFilter* chatFilter = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; + RakPeerInterface* chatServer = nullptr; std::mt19937 randomEngine; - - AssetManager* assetManager; - - RakPeerInterface* chatServer; SystemAddress chatSysAddr; } @@ -127,26 +124,21 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(zoneID, instanceID); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "worldconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); - Game::logger->SetLogToConsole(true); //We want this info to always be logged. Game::logger->Log("WorldServer", "Starting World server..."); Game::logger->Log("WorldServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("WorldServer", "Compiled on: %s", __TIMESTAMP__); -#ifndef _DEBUG - Game::logger->SetLogToConsole(false); //By default, turn it back off if not in debug. -#endif - - //Read our config: - dConfig config("worldconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - if (config.GetValue("disable_chat") == "1") chatDisabled = true; + if (Game::config->GetValue("disable_chat") == "1") chatDisabled = true; try { - std::string clientPathStr = config.GetValue("client_location"); + std::string clientPathStr = Game::config->GetValue("client_location"); if (clientPathStr.empty()) clientPathStr = "./res"; std::filesystem::path clientPath = std::filesystem::path(clientPathStr); if (clientPath.is_relative()) { @@ -166,28 +158,28 @@ int main(int argc, char** argv) { Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); - return -1; + return EXIT_FAILURE; } CDClientManager::Instance()->Initialize(); //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); - Diagnostics::SetProduceMemoryDump(config.GetValue("generate_dump") == "1"); + Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1"); - if (!config.GetValue("dump_folder").empty()) { - Diagnostics::SetOutDirectory(config.GetValue("dump_folder")); + if (!Game::config->GetValue("dump_folder").empty()) { + Diagnostics::SetOutDirectory(Game::config->GetValue("dump_folder")); } try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); } catch (sql::SQLException& ex) { Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s", ex.what()); - return 0; + return EXIT_FAILURE; } //Find out the master's IP: @@ -206,13 +198,13 @@ int main(int argc, char** argv) { ObjectIDManager::Instance()->Initialize(); UserManager::Instance()->Initialize(); LootGenerator::Instance(); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, zoneID); //Connect to the chat server: int chatPort = 1501; - if (config.GetValue("chat_server_port") != "") chatPort = std::atoi(config.GetValue("chat_server_port").c_str()); + if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); Game::chatServer = RakNetworkFactory::GetRakPeerInterface(); @@ -1279,16 +1271,15 @@ void WorldShutdownSequence() { } void FinalizeShutdown() { - //Delete our objects here: - if (Game::zoneManager) delete Game::zoneManager; - Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)", Game::server->GetZoneID(), instanceID); + //Delete our objects here: Metrics::Clear(); Database::Destroy("WorldServer"); - delete Game::chatFilter; - delete Game::server; - delete Game::logger; + if (Game::chatFilter) delete Game::chatFilter; + if (Game::server) delete Game::server; + if (Game::logger) delete Game::logger; + if (Game::config) delete Game::config; worldShutdownSequenceComplete = true; diff --git a/tests/dGameTests/GameDependencies.cpp b/tests/dGameTests/GameDependencies.cpp index 5ac3339a..7b0a8412 100644 --- a/tests/dGameTests/GameDependencies.cpp +++ b/tests/dGameTests/GameDependencies.cpp @@ -4,7 +4,6 @@ namespace Game { dLogger* logger; dServer* server; dZoneManager* zoneManager; - dpWorld* physicsWorld; dChatFilter* chatFilter; dConfig* config; std::mt19937 randomEngine; From 4775dbf27f6d82b31dbe33fa83b82ecaf8d4fce4 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 15 Dec 2022 19:55:07 -0800 Subject: [PATCH 06/63] Condense frame rates --- dAuthServer/AuthServer.cpp | 2 +- dChatServer/ChatServer.cpp | 2 +- dCommon/dEnums/dCommonVars.h | 15 +++++++++++---- dMasterServer/MasterServer.cpp | 4 ++-- dWorldServer/PerformanceManager.cpp | 26 +++++++------------------- dWorldServer/PerformanceManager.h | 5 ----- dWorldServer/WorldServer.cpp | 4 ++-- 7 files changed, 24 insertions(+), 34 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 3fd4b0bf..e4d8a052 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -138,7 +138,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Auth can run at a lower "fps" + t += std::chrono::milliseconds(mediumFrameDelta); //Auth can run at a lower "fps" std::this_thread::sleep_until(t); } diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index f3b2c123..8ae1a9bd 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -160,7 +160,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Chat can run at a lower "fps" + t += std::chrono::milliseconds(mediumFrameDelta); //Chat can run at a lower "fps" std::this_thread::sleep_until(t); } diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index f64d496f..f3d02bf7 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -6,15 +6,22 @@ #include #include #include -#include "../thirdparty/raknet/Source/BitStream.h" +#include "BitStream.h" #pragma warning (disable:4251) //Disables SQL warnings typedef int RESTICKET; -const int highFrameRate = 16; //60fps -const int mediumFramerate = 33; //30fps -const int lowFramerate = 66; //15fps +#define FRAMES_TO_MS(x) 1000 / x + +//=========== FRAME TIMINGS =========== +constexpr uint32_t highFramerate = 60; +constexpr uint32_t mediumFramerate = 30; +constexpr uint32_t lowFramerate = 15; + +constexpr uint32_t highFrameDelta = FRAMES_TO_MS(highFramerate); +constexpr uint32_t mediumFrameDelta = FRAMES_TO_MS(mediumFramerate); +constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate); //========== MACROS =========== diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index bfe9f323..49919568 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -373,7 +373,7 @@ int main(int argc, char** argv) { } } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(highFrameDelta); std::this_thread::sleep_until(t); } return FinalizeShutdown(EXIT_SUCCESS); @@ -876,7 +876,7 @@ void ShutdownSequence(int signal) { break; } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(highFrameDelta); std::this_thread::sleep_until(t); ticks++; diff --git a/dWorldServer/PerformanceManager.cpp b/dWorldServer/PerformanceManager.cpp index 85546f28..66dcb615 100644 --- a/dWorldServer/PerformanceManager.cpp +++ b/dWorldServer/PerformanceManager.cpp @@ -2,23 +2,18 @@ #include "UserManager.h" -//Times are 1 / fps, in ms -#define HIGH 16 //60 fps -#define MEDIUM 33 //30 fps -#define LOW 66 //15 fps - -#define SOCIAL { LOW } -#define SOCIAL_HUB { MEDIUM } //Added to compensate for the large playercounts in NS and NT -#define BATTLE { HIGH } -#define BATTLE_INSTANCE { MEDIUM } -#define RACE { HIGH } -#define PROPERTY { LOW } +#define SOCIAL { lowFrameDelta } +#define SOCIAL_HUB { mediumFrameDelta } //Added to compensate for the large playercounts in NS and NT +#define BATTLE { highFrameDelta } +#define BATTLE_INSTANCE { mediumFrameDelta } +#define RACE { highFrameDelta } +#define PROPERTY { lowFrameDelta } PerformanceProfile PerformanceManager::m_CurrentProfile = SOCIAL; PerformanceProfile PerformanceManager::m_DefaultProfile = SOCIAL; -PerformanceProfile PerformanceManager::m_InactiveProfile = { LOW }; +PerformanceProfile PerformanceManager::m_InactiveProfile = { lowFrameDelta }; std::map PerformanceManager::m_Profiles = { // VE @@ -72,13 +67,6 @@ std::map PerformanceManager::m_Profiles = { { 2001, BATTLE_INSTANCE }, }; - -PerformanceManager::PerformanceManager() { -} - -PerformanceManager::~PerformanceManager() { -} - void PerformanceManager::SelectProfile(LWOMAPID mapID) { const auto pair = m_Profiles.find(mapID); diff --git a/dWorldServer/PerformanceManager.h b/dWorldServer/PerformanceManager.h index b8a090e0..3d8517eb 100644 --- a/dWorldServer/PerformanceManager.h +++ b/dWorldServer/PerformanceManager.h @@ -8,18 +8,13 @@ struct PerformanceProfile { uint32_t serverFramerate; }; - class PerformanceManager { public: - ~PerformanceManager(); - static void SelectProfile(LWOMAPID mapID); static uint32_t GetServerFramerate(); private: - PerformanceManager(); - static PerformanceProfile m_CurrentProfile; static PerformanceProfile m_DefaultProfile; static PerformanceProfile m_InactiveProfile; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 594d3dc7..c531595f 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -232,7 +232,7 @@ int main(int argc, char** argv) { bool ready = false; int framesSinceMasterStatus = 0; int framesSinceShutdownSequence = 0; - int currentFramerate = highFrameRate; + int currentFramerate = highFrameDelta; int ghostingStepCount = 0; auto ghostingLastTime = std::chrono::high_resolution_clock::now(); @@ -300,7 +300,7 @@ int main(int argc, char** argv) { const auto occupied = UserManager::Instance()->GetUserCount() != 0; if (!ready) { - currentFramerate = highFrameRate; + currentFramerate = highFrameDelta; } else { currentFramerate = PerformanceManager::GetServerFramerate(); } From 3c581fffbbb67c414add2be5afccb76c24ff42b6 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 15 Dec 2022 20:39:29 -0800 Subject: [PATCH 07/63] Remove magic numbers Replace magic numbers with constexpr calculated times. Tested that trying to create a new instance while shutting down doesn't allow a new instance to be created. --- dMasterServer/InstanceManager.cpp | 20 +++++++- dMasterServer/InstanceManager.h | 6 +++ dMasterServer/MasterServer.cpp | 81 ++++++++++++++++++------------- 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 868bf6ee..b277adbf 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -31,6 +31,15 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW Instance* instance = FindInstance(mapID, isFriendTransfer, cloneID); if (instance) return instance; + // If we are shutting down, return a nullptr so a new instance is not created. + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } //TODO: Update this so that the IP is read from a configuration file instead int softCap = 8; @@ -238,7 +247,7 @@ void InstanceManager::RedirectPendingRequests(Instance* instance) { for (const auto& request : instance->GetPendingAffirmations()) { auto* in = Game::im->GetInstance(zoneId.GetMapID(), false, zoneId.GetCloneID()); - if (!in->GetIsReady()) // Instance not ready, make a pending request + if (in && !in->GetIsReady()) // Instance not ready, make a pending request { in->GetPendingRequests().push_back(request); @@ -295,6 +304,15 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon return instance; } + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new private instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } + int maxPlayers = 999; uint32_t port = GetFreePort(); diff --git a/dMasterServer/InstanceManager.h b/dMasterServer/InstanceManager.h index 2c5083d4..5f48f93b 100644 --- a/dMasterServer/InstanceManager.h +++ b/dMasterServer/InstanceManager.h @@ -128,6 +128,7 @@ public: Instance* CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password); Instance* FindPrivateInstance(const std::string& password); + void SetIsShuttingDown(bool value) { this->m_IsShuttingDown = value; }; private: dLogger* mLogger; @@ -136,6 +137,11 @@ private: unsigned short m_LastPort; LWOINSTANCEID m_LastInstanceID; + /** + * Whether or not the master server is currently shutting down. + */ + bool m_IsShuttingDown = false; + //Private functions: bool IsInstanceFull(Instance* instance, bool isFriendTransfer); int GetSoftCap(LWOMAPID mapID); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 49919568..ed94ff83 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -63,6 +63,8 @@ SystemAddress authServerMasterPeerSysAddr; SystemAddress chatServerMasterPeerSysAddr; int main(int argc, char** argv) { + constexpr uint32_t masterFramerate = mediumFramerate; + constexpr uint32_t masterFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Master"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -287,6 +289,10 @@ int main(int argc, char** argv) { auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; + constexpr uint32_t logFlushTime = 15 * masterFramerate; + constexpr uint32_t sqlPingTime = 10 * 60 * masterFramerate; + constexpr uint32_t shutdownUniverseTime = 10 * 60 * masterFramerate; + constexpr uint32_t instanceReadyTimeout = 30 * masterFramerate; int framesSinceLastFlush = 0; int framesSinceLastSQLPing = 0; int framesSinceKillUniverseCommand = 0; @@ -303,14 +309,14 @@ int main(int argc, char** argv) { } //Push our log every 15s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; int masterPort; @@ -330,7 +336,7 @@ int main(int argc, char** argv) { //10m shutdown for universe kill command if (Game::shouldShutdown) { - if (framesSinceKillUniverseCommand >= 40000) { + if (framesSinceKillUniverseCommand >= shutdownUniverseTime) { //Break main loop and exit break; } else @@ -354,7 +360,7 @@ int main(int argc, char** argv) { instance->SetAffirmationTimeout(affirmTimeout); - if (affirmTimeout == 1000) { + if (affirmTimeout == instanceReadyTimeout) { instance->Shutdown(); instance->SetIsShuttingDown(true); @@ -373,7 +379,7 @@ int main(int argc, char** argv) { } } - t += std::chrono::milliseconds(highFrameDelta); + t += std::chrono::milliseconds(masterFrameDelta); std::this_thread::sleep_until(t); } return FinalizeShutdown(EXIT_SUCCESS); @@ -424,7 +430,6 @@ void HandlePacket(Packet* packet) { if (instance) { LWOZONEID zoneID = instance->GetZoneID(); //Get the zoneID so we can recreate a server Game::im->RemoveInstance(instance); //Delete the old - //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new } if (packet->systemAddress == chatServerMasterPeerSysAddr) { @@ -465,14 +470,17 @@ void HandlePacket(Packet* packet) { inStream.Read(mythranShift); inStream.Read(zoneID); inStream.Read(zoneClone); - + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not creating a new zone."); + break; + } Instance* in = Game::im->GetInstance(zoneID, false, zoneClone); for (auto* instance : Game::im->GetInstances()) { Game::logger->Log("MasterServer", "Instance: %i/%i/%i -> %i", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance == in); } - if (!in->GetIsReady()) //Instance not ready, make a pending request + if (in && !in->GetIsReady()) //Instance not ready, make a pending request { in->GetPendingRequests().push_back({ requestID, static_cast(mythranShift), packet->systemAddress }); Game::logger->Log("MasterServer", "Server not ready, adding pending request %llu %i %i", requestID, zoneID, zoneClone); @@ -720,9 +728,13 @@ void HandlePacket(Packet* packet) { int zoneID; inStream.Read(zoneID); - - Game::logger->Log("MasterServer", "Prepping zone %i", zoneID); - Game::im->GetInstance(zoneID, false, 0); + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not prepping a new zone."); + break; + } else { + Game::logger->Log("MasterServer", "Prepping zone %i", zoneID); + Game::im->GetInstance(zoneID, false, 0); + } break; } @@ -770,8 +782,8 @@ void HandlePacket(Packet* packet) { default: Game::logger->Log("MasterServer", "Unknown master packet ID from server: %i", packet->data[3]); } - } } +} void StartChatServer() { if (Game::shouldShutdown) { @@ -788,9 +800,9 @@ void StartChatServer() { auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } else { auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); - } +} #endif - } +} void StartAuthServer() { if (Game::shouldShutdown) { @@ -806,7 +818,7 @@ void StartAuthServer() { auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } else { auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); - } +} #endif } @@ -815,6 +827,11 @@ void ShutdownSequence(int signal) { return; } + if (!Game::im) { + FinalizeShutdown(EXIT_FAILURE); + } + + Game::im->SetIsShuttingDown(true); shutdownSequenceStarted = true; Game::shouldShutdown = true; @@ -826,40 +843,38 @@ void ShutdownSequence(int signal) { } auto* objIdManager = ObjectIDManager::TryInstance(); - if (objIdManager != nullptr) { + if (objIdManager) { objIdManager->SaveToDatabase(); Game::logger->Log("MasterServer", "Saved ObjectIDTracker to DB"); } - auto t = std::chrono::high_resolution_clock::now(); - auto ticks = 0; - - if (!Game::im) { - FinalizeShutdown(EXIT_FAILURE); - } - // A server might not be finished spinning up yet, remove all of those here. - for (auto instance : Game::im->GetInstances()) { + for (auto* instance : Game::im->GetInstances()) { if (!instance->GetIsReady()) { Game::im->RemoveInstance(instance); } } - for (auto instance : Game::im->GetInstances()) { + for (auto* instance : Game::im->GetInstances()) { instance->SetIsShuttingDown(true); } Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); + auto t = std::chrono::high_resolution_clock::now(); + uint32_t framesSinceShutdownStart = 0; + constexpr uint32_t maxShutdownTime = 60 * mediumFramerate; + bool allInstancesShutdown = false; + Packet* packet = nullptr; while (true) { - auto packet = Game::server->Receive(); + packet = Game::server->Receive(); if (packet) { HandlePacket(packet); Game::server->DeallocatePacket(packet); packet = nullptr; } - auto done = true; + allInstancesShutdown = true; for (auto* instance : Game::im->GetInstances()) { if (instance == nullptr) { @@ -867,21 +882,21 @@ void ShutdownSequence(int signal) { } if (!instance->GetShutdownComplete()) { - done = false; + allInstancesShutdown = false; } } - - if (done && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) { + + if (allInstancesShutdown && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) { Game::logger->Log("MasterServer", "Finished shutting down MasterServer!"); break; } - t += std::chrono::milliseconds(highFrameDelta); + t += std::chrono::milliseconds(mediumFrameDelta); std::this_thread::sleep_until(t); - ticks++; + framesSinceShutdownStart++; - if (ticks == 600 * 6) { + if (framesSinceShutdownStart == maxShutdownTime) { Game::logger->Log("MasterServer", "Finished shutting down by timeout!"); break; } From 213c3c37b0ac03d9ee6ffeb76e69e4f8dc5617e9 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 15 Dec 2022 22:10:58 -0800 Subject: [PATCH 08/63] Fix crash in BasicAttackBehavior (#862) * Add failArmor server side Address out of bounds reading in behavior Address the basicAttackBehavior reading out of bounds memory and reading bits that didnt exist, which occasionally caused crashes and also caused the behavior to do undefined behavior due to the bad reads. Tested that attacking a wall anywhere with a projectile now does not crash the game. Tested with logs that the behavior correctly returned when there were no allocated bits or returned when other states were met. Add back logs and add fail handle Remove comment block Revert "Add back logs and add fail handle" This reverts commit db19be0906fc8bf35bf89037e2bfba39f5ef9c0c. Split out checks * Remove case 2 * Update SkillComponent.cpp --- dGame/dBehaviors/BasicAttackBehavior.cpp | 85 ++++++++++++++++-------- dGame/dBehaviors/BasicAttackBehavior.h | 14 ++-- dGame/dComponents/SkillComponent.cpp | 29 +------- 3 files changed, 65 insertions(+), 63 deletions(-) diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index fe773f36..f166f00c 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -14,43 +14,65 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi auto* destroyableComponent = entity->GetComponent(); if (destroyableComponent != nullptr) { PlayFx(u"onhit", entity->GetObjectID()); - destroyableComponent->Damage(this->m_maxDamage, context->originator, context->skillID); + destroyableComponent->Damage(this->m_MaxDamage, context->originator, context->skillID); } - this->m_onSuccess->Handle(context, bitStream, branch); + this->m_OnSuccess->Handle(context, bitStream, branch); return; } bitStream->AlignReadToByteBoundary(); - uint16_t allocatedBits; - bitStream->Read(allocatedBits); - + uint16_t allocatedBits{}; + if (!bitStream->Read(allocatedBits) || allocatedBits == 0) { + Game::logger->LogDebug("BasicAttackBehavior", "No allocated bits"); + return; + } + Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits); const auto baseAddress = bitStream->GetReadOffset(); - if (bitStream->ReadBit()) { // Blocked + bool isBlocked{}; + bool isImmune{}; + bool isSuccess{}; + + if (!bitStream->Read(isBlocked)) { + Game::logger->LogDebug("BasicAttackBehavior", "Unable to read isBlocked"); return; } - if (bitStream->ReadBit()) { // Immune + if (isBlocked) return; + + if (!bitStream->Read(isImmune)) { + Game::logger->LogDebug("BasicAttackBehavior", "Unable to read isImmune"); return; } - if (bitStream->ReadBit()) { // Success - uint32_t unknown; - bitStream->Read(unknown); + if (isImmune) return; - uint32_t damageDealt; - bitStream->Read(damageDealt); + if (bitStream->Read(isSuccess) && isSuccess) { // Success + uint32_t unknown{}; + if (!bitStream->Read(unknown)) { + Game::logger->LogDebug("BasicAttackBehavior", "Unable to read unknown"); + return; + } + + uint32_t damageDealt{}; + if (!bitStream->Read(damageDealt)) { + Game::logger->LogDebug("BasicAttackBehavior", "Unable to read damageDealt"); + return; + } // A value that's too large may be a cheating attempt, so we set it to MIN too - if (damageDealt > this->m_maxDamage || damageDealt < this->m_minDamage) { - damageDealt = this->m_minDamage; + if (damageDealt > this->m_MaxDamage || damageDealt < this->m_MinDamage) { + damageDealt = this->m_MinDamage; } auto* entity = EntityManager::Instance()->GetEntity(branch.target); - bool died; - bitStream->Read(died); + bool died{}; + if (!bitStream->Read(died)) { + Game::logger->LogDebug("BasicAttackBehavior", "Unable to read died"); + return; + } if (entity != nullptr) { auto* destroyableComponent = entity->GetComponent(); @@ -61,15 +83,18 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi } } - uint8_t successState; - bitStream->Read(successState); + uint8_t successState{}; + if (!bitStream->Read(successState)) { + Game::logger->LogDebug("BasicAttackBehavior", "Unable to read success state"); + return; + } switch (successState) { case 1: - this->m_onSuccess->Handle(context, bitStream, branch); + this->m_OnSuccess->Handle(context, bitStream, branch); break; default: - Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + Game::logger->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState); break; } @@ -79,7 +104,7 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* self = EntityManager::Instance()->GetEntity(context->originator); if (self == nullptr) { - Game::logger->Log("BasicAttackBehavior", "Invalid self entity (%llu)!", context->originator); + Game::logger->LogDebug("BasicAttackBehavior", "Invalid self entity (%llu)!", context->originator); return; } @@ -99,7 +124,7 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* uint32_t unknown3 = 0; bitStream->Write(unknown3); - auto damage = this->m_minDamage; + auto damage = this->m_MinDamage; auto* entity = EntityManager::Instance()->GetEntity(branch.target); if (entity == nullptr) { @@ -124,10 +149,10 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* switch (successState) { case 1: - this->m_onSuccess->Calculate(context, bitStream, branch); + this->m_OnSuccess->Calculate(context, bitStream, branch); break; default: - Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + Game::logger->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState); break; } @@ -140,11 +165,13 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* } void BasicAttackBehavior::Load() { - this->m_minDamage = GetInt("min damage"); - if (this->m_minDamage == 0) this->m_minDamage = 1; + this->m_MinDamage = GetInt("min damage"); + if (this->m_MinDamage == 0) this->m_MinDamage = 1; - this->m_maxDamage = GetInt("max damage"); - if (this->m_maxDamage == 0) this->m_maxDamage = 1; + this->m_MaxDamage = GetInt("max damage"); + if (this->m_MaxDamage == 0) this->m_MaxDamage = 1; - this->m_onSuccess = GetAction("on_success"); + this->m_OnSuccess = GetAction("on_success"); + + this->m_OnFailArmor = GetAction("on_fail_armor"); } diff --git a/dGame/dBehaviors/BasicAttackBehavior.h b/dGame/dBehaviors/BasicAttackBehavior.h index 8e23d443..9c08141c 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.h +++ b/dGame/dBehaviors/BasicAttackBehavior.h @@ -4,12 +4,6 @@ class BasicAttackBehavior final : public Behavior { public: - uint32_t m_minDamage; - - uint32_t m_maxDamage; - - Behavior* m_onSuccess; - explicit BasicAttackBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } @@ -18,4 +12,12 @@ public: void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; +private: + uint32_t m_MinDamage; + + uint32_t m_MaxDamage; + + Behavior* m_OnSuccess; + + Behavior* m_OnFailArmor; }; diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index f7e8e7d9..c749dbaf 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -319,34 +319,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime) { const auto distance = Vector3::DistanceSquared(targetPosition, closestPoint); if (distance > 3 * 3) { - /* - if (entry.TrackTarget && distance <= entry.TrackRadius) - { - const auto rotation = NiQuaternion::LookAtUnlocked(position, targetPosition); - - const auto speed = entry.Velocity.Length(); - - const auto homingTarget = rotation.GetForwardVector() * speed; - - Vector3 homing; - - // Move towards - - const auto difference = homingTarget - entry.Velocity; - const auto mag = difference.Length(); - if (mag <= speed || mag == 0) - { - homing = homingTarget; - } - else - { - entry.Velocity + homingTarget / mag * speed; - } - - entry.Velocity = homing; - } - */ - + // TODO There is supposed to be an implementation for homing projectiles here continue; } From 1ed3af63b9f2be42ecd1c7966c65a6ee604f90a7 Mon Sep 17 00:00:00 2001 From: Daniel Seiler Date: Fri, 16 Dec 2022 07:32:36 +0100 Subject: [PATCH 09/63] Log some recvfrom errors on linux (#885) --- thirdparty/raknet/Source/SocketLayer.cpp | 51 +++++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/thirdparty/raknet/Source/SocketLayer.cpp b/thirdparty/raknet/Source/SocketLayer.cpp index b6af8751..6cb4f7c6 100644 --- a/thirdparty/raknet/Source/SocketLayer.cpp +++ b/thirdparty/raknet/Source/SocketLayer.cpp @@ -417,8 +417,14 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode, uns assert( 0 ); #endif - *errorCode = -1; - return -1; + //*errorCode = -1; +#ifdef __linux__ + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN); + printf("[RakNet] SocketLayer::RecvFrom: empty datagram from %s", str); +#endif + //return -1; + return 0; } if ( len > 0 ) @@ -479,6 +485,47 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode, uns } #endif } +#elif defined(__linux__) + if (len < -1) + { + printf("[RakNet] SocketLayer::RecvFrom: Unexpected return value."); + return -1; + } + + int local_errno = errno; + if (local_errno == EAGAIN || local_errno == EWOULDBLOCK) + { + return 0; // no data + } + + if (local_errno == EINTR) + { + printf("[RakNet] SocketLayer::RecvFrom: The receive was interrupted by delivery of a signal before any data were available."); + return 0; // log, but ignore + } + + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN); + printf("[RakNet] SocketLayer::RecvFrom: Error receiving data from %s", str); + + switch (local_errno) { + case EINVAL: + printf("[RakNet] SocketLayer::RecvFrom: Invalid argument passed."); break; + case ENOMEM: + case ENOBUFS: + printf("[RakNet] SocketLayer::RecvFrom: Could not allocate memory for recvmsg()."); break; + case EFAULT: + printf("[RakNet] SocketLayer::RecvFrom: The receive buffer pointer(s) point outside the process's address space."); break; + case EBADF: + printf("[RakNet] SocketLayer::RecvFrom: The argument sockfd is an invalid descriptor."); break; + case ENOTSOCK: + printf("[RakNet] SocketLayer::RecvFrom: The argument sockfd does not refer to a socket."); break; + case EPIPE: + printf("[RakNet] SocketLayer::RecvFrom: The connection was unexpectedly closed or shut down by the other end. "); break; + default: + printf("[RakNet] SocketLayer::RecvFrom: Unknown Error %d", local_errno); break; + } + return -1; #endif } From 3f1b4339f5df28a9b4510349f32819f184239c88 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Fri, 16 Dec 2022 02:24:02 -0800 Subject: [PATCH 10/63] Improve chat and Auth Also change most uses of int to specified lengths. --- dAuthServer/AuthServer.cpp | 26 ++++++++------ dChatServer/ChatServer.cpp | 33 ++++++++++-------- dMasterServer/MasterServer.cpp | 30 ++++++++-------- dWorldServer/WorldServer.cpp | 62 +++++++++++++++++----------------- 4 files changed, 80 insertions(+), 71 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index e4d8a052..f5090495 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -32,6 +32,8 @@ dLogger* SetupLogger(); void HandlePacket(Packet* packet); int main(int argc, char** argv) { + constexpr uint32_t authFramerate = mediumFramerate; + constexpr uint32_t authFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Auth"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -67,7 +69,7 @@ int main(int argc, char** argv) { //Find out the master's IP: std::string masterIP; - int masterPort = 1500; + uint32_t masterPort = 1500; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -79,8 +81,8 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. + uint32_t maxClients = 50; + uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); @@ -89,16 +91,18 @@ int main(int argc, char** argv) { //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * authFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * authFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= authFramerate) break; //Exit our loop, shut down. } else framesSinceMasterDisconnect = 0; @@ -114,16 +118,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -138,7 +142,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFrameDelta); //Auth can run at a lower "fps" + t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps" std::this_thread::sleep_until(t); } diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 8ae1a9bd..a75c4d51 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -19,6 +19,9 @@ #include "ChatPacketHandler.h" #include "Game.h" + +//RakNet includes: +#include "RakNetDefines.h" namespace Game { dLogger* logger = nullptr; dServer* server = nullptr; @@ -28,8 +31,6 @@ namespace Game { bool shouldShutdown = false; } -//RakNet includes: -#include "RakNetDefines.h" dLogger* SetupLogger(); void HandlePacket(Packet* packet); @@ -37,6 +38,8 @@ void HandlePacket(Packet* packet); PlayerContainer playerContainer; int main(int argc, char** argv) { + constexpr uint32_t chatFramerate = mediumFramerate; + constexpr uint32_t chatFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Chat"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -65,7 +68,7 @@ int main(int argc, char** argv) { Game::assetManager = new AssetManager(clientPath); } catch (std::runtime_error& ex) { Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what()); - + return EXIT_FAILURE; } @@ -87,7 +90,7 @@ int main(int argc, char** argv) { //Find out the master's IP: std::string masterIP; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -99,8 +102,8 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1501; + uint32_t maxClients = 50; + uint32_t ourPort = 1501; if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); @@ -111,16 +114,18 @@ int main(int argc, char** argv) { //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * chatFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * chatFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= chatFramerate) break; //Exit our loop, shut down. } else framesSinceMasterDisconnect = 0; @@ -136,16 +141,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -160,7 +165,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFrameDelta); //Chat can run at a lower "fps" + t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps" std::this_thread::sleep_until(t); } diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index ed94ff83..5bbe7a8c 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -52,8 +52,8 @@ namespace Game { } //namespace Game bool shutdownSequenceStarted = false; -void ShutdownSequence(int signal = -1); -int FinalizeShutdown(int signal = -1); +void ShutdownSequence(int32_t signal = -1); +int32_t FinalizeShutdown(int32_t signal = -1); dLogger* SetupLogger(); void StartAuthServer(); void StartChatServer(); @@ -75,8 +75,8 @@ int main(int argc, char** argv) { //Triggers the shutdown sequence at application exit std::atexit([]() { ShutdownSequence(); }); - signal(SIGINT, [](int signal) { ShutdownSequence(EXIT_FAILURE); }); - signal(SIGTERM, [](int signal) { ShutdownSequence(EXIT_FAILURE); }); + signal(SIGINT, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); + signal(SIGTERM, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); //Create all the objects we need to run our service: Game::logger = SetupLogger(); @@ -239,8 +239,8 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } - int maxClients = 999; - int ourPort = 1000; + uint32_t maxClients = 999; + uint32_t ourPort = 1000; if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port")); @@ -293,9 +293,9 @@ int main(int argc, char** argv) { constexpr uint32_t sqlPingTime = 10 * 60 * masterFramerate; constexpr uint32_t shutdownUniverseTime = 10 * 60 * masterFramerate; constexpr uint32_t instanceReadyTimeout = 30 * masterFramerate; - int framesSinceLastFlush = 0; - int framesSinceLastSQLPing = 0; - int framesSinceKillUniverseCommand = 0; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceKillUniverseCommand = 0; while (true) { //In world we'd update our other systems here. @@ -319,7 +319,7 @@ int main(int argc, char** argv) { if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -652,7 +652,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read(character); password += character; @@ -678,7 +678,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { char character; inStream.Read(character); password += character; } @@ -726,7 +726,7 @@ void HandlePacket(Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); - int zoneID; + int32_t zoneID; inStream.Read(zoneID); if (shutdownSequenceStarted) { Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not prepping a new zone."); @@ -822,7 +822,7 @@ void StartAuthServer() { #endif } -void ShutdownSequence(int signal) { +void ShutdownSequence(int32_t signal) { if (shutdownSequenceStarted) { return; } @@ -905,7 +905,7 @@ void ShutdownSequence(int signal) { FinalizeShutdown(signal); } -int FinalizeShutdown(int signal) { +int32_t FinalizeShutdown(int32_t signal) { //Delete our objects here: Database::Destroy("MasterServer"); if (Game::config) delete Game::config; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index c531595f..c8826efe 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -81,7 +81,7 @@ void WorldShutdownProcess(uint32_t zoneId); void FinalizeShutdown(); void SendShutdownMessageToMaster(); -dLogger* SetupLogger(int zoneID, int instanceID); +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID); void HandlePacketChat(Packet* packet); void HandlePacket(Packet* packet); @@ -91,8 +91,8 @@ struct tempSessionInfo { }; std::map m_PendingUsers; -int instanceID = 0; -int g_CloneID = 0; +uint32_t instanceID = 0; +uint32_t g_CloneID = 0; std::string databaseChecksum = ""; int main(int argc, char** argv) { @@ -106,13 +106,13 @@ int main(int argc, char** argv) { signal(SIGINT, [](int) { WorldShutdownSequence(); }); signal(SIGTERM, [](int) { WorldShutdownSequence(); }); - int zoneID = 1000; - int cloneID = 0; - int maxClients = 8; - int ourPort = 2007; + uint32_t zoneID = 1000; + uint32_t cloneID = 0; + uint32_t maxClients = 8; + uint32_t ourPort = 2007; //Check our arguments: - for (int i = 0; i < argc; ++i) { + for (int32_t i = 0; i < argc; ++i) { std::string argument(argv[i]); if (argument == "-zone") zoneID = atoi(argv[i + 1]); @@ -184,7 +184,7 @@ int main(int argc, char** argv) { //Find out the master's IP: std::string masterIP = "localhost"; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -203,7 +203,7 @@ int main(int argc, char** argv) { Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::shouldShutdown, zoneID); //Connect to the chat server: - int chatPort = 1501; + uint32_t chatPort = 1501; if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); @@ -219,22 +219,22 @@ int main(int argc, char** argv) { auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceChatDisconnect = 0; - int framesSinceLastUsersSave = 0; - int framesSinceLastSQLPing = 0; - int framesSinceLastUser = 0; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceChatDisconnect = 0; + uint32_t framesSinceLastUsersSave = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceLastUser = 0; const float maxPacketProcessingTime = 1.5f; //0.015f; - const int maxPacketsToProcess = 1024; + const uint32_t maxPacketsToProcess = 1024; bool ready = false; - int framesSinceMasterStatus = 0; - int framesSinceShutdownSequence = 0; - int currentFramerate = highFrameDelta; + uint32_t framesSinceMasterStatus = 0; + uint32_t framesSinceShutdownSequence = 0; + uint32_t currentFramerate = highFrameDelta; - int ghostingStepCount = 0; + uint32_t ghostingStepCount = 0; auto ghostingLastTime = std::chrono::high_resolution_clock::now(); PerformanceManager::SelectProfile(zoneID); @@ -263,7 +263,7 @@ int main(int argc, char** argv) { } } - const int bufferSize = 1024; + const int32_t bufferSize = 1024; MD5* md5 = new MD5(); char fileStreamBuffer[1024] = {}; @@ -314,7 +314,7 @@ int main(int argc, char** argv) { if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - int framesToWaitForMaster = ready ? 10 : 200; + uint32_t framesToWaitForMaster = ready ? 10 : 200; if (framesSinceMasterDisconnect >= framesToWaitForMaster && !Game::shouldShutdown) { Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", framesToWaitForMaster); Game::shouldShutdown = true; @@ -378,7 +378,7 @@ int main(int argc, char** argv) { UserManager::Instance()->DeletePendingRemovals(); auto t1 = std::chrono::high_resolution_clock::now(); - for (int curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { + for (uint32_t curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { packet = Game::server->Receive(); if (packet) { auto t1 = std::chrono::high_resolution_clock::now(); @@ -433,7 +433,7 @@ int main(int argc, char** argv) { if (framesSinceLastSQLPing >= 40000) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -482,7 +482,7 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } -dLogger* SetupLogger(int zoneID, int instanceID) { +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID) { std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID) + "_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; @@ -524,7 +524,7 @@ void HandlePacketChat(Packet* packet) { //Write our stream outwards: CBITSTREAM; - for (int i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { + for (BitSize_t i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { bitStream.Write(packet->data[i + 16]); //16 bytes == header + playerID to skip } @@ -543,7 +543,7 @@ void HandlePacketChat(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read(character); title += character; @@ -551,7 +551,7 @@ void HandlePacketChat(Packet* packet) { len = 0; inStream.Read(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read(character); msg += character; @@ -804,7 +804,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { char character; inStream.Read(character); username += character; } @@ -1027,7 +1027,7 @@ void HandlePacket(Packet* packet) { //Check for BBB models: auto stmt = Database::CreatePreppedStmt("SELECT ugc_id FROM properties_contents WHERE lot=14 AND property_id=?"); - int templateId = result.getIntField(0); + int32_t templateId = result.getIntField(0); result.finalize(); From 0d460c0eb30c31d7b3e2ff1c520400b9a43281ae Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Fri, 16 Dec 2022 03:46:38 -0800 Subject: [PATCH 11/63] Update WorldServer timings --- dCommon/dEnums/dCommonVars.h | 3 ++ dWorldServer/PerformanceManager.cpp | 6 ++-- dWorldServer/PerformanceManager.h | 4 +-- dWorldServer/WorldServer.cpp | 48 ++++++++++++++++++++--------- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index f3d02bf7..68339032 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -12,7 +12,10 @@ typedef int RESTICKET; +// These are the same define, but they mean two different things in different contexts +// so a different define to distinguish what calculation is happening will help clarity. #define FRAMES_TO_MS(x) 1000 / x +#define MS_TO_FRAMES(x) 1000 / x //=========== FRAME TIMINGS =========== constexpr uint32_t highFramerate = 60; diff --git a/dWorldServer/PerformanceManager.cpp b/dWorldServer/PerformanceManager.cpp index 66dcb615..19f38d00 100644 --- a/dWorldServer/PerformanceManager.cpp +++ b/dWorldServer/PerformanceManager.cpp @@ -79,10 +79,10 @@ void PerformanceManager::SelectProfile(LWOMAPID mapID) { m_CurrentProfile = pair->second; } -uint32_t PerformanceManager::GetServerFramerate() { +uint32_t PerformanceManager::GetServerFrameDelta() { if (UserManager::Instance()->GetUserCount() == 0) { - return m_InactiveProfile.serverFramerate; + return m_InactiveProfile.serverFrameDelta; } - return m_CurrentProfile.serverFramerate; + return m_CurrentProfile.serverFrameDelta; } diff --git a/dWorldServer/PerformanceManager.h b/dWorldServer/PerformanceManager.h index 3d8517eb..c584d4ac 100644 --- a/dWorldServer/PerformanceManager.h +++ b/dWorldServer/PerformanceManager.h @@ -5,14 +5,14 @@ #include "dCommonVars.h" struct PerformanceProfile { - uint32_t serverFramerate; + uint32_t serverFrameDelta; }; class PerformanceManager { public: static void SelectProfile(LWOMAPID mapID); - static uint32_t GetServerFramerate(); + static uint32_t GetServerFrameDelta(); private: static PerformanceProfile m_CurrentProfile; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index c8826efe..0ed994fe 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -232,7 +232,7 @@ int main(int argc, char** argv) { bool ready = false; uint32_t framesSinceMasterStatus = 0; uint32_t framesSinceShutdownSequence = 0; - uint32_t currentFramerate = highFrameDelta; + uint32_t currentFramerate = highFramerate; uint32_t ghostingStepCount = 0; auto ghostingLastTime = std::chrono::high_resolution_clock::now(); @@ -287,6 +287,14 @@ int main(int argc, char** argv) { } } + uint32_t currentFrameDelta = highFrameDelta; + // These values are adjust them selves to the current framerate should it update. + uint32_t logFlushTime = 15 * currentFramerate; // 15 seconds in frames + uint32_t shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + uint32_t chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + uint32_t saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames while (true) { Metrics::StartMeasurement(MetricVariable::Frame); Metrics::StartMeasurement(MetricVariable::GameLoop); @@ -299,24 +307,37 @@ int main(int argc, char** argv) { const auto occupied = UserManager::Instance()->GetUserCount() != 0; + uint32_t newFrameDelta = currentFrameDelta; if (!ready) { - currentFramerate = highFrameDelta; + newFrameDelta = highFrameDelta; } else { - currentFramerate = PerformanceManager::GetServerFramerate(); + newFrameDelta = PerformanceManager::GetServerFrameDelta(); + } + + // Update to the new framerate + if (newFrameDelta != currentFrameDelta) { + currentFrameDelta = newFrameDelta; + currentFramerate = MS_TO_FRAMES(newFrameDelta); + Game::logger->LogDebug("WorldServer", "Framerate for zone/instance/clone %i/%i/%i is now %i", zoneID, instanceID, cloneID, currentFramerate); + logFlushTime = 15 * currentFramerate; // 15 seconds in frames + shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames } //Warning if we ran slow - if (deltaTime > currentFramerate) { - Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate)", deltaTime, currentFramerate); + if (deltaTime > currentFrameDelta) { + Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate %i)", deltaTime, currentFrameDelta, currentFramerate); } //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - uint32_t framesToWaitForMaster = ready ? 10 : 200; - if (framesSinceMasterDisconnect >= framesToWaitForMaster && !Game::shouldShutdown) { - Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", framesToWaitForMaster); + if (framesSinceMasterDisconnect >= noMasterConnectionTimeout && !Game::shouldShutdown) { + Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", noMasterConnectionTimeout); Game::shouldShutdown = true; } } else framesSinceMasterDisconnect = 0; @@ -325,8 +346,7 @@ int main(int argc, char** argv) { if (!chatConnected) { framesSinceChatDisconnect++; - // Attempt to reconnect every 30 seconds. - if (framesSinceChatDisconnect >= 2000) { + if (framesSinceChatDisconnect >= chatReconnectionTime) { framesSinceChatDisconnect = 0; Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8); @@ -403,7 +423,7 @@ int main(int argc, char** argv) { Metrics::EndMeasurement(MetricVariable::UpdateReplica); //Push our log every 15s: - if (framesSinceLastFlush >= 1000) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; @@ -420,7 +440,7 @@ int main(int argc, char** argv) { } //Save all connected users every 10 minutes: - if (framesSinceLastUsersSave >= 40000 && zoneID != 0) { + if (framesSinceLastUsersSave >= saveTime && zoneID != 0) { UserManager::Instance()->SaveAllActiveCharacters(); framesSinceLastUsersSave = 0; @@ -430,7 +450,7 @@ int main(int argc, char** argv) { } else framesSinceLastUsersSave++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; uint32_t masterPort; @@ -451,7 +471,7 @@ int main(int argc, char** argv) { Metrics::StartMeasurement(MetricVariable::Sleep); - t += std::chrono::milliseconds(currentFramerate); + t += std::chrono::milliseconds(currentFrameDelta); std::this_thread::sleep_until(t); Metrics::EndMeasurement(MetricVariable::Sleep); From b33a3df012375a2ddd873f8d2f47bcbc5ba00e7e Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Fri, 16 Dec 2022 04:02:54 -0800 Subject: [PATCH 12/63] Scale timers --- dWorldServer/WorldServer.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 0ed994fe..37dce5cd 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -287,7 +287,7 @@ int main(int argc, char** argv) { } } - uint32_t currentFrameDelta = highFrameDelta; + uint32_t currentFrameDelta = highFrameDelta; // These values are adjust them selves to the current framerate should it update. uint32_t logFlushTime = 15 * currentFramerate; // 15 seconds in frames uint32_t shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames @@ -314,17 +314,24 @@ int main(int argc, char** argv) { newFrameDelta = PerformanceManager::GetServerFrameDelta(); } - // Update to the new framerate + // Update to the new framerate and scale all timings to said new framerate if (newFrameDelta != currentFrameDelta) { + float_t ratioBeforeToAfter = (float)currentFrameDelta / (float)newFrameDelta; currentFrameDelta = newFrameDelta; currentFramerate = MS_TO_FRAMES(newFrameDelta); Game::logger->LogDebug("WorldServer", "Framerate for zone/instance/clone %i/%i/%i is now %i", zoneID, instanceID, cloneID, currentFramerate); logFlushTime = 15 * currentFramerate; // 15 seconds in frames + framesSinceLastFlush *= ratioBeforeToAfter; shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUser *= ratioBeforeToAfter; noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + framesSinceMasterDisconnect *= ratioBeforeToAfter; chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + framesSinceChatDisconnect *= ratioBeforeToAfter; saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUsersSave *= ratioBeforeToAfter; sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastSQLPing *= ratioBeforeToAfter; } //Warning if we ran slow From a2ca2733702f2be1e8a0277c1f9ba64edc0c1b65 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 16 Dec 2022 13:23:02 -0800 Subject: [PATCH 13/63] Cleanup behavior bitstream reads (#888) * Add failArmor server side Address out of bounds reading in behavior Address the basicAttackBehavior reading out of bounds memory and reading bits that didnt exist, which occasionally caused crashes and also caused the behavior to do undefined behavior due to the bad reads. Tested that attacking a wall anywhere with a projectile now does not crash the game. Tested with logs that the behavior correctly returned when there were no allocated bits or returned when other states were met. Add back logs and add fail handle Remove comment block Revert "Add back logs and add fail handle" This reverts commit db19be0906fc8bf35bf89037e2bfba39f5ef9c0c. Split out checks * Cleanup Behavior streams --- dGame/dBehaviors/AirMovementBehavior.cpp | 27 +++++++++++++------ dGame/dBehaviors/AirMovementBehavior.h | 2 +- dGame/dBehaviors/AreaOfEffectBehavior.cpp | 16 ++++++++--- dGame/dBehaviors/AttackDelayBehavior.cpp | 7 +++-- dGame/dBehaviors/ChainBehavior.cpp | 15 +++++++---- dGame/dBehaviors/ChargeUpBehavior.cpp | 8 ++++-- dGame/dBehaviors/ForceMovementBehavior.cpp | 23 +++++++++++----- dGame/dBehaviors/InterruptBehavior.cpp | 15 ++++++++--- dGame/dBehaviors/KnockbackBehavior.cpp | 9 +++++-- dGame/dBehaviors/MovementSwitchBehavior.cpp | 9 ++++--- dGame/dBehaviors/ProjectileAttackBehavior.cpp | 21 ++++++++++----- dGame/dBehaviors/StunBehavior.cpp | 7 +++-- dGame/dBehaviors/SwitchBehavior.cpp | 5 +++- dGame/dBehaviors/SwitchMultipleBehavior.cpp | 12 +++++---- dGame/dBehaviors/TacArcBehavior.cpp | 18 +++++++++---- 15 files changed, 138 insertions(+), 56 deletions(-) diff --git a/dGame/dBehaviors/AirMovementBehavior.cpp b/dGame/dBehaviors/AirMovementBehavior.cpp index 469ac6e4..932297b9 100644 --- a/dGame/dBehaviors/AirMovementBehavior.cpp +++ b/dGame/dBehaviors/AirMovementBehavior.cpp @@ -2,11 +2,16 @@ #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "EntityManager.h" +#include "Game.h" +#include "dLogger.h" void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - uint32_t handle; + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("AirMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } context->RegisterSyncBehavior(handle, this, branch); } @@ -17,14 +22,20 @@ void AirMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream->Write(handle); } -void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { - uint32_t behaviorId; +void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + uint32_t behaviorId{}; - bit_stream->Read(behaviorId); + if (!bitStream->Read(behaviorId)) { + Game::logger->Log("AirMovementBehavior", "Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - LWOOBJID target; + LWOOBJID target{}; - bit_stream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("AirMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } auto* behavior = CreateBehavior(behaviorId); @@ -32,7 +43,7 @@ void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bit_ branch.target = target; } - behavior->Handle(context, bit_stream, branch); + behavior->Handle(context, bitStream, branch); } void AirMovementBehavior::Load() { diff --git a/dGame/dBehaviors/AirMovementBehavior.h b/dGame/dBehaviors/AirMovementBehavior.h index 323edf37..89dc1e05 100644 --- a/dGame/dBehaviors/AirMovementBehavior.h +++ b/dGame/dBehaviors/AirMovementBehavior.h @@ -16,7 +16,7 @@ public: void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/AreaOfEffectBehavior.cpp b/dGame/dBehaviors/AreaOfEffectBehavior.cpp index 898d1f99..ca3bdf93 100644 --- a/dGame/dBehaviors/AreaOfEffectBehavior.cpp +++ b/dGame/dBehaviors/AreaOfEffectBehavior.cpp @@ -9,11 +9,16 @@ #include "BehaviorContext.h" #include "RebuildComponent.h" #include "DestroyableComponent.h" +#include "Game.h" +#include "dLogger.h" void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - uint32_t targetCount; + uint32_t targetCount{}; - bitStream->Read(targetCount); + if (!bitStream->Read(targetCount)) { + Game::logger->Log("AreaOfEffectBehavior", "Unable to read targetCount from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } if (targetCount > this->m_maxTargets) { return; @@ -24,9 +29,12 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b targets.reserve(targetCount); for (auto i = 0u; i < targetCount; ++i) { - LWOOBJID target; + LWOOBJID target{}; - bitStream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("AreaOfEffectBehavior", "failed to read in target %i from bitStream, aborting target Handle!", i); + return; + }; targets.push_back(target); } diff --git a/dGame/dBehaviors/AttackDelayBehavior.cpp b/dGame/dBehaviors/AttackDelayBehavior.cpp index 450741ec..201921a3 100644 --- a/dGame/dBehaviors/AttackDelayBehavior.cpp +++ b/dGame/dBehaviors/AttackDelayBehavior.cpp @@ -5,9 +5,12 @@ #include "dLogger.h" void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - uint32_t handle; + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("AttackDelayBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; for (auto i = 0u; i < this->m_numIntervals; ++i) { context->RegisterSyncBehavior(handle, this, branch); diff --git a/dGame/dBehaviors/ChainBehavior.cpp b/dGame/dBehaviors/ChainBehavior.cpp index 3ef8c15b..ec0f8969 100644 --- a/dGame/dBehaviors/ChainBehavior.cpp +++ b/dGame/dBehaviors/ChainBehavior.cpp @@ -4,14 +4,19 @@ #include "dLogger.h" void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - uint32_t chain_index; + uint32_t chainIndex{}; - bitStream->Read(chain_index); + if (!bitStream->Read(chainIndex)) { + Game::logger->Log("ChainBehavior", "Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - chain_index--; + chainIndex--; - if (chain_index < this->m_behaviors.size()) { - this->m_behaviors.at(chain_index)->Handle(context, bitStream, branch); + if (chainIndex < this->m_behaviors.size()) { + this->m_behaviors.at(chainIndex)->Handle(context, bitStream, branch); + } else { + Game::logger->Log("ChainBehavior", "chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream->GetNumberOfUnreadBits()); } } diff --git a/dGame/dBehaviors/ChargeUpBehavior.cpp b/dGame/dBehaviors/ChargeUpBehavior.cpp index fa9fa34b..1b9ba433 100644 --- a/dGame/dBehaviors/ChargeUpBehavior.cpp +++ b/dGame/dBehaviors/ChargeUpBehavior.cpp @@ -1,12 +1,16 @@ #include "ChargeUpBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" +#include "Game.h" #include "dLogger.h" void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - uint32_t handle; + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("ChargeUpBehavior", "Unable to read handle from bitStream, aborting Handle! variable_type"); + return; + }; context->RegisterSyncBehavior(handle, this, branch); } diff --git a/dGame/dBehaviors/ForceMovementBehavior.cpp b/dGame/dBehaviors/ForceMovementBehavior.cpp index e1ac6133..e095447c 100644 --- a/dGame/dBehaviors/ForceMovementBehavior.cpp +++ b/dGame/dBehaviors/ForceMovementBehavior.cpp @@ -3,23 +3,34 @@ #include "BehaviorContext.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" +#include "Game.h" +#include "dLogger.h" void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { return; } - uint32_t handle; - bitStream->Read(handle); + uint32_t handle{}; + if (!bitStream->Read(handle)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } context->RegisterSyncBehavior(handle, this, branch); } void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - uint32_t next; - bitStream->Read(next); + uint32_t next{}; + if (!bitStream->Read(next)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - LWOOBJID target; - bitStream->Read(target); + LWOOBJID target{}; + if (!bitStream->Read(target)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } branch.target = target; auto* behavior = CreateBehavior(next); diff --git a/dGame/dBehaviors/InterruptBehavior.cpp b/dGame/dBehaviors/InterruptBehavior.cpp index b42eadb0..9035c092 100644 --- a/dGame/dBehaviors/InterruptBehavior.cpp +++ b/dGame/dBehaviors/InterruptBehavior.cpp @@ -11,7 +11,10 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS if (branch.target != context->originator) { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown1 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (unknown) return; } @@ -19,7 +22,10 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS if (!this->m_interruptBlock) { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown2 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (unknown) return; } @@ -28,7 +34,10 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown3 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } if (branch.target == context->originator) return; diff --git a/dGame/dBehaviors/KnockbackBehavior.cpp b/dGame/dBehaviors/KnockbackBehavior.cpp index 83c82010..1b878ed0 100644 --- a/dGame/dBehaviors/KnockbackBehavior.cpp +++ b/dGame/dBehaviors/KnockbackBehavior.cpp @@ -6,11 +6,16 @@ #include "EntityManager.h" #include "GameMessages.h" #include "DestroyableComponent.h" +#include "Game.h" +#include "dLogger.h" void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - bool unknown; + bool unknown{}; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("KnockbackBehavior", "Unable to read unknown from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { diff --git a/dGame/dBehaviors/MovementSwitchBehavior.cpp b/dGame/dBehaviors/MovementSwitchBehavior.cpp index 17ed5c40..c893e6e1 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.cpp +++ b/dGame/dBehaviors/MovementSwitchBehavior.cpp @@ -13,9 +13,11 @@ void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* return; } - uint32_t movementType; - - bitStream->Read(movementType); + uint32_t movementType{}; + if (!bitStream->Read(movementType)) { + Game::logger->Log("MovementSwitchBehavior", "Unable to read movementType from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; switch (movementType) { case 1: @@ -55,4 +57,3 @@ void MovementSwitchBehavior::Load() { this->m_jumpAction = GetAction("jump_action"); } - diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.cpp b/dGame/dBehaviors/ProjectileAttackBehavior.cpp index 350234e2..c14f032d 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.cpp +++ b/dGame/dBehaviors/ProjectileAttackBehavior.cpp @@ -8,9 +8,12 @@ #include "../dWorldServer/ObjectIDManager.h" void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - LWOOBJID target; + LWOOBJID target{}; - bitStream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; auto* entity = EntityManager::Instance()->GetEntity(context->originator); @@ -30,15 +33,21 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea if (m_useMouseposit) { NiPoint3 targetPosition = NiPoint3::ZERO; - bitStream->Read(targetPosition); + if (!bitStream->Read(targetPosition)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } auto* targetEntity = EntityManager::Instance()->GetEntity(target); for (auto i = 0u; i < this->m_projectileCount; ++i) { - LWOOBJID projectileId; + LWOOBJID projectileId{}; - bitStream->Read(projectileId); + if (!bitStream->Read(projectileId)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; branch.target = target; branch.isProjectile = true; @@ -98,7 +107,7 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt for (auto i = 0u; i < this->m_projectileCount; ++i) { auto id = static_cast(ObjectIDManager::Instance()->GenerateObjectID()); - id = GeneralUtils::SetBit(id, OBJECT_BIT_CLIENT); + id = GeneralUtils::SetBit(id, OBJECT_BIT_SPAWNED); bitStream->Write(id); diff --git a/dGame/dBehaviors/StunBehavior.cpp b/dGame/dBehaviors/StunBehavior.cpp index 59a81440..065b7220 100644 --- a/dGame/dBehaviors/StunBehavior.cpp +++ b/dGame/dBehaviors/StunBehavior.cpp @@ -14,8 +14,11 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream return; } - bool blocked; - bitStream->Read(blocked); + bool blocked{}; + if (!bitStream->Read(blocked)) { + Game::logger->Log("StunBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; auto* target = EntityManager::Instance()->GetEntity(branch.target); diff --git a/dGame/dBehaviors/SwitchBehavior.cpp b/dGame/dBehaviors/SwitchBehavior.cpp index 78271b99..f6eb3ff5 100644 --- a/dGame/dBehaviors/SwitchBehavior.cpp +++ b/dGame/dBehaviors/SwitchBehavior.cpp @@ -10,7 +10,10 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre auto state = true; if (this->m_imagination > 0 || !this->m_isEnemyFaction) { - bitStream->Read(state); + if (!bitStream->Read(state)) { + Game::logger->Log("SwitchBehavior", "Unable to read state from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } auto* entity = EntityManager::Instance()->GetEntity(context->originator); diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.cpp b/dGame/dBehaviors/SwitchMultipleBehavior.cpp index 946e5e0f..e92393fc 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.cpp +++ b/dGame/dBehaviors/SwitchMultipleBehavior.cpp @@ -9,10 +9,12 @@ #include "EntityManager.h" -void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { - float value; +void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + float value{}; - bit_stream->Read(value); + if (!bitStream->Read(value)) { + Game::logger->Log("SwitchMultipleBehavior", "Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + }; uint32_t trigger = 0; @@ -30,10 +32,10 @@ void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* auto* behavior = this->m_behaviors.at(trigger).second; - behavior->Handle(context, bit_stream, branch); + behavior->Handle(context, bitStream, branch); } -void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { +void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { // TODO } diff --git a/dGame/dBehaviors/TacArcBehavior.cpp b/dGame/dBehaviors/TacArcBehavior.cpp index 8789f9b6..38efdea4 100644 --- a/dGame/dBehaviors/TacArcBehavior.cpp +++ b/dGame/dBehaviors/TacArcBehavior.cpp @@ -20,12 +20,16 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre bool hit = false; - bitStream->Read(hit); + if (!bitStream->Read(hit)) { + Game::logger->Log("TacArcBehavior", "Unable to read hit from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + }; if (this->m_checkEnv) { bool blocked = false; - bitStream->Read(blocked); + if (!bitStream->Read(blocked)) { + Game::logger->Log("TacArcBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + }; if (blocked) { this->m_blockedAction->Handle(context, bitStream, branch); @@ -37,7 +41,9 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre if (hit) { uint32_t count = 0; - bitStream->Read(count); + if (!bitStream->Read(count)) { + Game::logger->Log("TacArcBehavior", "Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + }; if (count > m_maxTargets && m_maxTargets > 0) { count = m_maxTargets; @@ -46,9 +52,11 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre std::vector targets; for (auto i = 0u; i < count; ++i) { - LWOOBJID id; + LWOOBJID id{}; - bitStream->Read(id); + if (!bitStream->Read(id)) { + Game::logger->Log("TacArcBehavior", "Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + }; targets.push_back(id); } From cd78a3dec72ac2e4c427ef21c9fbcb452fc02fe5 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 16 Dec 2022 13:23:09 -0800 Subject: [PATCH 14/63] Fix cannon super charge speed (#883) * Fix cannon * Update SGCannon.cpp --- dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 049837a4..912b9f58 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -722,7 +722,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { Game::logger->Log("SGCannon", "Player has %d equipped items", equippedItems.size()); auto skillID = constants.cannonSkill; - auto coolDown = constants.cannonRefireRate; + auto cooldown = constants.cannonRefireRate; auto* selfInventoryComponent = self->GetComponent(); @@ -738,7 +738,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { // TODO: Equip items skillID = constants.cannonSuperChargeSkill; - coolDown = 400; + cooldown = 400; } else { selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); @@ -761,7 +761,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { } } } - + cooldown = 800; self->SetVar(NumberOfChargesVariable, 0); } @@ -777,7 +777,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { properties.cannonFOV = 58.6f; properties.cannonVelocity = 129.0; - properties.cannonRefireRate = 800; + properties.cannonRefireRate = cooldown; properties.cannonMinDistance = 30; properties.cannonTimeout = -1; From 32f8bda53866996de7ece9cb591e2b82d1fb7e9c Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Fri, 16 Dec 2022 15:23:38 -0600 Subject: [PATCH 15/63] Allow the player to be interrupted (#881) --- dGame/dComponents/SkillComponent.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index c749dbaf..445a837e 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -181,17 +181,11 @@ void SkillComponent::Reset() { } void SkillComponent::Interrupt() { - if (m_Parent->IsPlayer()) return; - + // TODO: need to check immunities on the destroyable component, but they aren't implemented auto* combat = m_Parent->GetComponent(); + if (combat != nullptr && combat->GetStunImmune()) return; - if (combat != nullptr && combat->GetStunImmune()) { - return; - } - - for (const auto& behavior : this->m_managedBehaviors) { - behavior.second->Interrupt(); - } + for (const auto& behavior : this->m_managedBehaviors) behavior.second->Interrupt(); } void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot, const float maxTime, From 631365b7f70fe138fe39a390d5fac2134ffcca5e Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Fri, 16 Dec 2022 15:24:13 -0600 Subject: [PATCH 16/63] Add change idle flags behavior and GM (#871) * update naming for animation flag enum value 0 * Add change idle flags behaviors and GM * default to 0 when none is given --- dCommon/dEnums/dMessageIdentifiers.h | 1 + dCommon/dEnums/eAninmationFlags.h | 2 +- dGame/dBehaviors/Behavior.cpp | 5 ++- dGame/dBehaviors/CMakeLists.txt | 1 + dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp | 37 ++++++++++++++++++++ dGame/dBehaviors/ChangeIdleFlagsBehavior.h | 23 ++++++++++++ dGame/dBehaviors/SwitchBehavior.cpp | 2 +- dGame/dComponents/PossessableComponent.cpp | 4 +-- dGame/dComponents/PossessableComponent.h | 2 +- dGame/dGameMessages/GameMessages.cpp | 12 +++++++ dGame/dGameMessages/GameMessages.h | 10 ++++++ 11 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp create mode 100644 dGame/dBehaviors/ChangeIdleFlagsBehavior.h diff --git a/dCommon/dEnums/dMessageIdentifiers.h b/dCommon/dEnums/dMessageIdentifiers.h index 5a5c9088..129585a0 100644 --- a/dCommon/dEnums/dMessageIdentifiers.h +++ b/dCommon/dEnums/dMessageIdentifiers.h @@ -488,6 +488,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_MATCH_UPDATE = 1310, GAME_MSG_MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131, GAME_MSG_MODULE_ASSEMBLY_QUERY_DATA = 1132, + GAME_MSG_CHANGE_IDLE_FLAGS = 1338, GAME_MSG_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340, GAME_MSG_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341, GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION = 1342, diff --git a/dCommon/dEnums/eAninmationFlags.h b/dCommon/dEnums/eAninmationFlags.h index 9b2ea3fb..ce235ae9 100644 --- a/dCommon/dEnums/eAninmationFlags.h +++ b/dCommon/dEnums/eAninmationFlags.h @@ -6,7 +6,7 @@ #include enum class eAnimationFlags : uint32_t { - IDLE_INVALID = 0, // made up, for internal use!!! + IDLE_NONE = 0, IDLE_BASIC, IDLE_SWIM, IDLE_CARRY, diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index d0d6192b..cd9304d3 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -60,6 +60,7 @@ #include "SpeedBehavior.h" #include "DamageReductionBehavior.h" #include "JetPackBehavior.h" +#include "ChangeIdleFlagsBehavior.h" //CDClient includes #include "CDBehaviorParameterTable.h" @@ -196,7 +197,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { behavior = new SkillCastFailedBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_IMITATION_SKUNK_STINK: break; - case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: break; + case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: + behavior = new ChangeIdleFlagsBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_APPLY_BUFF: behavior = new ApplyBuffBehavior(behaviorId); break; diff --git a/dGame/dBehaviors/CMakeLists.txt b/dGame/dBehaviors/CMakeLists.txt index 297c389b..40ac0a9c 100644 --- a/dGame/dBehaviors/CMakeLists.txt +++ b/dGame/dBehaviors/CMakeLists.txt @@ -12,6 +12,7 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "BuffBehavior.cpp" "CarBoostBehavior.cpp" "ChainBehavior.cpp" + "ChangeIdleFlagsBehavior.cpp" "ChangeOrientationBehavior.cpp" "ChargeUpBehavior.cpp" "ClearTargetBehavior.cpp" diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp new file mode 100644 index 00000000..06a79fa7 --- /dev/null +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp @@ -0,0 +1,37 @@ + +#include "ChangeIdleFlagsBehavior.h" +#include "BehaviorContext.h" +#include "BehaviorBranchContext.h" + +void ChangeIdleFlagsBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; + if (!target) return; + + GameMessages::SendChangeIdleFlags(target, m_FlagsOn, m_FlagsOff, UNASSIGNED_SYSTEM_ADDRESS); + + if (branch.duration > 0.0f) { + context->RegisterTimerBehavior(this, branch); + } else if (branch.start > 0) { + context->RegisterEndBehavior(this, branch); + } +} + +void ChangeIdleFlagsBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); +} + +void ChangeIdleFlagsBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; + if (!target) return; + // flip on and off to end behavior + GameMessages::SendChangeIdleFlags(target, m_FlagsOff, m_FlagsOn, UNASSIGNED_SYSTEM_ADDRESS); +} + +void ChangeIdleFlagsBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + End(context, branch, second); +} + +void ChangeIdleFlagsBehavior::Load() { + m_FlagsOff = static_cast(GetInt("flags_off", 0)); + m_FlagsOn = static_cast(GetInt("flags_on", 0)); +} diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.h b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h new file mode 100644 index 00000000..91f802f4 --- /dev/null +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h @@ -0,0 +1,23 @@ + +#pragma once +#include "Behavior.h" +#include "eAninmationFlags.h" + +class ChangeIdleFlagsBehavior final : public Behavior { +public: + + /* + * Inherited + */ + explicit ChangeIdleFlagsBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} + + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + void Load() override; + +private: + eAnimationFlags m_FlagsOff; + eAnimationFlags m_FlagsOn; +}; diff --git a/dGame/dBehaviors/SwitchBehavior.cpp b/dGame/dBehaviors/SwitchBehavior.cpp index f6eb3ff5..c010f31b 100644 --- a/dGame/dBehaviors/SwitchBehavior.cpp +++ b/dGame/dBehaviors/SwitchBehavior.cpp @@ -28,7 +28,7 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre return; } - Game::logger->Log("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); + Game::logger->LogDebug("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); if (state || (entity->GetLOT() == 8092 && destroyableComponent->GetImagination() >= m_imagination)) { this->m_actionTrue->Handle(context, bitStream, branch); diff --git a/dGame/dComponents/PossessableComponent.cpp b/dGame/dComponents/PossessableComponent.cpp index 37591532..5c45a6c1 100644 --- a/dGame/dComponents/PossessableComponent.cpp +++ b/dGame/dComponents/PossessableComponent.cpp @@ -34,8 +34,8 @@ void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn outBitStream->Write(m_Possessor != LWOOBJID_EMPTY); if (m_Possessor != LWOOBJID_EMPTY) outBitStream->Write(m_Possessor); - outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_INVALID); - if (m_AnimationFlag != eAnimationFlags::IDLE_INVALID) outBitStream->Write(m_AnimationFlag); + outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_NONE); + if (m_AnimationFlag != eAnimationFlags::IDLE_NONE) outBitStream->Write(m_AnimationFlag); outBitStream->Write(m_ImmediatelyDepossess); m_ImmediatelyDepossess = false; // reset flag diff --git a/dGame/dComponents/PossessableComponent.h b/dGame/dComponents/PossessableComponent.h index 43ce8610..e1dc5ccd 100644 --- a/dGame/dComponents/PossessableComponent.h +++ b/dGame/dComponents/PossessableComponent.h @@ -109,7 +109,7 @@ private: * @brief What animaiton flag to use * */ - eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_INVALID; + eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_NONE; /** * @brief Should this be immediately depossessed diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index fcc25fdc..8c82f644 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -3922,6 +3922,18 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string SEND_PACKET; } + +void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags FlagsOn, eAnimationFlags FlagsOff, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_CHANGE_IDLE_FLAGS); + bitStream.Write(FlagsOff); + bitStream.Write(FlagsOn); + + SEND_PACKET_BROADCAST; +} // Mounts void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr) { diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index f9968d14..4f92480f 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -14,6 +14,7 @@ #include "TradingManager.h" #include "LeaderboardManager.h" #include "MovingPlatformComponent.h" +#include "eAninmationFlags.h" class NiQuaternion; class User; @@ -373,6 +374,15 @@ namespace GameMessages { void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr); + /** + * @brief + * + * @param objectId ID of the entity to set idle flags + * @param FlagsOn Flag to turn on + * @param FlagsOff Flag to turn off + */ + void SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags FlagsOn, eAnimationFlags FlagsOff, const SystemAddress& sysAddr); + // Mounts /** * @brief Set the Inventory LWOOBJID of the mount From 1da2db9db60379e23d36f0971cd08392bbdea542 Mon Sep 17 00:00:00 2001 From: Jett <55758076+Jettford@users.noreply.github.com> Date: Sat, 17 Dec 2022 16:03:18 +0000 Subject: [PATCH 17/63] Resolve some string related issues for Windows Debug --- dGame/dComponents/PropertyManagementComponent.cpp | 2 +- dGame/dUtilities/Mail.cpp | 6 +++--- dMasterServer/MasterServer.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index eaade8be..648edff8 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -717,7 +717,7 @@ void PropertyManagementComponent::Save() { insertion->setDouble(9, rotation.y); insertion->setDouble(10, rotation.z); insertion->setDouble(11, rotation.w); - insertion->setString(12, "Objects_" + std::to_string(entity->GetLOT()) + "_name"); // Model name. TODO make this customizable + insertion->setString(12, ("Objects_" + std::to_string(entity->GetLOT()) + "_name").c_str()); // Model name. TODO make this customizable insertion->setString(13, ""); // Model description. TODO implement this. insertion->setDouble(14, 0); // behavior 1. TODO implement this. insertion->setDouble(15, 0); // behavior 2. TODO implement this. diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index 8280b627..7047972f 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -74,12 +74,12 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ auto* ins = Database::CreatePreppedStmt("INSERT INTO `mail`(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)"); ins->setUInt(1, sender); - ins->setString(2, senderName); + ins->setString(2, senderName.c_str()); ins->setUInt(3, recipient); ins->setString(4, recipientName.c_str()); ins->setUInt64(5, time(nullptr)); - ins->setString(6, subject); - ins->setString(7, body); + ins->setString(6, subject.c_str()); + ins->setString(7, body.c_str()); ins->setUInt(8, 0); ins->setInt(9, attachment); ins->setInt(10, 0); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 4c18566e..3d55f046 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -220,7 +220,7 @@ int main(int argc, char** argv) { //Create account auto* statement = Database::CreatePreppedStmt("INSERT INTO accounts (name, password, ""gm_level) VALUES (?, ?, ?);"); - statement->setString(1, username); + statement->setString(1, username.c_str()); statement->setString(2, std::string(hash, BCRYPT_HASHSIZE).c_str()); statement->setInt(3, 9); From e1bcde628faa0944f0dab60a9aa46b0c62f3175e Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 17 Dec 2022 20:54:41 -0800 Subject: [PATCH 18/63] Implement lower cap datagram size (#890) --- dNet/dServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 481667b8..96bb5bc8 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -67,7 +67,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect } else { mLogger->Log("dServer", "FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port); return; } mLogger->SetLogToConsole(prevLogSetting); - + mPeer->SetMTUSize(1228); // This is hard coded by lu for some reason. //Connect to master if we are not master: if (serverType != ServerType::Master) { SetupForMasterConnection(); From b972acbacc773f221094d61c28d5f2c385913d20 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sun, 18 Dec 2022 06:49:13 -0800 Subject: [PATCH 19/63] Fix stream reads (#894) No changes expected --- dGame/dBehaviors/SwitchMultipleBehavior.cpp | 1 + dGame/dBehaviors/TacArcBehavior.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.cpp b/dGame/dBehaviors/SwitchMultipleBehavior.cpp index e92393fc..078464bb 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.cpp +++ b/dGame/dBehaviors/SwitchMultipleBehavior.cpp @@ -14,6 +14,7 @@ void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* if (!bitStream->Read(value)) { Game::logger->Log("SwitchMultipleBehavior", "Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; }; uint32_t trigger = 0; diff --git a/dGame/dBehaviors/TacArcBehavior.cpp b/dGame/dBehaviors/TacArcBehavior.cpp index 38efdea4..91df3879 100644 --- a/dGame/dBehaviors/TacArcBehavior.cpp +++ b/dGame/dBehaviors/TacArcBehavior.cpp @@ -22,6 +22,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre if (!bitStream->Read(hit)) { Game::logger->Log("TacArcBehavior", "Unable to read hit from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; }; if (this->m_checkEnv) { @@ -29,6 +30,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre if (!bitStream->Read(blocked)) { Game::logger->Log("TacArcBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; }; if (blocked) { @@ -43,6 +45,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre if (!bitStream->Read(count)) { Game::logger->Log("TacArcBehavior", "Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; }; if (count > m_maxTargets && m_maxTargets > 0) { @@ -56,6 +59,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre if (!bitStream->Read(id)) { Game::logger->Log("TacArcBehavior", "Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; }; targets.push_back(id); From 84c5d74450fca63a8da9aa68de9cd1682f1b7be7 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sun, 18 Dec 2022 07:46:04 -0800 Subject: [PATCH 20/63] Add Delete Inventory Slash Command (#865) * moving branch * Add deleteinven slash command * Change name of BRICKS_IN_BBB * Use string_view instead of strcmp * Remove GameConfig * Revert "Remove GameConfig" This reverts commit cef5cdeea2282e3fc09a118dbecb0009d851b95f. --- dCommon/GeneralUtils.h | 7 +++ dCommon/dEnums/dCommonVars.h | 20 ------- dCommon/dEnums/eInventoryType.h | 59 +++++++++++++++++++ dGame/Character.cpp | 1 + dGame/LeaderboardManager.cpp | 1 + dGame/UserManager.cpp | 1 + dGame/dBehaviors/OverTimeBehavior.cpp | 2 + dGame/dComponents/BuffComponent.cpp | 1 + dGame/dComponents/DestroyableComponent.cpp | 1 + dGame/dComponents/InventoryComponent.h | 1 + dGame/dComponents/MovementAIComponent.cpp | 1 + .../PropertyManagementComponent.cpp | 1 + .../dComponents/ScriptedActivityComponent.cpp | 1 + dGame/dGameMessages/GameMessages.cpp | 1 + dGame/dGameMessages/GameMessages.h | 3 +- dGame/dInventory/Inventory.cpp | 9 ++- dGame/dInventory/Inventory.h | 6 ++ dGame/dInventory/Item.cpp | 4 +- dGame/dInventory/Item.h | 1 + dGame/dMission/Mission.cpp | 3 +- dGame/dMission/MissionTask.cpp | 2 +- dGame/dUtilities/SlashCommandHandler.cpp | 27 +++++++++ .../02_server/Map/General/QbEnemyStunner.cpp | 1 + .../FireFirstSkillonStartup.cpp | 1 + .../ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp | 1 + dScripts/ai/NS/NsConcertInstrument.cpp | 1 + 26 files changed, 130 insertions(+), 27 deletions(-) create mode 100644 dCommon/dEnums/eInventoryType.h diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index af7c7012..d43ad9b1 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -14,6 +14,8 @@ #include "Game.h" #include "dLogger.h" +enum eInventoryType : uint32_t; + /*! \file GeneralUtils.hpp \brief A namespace containing general utility functions @@ -174,6 +176,11 @@ namespace GeneralUtils { return std::stoull(value); } + template <> + inline eInventoryType Parse(const char* value) { + return static_cast(std::stoul(value)); + } + template bool TryParse(const char* value, T& dst) { try { diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index f64d496f..d13e8b94 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -427,26 +427,6 @@ enum class UseItemResponse : uint32_t { MountsNotAllowed }; -/** - * Represents the different types of inventories an entity may have - */ -enum eInventoryType : uint32_t { - ITEMS = 0, - VAULT_ITEMS, - BRICKS, - MODELS_IN_BBB, - TEMP_ITEMS = 4, - MODELS, - TEMP_MODELS, - BEHAVIORS, - PROPERTY_DEEDS, - VENDOR_BUYBACK = 11, - HIDDEN = 12, //Used for missional items - VAULT_MODELS = 14, - ITEM_SETS, //internal - INVALID // made up, for internal use!!! -}; - enum eRebuildState : uint32_t { REBUILD_OPEN, REBUILD_COMPLETED = 2, diff --git a/dCommon/dEnums/eInventoryType.h b/dCommon/dEnums/eInventoryType.h new file mode 100644 index 00000000..12573aa4 --- /dev/null +++ b/dCommon/dEnums/eInventoryType.h @@ -0,0 +1,59 @@ +#pragma once + +#ifndef __EINVENTORYTYPE__H__ +#define __EINVENTORYTYPE__H__ + +#include +static const uint8_t NUMBER_OF_INVENTORIES = 17; +/** + * Represents the different types of inventories an entity may have + */ +enum eInventoryType : uint32_t { + ITEMS = 0, + VAULT_ITEMS, + BRICKS, + MODELS_IN_BBB, + TEMP_ITEMS, + MODELS, + TEMP_MODELS, + BEHAVIORS, + PROPERTY_DEEDS, + BRICKS_IN_BBB, + VENDOR, + VENDOR_BUYBACK, + QUEST, //Used for mission items + DONATION, + VAULT_MODELS, + ITEM_SETS, //internal, technically this is BankBehaviors. + INVALID // made up, for internal use!!!, Technically this called the ALL inventory. +}; + +class InventoryType { +public: + static const char* InventoryTypeToString(eInventoryType inventory) { + const char* eInventoryTypeTable[NUMBER_OF_INVENTORIES] = { + "ITEMS", + "VAULT_ITEMS", + "BRICKS", + "MODELS_IN_BBB", + "TEMP_ITEMS", + "MODELS", + "TEMP_MODELS", + "BEHAVIORS", + "PROPERTY_DEEDS", + "BRICKS_IN_BBB", + "VENDOR", + "VENDOR_BUYBACK", + "QUEST", //Used for mission items + "DONATION", + "VAULT_MODELS", + "ITEM_SETS", //internal, technically this is BankBehaviors. + "INVALID" // made up, for internal use!!!, Technically this called the ALL inventory. + }; + + if (inventory > NUMBER_OF_INVENTORIES - 1) return nullptr; + return eInventoryTypeTable[inventory]; + }; +}; + +#endif //!__EINVENTORYTYPE__H__ diff --git a/dGame/Character.cpp b/dGame/Character.cpp index a9cffc65..67a0bf1b 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -15,6 +15,7 @@ #include "Zone.h" #include "ChatPackets.h" #include "Inventory.h" +#include "InventoryComponent.h" Character::Character(uint32_t id, User* parentUser) { //First load the name, etc: diff --git a/dGame/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index b069e761..a0df940f 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -7,6 +7,7 @@ #include "GameMessages.h" #include "dLogger.h" #include "dConfig.h" +#include "CDClientManager.h" Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector entries, LWOOBJID relatedPlayer, LeaderboardType leaderboardType) { diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 6779a42c..70e76016 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -21,6 +21,7 @@ #include "EntityManager.h" #include "SkillComponent.h" #include "AssetManager.h" +#include "CDClientDatabase.h" UserManager* UserManager::m_Address = nullptr; diff --git a/dGame/dBehaviors/OverTimeBehavior.cpp b/dGame/dBehaviors/OverTimeBehavior.cpp index 43ac9bc2..20dd89af 100644 --- a/dGame/dBehaviors/OverTimeBehavior.cpp +++ b/dGame/dBehaviors/OverTimeBehavior.cpp @@ -6,6 +6,8 @@ #include "EntityManager.h" #include "SkillComponent.h" #include "DestroyableComponent.h" +#include "CDClientDatabase.h" +#include "CDClientManager.h" void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { const auto originator = context->originator; diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index af20fc00..d8d7428d 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -9,6 +9,7 @@ #include "SkillComponent.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" +#include "CDClientManager.h" std::unordered_map> BuffComponent::m_Cache{}; diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 3cf206da..c899d9e8 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -28,6 +28,7 @@ #include "CharacterComponent.h" #include "PossessableComponent.h" #include "PossessorComponent.h" +#include "InventoryComponent.h" #include "dZoneManager.h" DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 394cb801..8ae35f6c 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -19,6 +19,7 @@ #include "ItemSetPassiveAbility.h" #include "ItemSetPassiveAbilityID.h" #include "PossessorComponent.h" +#include "eInventoryType.h" class Entity; class ItemSet; diff --git a/dGame/dComponents/MovementAIComponent.cpp b/dGame/dComponents/MovementAIComponent.cpp index ed6ed483..92397a55 100644 --- a/dGame/dComponents/MovementAIComponent.cpp +++ b/dGame/dComponents/MovementAIComponent.cpp @@ -9,6 +9,7 @@ #include "dpWorld.h" #include "EntityManager.h" #include "SimplePhysicsComponent.h" +#include "CDClientManager.h" std::map MovementAIComponent::m_PhysicsSpeedCache = {}; diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index 648edff8..8d23c17e 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -17,6 +17,7 @@ #include "Player.h" #include "RocketLaunchpadControlComponent.h" #include "PropertyEntranceComponent.h" +#include "InventoryComponent.h" #include #include "CppScripts.h" diff --git a/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index f6d50d66..da546910 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -16,6 +16,7 @@ #include "GeneralUtils.h" #include "dZoneManager.h" #include "dConfig.h" +#include "InventoryComponent.h" #include "DestroyableComponent.h" ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) { diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 8c82f644..9aa8eda2 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -49,6 +49,7 @@ #include "ScriptComponent.h" #include "RebuildComponent.h" #include "VendorComponent.h" +#include "InventoryComponent.h" #include "RocketLaunchpadControlComponent.h" #include "PropertyEntranceComponent.h" #include "MovingPlatformComponent.h" diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 4f92480f..8a1c2fe5 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -5,7 +5,6 @@ #include "dCommonVars.h" #include "RakNetTypes.h" #include -#include "InventoryComponent.h" #include "dMessageIdentifiers.h" #include "AMFFormat.h" #include "AMFFormat_BitStream.h" @@ -21,6 +20,8 @@ class User; class Entity; class NiPoint3; enum class eUnequippableActiveType; +enum eInventoryType : uint32_t; +class Item; namespace GameMessages { class PropertyDataMessage; diff --git a/dGame/dInventory/Inventory.cpp b/dGame/dInventory/Inventory.cpp index 151e3164..990b08f3 100644 --- a/dGame/dInventory/Inventory.cpp +++ b/dGame/dInventory/Inventory.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "Game.h" #include "Item.h" +#include "InventoryComponent.h" #include "eItemType.h" std::vector Inventory::m_GameMasterRestrictedItems = { @@ -266,7 +267,7 @@ eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot) { case eItemType::ITEM_TYPE_QUEST_OBJECT: case eItemType::ITEM_TYPE_UNKNOWN: default: - return HIDDEN; + return QUEST; } } @@ -300,6 +301,12 @@ const std::vector& Inventory::GetAllGMItems() { return m_GameMasterRestrictedItems; } +void Inventory::DeleteAllItems() { + while (!this->items.empty()) { + if (items.begin()->second) items.begin()->second->SetCount(0); + } +} + Inventory::~Inventory() { for (auto item : items) { delete item.second; diff --git a/dGame/dInventory/Inventory.h b/dGame/dInventory/Inventory.h index 6c6a4306..cd381db3 100644 --- a/dGame/dInventory/Inventory.h +++ b/dGame/dInventory/Inventory.h @@ -10,6 +10,7 @@ #include "CDClientManager.h" #include "dCommonVars.h" +enum eInventoryType : uint32_t; class Item; class InventoryComponent; @@ -152,6 +153,11 @@ public: */ static const std::vector& GetAllGMItems(); + /** + * Remove ALL Items from this inventory. + */ + void DeleteAllItems(); + ~Inventory(); private: diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index 02739ec2..778d8237 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -14,9 +14,7 @@ #include "CharacterComponent.h" #include "eItemType.h" #include "AssetManager.h" - -class Inventory; - +#include "InventoryComponent.h" Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) { if (!Inventory::IsValidItem(lot)) { diff --git a/dGame/dInventory/Item.h b/dGame/dInventory/Item.h index db7e246a..bb8316d7 100644 --- a/dGame/dInventory/Item.h +++ b/dGame/dInventory/Item.h @@ -6,6 +6,7 @@ #include "CDClientManager.h" #include "dLogger.h" #include "Preconditions.h" +#include "eInventoryType.h" /** * An item that can be stored in an inventory and optionally consumed or equipped diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 0a8a57fe..61b41992 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -16,6 +16,7 @@ #include "dLogger.h" #include "dServer.h" #include "dZoneManager.h" +#include "InventoryComponent.h" #include "Database.h" Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { @@ -424,7 +425,7 @@ void Mission::YieldRewards() { for (const auto target : task->GetAllTargets()) { // This is how live did it. ONLY remove item collection items from the items and hidden inventories and none of the others. inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::ITEMS); - inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::HIDDEN); + inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::QUEST); missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, target, LWOOBJID_EMPTY, "", -task->GetClientInfo().targetValue); } diff --git a/dGame/dMission/MissionTask.cpp b/dGame/dMission/MissionTask.cpp index dc2cb149..d52e6e95 100644 --- a/dGame/dMission/MissionTask.cpp +++ b/dGame/dMission/MissionTask.cpp @@ -11,9 +11,9 @@ #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "dZoneManager.h" +#include "InventoryComponent.h" #include "MissionComponent.h" - MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) { this->info = info; this->mission = mission; diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 89f11346..7b1bf66c 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -1803,6 +1803,33 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, message); } + if (chatCommand == "deleteinven" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + eInventoryType inventoryType = eInventoryType::INVALID; + if (!GeneralUtils::TryParse(args[0], inventoryType)) { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(args[0].begin(), args[0].end(),args[0].begin(), ::toupper); + Game::logger->Log("SlashCommandHandler", "looking for inventory %s", args[0].c_str()); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(args[0]) == std::string_view(InventoryType::InventoryTypeToString(static_cast(index)))) inventoryType = static_cast(index); + } + } + + if (inventoryType == eInventoryType::INVALID || inventoryType >= NUMBER_OF_INVENTORIES) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory provided."); + return; + } + + auto* inventoryComponent = entity->GetComponent(); + if (!inventoryComponent) return; + + auto* inventoryToDelete = inventoryComponent->GetInventory(inventoryType); + if (!inventoryToDelete) return; + + inventoryToDelete->DeleteAllItems(); + Game::logger->Log("SlashCommandHandler", "Deleted inventory %s for user %llu", args[0].c_str(), entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(args[0])); + } + if (chatCommand == "inspect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { Entity* closest = nullptr; diff --git a/dScripts/02_server/Map/General/QbEnemyStunner.cpp b/dScripts/02_server/Map/General/QbEnemyStunner.cpp index 5d31a788..2b15a056 100644 --- a/dScripts/02_server/Map/General/QbEnemyStunner.cpp +++ b/dScripts/02_server/Map/General/QbEnemyStunner.cpp @@ -1,5 +1,6 @@ #include "QbEnemyStunner.h" #include "SkillComponent.h" +#include "CDClientManager.h" #include "DestroyableComponent.h" void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) { diff --git a/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp b/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp index cd0d94f2..dcccc337 100644 --- a/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp +++ b/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp @@ -3,6 +3,7 @@ #include "SkillComponent.h" #include "CDClientDatabase.h" #include "CDObjectSkillsTable.h" +#include "CDClientManager.h" void FireFirstSkillonStartup::OnStartup(Entity* self) { auto skillComponent = self->GetComponent(); diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 912b9f58..47bca374 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -11,6 +11,7 @@ #include "MovementAIComponent.h" #include "../dWorldServer/ObjectIDManager.h" #include "MissionComponent.h" +#include "InventoryComponent.h" void SGCannon::OnStartup(Entity* self) { Game::logger->Log("SGCannon", "OnStartup"); diff --git a/dScripts/ai/NS/NsConcertInstrument.cpp b/dScripts/ai/NS/NsConcertInstrument.cpp index 508b7b5b..bba3986d 100644 --- a/dScripts/ai/NS/NsConcertInstrument.cpp +++ b/dScripts/ai/NS/NsConcertInstrument.cpp @@ -5,6 +5,7 @@ #include "EntityManager.h" #include "RebuildComponent.h" #include "SoundTriggerComponent.h" +#include "InventoryComponent.h" #include "MissionComponent.h" // Constants are at the bottom From f311685dda33dc2d96d6840852db709e0f1227ce Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 19 Dec 2022 00:07:43 -0800 Subject: [PATCH 21/63] Fix Some missions not progressing if they are the last item in the inventory (#899) --- dGame/dGameMessages/GameMessages.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 9aa8eda2..9753868d 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -5736,16 +5736,16 @@ void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* } auto* item = inventory->FindItemById(itemConsumed); - if (item == nullptr) { return; } + LOT itemLot = item->GetLot(); item->Consume(); auto* missions = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); if (missions != nullptr) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_FOOD, item->GetLot()); + missions->Progress(MissionTaskType::MISSION_TASK_TYPE_FOOD, itemLot); } } From 157a05239ed969b9116158147e5eb69db5be42c4 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Mon, 19 Dec 2022 13:45:50 -0600 Subject: [PATCH 22/63] Add speedbase readling and writing to the level prograssion component and impli proper character versions for fixes (#856) * Add speed base readling and writing to the level prograssion component Add retroactive fix to the world transfer TODO: see about versioning charxml fixes to make them not run every time * version all current changes * cleanup speed behavior add calculate for future use in scripts make < 1 speed multiplier possible tested wormholer and it plays anims correctly * cap the lower end of the speed multiplier until the ending the behavior on hit properly works * address feedback add emun for character version make set ignore multipliers consistent in speed behavior switch case for char version upgrades * remove the ability to stack speed boosts * update value on level ups --- dCommon/dEnums/eCharacterVersion.h | 21 ++++++ dGame/Entity.cpp | 4 +- dGame/dBehaviors/SpeedBehavior.cpp | 67 ++++--------------- dGame/dBehaviors/SpeedBehavior.h | 2 + .../ControllablePhysicsComponent.cpp | 38 ++++++++--- .../ControllablePhysicsComponent.h | 17 +++++ .../dComponents/LevelProgressionComponent.cpp | 19 +++++- dGame/dComponents/LevelProgressionComponent.h | 42 ++++++++++++ dWorldServer/WorldServer.cpp | 25 ++++++- 9 files changed, 166 insertions(+), 69 deletions(-) create mode 100644 dCommon/dEnums/eCharacterVersion.h diff --git a/dCommon/dEnums/eCharacterVersion.h b/dCommon/dEnums/eCharacterVersion.h new file mode 100644 index 00000000..0fab4498 --- /dev/null +++ b/dCommon/dEnums/eCharacterVersion.h @@ -0,0 +1,21 @@ +#pragma once + +#ifndef __ECHARACTERVERSION__H__ +#define __ECHARACTERVERSION__H__ + +#include + +enum class eCharacterVersion : uint32_t { +// Versions from the live game + RELEASE = 0, // Initial release of the game + LIVE, // Fixes for the 1.9 release bug fixes for missions leading up to joining a faction +// New versions for DLU fixes + // Fixes the "Joined a faction" player flag not being set properly + PLAYER_FACTION_FLAGS, + // Fixes vault size value + VAULT_SIZE, + // Fixes speed base value in level component + UP_TO_DATE, // will become SPEED_BASE +}; + +#endif //!__ECHARACTERVERSION__H__ diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 1f094291..cbab87db 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -769,8 +769,8 @@ no_ghosting: auto* controllablePhysicsComponent = GetComponent(); auto* levelComponent = GetComponent(); - if (controllablePhysicsComponent != nullptr && levelComponent->GetLevel() >= 20) { - controllablePhysicsComponent->SetSpeedMultiplier(525.0f / 500.0f); + if (controllablePhysicsComponent && levelComponent) { + controllablePhysicsComponent->SetSpeedMultiplier(levelComponent->GetSpeedBase() / 500.0f); } } } diff --git a/dGame/dBehaviors/SpeedBehavior.cpp b/dGame/dBehaviors/SpeedBehavior.cpp index c7855557..bec2b1cb 100644 --- a/dGame/dBehaviors/SpeedBehavior.cpp +++ b/dGame/dBehaviors/SpeedBehavior.cpp @@ -7,85 +7,44 @@ void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - if (m_AffectsCaster) { - branch.target = context->caster; - } + if (m_AffectsCaster) branch.target = context->caster; auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } + if (!target) return; auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current + ((m_RunSpeed - 500.0f) / 500.0f)); - + controllablePhysicsComponent->AddSpeedboost(m_RunSpeed); EntityManager::Instance()->SerializeEntity(target); if (branch.duration > 0.0f) { context->RegisterTimerBehavior(this, branch); } else if (branch.start > 0) { - controllablePhysicsComponent->SetIgnoreMultipliers(true); - context->RegisterEndBehavior(this, branch); } } -void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { - auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } - - auto* controllablePhysicsComponent = target->GetComponent(); - - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(target); +void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); } void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } + if (!target) return; auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetIgnoreMultipliers(false); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - + controllablePhysicsComponent->RemoveSpeedboost(m_RunSpeed); EntityManager::Instance()->SerializeEntity(target); } +void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + End(context, branch, second); +} + void SpeedBehavior::Load() { m_RunSpeed = GetFloat("run_speed"); - - if (m_RunSpeed < 500.0f) { - m_RunSpeed = 500.0f; - } - m_AffectsCaster = GetBoolean("affects_caster"); } diff --git a/dGame/dBehaviors/SpeedBehavior.h b/dGame/dBehaviors/SpeedBehavior.h index 04c0090f..57c46842 100644 --- a/dGame/dBehaviors/SpeedBehavior.h +++ b/dGame/dBehaviors/SpeedBehavior.h @@ -13,6 +13,8 @@ public: void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index d7caf6a9..a5e447c8 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -12,6 +12,7 @@ #include "EntityManager.h" #include "Character.h" #include "dZoneManager.h" +#include "LevelProgressionComponent.h" ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Component(entity) { m_Position = {}; @@ -73,13 +74,7 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo outBitStream->Write0(); //This contains info about immunities, but for now I'm leaving it out. } - if (m_SpeedMultiplier < 1.0f) { - m_DirtyCheats = false; - } - - if (m_IgnoreMultipliers) { - m_DirtyCheats = false; - } + if (m_IgnoreMultipliers) m_DirtyCheats = false; outBitStream->Write(m_DirtyCheats); if (m_DirtyCheats) { @@ -263,7 +258,7 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) { if (pos != m_ActivePickupRadiusScales.end()) { m_ActivePickupRadiusScales.erase(pos); } else { - Game::logger->Log("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size()); + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size()); return; } @@ -276,3 +271,30 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) { } EntityManager::Instance()->SerializeEntity(m_Parent); } + +void ControllablePhysicsComponent::AddSpeedboost(float value) { + m_ActiveSpeedBoosts.push_back(value); + m_SpeedBoost = value; + SetSpeedMultiplier(value / 500.0f); // 500 being the base speed +} + +void ControllablePhysicsComponent::RemoveSpeedboost(float value) { + const auto pos = std::find(m_ActiveSpeedBoosts.begin(), m_ActiveSpeedBoosts.end(), value); + if (pos != m_ActiveSpeedBoosts.end()) { + m_ActiveSpeedBoosts.erase(pos); + } else { + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find speedboost %f in list of active speedboosts. List has %i active speedboosts.", value, m_ActiveSpeedBoosts.size()); + return; + } + + // Recalculate speedboost since we removed one + m_SpeedBoost = 0.0f; + if (m_ActiveSpeedBoosts.size() == 0) { // no active speed boosts left, so return to base speed + auto* levelProgressionComponent = m_Parent->GetComponent(); + if (levelProgressionComponent) m_SpeedBoost = levelProgressionComponent->GetSpeedBase(); + } else { // Used the last applied speedboost + m_SpeedBoost = m_ActiveSpeedBoosts.back(); + } + SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed + EntityManager::Instance()->SerializeEntity(m_Parent); +} diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index ac481b9f..e029d607 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -257,6 +257,13 @@ public: */ std::vector GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; }; + + void AddSpeedboost(float value); + + void RemoveSpeedboost(float value); + + std::vector GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; }; + private: /** * The entity that owns this component @@ -372,6 +379,16 @@ private: * If the entity is teleporting */ bool m_IsTeleporting; + + /** + * The list of speed boosts for this entity + */ + std::vector m_ActiveSpeedBoosts; + + /** + * The active speed boost for this entity + */ + float m_SpeedBoost; }; #endif // CONTROLLABLEPHYSICSCOMPONENT_H diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp index ee3cfc6b..6e6b823e 100644 --- a/dGame/dComponents/LevelProgressionComponent.cpp +++ b/dGame/dComponents/LevelProgressionComponent.cpp @@ -7,6 +7,8 @@ LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component(parent) { m_Parent = parent; m_Level = 1; + m_SpeedBase = 500.0f; + m_CharacterVersion = eCharacterVersion::LIVE; } void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { @@ -16,7 +18,8 @@ void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { return; } level->SetAttribute("l", m_Level); - + level->SetAttribute("sb", m_SpeedBase); + level->SetAttribute("cv", static_cast(m_CharacterVersion)); } void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { @@ -26,7 +29,10 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { return; } level->QueryAttribute("l", &m_Level); - + level->QueryAttribute("sb", &m_SpeedBase); + uint32_t characterVersion; + level->QueryAttribute("cv", &characterVersion); + m_CharacterVersion = static_cast(characterVersion); } void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { @@ -60,7 +66,8 @@ void LevelProgressionComponent::HandleLevelUp() { } break; case 9: - controllablePhysicsComponent->SetSpeedMultiplier(static_cast(reward->value) / 500.0f); + SetSpeedBase(static_cast(reward->value) ); + controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f); break; case 11: case 12: @@ -72,3 +79,9 @@ void LevelProgressionComponent::HandleLevelUp() { // Tell the client we have finished sending level rewards. if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, !rewardingItem); } + +void LevelProgressionComponent::SetRetroactiveBaseSpeed(){ + if (m_Level >= 20) m_SpeedBase = 525.0f; + auto* controllablePhysicsComponent = m_Parent->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetSpeedMultiplier(m_SpeedBase / 500.0f); +} diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h index 53f6693e..dd3fbfbb 100644 --- a/dGame/dComponents/LevelProgressionComponent.h +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -3,11 +3,13 @@ #include "Entity.h" #include "GameMessages.h" #include "Component.h" +#include "eCharacterVersion.h" /** * Component that handles level progression and serilization. * */ + class LevelProgressionComponent : public Component { public: static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_LEVEL_PROGRESSION; @@ -44,11 +46,40 @@ public: */ void SetLevel(uint32_t level) { m_Level = level; m_DirtyLevelInfo = true; } + /** + * Gets the current Speed Base of the entity + * @return the current Speed Base of the entity + */ + const uint32_t GetSpeedBase() const { return m_SpeedBase; } + + /** + * Sets the Speed Base of the entity + * @param SpeedBase the Speed Base to set + */ + void SetSpeedBase(uint32_t SpeedBase) { m_SpeedBase = SpeedBase; } + /** * Gives the player rewards for the last level that they leveled up from */ void HandleLevelUp(); + /** + * Gets the current Character Version of the entity + * @return the current Character Version of the entity + */ + const eCharacterVersion GetCharacterVersion() const { return m_CharacterVersion; } + + /** + * Sets the Character Version of the entity + * @param CharacterVersion the Character Version to set + */ + void SetCharacterVersion(eCharacterVersion CharacterVersion) { m_CharacterVersion = CharacterVersion; } + + /** + * Set the Base Speed retroactively of the entity + */ + void SetRetroactiveBaseSpeed(); + private: /** * whether the level is dirty @@ -59,4 +90,15 @@ private: * Level of the entity */ uint32_t m_Level; + + /** + * The base speed of the entity + */ + float m_SpeedBase; + + /** + * The Character format version + */ + eCharacterVersion m_CharacterVersion; + }; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 594d3dc7..d204d5c9 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -56,6 +56,7 @@ #include "Player.h" #include "PropertyManagementComponent.h" #include "AssetManager.h" +#include "LevelProgressionComponent.h" #include "eBlueprintSaveResponseType.h" #include "ZCompression.h" @@ -993,9 +994,29 @@ void HandlePacket(Packet* packet) { player->GetComponent()->RocketUnEquip(player); } - c->SetRetroactiveFlags(); + // Do charxml fixes here + auto* levelComponent = player->GetComponent(); + if (!levelComponent) return; - player->RetroactiveVaultSize(); + auto version = levelComponent->GetCharacterVersion(); + switch(version) { + case eCharacterVersion::RELEASE: + // TODO: Implement, super low priority + case eCharacterVersion::LIVE: + Game::logger->Log("WorldServer", "Updating Character Flags"); + c->SetRetroactiveFlags(); + levelComponent->SetCharacterVersion(eCharacterVersion::PLAYER_FACTION_FLAGS); + case eCharacterVersion::PLAYER_FACTION_FLAGS: + Game::logger->Log("WorldServer", "Updating Vault Size"); + player->RetroactiveVaultSize(); + levelComponent->SetCharacterVersion(eCharacterVersion::VAULT_SIZE); + case eCharacterVersion::VAULT_SIZE: + Game::logger->Log("WorldServer", "Updaing Speedbase"); + levelComponent->SetRetroactiveBaseSpeed(); + levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); + case eCharacterVersion::UP_TO_DATE: + break; + } player->GetCharacter()->SetTargetScene(""); From d69f733772d3bca27261aaf11b72c96754123724 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 19 Dec 2022 12:51:44 -0800 Subject: [PATCH 23/63] Fix trading taking the wrong item (#900) * Fix trading taking the wrong item * Add missing returns * Improve further Do all verification first. Then actually do the trade. Prevents possible cheating attempts --- dGame/TradingManager.cpp | 53 ++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/dGame/TradingManager.cpp b/dGame/TradingManager.cpp index e49cca70..ed55f217 100644 --- a/dGame/TradingManager.cpp +++ b/dGame/TradingManager.cpp @@ -103,6 +103,7 @@ void Trade::SetAccepted(LWOOBJID participant, bool value) { } Complete(); + TradingManager::Instance()->CancelTrade(m_TradeId); } } @@ -121,33 +122,59 @@ void Trade::Complete() { if (inventoryA == nullptr || inventoryB == nullptr || characterA == nullptr || characterB == nullptr || missionsA == nullptr || missionsB == nullptr) return; + // First verify both players have the coins and items requested for the trade. + if (characterA->GetCoins() < m_CoinsA || characterB->GetCoins() < m_CoinsB) { + Game::logger->Log("TradingManager", "Possible coin trade cheating attempt! Aborting trade."); + return; + } + + for (const auto& tradeItem : m_ItemsA) { + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str()); + return; + } + } + + for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } + + // Now actually do the trade. characterA->SetCoins(characterA->GetCoins() - m_CoinsA + m_CoinsB, eLootSourceType::LOOT_SOURCE_TRADE); characterB->SetCoins(characterB->GetCoins() - m_CoinsB + m_CoinsA, eLootSourceType::LOOT_SOURCE_TRADE); for (const auto& tradeItem : m_ItemsA) { - inventoryA->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); - + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); missionsA->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } - - for (const auto& tradeItem : m_ItemsB) { - inventoryB->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); - - missionsB->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } - - for (const auto& tradeItem : m_ItemsA) { inventoryB->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); } for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); + missionsB->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); inventoryA->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); } - TradingManager::Instance()->CancelTrade(m_TradeId); - characterA->SaveXMLToDatabase(); characterB->SaveXMLToDatabase(); + return; } void Trade::Cancel() { From 2fdcf62ec61ca551ff4bca4ca68d47891d1e7ceb Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 19 Dec 2022 12:52:00 -0800 Subject: [PATCH 24/63] Fix overread in projectile behavior and address broken stuns (#898) * Fix overread in projectile behavior * Fix stuns * Correctly read in bitStream --- dGame/dBehaviors/AttackDelayBehavior.cpp | 2 +- dGame/dBehaviors/BehaviorContext.cpp | 3 ++- dGame/dBehaviors/BehaviorContext.h | 2 +- dGame/dBehaviors/ProjectileAttackBehavior.cpp | 4 +++- dGame/dBehaviors/ProjectileAttackBehavior.h | 2 ++ 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dGame/dBehaviors/AttackDelayBehavior.cpp b/dGame/dBehaviors/AttackDelayBehavior.cpp index 201921a3..ccea5fd9 100644 --- a/dGame/dBehaviors/AttackDelayBehavior.cpp +++ b/dGame/dBehaviors/AttackDelayBehavior.cpp @@ -13,7 +13,7 @@ void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi }; for (auto i = 0u; i < this->m_numIntervals; ++i) { - context->RegisterSyncBehavior(handle, this, branch); + context->RegisterSyncBehavior(handle, this, branch, m_ignoreInterrupts); } } diff --git a/dGame/dBehaviors/BehaviorContext.cpp b/dGame/dBehaviors/BehaviorContext.cpp index 4cd9e415..c2f0c88e 100644 --- a/dGame/dBehaviors/BehaviorContext.cpp +++ b/dGame/dBehaviors/BehaviorContext.cpp @@ -45,12 +45,13 @@ uint32_t BehaviorContext::GetUniqueSkillId() const { } -void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext) { +void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext, bool ignoreInterrupts) { auto entry = BehaviorSyncEntry(); entry.handle = syncId; entry.behavior = behavior; entry.branchContext = branchContext; + entry.ignoreInterrupts = ignoreInterrupts; this->syncEntries.push_back(entry); } diff --git a/dGame/dBehaviors/BehaviorContext.h b/dGame/dBehaviors/BehaviorContext.h index 0462d97f..dbba4d91 100644 --- a/dGame/dBehaviors/BehaviorContext.h +++ b/dGame/dBehaviors/BehaviorContext.h @@ -80,7 +80,7 @@ struct BehaviorContext uint32_t GetUniqueSkillId() const; - void RegisterSyncBehavior(uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext); + void RegisterSyncBehavior(uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext, bool ignoreInterrupts = false); void RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, LWOOBJID second = LWOOBJID_EMPTY); diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.cpp b/dGame/dBehaviors/ProjectileAttackBehavior.cpp index c14f032d..2b38db8f 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.cpp +++ b/dGame/dBehaviors/ProjectileAttackBehavior.cpp @@ -31,7 +31,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea return; } - if (m_useMouseposit) { + if (m_ProjectileType == 1) { NiPoint3 targetPosition = NiPoint3::ZERO; if (!bitStream->Read(targetPosition)) { Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); @@ -157,4 +157,6 @@ void ProjectileAttackBehavior::Load() { this->m_trackRadius = GetFloat("track_radius"); this->m_useMouseposit = GetBoolean("use_mouseposit"); + + this->m_ProjectileType = GetInt("projectile_type"); } diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.h b/dGame/dBehaviors/ProjectileAttackBehavior.h index 17353a2a..b307e66c 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.h +++ b/dGame/dBehaviors/ProjectileAttackBehavior.h @@ -23,6 +23,8 @@ public: bool m_useMouseposit; + int32_t m_ProjectileType; + /* * Inherited */ From f2fa81b5c3b4be084b2664b83debc26ac5d0a8dd Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Tue, 20 Dec 2022 13:20:44 -0800 Subject: [PATCH 25/63] Fix lobbies (#901) --- dGame/dComponents/ScriptedActivityComponent.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index da546910..ee7ca22e 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -208,7 +208,7 @@ void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) { } void ScriptedActivityComponent::Update(float deltaTime) { - + std::vector lobbiesToRemove{}; // Ticks all the lobbies, not applicable for non-instance activities for (Lobby* lobby : m_Queue) { for (LobbyPlayer* player : lobby->players) { @@ -219,6 +219,11 @@ void ScriptedActivityComponent::Update(float deltaTime) { } } + if (lobby->players.empty()) { + lobbiesToRemove.push_back(lobby); + continue; + } + // Update the match time for all players if (m_ActivityInfo.maxTeamSize != 1 && lobby->players.size() >= m_ActivityInfo.minTeamSize || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() >= m_ActivityInfo.minTeams) { @@ -262,13 +267,17 @@ void ScriptedActivityComponent::Update(float deltaTime) { // The timer has elapsed, start the instance if (lobby->timer <= 0.0f) { Game::logger->Log("ScriptedActivityComponent", "Setting up instance."); - ActivityInstance* instance = NewInstance(); LoadPlayersIntoInstance(instance, lobby->players); - RemoveLobby(lobby); instance->StartZone(); + lobbiesToRemove.push_back(lobby); } } + + while (!lobbiesToRemove.empty()) { + RemoveLobby(lobbiesToRemove.front()); + lobbiesToRemove.erase(lobbiesToRemove.begin()); + } } void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) { From 0a31db9d4410d2ca28b12f3fab2631a580d1ae2d Mon Sep 17 00:00:00 2001 From: Neal Spellman Date: Tue, 20 Dec 2022 17:10:54 -0500 Subject: [PATCH 26/63] Updated README and CREDITS (#904) - README now has proper capitalization for categories in the credits. - New layout with former contributors moved to below active contributors. - LEGO Universe credits linked for the special thanks. - Aronwk properly recognized as DLU team member after mistakenly not included. - Vanity credits updated to more closely mirror categories in README's credits. --- README.md | 26 +++++++++++++------------- vanity/CREDITS.md | 13 ++++++------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 87319c10..bd9dd6b7 100644 --- a/README.md +++ b/README.md @@ -422,11 +422,6 @@ Here is a summary of the commands available in-game. All commands are prefixed b # Credits -## Active Contributors -* [EmosewaMC](https://github.com/EmosewaMC) -* [Jettford](https://github.com/Jettford) -* [Aaron K.](https://github.com/aronwk-aaron) - ## DLU Team * [DarwinAnim8or](https://github.com/DarwinAnim8or) * [Wincent01](https://github.com/Wincent01) @@ -434,25 +429,30 @@ Here is a summary of the commands available in-game. All commands are prefixed b * [averysumner](https://github.com/codeshaunted) * [Jon002](https://github.com/jaller200) * [Jonny](https://github.com/cuzitsjonny) +* [Aaron K.](https://github.com/aronwk-aaron) -### Research and tools +### Research and Tools * [lcdr](https://github.com/lcdr) * [Xiphoseer](https://github.com/Xiphoseer) -### Community management +### Community Management * [Neal](https://github.com/NealSpellman) -### Former contributors +### Logo +* Cole Peterson (BlasterBuilder) + +## Active Contributors +* [EmosewaMC](https://github.com/EmosewaMC) +* [Jettford](https://github.com/Jettford) + +## Former Contributors * TheMachine * Matthew * [Raine](https://github.com/Rainebannister) * Bricknave -### Logo -* Cole Peterson (BlasterBuilder) - -## Special thanks +## Special Thanks * humanoid24 * pwjones1969 * [Simon](https://github.com/SimonNitzsche) -* ALL OF THE NETDEVIL AND LEGO TEAMS! +* [ALL OF THE NETDEVIL AND LEGO TEAMS!](https://www.mobygames.com/game/macintosh/lego-universe/credits) diff --git a/vanity/CREDITS.md b/vanity/CREDITS.md index e130cfb3..6780cff7 100644 --- a/vanity/CREDITS.md +++ b/vanity/CREDITS.md @@ -1,18 +1,17 @@ # CREDITS -## Developers +## DLU Team DarwinAnim8or (Max) Wincent01 Mick averysumner (codeshaunted) Jon002 Jonny -EmosewaMC -Jettford - -## Research & Tooling Xiphoseer lcdr - -## Community Management +Aaron K. Neal + +## Active Contributors +EmosewaMC +Jettford \ No newline at end of file From 38eb441ca14037b626339f17fd40bdc870f9fc84 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 21 Dec 2022 00:26:17 -0800 Subject: [PATCH 27/63] Correct Projectile behavior bitStream reads (#907) --- dGame/dBehaviors/BehaviorBranchContext.h | 2 ++ dGame/dBehaviors/BehaviorContext.cpp | 1 + dGame/dBehaviors/ProjectileAttackBehavior.cpp | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dGame/dBehaviors/BehaviorBranchContext.h b/dGame/dBehaviors/BehaviorBranchContext.h index 5b2ec595..2e56cd35 100644 --- a/dGame/dBehaviors/BehaviorBranchContext.h +++ b/dGame/dBehaviors/BehaviorBranchContext.h @@ -15,6 +15,8 @@ struct BehaviorBranchContext uint32_t start = 0; + bool isSync = false; + BehaviorBranchContext(); BehaviorBranchContext(LWOOBJID target, float duration = 0, const NiPoint3& referencePosition = NiPoint3(0, 0, 0)); diff --git a/dGame/dBehaviors/BehaviorContext.cpp b/dGame/dBehaviors/BehaviorContext.cpp index c2f0c88e..ebed10ba 100644 --- a/dGame/dBehaviors/BehaviorContext.cpp +++ b/dGame/dBehaviors/BehaviorContext.cpp @@ -51,6 +51,7 @@ void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* beha entry.handle = syncId; entry.behavior = behavior; entry.branchContext = branchContext; + entry.branchContext.isSync = true; entry.ignoreInterrupts = ignoreInterrupts; this->syncEntries.push_back(entry); diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.cpp b/dGame/dBehaviors/ProjectileAttackBehavior.cpp index 2b38db8f..3ce6c415 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.cpp +++ b/dGame/dBehaviors/ProjectileAttackBehavior.cpp @@ -31,7 +31,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea return; } - if (m_ProjectileType == 1) { + if (m_useMouseposit && !branch.isSync) { NiPoint3 targetPosition = NiPoint3::ZERO; if (!bitStream->Read(targetPosition)) { Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); From 51dd56f0a0479eae60da3d09279b6c2685b96a70 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 21 Dec 2022 08:51:27 -0800 Subject: [PATCH 28/63] Add MTU config option (#908) * Add config option * Add reloading --- dGame/dUtilities/SlashCommandHandler.cpp | 1 + dNet/dServer.cpp | 8 +++++++- dNet/dServer.h | 1 + resources/sharedconfig.ini | 10 +++++++++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 7b1bf66c..9a63f83c 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -1762,6 +1762,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit scriptedActivityComponent->ReloadConfig(); } + Game::server->UpdateMaximumMtuSize(); Game::server->UpdateBandwidthLimit(); ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); } diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 55e07da3..a3961d45 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -68,7 +68,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect } else { mLogger->Log("dServer", "FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port); return; } mLogger->SetLogToConsole(prevLogSetting); - mPeer->SetMTUSize(1228); // This is hard coded by lu for some reason. + //Connect to master if we are not master: if (serverType != ServerType::Master) { SetupForMasterConnection(); @@ -188,6 +188,7 @@ bool dServer::Startup() { mPeer->SetIncomingPassword("3.25 DARKFLAME1", 15); } else { UpdateBandwidthLimit(); + UpdateMaximumMtuSize(); mPeer->SetIncomingPassword("3.25 ND1", 8); } @@ -197,6 +198,11 @@ bool dServer::Startup() { return true; } +void dServer::UpdateMaximumMtuSize() { + auto maxMtuSize = mConfig->GetValue("maximum_mtu_size"); + mPeer->SetMTUSize(maxMtuSize.empty() ? 1228 : std::stoi(maxMtuSize)); +} + void dServer::UpdateBandwidthLimit() { auto newBandwidth = mConfig->GetValue("maximum_outgoing_bandwidth"); mPeer->SetPerConnectionOutgoingBandwidthLimit(!newBandwidth.empty() ? std::stoi(newBandwidth) : 0); diff --git a/dNet/dServer.h b/dNet/dServer.h index af4c8322..d9e74d2e 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -57,6 +57,7 @@ public: ReplicaManager* GetReplicaManager() { return mReplicaManager; } void UpdateReplica(); void UpdateBandwidthLimit(); + void UpdateMaximumMtuSize(); int GetPing(const SystemAddress& sysAddr) const; int GetLatestPing(const SystemAddress& sysAddr) const; diff --git a/resources/sharedconfig.ini b/resources/sharedconfig.ini index 439ffe2f..d2c43d11 100644 --- a/resources/sharedconfig.ini +++ b/resources/sharedconfig.ini @@ -26,5 +26,13 @@ dump_folder= # Either the folder with /res or with /client and /versions client_location= -# The maximum outgoing bandwidth in bits +# The maximum outgoing bandwidth in bits. If your clients are having +# issues with enemies taking a while to catch up to them, increse this value. maximum_outgoing_bandwidth=80000 + +# The Maximum Translation Unit (MTU) size for packets. If players are +# getting stuck at 55% on the loading screen, lower this number to +# reduce the chances of packet loss. This value only has an effect +# from 512 <= maximum_mtu_size <= 1492 so make sure to keep this +# value within that range. +maximum_mtu_size=1228 From bd7f532a280e959c622685b53aa325f56226087f Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 21 Dec 2022 14:33:41 -0800 Subject: [PATCH 29/63] Implement the Imaginite Backpack and Shard armor scripts (#886) * Imaginite Pack now works * Remove unused params * Address issues * Add TeslaPack script Co-authored-by: aronwk-aaron --- CMakeLists.txt | 1 + dGame/Entity.cpp | 16 ++++++++ dGame/Entity.h | 8 ++++ dGame/dComponents/DestroyableComponent.cpp | 24 ++++++++++++ dGame/dComponents/DestroyableComponent.h | 20 ++++++++++ dGame/dComponents/InventoryComponent.cpp | 38 ++++++++++++++++++- dGame/dComponents/InventoryComponent.h | 14 +++++++ dScripts/CMakeLists.txt | 6 +++ dScripts/CppScripts.cpp | 9 +++++ dScripts/CppScripts.h | 23 +++++++++++ dScripts/EquipmentTriggers/CMakeLists.txt | 3 ++ .../EquipmentTriggers/CoilBackpackBase.cpp | 25 ++++++++++++ dScripts/EquipmentTriggers/CoilBackpackBase.h | 21 ++++++++++ dScripts/EquipmentTriggers/GemPack.h | 14 +++++++ dScripts/EquipmentTriggers/ShardArmor.h | 14 +++++++ dScripts/EquipmentTriggers/TeslaPack.h | 14 +++++++ 16 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 dScripts/EquipmentTriggers/CMakeLists.txt create mode 100644 dScripts/EquipmentTriggers/CoilBackpackBase.cpp create mode 100644 dScripts/EquipmentTriggers/CoilBackpackBase.h create mode 100644 dScripts/EquipmentTriggers/GemPack.h create mode 100644 dScripts/EquipmentTriggers/ShardArmor.h create mode 100644 dScripts/EquipmentTriggers/TeslaPack.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 163196fb..b9596649 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,6 +176,7 @@ set(INCLUDED_DIRECTORIES "dScripts/ai" "dScripts/client" "dScripts/EquipmentScripts" + "dScripts/EquipmentTriggers" "dScripts/zone" "dScripts/02_server/DLU" "dScripts/02_server/Enemy" diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index cbab87db..16b2c5a1 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -824,6 +824,22 @@ std::vector Entity::GetScriptComponents() { return comps; } +void Entity::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName) { + if (notificationName == "HitOrHealResult" || notificationName == "Hit") { + auto* destroyableComponent = GetComponent(); + if (!destroyableComponent) return; + destroyableComponent->Subscribe(scriptObjId, scriptToAdd); + } +} + +void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName) { + if (notificationName == "HitOrHealResult" || notificationName == "Hit") { + auto* destroyableComponent = GetComponent(); + if (!destroyableComponent) return; + destroyableComponent->Unsubscribe(scriptObjId); + } +} + void Entity::SetProximityRadius(float proxRadius, std::string name) { ProximityMonitorComponent* proxMon = GetComponent(); if (!proxMon) { diff --git a/dGame/Entity.h b/dGame/Entity.h index 6c0968f8..e0d38308 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -26,8 +26,13 @@ class Spawner; class ScriptComponent; class dpEntity; class Component; +class Item; class Character; +namespace CppScripts { + class Script; +}; + /** * An entity in the world. Has multiple components. */ @@ -139,6 +144,9 @@ public: std::vector GetScriptComponents(); + void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName); + void Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName); + void SetProximityRadius(float proxRadius, std::string name); void SetProximityRadius(dpEntity* entity, std::string name); diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index c899d9e8..6902917f 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -631,6 +631,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 auto* attacker = EntityManager::Instance()->GetEntity(source); m_Parent->OnHit(attacker); m_Parent->OnHitOrHealResult(attacker, sourceDamage); + NotifySubscribers(attacker, sourceDamage); for (const auto& cb : m_OnHitCallbacks) { cb(attacker); @@ -648,6 +649,29 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 Smash(source, eKillType::VIOLENT, u"", skillID); } +void DestroyableComponent::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd) { + m_SubscribedScripts.insert(std::make_pair(scriptObjId, scriptToAdd)); + Game::logger->LogDebug("DestroyableComponent", "Added script %llu to entity %llu", scriptObjId, m_Parent->GetObjectID()); + Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); +} + +void DestroyableComponent::Unsubscribe(LWOOBJID scriptObjId) { + auto foundScript = m_SubscribedScripts.find(scriptObjId); + if (foundScript != m_SubscribedScripts.end()) { + m_SubscribedScripts.erase(foundScript); + Game::logger->LogDebug("DestroyableComponent", "Removed script %llu from entity %llu", scriptObjId, m_Parent->GetObjectID()); + } else { + Game::logger->LogDebug("DestroyableComponent", "Tried to remove a script for Entity %llu but script %llu didnt exist", m_Parent->GetObjectID(), scriptObjId); + } + Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); +} + +void DestroyableComponent::NotifySubscribers(Entity* attacker, uint32_t damage) { + for (auto script : m_SubscribedScripts) { + script.second->NotifyHitOrHealResult(m_Parent, attacker, damage); + } +} + void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID) { if (m_iHealth > 0) { SetArmor(0); diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index b8e81b33..5bb990a7 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -7,6 +7,10 @@ #include "Entity.h" #include "Component.h" +namespace CppScripts { + class Script; +}; //! namespace CppScripts + /** * Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which * indicate which enemies this entity has. @@ -422,6 +426,17 @@ public: */ void AddFactionNoLookup(int32_t faction) { m_FactionIDs.push_back(faction); }; + /** + * Notify subscribed scripts of Damage actions. + * + * @param attacker The attacking Entity + * @param damage The amount of damage that was done + */ + void NotifySubscribers(Entity* attacker, uint32_t damage); + + void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd); + void Unsubscribe(LWOOBJID scriptObjId); + private: /** * Whether or not the health should be serialized @@ -557,6 +572,11 @@ private: * The list of callbacks that will be called when this entity gets hit */ std::vector> m_OnHitCallbacks; + + /** + * The list of scripts subscribed to this components actions + */ + std::map m_SubscribedScripts; }; #endif // DESTROYABLECOMPONENT_H diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 8215664c..eeb6afa7 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -27,8 +27,9 @@ #include "dConfig.h" #include "eItemType.h" #include "eUnequippableActiveType.h" +#include "CppScripts.h" -InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { +InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document): Component(parent) { this->m_Dirty = true; this->m_Equipped = {}; this->m_Pushed = {}; @@ -867,6 +868,8 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { AddItemSkills(item->GetLot()); + EquipScripts(item); + EntityManager::Instance()->SerializeEntity(m_Parent); } @@ -895,6 +898,8 @@ void InventoryComponent::UnEquipItem(Item* item) { PurgeProxies(item); + UnequipScripts(item); + EntityManager::Instance()->SerializeEntity(m_Parent); // Trigger property event @@ -904,6 +909,37 @@ void InventoryComponent::UnEquipItem(Item* item) { } } + +void InventoryComponent::EquipScripts(Item* equippedItem) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + if (!compRegistryTable) return; + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1); + if (scriptComponentID > -1) { + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable("ScriptComponent"); + CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); + if (!itemScript) { + Game::logger->Log("InventoryComponent", "null script?"); + } + itemScript->OnFactionTriggerItemEquipped(m_Parent, equippedItem->GetId()); + } +} + +void InventoryComponent::UnequipScripts(Item* unequippedItem) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + if (!compRegistryTable) return; + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1); + if (scriptComponentID > -1) { + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable("ScriptComponent"); + CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); + if (!itemScript) { + Game::logger->Log("InventoryComponent", "null script?"); + } + itemScript->OnFactionTriggerItemUnequipped(m_Parent, unequippedItem->GetId()); + } +} + void InventoryComponent::HandlePossession(Item* item) { auto* characterComponent = m_Parent->GetComponent(); if (!characterComponent) return; diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 8ae35f6c..44636d95 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -352,6 +352,20 @@ public: */ static uint32_t FindSkill(LOT lot); + /** + * Call this when you equip an item. This calls OnFactionTriggerItemEquipped for any scripts found on the items. + * + * @param equippedItem The item script to lookup and call equip on + */ + void EquipScripts(Item* equippedItem); + + /** + * Call this when you unequip an item. This calls OnFactionTriggerItemUnequipped for any scripts found on the items. + * + * @param unequippedItem The item script to lookup and call unequip on + */ + void UnequipScripts(Item* unequippedItem); + ~InventoryComponent() override; private: diff --git a/dScripts/CMakeLists.txt b/dScripts/CMakeLists.txt index fce3b721..ac600dbc 100644 --- a/dScripts/CMakeLists.txt +++ b/dScripts/CMakeLists.txt @@ -39,6 +39,12 @@ foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS}) set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentScripts/${file}") endforeach() +add_subdirectory(EquipmentTriggers) + +foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentTriggers/${file}") +endforeach() + add_subdirectory(zone) foreach(file ${DSCRIPTS_SOURCES_ZONE}) diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index dce77e4b..745a74ae 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -278,6 +278,9 @@ #include "ImaginationBackpackHealServer.h" #include "LegoDieRoll.h" #include "BuccaneerValiantShip.h" +#include "GemPack.h" +#include "ShardArmor.h" +#include "TeslaPack.h" // Survival scripts #include "AgSurvivalStromling.h" @@ -837,6 +840,12 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new BuccaneerValiantShip(); else if (scriptName == "scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua") script = new FireFirstSkillonStartup(); + else if (scriptName == "scripts\\equipmenttriggers\\gempack.lua") + script = new GemPack(); + else if (scriptName == "scripts\\equipmenttriggers\\shardarmor.lua") + script = new ShardArmor(); + else if (scriptName == "scripts\\equipmenttriggers\\coilbackpack.lua") + script = new TeslaPack(); // FB else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua") diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index 916d2638..e4a6d655 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -172,6 +172,13 @@ namespace CppScripts { */ virtual void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; + /** + * Invoked when self has received either a hit or heal. Only used for scripts subscribed to an entity. + * + * Equivalent to 'function notifyHitOrHealResult(self, msg)' + */ + virtual void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; + /** * Invoked when a player has responsed to a mission. * @@ -316,6 +323,22 @@ namespace CppScripts { virtual void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, float_t pathTime, float_t totalTime, int32_t waypoint) { }; + + /** + * Used by items to tell their owner that they were equipped. + * + * @param itemOwner The owner of the item + * @param itemObjId The items Object ID + */ + virtual void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) {}; + + /** + * Used by items to tell their owner that they were unequipped. + * + * @param itemOwner The owner of the item + * @param itemObjId The items Object ID + */ + virtual void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) {}; }; Script* GetScript(Entity* parent, const std::string& scriptName); diff --git a/dScripts/EquipmentTriggers/CMakeLists.txt b/dScripts/EquipmentTriggers/CMakeLists.txt new file mode 100644 index 00000000..416ef553 --- /dev/null +++ b/dScripts/EquipmentTriggers/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS + "CoilBackpackBase.cpp" + PARENT_SCOPE) diff --git a/dScripts/EquipmentTriggers/CoilBackpackBase.cpp b/dScripts/EquipmentTriggers/CoilBackpackBase.cpp new file mode 100644 index 00000000..d3102e0e --- /dev/null +++ b/dScripts/EquipmentTriggers/CoilBackpackBase.cpp @@ -0,0 +1,25 @@ +#include "CoilBackpackBase.h" + +#include "Entity.h" +#include "SkillComponent.h" + +void CoilBackpackBase::OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) { + itemOwner->Subscribe(itemObjId, this, "HitOrHealResult"); + itemOwner->SetVar(u"coilCount", 0); +} + +void CoilBackpackBase::NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + if (damage > 0) { + self->SetVar(u"coilCount", self->GetVar(u"coilCount") + 1); + if (self->GetVar(u"coilCount") > 4) { + auto* skillComponent = self->GetComponent(); + if (!skillComponent) return; + skillComponent->CalculateBehavior(m_SkillId, m_BehaviorId, self->GetObjectID()); + self->SetVar(u"coilCount", 0); + } + } +} + +void CoilBackpackBase::OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) { + itemOwner->Unsubscribe(itemObjId, "HitOrHealResult"); +} diff --git a/dScripts/EquipmentTriggers/CoilBackpackBase.h b/dScripts/EquipmentTriggers/CoilBackpackBase.h new file mode 100644 index 00000000..290c6c0f --- /dev/null +++ b/dScripts/EquipmentTriggers/CoilBackpackBase.h @@ -0,0 +1,21 @@ +#ifndef __GemPackBase__H__ +#define __GemPackBase__H__ + +#include "CppScripts.h" + +class CoilBackpackBase: public CppScripts::Script { +public: + CoilBackpackBase(uint32_t skillId, uint32_t behaviorId) { + m_SkillId = skillId; + m_BehaviorId = behaviorId; + }; + + void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) override; + void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) override; +private: + uint32_t m_SkillId = 0; + uint32_t m_BehaviorId = 0; +}; + +#endif //!__GemPackBase__H__ diff --git a/dScripts/EquipmentTriggers/GemPack.h b/dScripts/EquipmentTriggers/GemPack.h new file mode 100644 index 00000000..13bf7b0b --- /dev/null +++ b/dScripts/EquipmentTriggers/GemPack.h @@ -0,0 +1,14 @@ +#ifndef __GEMPACK__H__ +#define __GEMPACK__H__ + +#include "CoilBackpackBase.h" + +class GemPack : public CoilBackpackBase { +public: + GemPack() : CoilBackpackBase(skillId, behaviorId) {}; +private: + static const uint32_t skillId = 1488; + static const uint32_t behaviorId = 36779; +}; + +#endif //!__GEMPACK__H__ diff --git a/dScripts/EquipmentTriggers/ShardArmor.h b/dScripts/EquipmentTriggers/ShardArmor.h new file mode 100644 index 00000000..01d2fe33 --- /dev/null +++ b/dScripts/EquipmentTriggers/ShardArmor.h @@ -0,0 +1,14 @@ +#ifndef __SHARDARMOR__H__ +#define __SHARDARMOR__H__ + +#include "CoilBackpackBase.h" + +class ShardArmor : public CoilBackpackBase { +public: + ShardArmor() : CoilBackpackBase(skillId, behaviorId) {}; +private: + static const uint32_t skillId = 1249; + static const uint32_t behaviorId = 29086; +}; + +#endif //!__SHARDARMOR__H__ diff --git a/dScripts/EquipmentTriggers/TeslaPack.h b/dScripts/EquipmentTriggers/TeslaPack.h new file mode 100644 index 00000000..6e8bc9a4 --- /dev/null +++ b/dScripts/EquipmentTriggers/TeslaPack.h @@ -0,0 +1,14 @@ +#ifndef __TESLAPACK__H__ +#define __TESLAPACK__H__ + +#include "CoilBackpackBase.h" + +class TeslaPack : public CoilBackpackBase { +public: + TeslaPack() : CoilBackpackBase(skillId, behaviorId) {}; +private: + static const uint32_t skillId = 1001; + static const uint32_t behaviorId = 20917; +}; + +#endif //!__TESLAPACK__H__ From fd9757d1215dd6dafe6431aa4aeb556902f3c4b2 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 21 Dec 2022 22:34:11 -0800 Subject: [PATCH 30/63] Implement a server res directory for server required client files (#891) --- CMakeLists.txt | 4 +- dCommon/FdbToSqlite.cpp | 73 +++++++++++---------- dCommon/FdbToSqlite.h | 116 +++++++++++++++++++++++++++++++-- dMasterServer/MasterServer.cpp | 40 ++++++++---- dWorldServer/WorldServer.cpp | 2 +- 5 files changed, 176 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9596649..54f0d0dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,8 +89,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -# Create a /res directory -make_directory(${CMAKE_BINARY_DIR}/res) +# Create a /resServer directory +make_directory(${CMAKE_BINARY_DIR}/resServer) # Create a /logs directory make_directory(${CMAKE_BINARY_DIR}/logs) diff --git a/dCommon/FdbToSqlite.cpp b/dCommon/FdbToSqlite.cpp index 6015fd3a..80251e89 100644 --- a/dCommon/FdbToSqlite.cpp +++ b/dCommon/FdbToSqlite.cpp @@ -13,7 +13,7 @@ #include "eSqliteDataType.h" -std::map FdbToSqlite::Convert::sqliteType = { +std::map FdbToSqlite::Convert::m_SqliteType = { { eSqliteDataType::NONE, "none"}, { eSqliteDataType::INT32, "int32"}, { eSqliteDataType::REAL, "real"}, @@ -23,15 +23,21 @@ std::map FdbToSqlite::Convert::sqliteType = { { eSqliteDataType::TEXT_8, "text_8"} }; -FdbToSqlite::Convert::Convert(std::string basePath) { - this->basePath = basePath; +FdbToSqlite::Convert::Convert(std::string basePath, std::string binaryOutPath) { + this->m_BasePath = basePath; + this->m_BinaryOutPath = binaryOutPath; + m_Fdb.open(m_BasePath + "/cdclient.fdb", std::ios::binary); +} + +FdbToSqlite::Convert::~Convert() { + this->m_Fdb.close(); } bool FdbToSqlite::Convert::ConvertDatabase() { - fdb.open(basePath + "/cdclient.fdb", std::ios::binary); - + if (m_ConversionStarted) return false; + this->m_ConversionStarted = true; try { - CDClientDatabase::Connect(basePath + "/CDServer.sqlite"); + CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite"); CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); @@ -44,13 +50,12 @@ bool FdbToSqlite::Convert::ConvertDatabase() { return false; } - fdb.close(); return true; } int32_t FdbToSqlite::Convert::ReadInt32() { int32_t nextInt{}; - BinaryIO::BinaryRead(fdb, nextInt); + BinaryIO::BinaryRead(m_Fdb, nextInt); return nextInt; } @@ -58,26 +63,26 @@ int64_t FdbToSqlite::Convert::ReadInt64() { int32_t prevPosition = SeekPointer(); int64_t value{}; - BinaryIO::BinaryRead(fdb, value); + BinaryIO::BinaryRead(m_Fdb, value); - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); return value; } std::string FdbToSqlite::Convert::ReadString() { int32_t prevPosition = SeekPointer(); - auto readString = BinaryIO::ReadString(fdb); + auto readString = BinaryIO::ReadString(m_Fdb); - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); return readString; } int32_t FdbToSqlite::Convert::SeekPointer() { int32_t position{}; - BinaryIO::BinaryRead(fdb, position); - int32_t prevPosition = fdb.tellg(); - fdb.seekg(position); + BinaryIO::BinaryRead(m_Fdb, position); + int32_t prevPosition = m_Fdb.tellg(); + m_Fdb.seekg(position); return prevPosition; } @@ -91,7 +96,7 @@ std::string FdbToSqlite::Convert::ReadColumnHeader() { std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");"; CDClientDatabase::ExecuteDML(newTable); - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); return tableName; } @@ -104,7 +109,7 @@ void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables) { ReadRowHeader(columnHeader); } - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); } std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns) { @@ -117,10 +122,10 @@ std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns) { if (i != 0) columnsToCreate << ", "; dataType = static_cast(ReadInt32()); name = ReadString(); - columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::sqliteType[dataType]; + columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType]; } - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); return columnsToCreate.str(); } @@ -131,7 +136,7 @@ void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName) { if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0); // assert power of 2 allocation size ReadRows(numberOfAllocatedRows, tableName); - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); } void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName) { @@ -141,28 +146,24 @@ void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& for (int32_t row = 0; row < numberOfAllocatedRows; row++) { int32_t rowPointer = ReadInt32(); if (rowPointer == -1) rowid++; - else ReadRow(rowid, rowPointer, tableName); + else ReadRow(rowPointer, tableName); } - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); } -void FdbToSqlite::Convert::ReadRow(int32_t& rowid, int32_t& position, std::string& tableName) { - int32_t prevPosition = fdb.tellg(); - fdb.seekg(position); +void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName) { + int32_t prevPosition = m_Fdb.tellg(); + m_Fdb.seekg(position); while (true) { ReadRowInfo(tableName); int32_t linked = ReadInt32(); - - rowid += 1; - if (linked == -1) break; - - fdb.seekg(linked); + m_Fdb.seekg(linked); } - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); } void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName) { @@ -171,7 +172,7 @@ void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName) { int32_t numberOfColumns = ReadInt32(); ReadRowValues(numberOfColumns, tableName); - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); } void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName) { @@ -191,7 +192,7 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row. switch (static_cast(ReadInt32())) { case eSqliteDataType::NONE: - BinaryIO::BinaryRead(fdb, emptyValue); + BinaryIO::BinaryRead(m_Fdb, emptyValue); assert(emptyValue == 0); insertedRow << "NULL"; break; @@ -202,7 +203,7 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& break; case eSqliteDataType::REAL: - BinaryIO::BinaryRead(fdb, floatValue); + BinaryIO::BinaryRead(m_Fdb, floatValue); insertedRow << std::fixed << std::setprecision(34) << floatValue; // maximum precision of floating point number break; @@ -224,7 +225,7 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& } case eSqliteDataType::INT_BOOL: - BinaryIO::BinaryRead(fdb, boolValue); + BinaryIO::BinaryRead(m_Fdb, boolValue); insertedRow << static_cast(boolValue); break; @@ -244,5 +245,5 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& auto copiedString = insertedRow.str(); CDClientDatabase::ExecuteDML(copiedString); - fdb.seekg(prevPosition); + m_Fdb.seekg(prevPosition); } diff --git a/dCommon/FdbToSqlite.h b/dCommon/FdbToSqlite.h index a9611220..cfa5263b 100644 --- a/dCommon/FdbToSqlite.h +++ b/dCommon/FdbToSqlite.h @@ -12,38 +12,142 @@ enum class eSqliteDataType : int32_t; namespace FdbToSqlite { class Convert { public: - Convert(std::string inputFile); + /** + * Create a new convert object with an input .fdb file and an output binary path. + * + * @param inputFile The file which ends in .fdb to be converted + * @param binaryPath The base path where the file will be saved + */ + Convert(std::string inputFile, std::string binaryOutPath); + /** + * Destroy the convert object and close the fdb file. + */ + ~Convert(); + + /** + * Converts the input file to sqlite. Calling multiple times is safe. + * + * @return true if the database was converted properly, false otherwise. + */ bool ConvertDatabase(); + /** + * @brief Reads a 32 bit int from the fdb file. + * + * @return The read value + */ int32_t ReadInt32(); + /** + * @brief Reads a 64 bit integer from the fdb file. + * + * @return The read value + */ int64_t ReadInt64(); + /** + * @brief Reads a string from the fdb file. + * + * @return The read string + * + * TODO This needs to be translated to latin-1! + */ std::string ReadString(); + /** + * @brief Seeks to a pointer position. + * + * @return The previous position before the seek + */ int32_t SeekPointer(); + /** + * @brief Reads a column header from the fdb file and creates the table in the database + * + * @return The table name + */ std::string ReadColumnHeader(); + /** + * @brief Read the tables from the fdb file. + * + * @param numberOfTables The number of tables to read + */ void ReadTables(int32_t& numberOfTables); + /** + * @brief Reads the columns from the fdb file. + * + * @param numberOfColumns The number of columns to read + * @return All columns of the table formatted for a sql query + */ std::string ReadColumns(int32_t& numberOfColumns); + /** + * @brief Reads the row header from the fdb file. + * + * @param tableName The tables name + */ void ReadRowHeader(std::string& tableName); + /** + * @brief Read the rows from the fdb file., + * + * @param numberOfAllocatedRows The number of rows that were allocated. Always a power of 2! + * @param tableName The tables name. + */ void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName); - void ReadRow(int32_t& rowid, int32_t& position, std::string& tableName); + /** + * @brief Reads a row from the fdb file. + * + * @param position The position to seek in the fdb to + * @param tableName The tables name + */ + void ReadRow(int32_t& position, std::string& tableName); + /** + * @brief Reads the row info from the fdb file. + * + * @param tableName The tables name + */ void ReadRowInfo(std::string& tableName); + /** + * @brief Reads each row and its values from the fdb file and inserts them into the database + * + * @param numberOfColumns The number of columns to read in + * @param tableName The tables name + */ void ReadRowValues(int32_t& numberOfColumns, std::string& tableName); private: - static std::map sqliteType; - std::string basePath{}; - std::ifstream fdb{}; - }; // class FdbToSqlite + + /** + * Maps each sqlite data type to its string equivalent. + */ + static std::map m_SqliteType; + + /** + * Base path of the folder containing the fdb file + */ + std::string m_BasePath{}; + + /** + * ifstream containing the fdb file + */ + std::ifstream m_Fdb{}; + + /** + * Whether or not a conversion was started. If one was started, do not attempt to convert the file again. + */ + bool m_ConversionStarted{}; + + /** + * The path where the CDServer will be stored + */ + std::string m_BinaryOutPath{}; + }; //! class FdbToSqlite }; //! namespace FdbToSqlite #endif //!__FDBTOSQLITE__H__ diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index ba36247c..34ce59c7 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -146,26 +146,38 @@ int main(int argc, char** argv) { MigrationRunner::RunMigrations(); - // Check CDClient exists - if (!std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite")) { - Game::logger->Log("WorldServer", "CDServer.sqlite could not be opened. Looking for cdclient.fdb to convert to sqlite."); + const bool cdServerExists = std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); + const bool oldCDServerExists = std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite"); + const bool fdbExists = std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb"); - if (!std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb")) { - Game::logger->Log("WorldServer", "cdclient.fdb could not be opened. Please move a cdclient.fdb or an already converted database to build/res."); - return EXIT_FAILURE; - } - - Game::logger->Log("WorldServer", "Found cdclient.fdb. Converting to SQLite"); - - if (FdbToSqlite::Convert(Game::assetManager->GetResPath().string()).ConvertDatabase() == false) { - Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite"); - return EXIT_FAILURE; + if (!cdServerExists) { + if (oldCDServerExists) { + // If the file doesn't exist in the new CDServer location, copy it there. We copy because we may not have write permissions from the previous directory. + Game::logger->Log("MasterServer", "CDServer.sqlite is not located at resServer, but is located at res path. Copying file..."); + std::filesystem::copy_file(Game::assetManager->GetResPath() / "CDServer.sqlite", BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); + } else { + Game::logger->Log("WorldServer", + "%s could not be found in resServer or res. Looking for %s to convert to sqlite.", + (BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(), + (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + if (!fdbExists) { + Game::logger->Log("WorldServer", + "%s could not be opened. Please move cdclient.fdb to %s", + (Game::assetManager->GetResPath() / "cdclient.fdb").c_str(), + (Game::assetManager->GetResPath().c_str())); + return FinalizeShutdown(); + } + Game::logger->Log("WorldServer", "Found cdclient.fdb. Converting to SQLite"); + if (FdbToSqlite::Convert(Game::assetManager->GetResPath().string(), (BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase() == false) { + Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite."); + return FinalizeShutdown(); + } } } //Connect to CDClient try { - CDClientDatabase::Connect((Game::assetManager->GetResPath() / "CDServer.sqlite").string()); + CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); } catch (CppSQLite3Exception& e) { Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index adb87ba0..32060a51 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -154,7 +154,7 @@ int main(int argc, char** argv) { // Connect to CDClient try { - CDClientDatabase::Connect((Game::assetManager->GetResPath() / "CDServer.sqlite").string()); + CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); } catch (CppSQLite3Exception& e) { Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); From d052ed6a631341d89b9eb395b9936c9a25f9c13e Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 22 Dec 2022 04:06:59 -0800 Subject: [PATCH 31/63] Update MigrationRunner.cpp (#911) --- dDatabase/MigrationRunner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp index 54def9e2..5e70c401 100644 --- a/dDatabase/MigrationRunner.cpp +++ b/dDatabase/MigrationRunner.cpp @@ -54,7 +54,7 @@ void MigrationRunner::RunMigrations() { if (doExit) continue; Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str()); - if (migration.name == "5_brick_model_sd0.sql") { + if (migration.name == "dlu/5_brick_model_sd0.sql") { runSd0Migrations = true; } else { finalSQL.append(migration.data.c_str()); From dff02773a0d3904e2682ff483a5d8ae9b44f00fb Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 22 Dec 2022 05:16:08 -0800 Subject: [PATCH 32/63] Fix dragon stuns (#915) --- dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp | 5 ++++- dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp index 8ec49d3e..9e0570ef 100644 --- a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp @@ -63,10 +63,11 @@ void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } self->SetVar(u"weakpoint", 2); - + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); self->AddTimer("timeToStunLoop", 1); @@ -131,7 +132,9 @@ void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { } if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"weakspot", -1); GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp index 47ddb4bf..ec513694 100644 --- a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp @@ -59,8 +59,6 @@ void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_ auto* destroyableComponent = self->GetComponent(); if (destroyableComponent != nullptr) { - Game::logger->Log("FvMaelstromDragon", "Hit %i", destroyableComponent->GetArmor()); - if (destroyableComponent->GetArmor() > 0) return; auto weakpoint = self->GetVar(u"weakpoint"); @@ -80,10 +78,12 @@ void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_ if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } self->SetVar(u"weakpoint", 2); + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); self->AddTimer("timeToStunLoop", 1); @@ -150,8 +150,9 @@ void FvMaelstromDragon::OnTimerDone(Entity* self, std::string timerName) { if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } - + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"weakspot", -1); GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); From 015cbc06ea020c391bce22d1d6c56023c2daa84e Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 22 Dec 2022 05:16:18 -0800 Subject: [PATCH 33/63] Fix racing spawn positions (#913) --- dGame/dComponents/RacingControlComponent.cpp | 47 +++++++------------- dGame/dComponents/RacingControlComponent.h | 2 +- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index 75465669..4b5743cd 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -98,7 +98,7 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) { } void RacingControlComponent::LoadPlayerVehicle(Entity* player, - bool initialLoad) { + uint32_t positionNumber, bool initialLoad) { // Load the player's vehicle. if (player == nullptr) { @@ -126,33 +126,18 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player, auto* path = dZoneManager::Instance()->GetZone()->GetPath( GeneralUtils::UTF16ToWTF8(m_PathName)); - auto startPosition = path->pathWaypoints[0].position + NiPoint3::UNIT_Y * 3; - - const auto spacing = 15; - - // This sometimes spawns the vehicle out of the map if there are lots of - // players loaded. - - const auto range = m_LoadedPlayers * spacing; - - startPosition = - startPosition + NiPoint3::UNIT_Z * ((m_LeadingPlayer / 2) + - m_RacingPlayers.size() * spacing); - - auto startRotation = - NiQuaternion::LookAt(startPosition, startPosition + NiPoint3::UNIT_X); - - auto angles = startRotation.GetEulerAngles(); - - angles.y -= M_PI; - - startRotation = NiQuaternion::FromEulerAngles(angles); - - Game::logger->Log("RacingControlComponent", - "Start position <%f, %f, %f>, <%f, %f, %f>", - startPosition.x, startPosition.y, startPosition.z, - angles.x * (180.0f / M_PI), angles.y * (180.0f / M_PI), - angles.z * (180.0f / M_PI)); + auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843); + auto startPosition = NiPoint3::ZERO; + auto startRotation = NiQuaternion::IDENTITY; + const std::string placementAsString = std::to_string(positionNumber); + for (auto entity : spawnPointEntities) { + if (!entity) continue; + if (entity->GetVarAsString(u"placement") == placementAsString) { + startPosition = entity->GetPosition(); + startRotation = entity->GetRotation(); + break; + } + } // Make sure the player is at the correct position. @@ -567,12 +552,12 @@ void RacingControlComponent::Update(float deltaTime) { Game::logger->Log("RacingControlComponent", "Loading all players..."); - for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { + for (size_t positionNumber = 0; positionNumber < m_LobbyPlayers.size(); positionNumber++) { Game::logger->Log("RacingControlComponent", "Loading player now!"); auto* player = - EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); + EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]); if (player == nullptr) { return; @@ -581,7 +566,7 @@ void RacingControlComponent::Update(float deltaTime) { Game::logger->Log("RacingControlComponent", "Loading player now NOW!"); - LoadPlayerVehicle(player, true); + LoadPlayerVehicle(player, positionNumber + 1, true); m_Loaded = true; } diff --git a/dGame/dComponents/RacingControlComponent.h b/dGame/dComponents/RacingControlComponent.h index dac60962..933178cc 100644 --- a/dGame/dComponents/RacingControlComponent.h +++ b/dGame/dComponents/RacingControlComponent.h @@ -123,7 +123,7 @@ public: * @param player The player who's vehicle to initialize. * @param initialLoad Is this the first time the player is loading in this race? */ - void LoadPlayerVehicle(Entity* player, bool initialLoad = false); + void LoadPlayerVehicle(Entity* player, uint32_t positionNumber, bool initialLoad = false); /** * Invoked when the client says it has loaded in. From 96313ecd695de9ad60b4634ea90919fa4f2f4328 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 22 Dec 2022 05:16:35 -0800 Subject: [PATCH 34/63] Calculate world shutdown timer (#910) --- dWorldServer/WorldServer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 32060a51..de6deb2a 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -296,6 +296,7 @@ int main(int argc, char** argv) { uint32_t chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames uint32_t saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames uint32_t sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t emptyShutdownTime = (cloneID == 0 ? 30 : 5) * 60 * currentFramerate; // 30 minutes for main worlds, 5 for all others. while (true) { Metrics::StartMeasurement(MetricVariable::Frame); Metrics::StartMeasurement(MetricVariable::GameLoop); @@ -333,6 +334,8 @@ int main(int argc, char** argv) { framesSinceLastUsersSave *= ratioBeforeToAfter; sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames framesSinceLastSQLPing *= ratioBeforeToAfter; + emptyShutdownTime = (cloneID == 0 ? 30 : 5) * 60 * currentFramerate; // 30 minutes for main worlds, 5 for all others. + framesSinceLastUser *= ratioBeforeToAfter; } //Warning if we ran slow @@ -440,7 +443,7 @@ int main(int argc, char** argv) { framesSinceLastUser++; //If we haven't had any players for a while, time out and shut down: - if (framesSinceLastUser == (cloneID != 0 ? 4000 : 40000)) { + if (framesSinceLastUser >= emptyShutdownTime) { Game::shouldShutdown = true; } } else { From 9ebb06ba24d3b7e26d6270d7efbaa46ee975cfee Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Thu, 22 Dec 2022 07:24:59 -0600 Subject: [PATCH 35/63] Qb team credit (#912) * give credit to whole team for qb's * fix compiling --- dGame/dComponents/RebuildComponent.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index 6ec9b964..c7c4e3a5 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -14,6 +14,7 @@ #include "Spawner.h" #include "MovingPlatformComponent.h" #include "Preconditions.h" +#include "TeamManager.h" #include "CppScripts.h" @@ -464,12 +465,20 @@ void RebuildComponent::CompleteRebuild(Entity* user) { auto* builder = GetBuilder(); - if (builder != nullptr) { - auto* missionComponent = builder->GetComponent(); - if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); + if (builder) { + auto* team = TeamManager::Instance()->GetTeam(builder->GetObjectID()); + if (team) { + for (const auto memberId : team->members) { // progress missions for all team members + auto* member = EntityManager::Instance()->GetEntity(memberId); + if (member) { + auto* missionComponent = member->GetComponent(); + if (missionComponent) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); + } + } + } else{ + auto* missionComponent = builder->GetComponent(); + if (missionComponent) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); } - LootGenerator::Instance().DropActivityLoot(builder, m_Parent, m_ActivityId, 1); } From 675cf1d2a4f5a6955959e4884193fd733ea6185f Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:14:51 -0800 Subject: [PATCH 36/63] Fix baseEnemyApe stuns and fix IdleFlags serialization (#914) * Fix baseEnemyApe stuns * Correct serialization --- dGame/dGameMessages/GameMessages.cpp | 8 +++++--- dScripts/02_server/Enemy/General/BaseEnemyApe.cpp | 8 ++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 9753868d..c3b86647 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -3924,14 +3924,16 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string } -void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags FlagsOn, eAnimationFlags FlagsOff, const SystemAddress& sysAddr) { +void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsOn, eAnimationFlags flagsOff, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); bitStream.Write(GAME_MSG::GAME_MSG_CHANGE_IDLE_FLAGS); - bitStream.Write(FlagsOff); - bitStream.Write(FlagsOn); + bitStream.Write(flagsOff != eAnimationFlags::IDLE_NONE); + if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff); + bitStream.Write(flagsOn != eAnimationFlags::IDLE_NONE); + if (flagsOn != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOn); SEND_PACKET_BROADCAST; } diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp index 3d0b8e25..96419c08 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp @@ -31,9 +31,12 @@ void BaseEnemyApe::OnHit(Entity* self, Entity* attacker) { if (destroyableComponent != nullptr && destroyableComponent->GetArmor() < 1 && !self->GetBoolean(u"knockedOut")) { StunApe(self, true); self->CancelTimer("spawnQBTime"); - + auto* skillComponent = self->GetComponent(); + if (skillComponent) { + skillComponent->Reset(); + } GameMessages::SendPlayAnimation(self, u"disable", 1.7f); - + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); const auto reviveTime = self->GetVar(u"reviveTime") != 0.0f ? self->GetVar(u"reviveTime") : 12.0f; self->AddTimer("reviveTime", reviveTime); @@ -50,6 +53,7 @@ void BaseEnemyApe::OnTimerDone(Entity* self, std::string timerName) { destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned); } EntityManager::Instance()->SerializeEntity(self); + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"timesStunned", timesStunned + 1); StunApe(self, false); From bbd5a49ea2c682469a1c3f48e418c93d932dec1c Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 23 Dec 2022 18:05:30 -0800 Subject: [PATCH 37/63] Update DarkInspirationBehavior.cpp (#897) --- dGame/dBehaviors/AreaOfEffectBehavior.cpp | 5 +- dGame/dBehaviors/Behavior.cpp | 5 +- dGame/dBehaviors/CMakeLists.txt | 1 + dGame/dBehaviors/DarkInspirationBehavior.cpp | 52 ++++++++++++++++++++ dGame/dBehaviors/DarkInspirationBehavior.h | 22 +++++++++ dGame/dComponents/DestroyableComponent.cpp | 2 +- dGame/dComponents/InventoryComponent.cpp | 4 +- dGame/dComponents/InventoryComponent.h | 2 +- dGame/dInventory/ItemSet.cpp | 4 +- dGame/dInventory/ItemSet.h | 2 +- dGame/dInventory/ItemSetPassiveAbility.cpp | 14 +++--- dGame/dInventory/ItemSetPassiveAbility.h | 6 +-- 12 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 dGame/dBehaviors/DarkInspirationBehavior.cpp create mode 100644 dGame/dBehaviors/DarkInspirationBehavior.h diff --git a/dGame/dBehaviors/AreaOfEffectBehavior.cpp b/dGame/dBehaviors/AreaOfEffectBehavior.cpp index ca3bdf93..dedede2a 100644 --- a/dGame/dBehaviors/AreaOfEffectBehavior.cpp +++ b/dGame/dBehaviors/AreaOfEffectBehavior.cpp @@ -48,9 +48,8 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* self = EntityManager::Instance()->GetEntity(context->caster); - if (self == nullptr) { - Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!", context->originator); + Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator); return; } @@ -79,7 +78,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream auto* entity = EntityManager::Instance()->GetEntity(validTarget); if (entity == nullptr) { - Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); + Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); continue; } diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index cd9304d3..568780d0 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -61,6 +61,7 @@ #include "DamageReductionBehavior.h" #include "JetPackBehavior.h" #include "ChangeIdleFlagsBehavior.h" +#include "DarkInspirationBehavior.h" //CDClient includes #include "CDBehaviorParameterTable.h" @@ -169,7 +170,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { case BehaviorTemplates::BEHAVIOR_SPEED: behavior = new SpeedBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: break; + case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: + behavior = new DarkInspirationBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_LOOT_BUFF: behavior = new LootBuffBehavior(behaviorId); break; diff --git a/dGame/dBehaviors/CMakeLists.txt b/dGame/dBehaviors/CMakeLists.txt index 40ac0a9c..e274872d 100644 --- a/dGame/dBehaviors/CMakeLists.txt +++ b/dGame/dBehaviors/CMakeLists.txt @@ -18,6 +18,7 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "ClearTargetBehavior.cpp" "DamageAbsorptionBehavior.cpp" "DamageReductionBehavior.cpp" + "DarkInspirationBehavior.cpp" "DurationBehavior.cpp" "EmptyBehavior.cpp" "EndBehavior.cpp" diff --git a/dGame/dBehaviors/DarkInspirationBehavior.cpp b/dGame/dBehaviors/DarkInspirationBehavior.cpp new file mode 100644 index 00000000..ea80cbba --- /dev/null +++ b/dGame/dBehaviors/DarkInspirationBehavior.cpp @@ -0,0 +1,52 @@ +#include "DarkInspirationBehavior.h" + +#include "BehaviorBranchContext.h" +#include "Entity.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "BehaviorContext.h" + +void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + + if (target == nullptr) { + Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); + return; + } + + auto* destroyableComponent = target->GetComponent(); + + if (destroyableComponent == nullptr) { + return; + } + + if (destroyableComponent->HasFaction(m_FactionList)) { + this->m_ActionIfFactionMatches->Handle(context, bitStream, branch); + } +} + +void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + + if (target == nullptr) { + Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); + + return; + } + + auto* destroyableComponent = target->GetComponent(); + + if (destroyableComponent == nullptr) { + return; + } + + if (destroyableComponent->HasFaction(m_FactionList)) { + this->m_ActionIfFactionMatches->Calculate(context, bitStream, branch); + } +} + +void DarkInspirationBehavior::Load() { + this->m_ActionIfFactionMatches = GetAction("action"); + + this->m_FactionList = GetInt("faction_list"); +} diff --git a/dGame/dBehaviors/DarkInspirationBehavior.h b/dGame/dBehaviors/DarkInspirationBehavior.h new file mode 100644 index 00000000..f8298742 --- /dev/null +++ b/dGame/dBehaviors/DarkInspirationBehavior.h @@ -0,0 +1,22 @@ +#pragma once +#include "Behavior.h" + +class DarkInspirationBehavior final : public Behavior +{ +public: + /* + * Inherited + */ + + explicit DarkInspirationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; +private: + Behavior* m_ActionIfFactionMatches; + uint32_t m_FactionList; +}; diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 6902917f..d832ef93 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -694,7 +694,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* inventoryComponent = owner->GetComponent(); if (inventoryComponent != nullptr && isEnemy) { - inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed); + inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed, m_Parent); } auto* missions = owner->GetComponent(); diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index eeb6afa7..6247f32d 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1196,9 +1196,9 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) { } } -void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger) { +void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) { for (auto* set : m_Itemsets) { - set->TriggerPassiveAbility(trigger); + set->TriggerPassiveAbility(trigger, target); } } diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 44636d95..f63a8d70 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -283,7 +283,7 @@ public: * Triggers one of the passive abilities from the equipped item set * @param trigger the trigger to fire */ - void TriggerPassiveAbility(PassiveAbilityTrigger trigger); + void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); /** * Returns if the entity has any of the passed passive abilities equipped diff --git a/dGame/dInventory/ItemSet.cpp b/dGame/dInventory/ItemSet.cpp index 5063139e..1c67f6d6 100644 --- a/dGame/dInventory/ItemSet.cpp +++ b/dGame/dInventory/ItemSet.cpp @@ -180,9 +180,9 @@ void ItemSet::Update(float deltaTime) { } } -void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger) { +void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) { for (auto& passiveAbility : m_PassiveAbilities) { - passiveAbility.Trigger(trigger); + passiveAbility.Trigger(trigger, target); } } diff --git a/dGame/dInventory/ItemSet.h b/dGame/dInventory/ItemSet.h index 7c713f03..d167cfaa 100644 --- a/dGame/dInventory/ItemSet.h +++ b/dGame/dInventory/ItemSet.h @@ -52,7 +52,7 @@ public: * Triggers all the passive abilities in this item set that match this trigger * @param trigger the trigger to use to trigger passive abilities */ - void TriggerPassiveAbility(PassiveAbilityTrigger trigger); + void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); /** * Returns the skills that can be equipped for a specified amount of equipped items diff --git a/dGame/dInventory/ItemSetPassiveAbility.cpp b/dGame/dInventory/ItemSetPassiveAbility.cpp index d90f6e4e..83db4405 100644 --- a/dGame/dInventory/ItemSetPassiveAbility.cpp +++ b/dGame/dInventory/ItemSetPassiveAbility.cpp @@ -16,12 +16,12 @@ ItemSetPassiveAbility::ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Enti ItemSetPassiveAbility::~ItemSetPassiveAbility() { } -void ItemSetPassiveAbility::Trigger(PassiveAbilityTrigger trigger) { +void ItemSetPassiveAbility::Trigger(PassiveAbilityTrigger trigger, Entity* target) { if (m_Trigger != trigger || m_Cooldown > 0.0f) { return; } - Activate(); + Activate(target); } void ItemSetPassiveAbility::Update(float deltaTime) { @@ -30,9 +30,9 @@ void ItemSetPassiveAbility::Update(float deltaTime) { } } -void ItemSetPassiveAbility::Activate() { +void ItemSetPassiveAbility::Activate(Entity* target) { if (m_Trigger == PassiveAbilityTrigger::EnemySmashed) { - OnEnemySmshed(); + OnEnemySmshed(target); return; } @@ -195,7 +195,7 @@ std::vector ItemSetPassiveAbility::FindAbilities(uint32_t return abilities; } -void ItemSetPassiveAbility::OnEnemySmshed() { +void ItemSetPassiveAbility::OnEnemySmshed(Entity* target) { auto* destroyableComponent = m_Parent->GetComponent(); auto* skillComponent = m_Parent->GetComponent(); @@ -293,8 +293,8 @@ void ItemSetPassiveAbility::OnEnemySmshed() { break; } case ItemSetPassiveAbilityID::ShinobiRank3: { - if (equippedCount < 4) return; - destroyableComponent->Imagine(3); + if (equippedCount < 4 || !target) return; + skillComponent->CalculateBehavior(695, 11399, target->GetObjectID()); break; } diff --git a/dGame/dInventory/ItemSetPassiveAbility.h b/dGame/dInventory/ItemSetPassiveAbility.h index ff945df2..8735e695 100644 --- a/dGame/dInventory/ItemSetPassiveAbility.h +++ b/dGame/dInventory/ItemSetPassiveAbility.h @@ -30,12 +30,12 @@ public: * Attempts to trigger a passive ability for this item set, if this is the wrong trigger this is a no-op * @param trigger the trigger to attempt to fire */ - void Trigger(PassiveAbilityTrigger trigger); + void Trigger(PassiveAbilityTrigger trigger, Entity* target = nullptr); /** * Activates the passive ability */ - void Activate(); + void Activate(Entity* target = nullptr); /** * Finds all the passive abilities associated with a certain item set @@ -47,7 +47,7 @@ public: static std::vector FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet); private: - void OnEnemySmshed(); + void OnEnemySmshed(Entity* target = nullptr); /** * The means of triggering this ability From 6ec921025deb43a43f2413e150b121250f635df4 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Sat, 24 Dec 2022 02:49:31 -0600 Subject: [PATCH 38/63] Use new logic for applying speed changes in ApplyBuff (#919) --- dGame/dComponents/BuffComponent.cpp | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index d8d7428d..974d0bd2 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -170,17 +170,10 @@ void BuffComponent::ApplyBuffEffect(int32_t id) { destroyable->SetMaxImagination(destroyable->GetMaxImagination() + maxImagination); } else if (parameter.name == "speed") { - const auto speed = parameter.value; - auto* controllablePhysicsComponent = this->GetParent()->GetComponent(); - - if (controllablePhysicsComponent == nullptr) return; - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current + ((speed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(this->GetParent()); + if (!controllablePhysicsComponent) return; + const auto speed = parameter.value; + controllablePhysicsComponent->AddSpeedboost(speed); } } } @@ -213,17 +206,10 @@ void BuffComponent::RemoveBuffEffect(int32_t id) { destroyable->SetMaxImagination(destroyable->GetMaxImagination() - maxImagination); } else if (parameter.name == "speed") { - const auto speed = parameter.value; - auto* controllablePhysicsComponent = this->GetParent()->GetComponent(); - - if (controllablePhysicsComponent == nullptr) return; - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((speed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(this->GetParent()); + if (!controllablePhysicsComponent) return; + const auto speed = parameter.value; + controllablePhysicsComponent->RemoveSpeedboost(speed); } } } From 85ab573665e8ed17ab1ef4c05b4f707253b53673 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 24 Dec 2022 00:51:59 -0800 Subject: [PATCH 39/63] Fix duping issue (#921) --- dGame/dGameMessages/GameMessages.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index c3b86647..26b1bb3c 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -4728,13 +4728,13 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit float sellScalar = vend->GetSellScalar(); if (Inventory::IsValidItem(itemComp.currencyLOT)) { - const auto altCurrency = (itemComp.altCurrencyCost * sellScalar) * count; + const auto altCurrency = static_cast(itemComp.altCurrencyCost * sellScalar) * count; inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::LOOT_SOURCE_VENDOR); // Return alt currencies like faction tokens. } //inv->RemoveItem(count, -1, iObjID); inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true); - character->SetCoins(std::floor(character->GetCoins() + ((itemComp.baseValue * sellScalar) * count)), eLootSourceType::LOOT_SOURCE_VENDOR); + character->SetCoins(std::floor(character->GetCoins() + (static_cast(itemComp.baseValue * sellScalar) * count)), eLootSourceType::LOOT_SOURCE_VENDOR); //EntityManager::Instance()->SerializeEntity(player); // so inventory updates GameMessages::SendVendorTransactionResult(entity, sysAddr); } From 1470af99c3454424264f3dcb1e71a1f3332eb20d Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 24 Dec 2022 04:06:27 -0800 Subject: [PATCH 40/63] Correct Property FX incorrect skill cast (#920) --- dScripts/ai/PROPERTY/PropertyFXDamage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dScripts/ai/PROPERTY/PropertyFXDamage.cpp b/dScripts/ai/PROPERTY/PropertyFXDamage.cpp index d12cc9e1..56079384 100644 --- a/dScripts/ai/PROPERTY/PropertyFXDamage.cpp +++ b/dScripts/ai/PROPERTY/PropertyFXDamage.cpp @@ -12,7 +12,7 @@ void PropertyFXDamage::OnCollisionPhantom(Entity* self, Entity* target) { if (skills != nullptr && targetStats != nullptr) { auto targetFactions = targetStats->GetFactionIDs(); if (std::find(targetFactions.begin(), targetFactions.end(), 1) != targetFactions.end()) { - skills->CalculateBehavior(11386, 692, target->GetObjectID()); + skills->CalculateBehavior(692, 11386, target->GetObjectID()); } } } From 5cc7d470743694e21b6960a065fc3fba202ccd2a Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Sat, 24 Dec 2022 16:41:13 -0600 Subject: [PATCH 41/63] sanity check on opening packages (#923) --- dGame/dGameMessages/GameMessages.cpp | 6 +-- dGame/dInventory/Item.cpp | 68 +++++++++++++++------------- dGame/dInventory/Item.h | 2 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 26b1bb3c..37aeb093 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -5763,11 +5763,7 @@ void GameMessages::HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity auto* item = inv->FindItemById(itemConsumed); - if (item == nullptr) { - return; - } - - item->UseNonEquip(); + if (item) item->UseNonEquip(item); } void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entity) { diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index 778d8237..a3d4cfc0 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -262,7 +262,7 @@ bool Item::Consume() { return success; } -void Item::UseNonEquip() { +void Item::UseNonEquip(Item* item) { LOT thisLot = this->GetLot(); if (!GetInventory()) { Game::logger->LogDebug("Item", "item %i has no inventory??", this->GetLot()); @@ -292,45 +292,49 @@ void Item::UseNonEquip() { } // This precondition response is taken care of in SpawnPet(). } else { - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_PACKAGE); + bool success = false; + auto inventory = item->GetInventory(); + if (inventory && inventory->GetType() == eInventoryType::ITEMS) { + auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_PACKAGE); - if (packageComponentId == 0) return; + if (packageComponentId == 0) return; - auto* packCompTable = CDClientManager::Instance()->GetTable("PackageComponent"); - auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); + auto* packCompTable = CDClientManager::Instance()->GetTable("PackageComponent"); + auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); - auto success = !packages.empty(); - if (success) { - if (this->GetPreconditionExpression()->Check(playerInventoryComponent->GetParent())) { - auto* entityParent = playerInventoryComponent->GetParent(); - // Roll the loot for all the packages then see if it all fits. If it fits, give it to the player, otherwise don't. - std::unordered_map rolledLoot{}; - for (auto& pack : packages) { - auto thisPackage = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex); - for (auto& loot : thisPackage) { - // If we already rolled this lot, add it to the existing one, otherwise create a new entry. - auto existingLoot = rolledLoot.find(loot.first); - if (existingLoot == rolledLoot.end()) { - rolledLoot.insert(loot); - } else { - existingLoot->second += loot.second; + auto success = !packages.empty(); + if (success) { + if (this->GetPreconditionExpression()->Check(playerInventoryComponent->GetParent())) { + auto* entityParent = playerInventoryComponent->GetParent(); + // Roll the loot for all the packages then see if it all fits. If it fits, give it to the player, otherwise don't. + std::unordered_map rolledLoot{}; + for (auto& pack : packages) { + auto thisPackage = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex); + for (auto& loot : thisPackage) { + // If we already rolled this lot, add it to the existing one, otherwise create a new entry. + auto existingLoot = rolledLoot.find(loot.first); + if (existingLoot == rolledLoot.end()) { + rolledLoot.insert(loot); + } else { + existingLoot->second += loot.second; + } } } - } - if (playerInventoryComponent->HasSpaceForLoot(rolledLoot)) { - LootGenerator::Instance().GiveLoot(playerInventoryComponent->GetParent(), rolledLoot, eLootSourceType::LOOT_SOURCE_CONSUMPTION); - playerInventoryComponent->RemoveItem(lot, 1); + if (playerInventoryComponent->HasSpaceForLoot(rolledLoot)) { + LootGenerator::Instance().GiveLoot(playerInventoryComponent->GetParent(), rolledLoot, eLootSourceType::LOOT_SOURCE_CONSUMPTION); + item->SetCount(item->GetCount() - 1); + } else { + success = false; + } } else { + GameMessages::SendUseItemRequirementsResponse( + playerInventoryComponent->GetParent()->GetObjectID(), + playerInventoryComponent->GetParent()->GetSystemAddress(), + UseItemResponse::FailedPrecondition + ); success = false; } - } else { - GameMessages::SendUseItemRequirementsResponse( - playerInventoryComponent->GetParent()->GetObjectID(), - playerInventoryComponent->GetParent()->GetSystemAddress(), - UseItemResponse::FailedPrecondition - ); - success = false; } } Game::logger->LogDebug("Item", "Player %llu %s used item %i", playerEntity->GetObjectID(), success ? "successfully" : "unsuccessfully", thisLot); diff --git a/dGame/dInventory/Item.h b/dGame/dInventory/Item.h index bb8316d7..6993a0ba 100644 --- a/dGame/dInventory/Item.h +++ b/dGame/dInventory/Item.h @@ -195,7 +195,7 @@ public: /** * Uses this item if its non equip, essentially an interface for the linked GM */ - void UseNonEquip(); + void UseNonEquip(Item* item); /** * Disassembles the part LOTs of this item back into the inventory, if it has any From e41ed684475db90a59e1d70fc31ab2d7b39ac1b8 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 28 Dec 2022 13:58:53 -0800 Subject: [PATCH 42/63] Update README (#806) * Update README The README is very out of date, the following changes have been made - Update what the file tree should look like - Remove client Avant Gardens Survival script fix - Update some incorrect commands or commands that were missing packages. - Add packed client setup instructions - Add *config.ini setup instructions - Describe what configs should be modified and what you may want to change - More detail in the verify step - Change Account Manager link to Nexus Dashboard - Remove table of commands and reference Commands.md instead - Specify that UGCSERVERIP may need to be changed to localhost as well * Fix Avant Gardens Survival This addresses the Avant Gardens Survival bug. Squeezing it in with the README changes since it is a small change. * Remove Locale * Update README.md Co-authored-by: Jonathan Romano * Remove dLocale again? * Saving for the night * Revert "Fix Avant Gardens Survival" This reverts commit b1a1ce2d84e870c328a039673c9b77859e6e3dbd. * Update Mission.cpp * Update README.md Move comments and add pre-processor define Update README.md Update README.md Update CMakePresets.json Update CMakeVariables.txt Update README.md i love readmes Update README.md Update README.md Update README.md Update README.md Update README.md Update README.md Update README.md * Update README.md Co-authored-by: Daniel Seiler * Address feedback * Update README.md * Update Database.cpp * Update README.md * Revert tcp specification Co-authored-by: Jonathan Romano Co-authored-by: Aaron Kimbrell Co-authored-by: Daniel Seiler --- CMakePresets.json | 5 +- CMakeVariables.txt | 14 +- README.md | 587 +++++++++++++++++++-------------------------- docs/Commands.md | 4 +- 4 files changed, 257 insertions(+), 353 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 3968b3ce..f8170755 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -23,10 +23,7 @@ "name": "ci-macos-11", "displayName": "CI configure step for MacOS", "description": "Same as default, Used in GitHub actions workflow", - "inherits": "default", - "cacheVariables": { - "OPENSSL_ROOT_DIR": "/usr/local/opt/openssl@3/" - } + "inherits": "default" }, { "name": "ci-windows-2022", diff --git a/CMakeVariables.txt b/CMakeVariables.txt index 94e9cd20..d3c8b36f 100644 --- a/CMakeVariables.txt +++ b/CMakeVariables.txt @@ -8,15 +8,17 @@ LICENSE=AGPL-3.0 # 171022 - Unmodded client NET_VERSION=171022 # Debugging -__dynamic=1 # Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs. -# __ggdb=1 +__dynamic=1 # Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info. -# __include_backtrace__=1 +# __ggdb=1 # Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs. -# __compile_backtrace__=1 +# __include_backtrace__=1 # Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries. -__maria_db_connector_compile_jobs__=1 +# __compile_backtrace__=1 # Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with. -__enable_testing__=1 +__maria_db_connector_compile_jobs__=1 # When set to 1 and uncommented, compiling and linking testing folders and libraries will be done. +__enable_testing__=1 +# The path to OpenSSL. Change this if your OpenSSL install path is different than the default. +OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/ diff --git a/README.md b/README.md index bd9dd6b7..27de7d6d 100644 --- a/README.md +++ b/README.md @@ -18,210 +18,188 @@ Darkflame Universe is licensed under AGPLv3, please read [LICENSE](LICENSE). Som Throughout the entire build and setup process a level of familiarity with the command line and preferably a Unix-like development environment is greatly advantageous. ### Hosting a server -We do not recommend hosting public servers. DLU is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks. +We do not recommend hosting public servers. Darkflame Universe is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks. ### Supply of resource files -Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed in the resources tab below when checking if a client will work. +Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work. -## Build -Development of the latest iteration of Darkflame Universe has been done primarily in a Unix-like environment and is where it has been tested and designed for deployment. It is therefore highly recommended that Darkflame Universe be built and deployed using a Unix-like environment for the most streamlined experience. +## Steps to setup server +* [Clone this repository](#clone-the-repository) +* [Install dependencies](#install-dependencies) +* [Database setup](#database-setup) +* [Build the server](#build-the-server) +* [Configuring your server](#configuring-your-server) + * [Required Configuration](#required-configuration) + * [Optional Configuration](#optional-configuration) +* [Verify your setup](#verify-your-setup) +* [Running the server](#running-the-server) +* [User Guide](#user-guide) -### Prerequisites -#### Clone the repository +## Clone the repository +If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win) + +Then run the following command ```bash git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer ``` -#### Python -Some tools utilized to streamline the setup process require Python 3, make sure you have it installed. +## Install dependencies +### Windows packages +Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed. +You'll also need to download and install [CMake](https://cmake.org/download/) (version **CMake version 3.18** or later!). -### Choosing the right version for your client -DLU clients identify themselves using a higher version number than the regular live clients out there. -This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client. +### MacOS packages +Ensure you have [brew](https://brew.sh) installed. +You will need to install the following packages +```bash +brew install cmake gcc mariadb openssl zlib +``` -If you're using a DLU client you'll have to go into the "CMakeVariables.txt" file and change the NET_VERSION variable to 171023 to match the modified client's version number. +### Linux packages +Make sure packages like `gcc`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. You will also need a MySQL database solution to use. We recommend using `mariadb-server`. -### Enabling testing -While it is highly recommended to enable testing, if you would like to save compilation time, you'll want to comment out the enable_testing variable in CMakeVariables.txt. -It is recommended that after building and if testing is enabled, to run `ctest` and make sure all the tests pass. +For Ubuntu, you would run the following commands. On other systems, the package install command will differ. -### Using Docker -Refer to [Docker.md](/Docker.md). +```bash +sudo apt update && sudo apt upgrade -For Windows, refer to [Docker_Windows.md](/Docker_Windows.md). +# Install packages +sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-server cmake +``` -### Linux builds -Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. +#### Required CMake version +This project uses **CMake version 3.18** or higher and as such you will need to ensure you have this version installed. +You can check your CMake version by using the following command in a terminal. +```bash +cmake --version +``` -CMake must be version 3.14 or higher! +If you are going to be using an Ubuntu environment to run the server, you may need to get a more recent version of `cmake` than the packages available may provide. -#### Build the repository +The general approach to do so would be to obtain a copy of the signing key and then add the CMake repository to your apt. +You can do so with the following commands. +[Source of the below commands](https://askubuntu.com/questions/355565/how-do-i-install-the-latest-version-of-cmake-from-the-command-line) + +```bash +# Remove the old version of CMake +sudo apt purge --auto-remove cmake + +# Prepare for installation +sudo apt update && sudo apt install -y software-properties-common lsb-release && sudo apt clean all + +# Obtain a copy of the signing key +wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null + +# Add the repository to your sources list. +sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" + +# Next you'll want to ensure that Kitware's keyring stays up to date +sudo apt update +sudo apt install kitware-archive-keyring +sudo rm /etc/apt/trusted.gpg.d/kitware.gpg + +# If sudo apt update above returned an error, copy the public key at the end of the error message and run the following command +# if the error message was "The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 6AF7F09730B3F0A4" +# then the below command would be "sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6AF7F09730B3F0A4" +sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys + +# Finally update and install +sudo apt update +sudo apt install cmake +``` + +## Database setup +First you'll need to start MariaDB. + +For Windows the service is always running by default. + +For MacOS, run the following command +```bash +brew services start mariadb +``` + +For Linux, run the following command +```bash +sudo systemctl start mysql +# If systemctl is not a known command on your distribution, try the following instead +sudo service mysql start +``` + +**You will need to run this command every time you restart your environment** + +If you are using Linux and `systemctl` and want the MariaDB instance to start on startup, run the following command +```bash +sudo systemctl enable --now mysql +``` + +Once MariaDB is started, you'll need to create a user and an empty database for Darkflame Universe to use. + +First, login to the MariaDB instance. + +To do this on Ubuntu/Linux, MacOS, or another Unix like operating system, run the following command in a terminal +```bash +# Logs you into the MariaDB instance as root +sudo mysql +``` + +For Windows, run the following command in the `Command Prompt (MariaDB xx.xx)` terminal +```bash +# Logs you into the mysql instance +mysql -u root -p +# You will then be prompted for the password you set for root during installation of MariaDB +``` + +Now that you are logged in, run the following commands. + +```bash +# Creates a user for this computer which uses a password and grant said user all privileges. +# Change mydarkflameuser to a custom username and password to a custom password. +GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION; +FLUSH PRIVILEGES; + +# Then create a database for Darkflame Universe to use. +CREATE DATABASE darkflame; +``` + +## Build the server You can either run `build.sh` when in the root folder of the repository: ```bash ./build.sh ``` -Or manually run the commands used in `build.sh`: +Or manually run the commands used in [build.sh](build.sh). -```bash -# Create the build directory, preserving it if it already exists -mkdir -p build -cd build +### Notes +Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building: +* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory. +* If you are using a Darkflame Universe client, ensure NET_VERSION is changed to 171023. -# Run CMake to generate make files -cmake .. +## Configuring your server +This server has a few steps that need to be taken to configure the server for your use case. -# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8' -cmake --build . --config Release -``` +### Required Configuration +Darkflame Universe can run with either a packed or an unpacked client. +Navigate to `build/sharedconfig.ini` and fill in the following fields: +* `mysql_host` (This is the IP address or hostname of your MariaDB server. This is highly likely `localhost`) + * If you setup your MariaDB instance on a port other than 3306, which can be done on a Windows install, you will need to make this value `tcp://localhost:portNum` where portNum is replaced with the port you chose to run MariaDB on. +* `mysql_database` (This is the database you created for the server) +* `mysql_username` (This is the user you created for the server) +* `mysql_password` (This is the password for the user you created for the server) +* `client_location` (This is the location of the client files. This should be the folder path of a packed or unpacked client) + * Ideally the path to the client should not contain any spaces. -### MacOS builds -Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`). - -In the repository root folder run the following. Ensure -DOPENSSL_ROOT_DIR=/path/to/openssl points to your openssl install location -```bash -# Create the build directory, preserving it if it already exists -mkdir -p build -cd build - -# Run CMake to generate build files -cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl - -# Get cmake to build the project. If make files are being used then using make and appending `-j` and the amount of cores to utilize may be preferable, for example `make -j8` -cmake --build . --config Release -``` - -### Windows builds (native) -Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/). Currently on native Windows the server will only work in Release mode. - -#### Build the repository -```batch -:: Create the build directory -mkdir build -cd build - -:: Run CMake to generate make files -cmake .. - -:: Run CMake with build flag to build -cmake --build . --config Release -``` -#### Windows for ARM has not been tested but should build by doing the following -```batch -:: Create the build directory -mkdir build -cd build - -:: Run CMake to generate make files -cmake .. -DMARIADB_BUILD_SOURCE=ON - -:: Run CMake with build flag to build -cmake --build . --config Release -``` - -### Windows builds (WSL) -This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11. - -#### Open the Command Prompt application with Administrator permissions and run the following: -```bash -# Installing Windows Subsystem for Linux -wsl --install -``` - -#### Open the Ubuntu application and run the following: -```bash -# Make sure the install is up to date -apt update && apt upgrade - -# Make sure the gcc, cmake, and build-essentials are installed -sudo apt install gcc -sudo apt install cmake -sudo apt install build-essential -``` - -[**Follow the Linux instructions**](#linux-builds) - -### ARM builds -AArch64 builds should work on linux and MacOS using their respective build steps. Windows ARM should build but it has not been tested - -### Updating your build -To update your server to the latest version navigate to your cloned directory -```bash -cd /path/to/DarkflameServer -``` -run the following commands to update to the latest changes -```bash -git pull -git submodule update --init --recursive -``` -now follow the build section for your system - -## Setting up the environment - -### Resources - -#### LEGO® Universe 1.10.64 - -This repository does not distribute any LEGO® Universe files. A full install of LEGO® Universe version 1.10.64 (latest) is required to finish setting up Darkflame Universe. - -Known good SHA256 checksums of the client: -- `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed) -- `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed) -- `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed) - -Known good *SHA1* checksum of the DLU client: -- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed) - -How to generate a SHA256 checksum: -```bash -# Replace with the file path to the client - -# If on Linux or MacOS -shasum -a 256 - -# If on Windows -certutil -hashfile SHA256 -``` - -#### Unpacking the client -* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils) -* Use `pkextractor.pyw` to unpack the client files if they are not already unpacked - -#### Setup resource directory -* In the `build` directory create a `res` directory if it does not already exist. -* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, `names`, and `maps` in your client `res` directory to the server `build/res` directory -* Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes` - -#### Setup locale -* In the `build` directory create a `locale` directory if it does not already exist -* Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory - -#### Client database -* Move the file `res/cdclient.fdb` from the unpacked client to the `build/res` folder on the server. -* The server will automatically copy and convert the file from fdb to sqlite should `CDServer.sqlite` not already exist. -* You can also convert the database manually using `fdb_to_sqlite.py` using lcdr's utilities. Just make sure to rename the file to `CDServer.sqlite` instead of `cdclient.sqlite`. -* Migrations to the database are automatically run on server start. When migrations are needed to be ran, the server may take a bit longer to start. - -### Database -Darkflame Universe utilizes a MySQL/MariaDB database for account and character information. - -Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running. - -* All that you need to do is create a database to connect to. As long as the server can connect to the database, the schema will always be kept up to date when you start the server. - -#### Configuration - -After the server has been built there should be four `ini` files in the build director: `sharedconfig.ini`, `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary. - -#### Migrations - -The database is automatically setup and migrated to what it should look like for the latest commit whenever you start the server. - -#### Verify +### Optional Configuration +* After the server has been built there should be five `ini` files in the build directory: `sharedconfig.ini`, `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. +* `authconfig.ini` contains an option to enable or disable play keys on your server. Do not change the default port for auth. +* `chatconfig.ini` contains a port option. +* `masterconfig.ini` contains options related to permissions you want to run your servers with. +* `sharedconfig.ini` contains several options that are shared across all servers +* `worldconfig.ini` contains several options to turn on QOL improvements should you want them. If you would like the most vanilla experience possible, you will need to turn some of these settings off. +## Verify your setup Your build directory should now look like this: * AuthServer * ChatServer @@ -230,42 +208,35 @@ Your build directory should now look like this: * authconfig.ini * chatconfig.ini * masterconfig.ini +* sharedconfig.ini * worldconfig.ini -* **locale/** - * locale.xml -* **res/** - * cdclient.fdb - * chatplus_en_us.txt - * **macros/** - * ... - * **BrickModels/** - * ... - * **maps/** - * **navmeshes/** - * ... - * ... * ... ## Running the server -If everything has been configured correctly you should now be able to run the `MasterServer` binary. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the binary network permissions or run it under sudo. +If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the `AuthServer` binary network permissions or run it under sudo. +To give `AuthServer` network permissions and not require sudo, run the following command +```bash +sudo setcap 'cap_net_bind_service=+ep' AuthServer +``` +and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0. ### First admin user Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users! -### Account Manager +### Account management tool (Nexus Dashboard) +**If you are just using this server for yourself, you can skip setting up Nexus Dashboard** -Follow the instructions [here](https://github.com/DarkflameUniverse/AccountManager) to setup the DLU account management Python web application. This is the intended way for users to create accounts. +Follow the instructions [here](https://github.com/DarkflameUniverse/NexusDashboard) to setup the DLU Nexus Dashboard web application. This is the intended way for users to create accounts and the intended way for moderators to approve names/pets/properties and do other moderation actions. ### Admin levels +The admin level, or Game Master level (hereafter referred to as gmlevel), is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. gmlevel `8` should be used to give a player a majority of privileges without the safety critical once. -The admin level, or game master level, is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. Admin level `8` should be used to give a player a majority of privileges without the safety critical once. +While a character has a gmlevel of anything but `0`, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of `0`. -While a character has a gmlevel of anything but 0, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of 0. +# User guide +Some changes to the client `boot.cfg` file are needed to play on your server. -## User guide -A few modifications have to be made to the client. - -### Client configuration +## Allowing a user to connect to your server To connect to a server follow these steps: * In the client directory, locate `boot.cfg` * Open it in a text editor and locate where it says `AUTHSERVERIP=0:` @@ -273,155 +244,89 @@ To connect to a server follow these steps: * Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system * Note that if you are on WSL2, you will need to configure the public IP in the server and client to be the IP of the WSL2 instance and not localhost, which can be found by running `ifconfig` in the terminal. Windows defaults to WSL1, so this will not apply to most users. -### Brick-By-Brick building +## Brick-By-Brick building +Should you choose to do any brick building, you will want to have some form of a http server that returns a 404 error since we are unable to emulate live User Generated Content at the moment. If you attempt to do any brick building without a 404 server running properly, you will be unable to load into your game. Python is the easiest way to do this, but any thing that returns a 404 should work fine. +* Note: the client hard codes this request on port 80. -Brick-By-Brick building requires `PATCHSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be achieved by pointing it to `localhost` while having `sudo python -m http.server 80` running in the background. +**If you do not plan on doing any Brick Building, then you can skip this step.** -### In-game commands -Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](./dGame/dUtilities/SlashCommandHandler.cpp). +The easiest way to do this is to install [python](https://www.python.org/downloads/). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Command - - Usage - - Description - - Admin Level Requirement -
- info - - /info - - Displays server info to the user, including where to find the server's source code. - -
- credits - - /credits - - Displays the names of the people behind Darkflame Universe. - -
- instanceinfo - - /instanceinfo - - Displays in the chat the current zone, clone, and instance id. - -
- gmlevel - - /gmlevel <level> - - Within the authorized range of levels for the current account, changes the character's game master level to the specified value. This is required to use certain commands. - -
- testmap - - /testmap <zone> (clone-id) - - Transfers you to the given zone by id and clone id. - - 1 -
- ban - - /ban <username> - - Bans a user from the server. - - 4 -
- gmadditem - - /gmadditem <id> (count) - - Adds the given item to your inventory by id. - - 8 -
- spawn - - /spawn <id> - - Spawns an object at your location by id. - - 8 -
- metrics - - /metrics - - Prints some information about the server's performance. - - 8 -
+### Allowing a user to build in Brick-by-Brick mode +Brick-By-Brick building requires `PATCHSERVERIP=0:` and `UGCSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be most easily achieved by pointing both of those variables to `localhost` while having running in the background. +Each client must have their own 404 server running if they are using a locally hosted 404 server. +```bash +# If on linux run this command. Because this is run on a port below 1024, binary network permissions are needed. +sudo python3 -m http.server 80 + +# If on windows one of the following will work when run through Powershell or Command Prompt assuming python is installed +python3 -m http.server 80 +python http.server 80 +py -m http.server 80 +``` + +## Updating your server +To update your server to the latest version navigate to your cloned directory +```bash +cd path/to/DarkflameServer +``` +Run the following commands to update to the latest changes +```bash +git pull +git submodule update --init --recursive +``` +Now follow the [build](#build-the-server) section for your system and your server is up to date. + +## In-game commands +* A list of all in-game commands can be found [here](./docs/Commands.md). + +## Verifying your client files + +### LEGO® Universe 1.10.64 +To verify that you are indeed using a LEGO® Universe 1.10.64 client, make sure you have the full client compressed **in a rar file** and run the following command. +```bash +# Replace with the file path to the zipped client + +# If on Linux or MacOS +shasum -a 256 + +# If on Windows using the Command Prompt +certutil -hashfile SHA256 +``` + +Below are known good SHA256 checksums of the client: +* `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed) +* `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed) +* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed) + +If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64. + +### Darkflame Universe Client +Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there. +This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client. + +To verify that you are indeed using a Darkflame Universe client, make sure you have the full client compressed **in a zip file** and run the following command. + +```bash +# Replace with the file path to the zipped client + +# If on Linux or MacOS +shasum -a 1 + +# If on Windows using the Command Prompt +certutil -hashfile SHA1 +``` + +Known good *SHA1* checksum of the Darkflame Universe client: +- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed) + +# Development Documentation +This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server +[Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html) +[General system documentation](https://docs.lu-dev.net/en/latest/index.html) # Credits + ## DLU Team * [DarwinAnim8or](https://github.com/DarwinAnim8or) * [Wincent01](https://github.com/Wincent01) diff --git a/docs/Commands.md b/docs/Commands.md index 7a15bf37..060c2ba0 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -1,6 +1,5 @@ # In-game commands - -Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](../dGame/dUtilities/SlashCommandHandler.cpp). +* All commands are prefixed by `/` and typed in the in-game chat window. Some commands require elevated gmlevel privileges. Operands within `<>` are required, operands within `()` are not. ## General Commands @@ -71,6 +70,7 @@ These commands are primarily for development and testing. The usage of many of t |createprivate|`/createprivate `|Creates a private zone with password.|8| |debugui|`/debugui`|Toggle Debug UI.|8| |dismount|`/dismount`|Dismounts you from the vehicle or mount.|8| +|reloadconfig|`/reloadconfig`|Reloads the server with the new config values.|8| |force-save|`/force-save`|While saving to database usually happens on regular intervals and when you disconnect from the server, this command saves your player's data to the database.|8| |freecam|`/freecam`|Toggles freecam mode.|8| |freemoney|`/freemoney `|Gives coins.|8| From 0e9c0a8917f3afbcfda452ab9e8c66504aad15d9 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:03:07 -0800 Subject: [PATCH 43/63] Fix MovementSwitch Behavior (#927) --- dGame/dBehaviors/MovementSwitchBehavior.cpp | 55 ++++++++++++--------- dGame/dBehaviors/MovementSwitchBehavior.h | 13 ++++- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/dGame/dBehaviors/MovementSwitchBehavior.cpp b/dGame/dBehaviors/MovementSwitchBehavior.cpp index c893e6e1..0c11380f 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.cpp +++ b/dGame/dBehaviors/MovementSwitchBehavior.cpp @@ -4,17 +4,17 @@ #include "dLogger.h" void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - if (this->m_groundAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_jumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_fallingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_doubleJumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_airAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_jetpackAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { - return; - } - uint32_t movementType{}; if (!bitStream->Read(movementType)) { + if (this->m_groundAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_jumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_fallingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_doubleJumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_airAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_jetpackAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_movingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + return; + } Game::logger->Log("MovementSwitchBehavior", "Unable to read movementType from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); return; }; @@ -27,33 +27,40 @@ void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* this->m_jumpAction->Handle(context, bitStream, branch); break; case 3: - this->m_fallingAction->Handle(context, bitStream, branch); + this->m_airAction->Handle(context, bitStream, branch); break; case 4: this->m_doubleJumpAction->Handle(context, bitStream, branch); break; case 5: - this->m_airAction->Handle(context, bitStream, branch); + this->m_fallingAction->Handle(context, bitStream, branch); break; case 6: this->m_jetpackAction->Handle(context, bitStream, branch); break; default: - Game::logger->Log("MovementSwitchBehavior", "Invalid movement behavior type (%i)!", movementType); + this->m_groundAction->Handle(context, bitStream, branch); break; } } -void MovementSwitchBehavior::Load() { - this->m_airAction = GetAction("air_action"); - - this->m_doubleJumpAction = GetAction("double_jump_action"); - - this->m_fallingAction = GetAction("falling_action"); - - this->m_groundAction = GetAction("ground_action"); - - this->m_jetpackAction = GetAction("jetpack_action"); - - this->m_jumpAction = GetAction("jump_action"); +Behavior* MovementSwitchBehavior::LoadMovementType(std::string movementType) { + float actionValue = GetFloat(movementType, -1.0f); + auto loadedBehavior = GetAction(actionValue != -1.0f ? actionValue : 0.0f); + if (actionValue == -1.0f && loadedBehavior->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + loadedBehavior = this->m_groundAction; + } + return loadedBehavior; +} + +void MovementSwitchBehavior::Load() { + float groundActionValue = GetFloat("ground_action", -1.0f); + this->m_groundAction = GetAction(groundActionValue != -1.0f ? groundActionValue : 0.0f); + + this->m_airAction = LoadMovementType("air_action"); + this->m_doubleJumpAction = LoadMovementType("double_jump_action"); + this->m_fallingAction = LoadMovementType("falling_action"); + this->m_jetpackAction = LoadMovementType("jetpack_action"); + this->m_jumpAction = LoadMovementType("jump_action"); + this->m_movingAction = LoadMovementType("moving_action"); } diff --git a/dGame/dBehaviors/MovementSwitchBehavior.h b/dGame/dBehaviors/MovementSwitchBehavior.h index 82e1a9e9..e6ff96f6 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.h +++ b/dGame/dBehaviors/MovementSwitchBehavior.h @@ -3,7 +3,7 @@ class MovementSwitchBehavior final : public Behavior { -public: +private: /* * Members */ @@ -19,6 +19,17 @@ public: Behavior* m_jumpAction; + Behavior* m_movingAction; + + /** + * @brief Loads a movement type from the database into a behavior + * + * @param movementType The movement type to lookup in the database + * @param behaviorToLoad The Behavior where the result will be stored + */ + Behavior* LoadMovementType(std::string movementType); + +public: /* * Inherited */ From 99c0ca253cb587f3f43b440d39f9ce331748f62a Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:04:37 -0800 Subject: [PATCH 44/63] Basic Attack Behavior Live Accuracy Improvements (#926) * Overhaul BasicAttack Behavior so it matches the live 1.10.64 client --- dCommon/dEnums/eBasicAttackSuccessTypes.h | 12 ++ dGame/dBehaviors/BasicAttackBehavior.cpp | 232 +++++++++++++++------- dGame/dBehaviors/BasicAttackBehavior.h | 39 ++++ 3 files changed, 206 insertions(+), 77 deletions(-) create mode 100644 dCommon/dEnums/eBasicAttackSuccessTypes.h diff --git a/dCommon/dEnums/eBasicAttackSuccessTypes.h b/dCommon/dEnums/eBasicAttackSuccessTypes.h new file mode 100644 index 00000000..8c06da8a --- /dev/null +++ b/dCommon/dEnums/eBasicAttackSuccessTypes.h @@ -0,0 +1,12 @@ +#ifndef __EBASICATTACKSUCCESSTYPES__H__ +#define __EBASICATTACKSUCCESSTYPES__H__ + +#include + +enum class eBasicAttackSuccessTypes : uint8_t { + SUCCESS = 1, + FAILARMOR, + FAILIMMUNE +}; + +#endif //!__EBASICATTACKSUCCESSTYPES__H__ diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index f166f00c..0378cb5e 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -5,7 +5,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "BehaviorContext.h" - +#include "eBasicAttackSuccessTypes.h" void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { if (context->unmanaged) { @@ -31,130 +31,120 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi } Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits); const auto baseAddress = bitStream->GetReadOffset(); + + DoHandleBehavior(context, bitStream, branch); + + bitStream->SetReadOffset(baseAddress + allocatedBits); +} + +void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!targetEntity) { + Game::logger->Log("BasicAttackBehavior", "Target targetEntity %i not found.", branch.target); + return; + } + + auto* destroyableComponent = targetEntity->GetComponent(); + if (!destroyableComponent) { + Game::logger->Log("BasicAttackBehavior", "No destroyable found on the obj/lot %llu/%i", branch.target, targetEntity->GetLOT()); + return; + } + bool isBlocked{}; bool isImmune{}; bool isSuccess{}; if (!bitStream->Read(isBlocked)) { - Game::logger->LogDebug("BasicAttackBehavior", "Unable to read isBlocked"); + Game::logger->Log("BasicAttackBehavior", "Unable to read isBlocked"); return; } - if (isBlocked) return; + if (isBlocked) { + destroyableComponent->SetAttacksToBlock(std::min(destroyableComponent->GetAttacksToBlock() - 1, 0U)); + EntityManager::Instance()->SerializeEntity(targetEntity); + this->m_OnFailBlocked->Handle(context, bitStream, branch); + return; + } if (!bitStream->Read(isImmune)) { - Game::logger->LogDebug("BasicAttackBehavior", "Unable to read isImmune"); + Game::logger->Log("BasicAttackBehavior", "Unable to read isImmune"); return; } - if (isImmune) return; + if (isImmune) { + this->m_OnFailImmune->Handle(context, bitStream, branch); + return; + } - if (bitStream->Read(isSuccess) && isSuccess) { // Success - uint32_t unknown{}; - if (!bitStream->Read(unknown)) { - Game::logger->LogDebug("BasicAttackBehavior", "Unable to read unknown"); + if (!bitStream->Read(isSuccess)) { + Game::logger->Log("BasicAttackBehavior", "failed to read success from bitstream"); + return; + } + + if (isSuccess) { + uint32_t armorDamageDealt{}; + if (!bitStream->Read(armorDamageDealt)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read armorDamageDealt"); return; } - uint32_t damageDealt{}; - if (!bitStream->Read(damageDealt)) { - Game::logger->LogDebug("BasicAttackBehavior", "Unable to read damageDealt"); + uint32_t healthDamageDealt{}; + if (!bitStream->Read(healthDamageDealt)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read healthDamageDealt"); return; } - // A value that's too large may be a cheating attempt, so we set it to MIN too - if (damageDealt > this->m_MaxDamage || damageDealt < this->m_MinDamage) { - damageDealt = this->m_MinDamage; + uint32_t totalDamageDealt = armorDamageDealt + healthDamageDealt; + + // A value that's too large may be a cheating attempt, so we set it to MIN + if (totalDamageDealt > this->m_MaxDamage) { + totalDamageDealt = this->m_MinDamage; } - auto* entity = EntityManager::Instance()->GetEntity(branch.target); bool died{}; if (!bitStream->Read(died)) { - Game::logger->LogDebug("BasicAttackBehavior", "Unable to read died"); + Game::logger->Log("BasicAttackBehavior", "Unable to read died"); return; } - - if (entity != nullptr) { - auto* destroyableComponent = entity->GetComponent(); - if (destroyableComponent != nullptr) { - PlayFx(u"onhit", entity->GetObjectID()); - destroyableComponent->Damage(damageDealt, context->originator, context->skillID); - } - } + auto previousArmor = destroyableComponent->GetArmor(); + auto previousHealth = destroyableComponent->GetHealth(); + PlayFx(u"onhit", targetEntity->GetObjectID()); + destroyableComponent->Damage(totalDamageDealt, context->originator, context->skillID); } uint8_t successState{}; if (!bitStream->Read(successState)) { - Game::logger->LogDebug("BasicAttackBehavior", "Unable to read success state"); + Game::logger->Log("BasicAttackBehavior", "Unable to read success state"); return; } - switch (successState) { - case 1: + switch (static_cast(successState)) { + case eBasicAttackSuccessTypes::SUCCESS: this->m_OnSuccess->Handle(context, bitStream, branch); break; + case eBasicAttackSuccessTypes::FAILARMOR: + this->m_OnFailArmor->Handle(context, bitStream, branch); + break; default: - Game::logger->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState); + if (static_cast(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) { + Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + return; + } + this->m_OnFailImmune->Handle(context, bitStream, branch); break; } - - bitStream->SetReadOffset(baseAddress + allocatedBits); } void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - auto* self = EntityManager::Instance()->GetEntity(context->originator); - if (self == nullptr) { - Game::logger->LogDebug("BasicAttackBehavior", "Invalid self entity (%llu)!", context->originator); - return; - } - bitStream->AlignWriteToByteBoundary(); const auto allocatedAddress = bitStream->GetWriteOffset(); - bitStream->Write(uint16_t(0)); + bitStream->Write(0); const auto startAddress = bitStream->GetWriteOffset(); - bitStream->Write0(); // Blocked - bitStream->Write0(); // Immune - bitStream->Write1(); // Success - - if (true) { - uint32_t unknown3 = 0; - bitStream->Write(unknown3); - - auto damage = this->m_MinDamage; - auto* entity = EntityManager::Instance()->GetEntity(branch.target); - - if (entity == nullptr) { - damage = 0; - bitStream->Write(damage); - bitStream->Write(false); - } else { - bitStream->Write(damage); - bitStream->Write(true); - - auto* destroyableComponent = entity->GetComponent(); - if (damage != 0 && destroyableComponent != nullptr) { - PlayFx(u"onhit", entity->GetObjectID(), 1); - destroyableComponent->Damage(damage, context->originator, context->skillID, false); - context->ScheduleUpdate(branch.target); - } - } - } - - uint8_t successState = 1; - bitStream->Write(successState); - - switch (successState) { - case 1: - this->m_OnSuccess->Calculate(context, bitStream, branch); - break; - default: - Game::logger->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState); - break; - } + DoBehaviorCalculation(context, bitStream, branch); const auto endAddress = bitStream->GetWriteOffset(); const uint16_t allocate = endAddress - startAddress + 1; @@ -164,6 +154,87 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream->SetWriteOffset(startAddress + allocate); } +void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!targetEntity) { + Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target); + return; + } + + auto* destroyableComponent = targetEntity->GetComponent(); + if (!destroyableComponent || !destroyableComponent->GetParent()) { + Game::logger->Log("BasicAttackBehavior", "No destroyable component on %llu", branch.target); + return; + } + + const bool isBlocking = destroyableComponent->GetAttacksToBlock() > 0; + + bitStream->Write(isBlocking); + + if (isBlocking) { + destroyableComponent->SetAttacksToBlock(destroyableComponent->GetAttacksToBlock() - 1); + EntityManager::Instance()->SerializeEntity(targetEntity); + this->m_OnFailBlocked->Calculate(context, bitStream, branch); + return; + } + + const bool isImmune = destroyableComponent->IsImmune(); + + bitStream->Write(isImmune); + + if (isImmune) { + this->m_OnFailImmune->Calculate(context, bitStream, branch); + return; + } + + bool isSuccess = false; + const uint32_t previousHealth = destroyableComponent->GetHealth(); + const uint32_t previousArmor = destroyableComponent->GetArmor(); + + const auto damage = this->m_MinDamage; + + PlayFx(u"onhit", targetEntity->GetObjectID(), 1); + destroyableComponent->Damage(damage, context->originator, context->skillID, false); + context->ScheduleUpdate(branch.target); + + const uint32_t armorDamageDealt = previousArmor - destroyableComponent->GetArmor(); + const uint32_t healthDamageDealt = previousHealth - destroyableComponent->GetHealth(); + isSuccess = armorDamageDealt > 0 || healthDamageDealt > 0 || (armorDamageDealt + healthDamageDealt) > 0; + + bitStream->Write(isSuccess); + + eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE; + if (isSuccess) { + if (healthDamageDealt >= 1) { + successState = eBasicAttackSuccessTypes::SUCCESS; + } else if (armorDamageDealt >= 1) { + successState = this->m_OnFailArmor->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY ? eBasicAttackSuccessTypes::FAILIMMUNE : eBasicAttackSuccessTypes::FAILARMOR; + } + + bitStream->Write(armorDamageDealt); + bitStream->Write(healthDamageDealt); + bitStream->Write(targetEntity->GetIsDead()); + } + + bitStream->Write(successState); + + switch (static_cast(successState)) { + case eBasicAttackSuccessTypes::SUCCESS: + this->m_OnSuccess->Calculate(context, bitStream, branch); + break; + case eBasicAttackSuccessTypes::FAILARMOR: + this->m_OnFailArmor->Calculate(context, bitStream, branch); + break; + default: + if (static_cast(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) { + Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + break; + } + this->m_OnFailImmune->Calculate(context, bitStream, branch); + break; + } +} + void BasicAttackBehavior::Load() { this->m_MinDamage = GetInt("min damage"); if (this->m_MinDamage == 0) this->m_MinDamage = 1; @@ -171,7 +242,14 @@ void BasicAttackBehavior::Load() { this->m_MaxDamage = GetInt("max damage"); if (this->m_MaxDamage == 0) this->m_MaxDamage = 1; + // The client sets the minimum damage to maximum, so we'll do the same. These are usually the same value anyways. + if (this->m_MinDamage < this->m_MaxDamage) this->m_MinDamage = this->m_MaxDamage; + this->m_OnSuccess = GetAction("on_success"); this->m_OnFailArmor = GetAction("on_fail_armor"); + + this->m_OnFailImmune = GetAction("on_fail_immune"); + + this->m_OnFailBlocked = GetAction("on_fail_blocked"); } diff --git a/dGame/dBehaviors/BasicAttackBehavior.h b/dGame/dBehaviors/BasicAttackBehavior.h index 9c08141c..f6e3fa28 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.h +++ b/dGame/dBehaviors/BasicAttackBehavior.h @@ -7,10 +7,45 @@ public: explicit BasicAttackBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } + /** + * @brief Reads a 16bit short from the bitStream and when the actual behavior handling finishes with all of its branches, the bitStream + * is then offset to after the allocated bits for this stream. + * + */ + void DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + + /** + * @brief Handles a client initialized Basic Attack Behavior cast to be deserialized and verified on the server. + * + * @param context The Skill's Behavior context. All behaviors in the same tree share the same context + * @param bitStream The bitStream to deserialize. BitStreams will always check their bounds before reading in a behavior + * and will fail gracefully if an overread is detected. + * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. + */ void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + /** + * @brief Writes a 16bit short to the bitStream and when the actual behavior calculation finishes with all of its branches, the number + * of bits used is then written to where the 16bit short initially was. + * + */ void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + /** + * @brief Calculates a server initialized Basic Attack Behavior cast to be serialized to the client + * + * @param context The Skill's Behavior context. All behaviors in the same tree share the same context + * @param bitStream The bitStream to serialize to. + * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. + */ + void DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + + /** + * @brief Loads this Behaviors parameters from the database. For this behavior specifically: + * max and min damage will always be the same. If min is less than max, they are both set to max. + * If an action is not in the database, then no action is taken for that result. + * + */ void Load() override; private: uint32_t m_MinDamage; @@ -20,4 +55,8 @@ private: Behavior* m_OnSuccess; Behavior* m_OnFailArmor; + + Behavior* m_OnFailImmune; + + Behavior* m_OnFailBlocked; }; From bd28e4051fa5eb003c4a29366dd03c75eeeeb021 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 29 Dec 2022 01:43:52 -0800 Subject: [PATCH 45/63] Fix Hash Collisions in CDBehaviorParameter table (#930) * Fix hashing * Update CDBehaviorParameterTable.cpp --- dDatabase/Tables/CDBehaviorParameterTable.cpp | 41 ++++++++----------- dDatabase/Tables/CDBehaviorParameterTable.h | 12 +++--- dGame/dBehaviors/Behavior.cpp | 2 +- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/dDatabase/Tables/CDBehaviorParameterTable.cpp b/dDatabase/Tables/CDBehaviorParameterTable.cpp index 96015896..d09a71b2 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.cpp +++ b/dDatabase/Tables/CDBehaviorParameterTable.cpp @@ -4,9 +4,9 @@ //! Constructor CDBehaviorParameterTable::CDBehaviorParameterTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); - size_t hash = 0; + uint32_t uniqueParameterId = 0; + uint64_t hash = 0; while (!tableData.eof()) { - hash = 0; CDBehaviorParameter entry; entry.behaviorID = tableData.getIntField(0, -1); auto candidateStringToAdd = std::string(tableData.getStringField(1, "")); @@ -14,15 +14,13 @@ CDBehaviorParameterTable::CDBehaviorParameterTable(void) { if (parameter != m_ParametersList.end()) { entry.parameterID = parameter; } else { - entry.parameterID = m_ParametersList.insert(candidateStringToAdd).first; + entry.parameterID = m_ParametersList.insert(std::make_pair(candidateStringToAdd, uniqueParameterId)).first; + uniqueParameterId++; } + hash = entry.behaviorID; + hash = (hash << 31U) | entry.parameterID->second; entry.value = tableData.getFloatField(2, -1.0f); - GeneralUtils::hash_combine(hash, entry.behaviorID); - GeneralUtils::hash_combine(hash, *entry.parameterID); - - auto it = m_Entries.find(entry.behaviorID); - m_ParametersList.insert(*entry.parameterID); m_Entries.insert(std::make_pair(hash, entry)); tableData.nextRow(); @@ -38,31 +36,28 @@ std::string CDBehaviorParameterTable::GetName(void) const { return "BehaviorParameter"; } -CDBehaviorParameter CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) { - CDBehaviorParameter returnValue; - returnValue.behaviorID = 0; - returnValue.parameterID = m_ParametersList.end(); - returnValue.value = defaultValue; +float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) { + auto parameterID = this->m_ParametersList.find(name); + if (parameterID == this->m_ParametersList.end()) return defaultValue; - size_t hash = 0; - GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, name); + uint64_t hash = behaviorID; + + hash = (hash << 31U) | parameterID->second; // Search for specific parameter const auto& it = m_Entries.find(hash); - return it != m_Entries.end() ? it->second : returnValue; + return it != m_Entries.end() ? it->second.value : defaultValue; } std::map CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { - size_t hash; + uint64_t hashBase = behaviorID; std::map returnInfo; - for (auto parameterCandidate : m_ParametersList) { - hash = 0; - GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, parameterCandidate); + uint64_t hash; + for (auto& parameterCandidate : m_ParametersList) { + hash = (hashBase << 31U) | parameterCandidate.second; auto infoCandidate = m_Entries.find(hash); if (infoCandidate != m_Entries.end()) { - returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value)); + returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value)); } } return returnInfo; diff --git a/dDatabase/Tables/CDBehaviorParameterTable.h b/dDatabase/Tables/CDBehaviorParameterTable.h index f067e7d2..5d0d8b72 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.h +++ b/dDatabase/Tables/CDBehaviorParameterTable.h @@ -12,16 +12,16 @@ //! BehaviorParameter Entry Struct struct CDBehaviorParameter { - unsigned int behaviorID; //!< The Behavior ID - std::unordered_set::iterator parameterID; //!< The Parameter ID - float value; //!< The value of the behavior template + unsigned int behaviorID; //!< The Behavior ID + std::unordered_map::iterator parameterID; //!< The Parameter ID + float value; //!< The value of the behavior template }; //! BehaviorParameter table class CDBehaviorParameterTable : public CDTable { private: - std::unordered_map m_Entries; - std::unordered_set m_ParametersList; + std::unordered_map m_Entries; + std::unordered_map m_ParametersList; public: //! Constructor @@ -36,7 +36,7 @@ public: */ std::string GetName(void) const override; - CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); + float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); std::map GetParametersByBehaviorID(uint32_t behaviorID); }; diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 568780d0..40c37a95 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -439,7 +439,7 @@ Behavior::Behavior(const uint32_t behaviorId) { float Behavior::GetFloat(const std::string& name, const float defaultValue) const { // Get the behavior parameter entry and return its value. if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); - return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue).value; + return BehaviorParameterTable->GetValue(this->m_behaviorId, name, defaultValue); } From 9adbb7aa86a134707a9b5470d1bf83fb24ba5f90 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 29 Dec 2022 06:34:53 -0800 Subject: [PATCH 46/63] Address World Server Packet timing and erroneous log (#929) * Fix overread in projectile behavior * Fix stuns * Correctly read in bitStream * Fix projectile behavior * Address movement type issues * Update shutdown time to be accurate * Fix small issues --- dGame/dBehaviors/BasicAttackBehavior.cpp | 2 +- dWorldServer/WorldServer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index 0378cb5e..97068d91 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -40,7 +40,7 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); if (!targetEntity) { - Game::logger->Log("BasicAttackBehavior", "Target targetEntity %i not found.", branch.target); + Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target); return; } diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index de6deb2a..73157c09 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -416,7 +416,7 @@ int main(int argc, char** argv) { HandlePacket(packet); auto t2 = std::chrono::high_resolution_clock::now(); - timeSpent += std::chrono::duration_cast(t2 - t1).count(); + timeSpent += std::chrono::duration_cast>(t2 - t1).count(); Game::server->DeallocatePacket(packet); packet = nullptr; } else { From 34b5f0f9d646623f6cd8ee4f3183eef865629425 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Sat, 31 Dec 2022 02:46:25 -0600 Subject: [PATCH 47/63] add uncast to speed behavior (#932) --- dGame/dBehaviors/SpeedBehavior.cpp | 12 ++++++++---- dGame/dBehaviors/SpeedBehavior.h | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/dGame/dBehaviors/SpeedBehavior.cpp b/dGame/dBehaviors/SpeedBehavior.cpp index bec2b1cb..d326aa45 100644 --- a/dGame/dBehaviors/SpeedBehavior.cpp +++ b/dGame/dBehaviors/SpeedBehavior.cpp @@ -29,6 +29,14 @@ void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitSt Handle(context, bitStream, branch); } +void SpeedBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { + End(context, branch, LWOOBJID_EMPTY); +} + +void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + End(context, branch, second); +} + void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(branch.target); if (!target) return; @@ -40,10 +48,6 @@ void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, EntityManager::Instance()->SerializeEntity(target); } -void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { - End(context, branch, second); -} - void SpeedBehavior::Load() { m_RunSpeed = GetFloat("run_speed"); m_AffectsCaster = GetBoolean("affects_caster"); diff --git a/dGame/dBehaviors/SpeedBehavior.h b/dGame/dBehaviors/SpeedBehavior.h index 57c46842..88b85820 100644 --- a/dGame/dBehaviors/SpeedBehavior.h +++ b/dGame/dBehaviors/SpeedBehavior.h @@ -15,6 +15,8 @@ public: void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; From fab44142042789493667d4b5677c10f4663d91be Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 31 Dec 2022 03:56:12 -0800 Subject: [PATCH 48/63] Fix serratorizer chargeup time (#931) --- migrations/cdserver/5_serratorizer_chargeup_fix.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 migrations/cdserver/5_serratorizer_chargeup_fix.sql diff --git a/migrations/cdserver/5_serratorizer_chargeup_fix.sql b/migrations/cdserver/5_serratorizer_chargeup_fix.sql new file mode 100644 index 00000000..a61da2c2 --- /dev/null +++ b/migrations/cdserver/5_serratorizer_chargeup_fix.sql @@ -0,0 +1 @@ +UPDATE behaviorParameter SET value = 20 WHERE behaviorID = 21001 AND parameterID = "value 2"; From 737eaba54d3d96a2643b4f804c366c7c44883f92 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 31 Dec 2022 03:56:30 -0800 Subject: [PATCH 49/63] Serialize target with GameMessageStartSkill (#933) --- dGame/dComponents/SkillComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index 445a837e..0608c63b 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -246,6 +246,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c start.skillID = skillId; start.uiSkillHandle = context->skillUId; start.optionalOriginatorID = context->originator; + start.optionalTargetID = target; auto* originator = EntityManager::Instance()->GetEntity(context->originator); From 09157506bf503913a0199b86678ca26f7980677d Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sat, 31 Dec 2022 11:44:09 -0800 Subject: [PATCH 50/63] Fix Complete Overhaul (#934) Check your pointers :) --- dGame/dGameMessages/GameMessages.cpp | 15 +++++++++++++-- dGame/dInventory/Item.cpp | 9 +++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 37aeb093..2423915e 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -28,6 +28,7 @@ #include "GameConfig.h" #include "RocketLaunchLupComponent.h" #include "eUnequippableActiveType.h" +#include "RacingTaskParam.h" #include #include @@ -5482,7 +5483,8 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* auto* temp = inv->GetInventory(TEMP_MODELS); std::vector modList; - + auto& oldPartList = character->GetVar(u"currentModifiedBuild"); + bool everyPieceSwapped = !oldPartList.empty(); // If the player didn't put a build in initially, then they should not get this achievement. if (count >= 3) { std::u16string modules; @@ -5490,7 +5492,8 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* uint32_t mod; inStream->Read(mod); modList.push_back(mod); - modules += u"1:" + (GeneralUtils::to_u16string(mod)); + auto modToStr = GeneralUtils::to_u16string(mod); + modules += u"1:" + (modToStr); if (k + 1 != count) modules += u"+"; if (temp->GetLotCount(mod) > 0) { @@ -5498,6 +5501,13 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* } else { inv->RemoveItem(mod, 1); } + + // Doing this check for 1 singular mission that needs to know when you've swapped every part out during a car modular build. + // since all 8129's are the same, skip checking that + if (mod != 8129) { + if (oldPartList.find(GeneralUtils::UTF16ToWTF8(modToStr)) != std::string::npos) everyPieceSwapped = false; + + } } const auto moduleAssembly = new LDFData(u"assemblyPartLOTs", modules); @@ -5516,6 +5526,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* if (entity->GetLOT() != 9980 || Game::server->GetZoneID() != 1200) { if (missionComponent != nullptr) { missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, entity->GetLOT(), entity->GetObjectID()); + if (count >= 7 && everyPieceSwapped) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, LWOOBJID_EMPTY, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_MODULAR_BUILDING); } } } diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index a3d4cfc0..4f3626e3 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -347,6 +347,15 @@ void Item::Disassemble(const eInventoryType inventoryType) { if (data->GetKey() == u"assemblyPartLOTs") { auto modStr = data->GetValueAsString(); + // This shouldn't be null but always check your pointers. + if (GetInventory()) { + auto inventoryComponent = GetInventory()->GetComponent(); + if (inventoryComponent) { + auto entity = inventoryComponent->GetParent(); + if (entity) entity->SetVar(u"currentModifiedBuild", modStr); + } + } + std::vector modArray; std::stringstream ssData(modStr); From 19be0a61b2f4a9823796539e9e81a0effb7b0592 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Sun, 1 Jan 2023 04:51:22 -0800 Subject: [PATCH 51/63] Eliminate WorldConfig Magic Numbers Add comments for fields Use the name directly --- dGame/dComponents/DestroyableComponent.cpp | 19 ++--- dGame/dMission/Mission.cpp | 5 +- dGame/dUtilities/Mail.cpp | 6 +- dZoneManager/WorldConfig.h | 67 +++++++++++++++ dZoneManager/dZoneManager.cpp | 96 ++++++++++++++++++---- dZoneManager/dZoneManager.h | 31 +++---- 6 files changed, 177 insertions(+), 47 deletions(-) create mode 100644 dZoneManager/WorldConfig.h diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index d832ef93..aab4d670 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -30,6 +30,7 @@ #include "PossessorComponent.h" #include "InventoryComponent.h" #include "dZoneManager.h" +#include "WorldConfig.h" DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { m_iArmor = 0; @@ -765,20 +766,16 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType uint64_t coinsTotal = character->GetCoins(); if (coinsTotal > 0) { - uint64_t coinsToLoose = 1; + const uint64_t minCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMin; + const uint64_t maxCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMax; + const float coinPercentageToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathPercent; - if (coinsTotal >= 200) { - float hundreth = (coinsTotal / 100.0f); - coinsToLoose = static_cast(hundreth); - } + uint64_t coinsToLose = std::max(static_cast(coinsTotal * coinPercentageToLose), minCoinsToLose); + coinsToLose = std::min(maxCoinsToLose, coinsToLose); - if (coinsToLoose > 10000) { - coinsToLoose = 10000; - } + coinsTotal -= coinsToLose; - coinsTotal -= coinsToLoose; - - LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLoose, coinsToLoose); + LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLose, coinsToLose); character->SetCoins(coinsTotal, eLootSourceType::LOOT_SOURCE_PICKUP); } } diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 61b41992..a1ae724a 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -18,6 +18,7 @@ #include "dZoneManager.h" #include "InventoryComponent.h" #include "Database.h" +#include "WorldConfig.h" Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { m_MissionComponent = missionComponent; @@ -435,9 +436,9 @@ void Mission::YieldRewards() { int32_t coinsToSend = 0; if (info->LegoScore > 0) { eLootSourceType lootSource = info->isMission ? eLootSourceType::LOOT_SOURCE_MISSION : eLootSourceType::LOOT_SOURCE_ACHIEVEMENT; - if (levelComponent->GetLevel() >= dZoneManager::Instance()->GetMaxLevel()) { + if (levelComponent->GetLevel() >= dZoneManager::Instance()->GetWorldConfig()->levelCap) { // Since the character is at the level cap we reward them with coins instead of UScore. - coinsToSend += info->LegoScore * dZoneManager::Instance()->GetLevelCapCurrencyConversion(); + coinsToSend += info->LegoScore * dZoneManager::Instance()->GetWorldConfig()->levelCapCurrencyConversion; } else { characterComponent->SetUScore(characterComponent->GetUScore() + info->LegoScore); GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), info->LegoScore, lootSource); diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index 7047972f..a4ac63e1 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -22,6 +22,8 @@ #include "MissionComponent.h" #include "ChatPackets.h" #include "Character.h" +#include "dZoneManager.h" +#include "WorldConfig.h" void Mail::SendMail(const Entity* recipient, const std::string& subject, const std::string& body, const LOT attachment, const uint16_t attachmentCount) { @@ -191,7 +193,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd uint32_t itemID = static_cast(attachmentID); LOT itemLOT = 0; //Inventory::InventoryType itemType; - int mailCost = 25; + int mailCost = dZoneManager::Instance()->GetWorldConfig()->mailBaseFee; int stackSize = 0; auto inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); Item* item = nullptr; @@ -199,7 +201,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd if (itemID > 0 && attachmentCount > 0 && inv) { item = inv->FindItemById(attachmentID); if (item) { - mailCost += (item->GetInfo().baseValue * 0.1f); + mailCost += (item->GetInfo().baseValue * dZoneManager::Instance()->GetWorldConfig()->mailPercentAttachmentFee); stackSize = item->GetCount(); itemLOT = item->GetLot(); } else { diff --git a/dZoneManager/WorldConfig.h b/dZoneManager/WorldConfig.h new file mode 100644 index 00000000..a98433a1 --- /dev/null +++ b/dZoneManager/WorldConfig.h @@ -0,0 +1,67 @@ +#ifndef __WORLDCONFIG__H__ +#define __WORLDCONFIG__H__ + +#include +#include + +struct WorldConfig { + int32_t worldConfigID{}; //! Primary key for WorlcConfig table + float peGravityValue{}; //! Unknown + float peBroadphaseWorldSize{}; //! Unknown + float peGameObjScaleFactor{}; //! Unknown + float characterRotationSpeed{}; //! The players' rotation speed + float characterWalkForwardSpeed{}; //! The players' walk forward speed + float characterWalkBackwardSpeed{}; //! The players' walk backwards speed + float characterWalkStrafeSpeed{}; //! The players' strafe speed + float characterWalkStrafeForwardSpeed{}; //! The players' walk strafe forward speed + float characterWalkStrafeBackwardSpeed{}; //! The players' walk strage backwards speed + float characterRunBackwardSpeed{}; //! The players' run backwards speed + float characterRunStrafeSpeed{}; //! The players' run strafe speed + float characterRunStrafeForwardSpeed{}; //! The players' run strafe forward speed + float characterRunStrafeBackwardSpeed{}; //! The players' run strage backwards speed + float globalCooldown{}; //! The global ability cooldown + float characterGroundedTime{}; //! Unknown + float characterGroundedSpeed{}; //! Unknown + float globalImmunityTime{}; //! Unknown + float characterMaxSlope{}; //! Unknown + float defaultRespawnTime{}; //! Unknown + float missionTooltipTimeout{}; + float vendorBuyMultiplier{}; //! The buy scalar for buying from vendors + float petFollowRadius{}; //! The players' pet follow radius + float characterEyeHeight{}; //! The players' eye height + float flightVerticalVelocity{}; //! Unknown + float flightAirspeed{}; //! Unknown + float flightFuelRatio{}; //! Unknown + float flightMaxAirspeed{}; //! Unknown + float fReputationPerVote{}; //! Unknown + int32_t propertyCloneLimit{}; //! Unknown + int32_t defaultHomespaceTemplate{}; //! Unknown + float coinsLostOnDeathPercent{}; //! The percentage of coins to lose on a player death + int32_t coinsLostOnDeathMin{}; //! The minimum number of coins to lose on a player death + int32_t coinsLostOnDeathMax{}; //! The maximum number of coins to lose on a player death + int32_t characterVotesPerDay{}; //! Unknown + int32_t propertyModerationRequestApprovalCost{};//! Unknown + int32_t propertyModerationRequestReviewCost{}; //! Unknown + int32_t propertyModRequestsAllowedSpike{}; //! Unknown + int32_t propertyModRequestsAllowedInterval{}; //! Unknown + int32_t propertyModRequestsAllowedTotal{}; //! Unknown + int32_t propertyModRequestsSpikeDuration{}; //! Unknown + int32_t propertyModRequestsIntervalDuration{}; //! Unknown + bool modelModerateOnCreate{}; //! Unknown + float defaultPropertyMaxHeight{}; //! Unknown + float reputationPerVoteCast{}; //! Unknown + float reputationPerVoteReceived{}; //! Unknown + int32_t showcaseTopModelConsiderationBattles{}; //! Unknown + float reputationPerBattlePromotion{}; //! Unknown + float coinsLostOnDeathMinTimeout{}; //! Unknown + float coinsLostOnDeathMaxTimeout{}; //! Unknown + int32_t mailBaseFee{}; //! The base fee to take when a player sends mail + float mailPercentAttachmentFee{}; //! The scalar multiplied by an items base cost to determine how much that item costs to be mailed + int32_t propertyReputationDelay{}; //! Unknown + int32_t levelCap{}; //! The maximum player level + std::string levelUpBehaviorEffect{}; //! Unknown + int32_t characterVersion{}; //! Unknown + int32_t levelCapCurrencyConversion{}; //! The ratio of UScore (LEGO Score) to coins +}; + +#endif //! __WORLDCONFIG__H__ diff --git a/dZoneManager/dZoneManager.cpp b/dZoneManager/dZoneManager.cpp index 102fb3af..0b7844a3 100644 --- a/dZoneManager/dZoneManager.cpp +++ b/dZoneManager/dZoneManager.cpp @@ -8,6 +8,7 @@ #include "DestroyableComponent.h" #include "GameMessages.h" #include "VanityUtilities.h" +#include "WorldConfig.h" #include #include "../dWorldServer/ObjectIDManager.h" @@ -53,6 +54,8 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { endTime = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + LoadWorldConfig(); + Game::logger->Log("dZoneManager", "Zone prepared in: %llu ms", (endTime - startTime)); VanityUtilities::SpawnVanity(); @@ -69,6 +72,7 @@ dZoneManager::~dZoneManager() { m_Spawners.erase(p.first); } + if (m_WorldConfig) delete m_WorldConfig; } Zone* dZoneManager::GetZone() { @@ -117,24 +121,6 @@ LWOZONEID dZoneManager::GetZoneID() const { return m_ZoneID; } -uint32_t dZoneManager::GetMaxLevel() { - if (m_MaxLevel == 0) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT LevelCap FROM WorldConfig WHERE WorldConfigID = 1 LIMIT 1;"); - m_MaxLevel = tableData.getIntField(0, -1); - tableData.finalize(); - } - return m_MaxLevel; -} - -int32_t dZoneManager::GetLevelCapCurrencyConversion() { - if (m_CurrencyConversionRate == 0) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT LevelCapCurrencyConversion FROM WorldConfig WHERE WorldConfigID = 1 LIMIT 1;"); - m_CurrencyConversionRate = tableData.getIntField(0, -1); - tableData.finalize(); - } - return m_CurrencyConversionRate; -} - void dZoneManager::Update(float deltaTime) { for (auto spawner : m_Spawners) { spawner.second->Update(deltaTime); @@ -249,3 +235,77 @@ uint32_t dZoneManager::GetUniqueMissionIdStartingValue() { } return m_UniqueMissionIdStart; } + +void dZoneManager::LoadWorldConfig() { + Game::logger->Log("dZoneManager", "Loading WorldConfig into memory"); + + auto worldConfig = CDClientDatabase::ExecuteQuery("SELECT * FROM WorldConfig;"); + + if (!m_WorldConfig) m_WorldConfig = new WorldConfig(); + + if (worldConfig.eof()) { + Game::logger->Log("dZoneManager", "WorldConfig table is empty. Is this intended?"); + return; + } + + // Now read in the giant table + m_WorldConfig->worldConfigID = worldConfig.getIntField("WorldConfigID"); + m_WorldConfig->peGravityValue = worldConfig.getFloatField("pegravityvalue"); + m_WorldConfig->peBroadphaseWorldSize = worldConfig.getFloatField("pebroadphaseworldsize"); + m_WorldConfig->peGameObjScaleFactor = worldConfig.getFloatField("pegameobjscalefactor"); + m_WorldConfig->characterRotationSpeed = worldConfig.getFloatField("character_rotation_speed"); + m_WorldConfig->characterWalkForwardSpeed = worldConfig.getFloatField("character_walk_forward_speed"); + m_WorldConfig->characterWalkBackwardSpeed = worldConfig.getFloatField("character_walk_backward_speed"); + m_WorldConfig->characterWalkStrafeSpeed = worldConfig.getFloatField("character_walk_strafe_speed"); + m_WorldConfig->characterWalkStrafeForwardSpeed = worldConfig.getFloatField("character_walk_strafe_forward_speed"); + m_WorldConfig->characterWalkStrafeBackwardSpeed = worldConfig.getFloatField("character_walk_strafe_backward_speed"); + m_WorldConfig->characterRunBackwardSpeed = worldConfig.getFloatField("character_run_backward_speed"); + m_WorldConfig->characterRunStrafeSpeed = worldConfig.getFloatField("character_run_strafe_speed"); + m_WorldConfig->characterRunStrafeForwardSpeed = worldConfig.getFloatField("character_run_strafe_forward_speed"); + m_WorldConfig->characterRunStrafeBackwardSpeed = worldConfig.getFloatField("character_run_strafe_backward_speed"); + m_WorldConfig->globalCooldown = worldConfig.getFloatField("global_cooldown"); + m_WorldConfig->characterGroundedTime = worldConfig.getFloatField("characterGroundedTime"); + m_WorldConfig->characterGroundedSpeed = worldConfig.getFloatField("characterGroundedSpeed"); + m_WorldConfig->globalImmunityTime = worldConfig.getFloatField("globalImmunityTime"); + m_WorldConfig->characterMaxSlope = worldConfig.getFloatField("character_max_slope"); + m_WorldConfig->defaultRespawnTime = worldConfig.getFloatField("defaultrespawntime"); + m_WorldConfig->missionTooltipTimeout = worldConfig.getFloatField("mission_tooltip_timeout"); + m_WorldConfig->vendorBuyMultiplier = worldConfig.getFloatField("vendor_buy_multiplier"); + m_WorldConfig->petFollowRadius = worldConfig.getFloatField("pet_follow_radius"); + m_WorldConfig->characterEyeHeight = worldConfig.getFloatField("character_eye_height"); + m_WorldConfig->flightVerticalVelocity = worldConfig.getFloatField("flight_vertical_velocity"); + m_WorldConfig->flightAirspeed = worldConfig.getFloatField("flight_airspeed"); + m_WorldConfig->flightFuelRatio = worldConfig.getFloatField("flight_fuel_ratio"); + m_WorldConfig->flightMaxAirspeed = worldConfig.getFloatField("flight_max_airspeed"); + m_WorldConfig->fReputationPerVote = worldConfig.getFloatField("fReputationPerVote"); + m_WorldConfig->propertyCloneLimit = worldConfig.getIntField("nPropertyCloneLimit"); + m_WorldConfig->defaultHomespaceTemplate = worldConfig.getIntField("defaultHomespaceTemplate"); + m_WorldConfig->coinsLostOnDeathPercent = worldConfig.getFloatField("coins_lost_on_death_percent"); + m_WorldConfig->coinsLostOnDeathMin = worldConfig.getIntField("coins_lost_on_death_min"); + m_WorldConfig->coinsLostOnDeathMax = worldConfig.getIntField("coins_lost_on_death_max"); + m_WorldConfig->characterVotesPerDay = worldConfig.getIntField("character_votes_per_day"); + m_WorldConfig->propertyModerationRequestApprovalCost = worldConfig.getIntField("property_moderation_request_approval_cost"); + m_WorldConfig->propertyModerationRequestReviewCost = worldConfig.getIntField("property_moderation_request_review_cost"); + m_WorldConfig->propertyModRequestsAllowedSpike = worldConfig.getIntField("propertyModRequestsAllowedSpike"); + m_WorldConfig->propertyModRequestsAllowedInterval = worldConfig.getIntField("propertyModRequestsAllowedInterval"); + m_WorldConfig->propertyModRequestsAllowedTotal = worldConfig.getIntField("propertyModRequestsAllowedTotal"); + m_WorldConfig->propertyModRequestsSpikeDuration = worldConfig.getIntField("propertyModRequestsSpikeDuration"); + m_WorldConfig->propertyModRequestsIntervalDuration = worldConfig.getIntField("propertyModRequestsIntervalDuration"); + m_WorldConfig->modelModerateOnCreate = worldConfig.getIntField("modelModerateOnCreate") != 0; + m_WorldConfig->defaultPropertyMaxHeight = worldConfig.getFloatField("defaultPropertyMaxHeight"); + m_WorldConfig->reputationPerVoteCast = worldConfig.getFloatField("reputationPerVoteCast"); + m_WorldConfig->reputationPerVoteReceived = worldConfig.getFloatField("reputationPerVoteReceived"); + m_WorldConfig->showcaseTopModelConsiderationBattles = worldConfig.getIntField("showcaseTopModelConsiderationBattles"); + m_WorldConfig->reputationPerBattlePromotion = worldConfig.getFloatField("reputationPerBattlePromotion"); + m_WorldConfig->coinsLostOnDeathMinTimeout = worldConfig.getFloatField("coins_lost_on_death_min_timeout"); + m_WorldConfig->coinsLostOnDeathMaxTimeout = worldConfig.getFloatField("coins_lost_on_death_max_timeout"); + m_WorldConfig->mailBaseFee = worldConfig.getIntField("mail_base_fee"); + m_WorldConfig->mailPercentAttachmentFee = worldConfig.getFloatField("mail_percent_attachment_fee"); + m_WorldConfig->propertyReputationDelay = worldConfig.getIntField("propertyReputationDelay"); + m_WorldConfig->levelCap = worldConfig.getIntField("LevelCap"); + m_WorldConfig->levelUpBehaviorEffect = worldConfig.getStringField("LevelUpBehaviorEffect"); + m_WorldConfig->characterVersion = worldConfig.getIntField("CharacterVersion"); + m_WorldConfig->levelCapCurrencyConversion = worldConfig.getIntField("LevelCapCurrencyConversion"); + worldConfig.finalize(); + Game::logger->Log("dZoneManager", "Loaded WorldConfig into memory"); +} diff --git a/dZoneManager/dZoneManager.h b/dZoneManager/dZoneManager.h index b2fef1e3..c1776e79 100644 --- a/dZoneManager/dZoneManager.h +++ b/dZoneManager/dZoneManager.h @@ -4,6 +4,8 @@ #include "Spawner.h" #include +class WorldConfig; + class dZoneManager { public: enum class dZoneNotifier { @@ -16,6 +18,12 @@ public: InvalidNotifier }; +private: + /** + * Reads the WorldConfig from the CDClientDatabase into memory + */ + void LoadWorldConfig(); + public: static dZoneManager* Instance() { if (!m_Address) { @@ -33,8 +41,6 @@ public: void NotifyZone(const dZoneNotifier& notifier, const LWOOBJID& objectID); //Notifies the zone of a certain event or command. void AddSpawner(LWOOBJID id, Spawner* spawner); LWOZONEID GetZoneID() const; - uint32_t GetMaxLevel(); - int32_t GetLevelCapCurrencyConversion(); LWOOBJID MakeSpawner(SpawnerInfo info); Spawner* GetSpawner(LWOOBJID id); void RemoveSpawner(LWOOBJID id); @@ -45,27 +51,24 @@ public: bool GetPlayerLoseCoinOnDeath() { return m_PlayerLoseCoinsOnDeath; } uint32_t GetUniqueMissionIdStartingValue(); + // The world config should not be modified by a caller. + const WorldConfig* GetWorldConfig() { + if (!m_WorldConfig) LoadWorldConfig(); + return m_WorldConfig; + }; + private: - /** - * The maximum level of the world. - */ - uint32_t m_MaxLevel = 0; - - /** - * The ratio of LEGO Score to currency when the character has hit the max level. - */ - int32_t m_CurrencyConversionRate = 0; - /** * The starting unique mission ID. */ uint32_t m_UniqueMissionIdStart = 0; static dZoneManager* m_Address; //Singleton - Zone* m_pZone; + Zone* m_pZone = nullptr; LWOZONEID m_ZoneID; bool m_PlayerLoseCoinsOnDeath; //Do players drop coins in this zone when smashed std::map m_Spawners; + WorldConfig* m_WorldConfig = nullptr; - Entity* m_ZoneControlObject; + Entity* m_ZoneControlObject = nullptr; }; From 203a150a56688e5cbfdefa500fae80ada4fab40b Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Sun, 1 Jan 2023 16:36:10 -0800 Subject: [PATCH 52/63] Update DestroyableComponent.cpp --- dGame/dComponents/DestroyableComponent.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index aab4d670..8d8ed42a 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -764,9 +764,8 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType if (dZoneManager::Instance()->GetPlayerLoseCoinOnDeath()) { auto* character = m_Parent->GetCharacter(); uint64_t coinsTotal = character->GetCoins(); - - if (coinsTotal > 0) { - const uint64_t minCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMin; + const uint64_t minCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMin; + if (coinsTotal >= minCoinsToLose) { const uint64_t maxCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMax; const float coinPercentageToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathPercent; From dc7d0ce142f3badfaf362846a10179b22fca1086 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Tue, 3 Jan 2023 09:21:57 -0800 Subject: [PATCH 53/63] Fix Stuns of duration zero (#938) --- dGame/dComponents/BaseCombatAIComponent.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index c035a807..478058a7 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -179,7 +179,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { if (m_Disabled || m_Parent->GetIsDead()) return; - + bool stunnedThisFrame = m_Stunned; CalculateCombat(deltaTime); // Putting this here for now if (m_StartPosition == NiPoint3::ZERO) { @@ -192,7 +192,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { return; } - if (m_Stunned) { + if (stunnedThisFrame) { m_MovementAI->Stop(); return; @@ -248,13 +248,13 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { if (m_Disabled) return; - if (m_StunTime > 0.0f) { + if (m_Stunned) { m_StunTime -= deltaTime; if (m_StunTime > 0.0f) { return; } - + m_StunTime = 0.0f; m_Stunned = false; } From 1789ec7f20380376444d93064fc7dbaeee9bbe92 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Tue, 3 Jan 2023 09:22:04 -0800 Subject: [PATCH 54/63] delta compression fixes (#937) --- dGame/dComponents/BaseCombatAIComponent.cpp | 36 ++++++++++----- dGame/dComponents/BaseCombatAIComponent.h | 12 +++++ dGame/dComponents/PetComponent.cpp | 44 ++++++++++--------- .../PlayerForcedMovementComponent.cpp | 4 +- 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index 478058a7..081496a4 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -23,9 +23,9 @@ #include "RebuildComponent.h" #include "DestroyableComponent.h" -BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) : Component(parent) { +BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) { m_Target = LWOOBJID_EMPTY; - m_State = AiState::spawn; + SetAiState(AiState::spawn); m_Timer = 1.0f; m_StartPosition = parent->GetPosition(); m_MovementAI = nullptr; @@ -206,7 +206,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { switch (m_State) { case AiState::spawn: Stun(2.0f); - m_State = AiState::idle; + SetAiState(AiState::idle); break; case AiState::idle: @@ -320,9 +320,9 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { m_Timer = 0; } - m_State = AiState::aggro; + SetAiState(AiState::aggro); } else { - m_State = AiState::idle; + SetAiState(AiState::idle); } for (auto i = 0; i < m_SkillEntries.size(); ++i) { @@ -348,7 +348,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { } if (m_Target == LWOOBJID_EMPTY) { - m_State = AiState::idle; + SetAiState(AiState::idle); return; } @@ -375,7 +375,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { m_MovementAI->Stop(); } - m_State = AiState::aggro; + SetAiState(AiState::aggro); m_Timer = 0; @@ -532,11 +532,20 @@ bool BaseCombatAIComponent::IsMech() { void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write1(); - outBitStream->Write(uint32_t(m_State)); - outBitStream->Write(m_Target); + outBitStream->Write(m_DirtyStateOrTarget || bIsInitialUpdate); + if (m_DirtyStateOrTarget || bIsInitialUpdate) { + outBitStream->Write(uint32_t(m_State)); + outBitStream->Write(m_Target); + m_DirtyStateOrTarget = false; + } } +void BaseCombatAIComponent::SetAiState(AiState newState) { + if (newState == this->m_State) return; + this->m_State = newState; + m_DirtyStateOrTarget = true; + EntityManager::Instance()->SerializeEntity(m_Parent); +} bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { auto* entity = EntityManager::Instance()->GetEntity(target); @@ -585,7 +594,10 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { } void BaseCombatAIComponent::SetTarget(const LWOOBJID target) { + if (this->m_Target == target) return; m_Target = target; + m_DirtyStateOrTarget = true; + EntityManager::Instance()->SerializeEntity(m_Parent); } Entity* BaseCombatAIComponent::GetTargetEntity() const { @@ -700,7 +712,7 @@ void BaseCombatAIComponent::OnAggro() { m_MovementAI->SetDestination(targetPos); - m_State = AiState::tether; + SetAiState(AiState::tether); } m_Timer += 0.5f; @@ -726,7 +738,7 @@ void BaseCombatAIComponent::OnTether() { m_MovementAI->SetDestination(m_StartPosition); - m_State = AiState::aggro; + SetAiState(AiState::aggro); } else { if (IsMech() && Vector3::DistanceSquared(targetPos, currentPos) > m_AttackRadius * m_AttackRadius * 3 * 3) return; diff --git a/dGame/dComponents/BaseCombatAIComponent.h b/dGame/dComponents/BaseCombatAIComponent.h index 70a88a42..1f17d562 100644 --- a/dGame/dComponents/BaseCombatAIComponent.h +++ b/dGame/dComponents/BaseCombatAIComponent.h @@ -243,6 +243,12 @@ private: */ std::vector GetTargetWithinAggroRange() const; + /** + * @brief Sets the AiState and prepares the entity for serialization next frame. + * + */ + void SetAiState(AiState newState); + /** * The current state of the AI */ @@ -374,6 +380,12 @@ private: */ bool m_DirtyThreat = false; + /** + * Whether or not the Component has dirty information and should update next frame + * + */ + bool m_DirtyStateOrTarget = false; + /** * Whether the current entity is a mech enemy, needed as mechs tether radius works differently * @return whether this entity is a mech diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 0b136a5c..d11331e7 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -59,7 +59,7 @@ std::map PetComponent::petFlags = { { 13067, 838 }, // Skeleton dragon }; -PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(parent) { +PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(parent) { m_ComponentId = componentId; m_Interaction = LWOOBJID_EMPTY; @@ -118,21 +118,23 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd outBitStream->Write(m_Owner); } - outBitStream->Write(tamed); - if (tamed) { - outBitStream->Write(m_ModerationStatus); + if (bIsInitialUpdate) { + outBitStream->Write(tamed); + if (tamed) { + outBitStream->Write(m_ModerationStatus); - const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name); - const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName); + const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name); + const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName); - outBitStream->Write(static_cast(nameData.size())); - for (const auto c : nameData) { - outBitStream->Write(c); - } + outBitStream->Write(static_cast(nameData.size())); + for (const auto c : nameData) { + outBitStream->Write(c); + } - outBitStream->Write(static_cast(ownerNameData.size())); - for (const auto c : ownerNameData) { - outBitStream->Write(c); + outBitStream->Write(static_cast(ownerNameData.size())); + for (const auto c : ownerNameData) { + outBitStream->Write(c); + } } } } @@ -916,16 +918,16 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { return; } - // If we are out of imagination despawn the pet. - if (playerDestroyableComponent->GetImagination() == 0) { - this->Deactivate(); - auto playerEntity = playerDestroyableComponent->GetParent(); - if (!playerEntity) return; + // If we are out of imagination despawn the pet. + if (playerDestroyableComponent->GetImagination() == 0) { + this->Deactivate(); + auto playerEntity = playerDestroyableComponent->GetParent(); + if (!playerEntity) return; - GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet); - } + GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet); + } - this->AddDrainImaginationTimer(item); + this->AddDrainImaginationTimer(item); }); } diff --git a/dGame/dComponents/PlayerForcedMovementComponent.cpp b/dGame/dComponents/PlayerForcedMovementComponent.cpp index 3bcad677..76993507 100644 --- a/dGame/dComponents/PlayerForcedMovementComponent.cpp +++ b/dGame/dComponents/PlayerForcedMovementComponent.cpp @@ -7,8 +7,8 @@ PlayerForcedMovementComponent::PlayerForcedMovementComponent(Entity* parent) : C PlayerForcedMovementComponent::~PlayerForcedMovementComponent() {} void PlayerForcedMovementComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write(m_DirtyInfo); - if (m_DirtyInfo) { + outBitStream->Write(m_DirtyInfo || bIsInitialUpdate); + if (m_DirtyInfo || bIsInitialUpdate) { outBitStream->Write(m_PlayerOnRail); outBitStream->Write(m_ShowBillboard); } From 1a34f6f74adcadcb32af136831daf33475afe629 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 4 Jan 2023 06:15:06 -0800 Subject: [PATCH 55/63] Fix debug logging newline (#940) --- dCommon/dLogger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dCommon/dLogger.cpp b/dCommon/dLogger.cpp index d4e6a96e..7785a070 100644 --- a/dCommon/dLogger.cpp +++ b/dCommon/dLogger.cpp @@ -89,7 +89,7 @@ void dLogger::Log(const std::string& className, const std::string& message) { void dLogger::LogDebug(const char* className, const char* format, ...) { if (!m_logDebugStatements) return; va_list args; - std::string log = "[" + std::string(className) + "] " + std::string(format); + std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n"; va_start(args, format); vLog(log.c_str(), args); va_end(args); From bad3845d83712eaed717b29dab819e5f396d6866 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 6 Jan 2023 21:04:20 -0800 Subject: [PATCH 56/63] Address Docker issues and remove need to extract cdclient.fdb (#895) * Implement a server res directory * Only convert if neither exist * Remove unzip, Update RegEx * readme updates Run setup after setting working dir Address several docker issues Revert "Run setup after setting working dir" This reverts commit fd2fb9228e82a350204c1ef61f7ba059479bb12f. Fix docker * Remove extra submodules * Rework logic * Switch if block * Remove need to extract fdb from client * Change log name * Update FdbToSqlite.cpp --- .gitmodules | 6 -- Docker.md | 2 +- Docker_Windows.md | 2 +- dCommon/FdbToSqlite.cpp | 142 +++++++++++++++---------------- dCommon/FdbToSqlite.h | 40 ++++----- dCommon/dClient/AssetManager.cpp | 28 ------ dCommon/dClient/AssetManager.h | 1 - dMasterServer/MasterServer.cpp | 23 ++--- docker/Dockerfile | 7 +- docker/setup.Dockerfile | 15 +--- docker/setup.sh | 55 +----------- docker/start_server.sh | 29 +------ thirdparty/LUnpack | 1 - thirdparty/docker-utils | 1 - 14 files changed, 109 insertions(+), 243 deletions(-) mode change 100644 => 100755 docker/start_server.sh delete mode 160000 thirdparty/LUnpack delete mode 160000 thirdparty/docker-utils diff --git a/.gitmodules b/.gitmodules index 6fb56bde..33193447 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,12 +14,6 @@ path = thirdparty/mariadb-connector-cpp url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git ignore = dirty -[submodule "thirdparty/docker-utils"] - path = thirdparty/docker-utils - url = https://github.com/lcdr/utils.git -[submodule "thirdparty/LUnpack"] - path = thirdparty/LUnpack - url = https://github.com/Xiphoseer/LUnpack.git [submodule "thirdparty/AccountManager"] path = thirdparty/AccountManager url = https://github.com/DarkflameUniverse/AccountManager diff --git a/Docker.md b/Docker.md index 54d0ce19..b06bd0fe 100644 --- a/Docker.md +++ b/Docker.md @@ -4,7 +4,7 @@ - [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker) - [Docker Compose](https://docs.docker.com/compose/install/) (Included in Docker Desktop) -- LEGO® Universe packed Client. Check the main [README](./README.md) for details on this. +- LEGO® Universe Client. Check the main [README](./README.md) for details on this. ## Run server inside Docker diff --git a/Docker_Windows.md b/Docker_Windows.md index 1cc633cc..984bbe57 100644 --- a/Docker_Windows.md +++ b/Docker_Windows.md @@ -25,7 +25,7 @@ 11. Once the command has completed (you can see you path again and can enter commands), close the window. 12. Inside the downloaded folder, copy `.env.example` and name the copy `.env` 13. Open `.env` with Notepad by right-clicking it and selecting _Open With_ -> _More apps_ -> _Notepad_. -14. Change the text after `CLIENT_PATH=` to the location of your client. The folder you are pointing to must contain a folder called `client` which should contain the client files. +14. Change the text after `CLIENT_PATH=` to the location of your client. This folder must contain either a folder `client` or `legouniverse.exe`. > If you need the extra performance, place the client files in `\\wsl$\\...` to avoid working across file systems, see [Docker Best Practices](https://docs.docker.com/desktop/windows/wsl/#best-practices) and [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems). 15. Optionally, you can change the number after `BUILD_THREADS=` to the number of cores / threads your processor has. If your computer crashes while building, you can try to reduce this value. diff --git a/dCommon/FdbToSqlite.cpp b/dCommon/FdbToSqlite.cpp index 80251e89..e05286a9 100644 --- a/dCommon/FdbToSqlite.cpp +++ b/dCommon/FdbToSqlite.cpp @@ -10,6 +10,7 @@ #include "GeneralUtils.h" #include "Game.h" #include "dLogger.h" +#include "AssetManager.h" #include "eSqliteDataType.h" @@ -23,26 +24,23 @@ std::map FdbToSqlite::Convert::m_SqliteType = { { eSqliteDataType::TEXT_8, "text_8"} }; -FdbToSqlite::Convert::Convert(std::string basePath, std::string binaryOutPath) { - this->m_BasePath = basePath; +FdbToSqlite::Convert::Convert(std::string binaryOutPath) { this->m_BinaryOutPath = binaryOutPath; - m_Fdb.open(m_BasePath + "/cdclient.fdb", std::ios::binary); } -FdbToSqlite::Convert::~Convert() { - this->m_Fdb.close(); -} - -bool FdbToSqlite::Convert::ConvertDatabase() { +bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) { if (m_ConversionStarted) return false; + + std::istream cdClientBuffer(&buffer); + this->m_ConversionStarted = true; try { CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite"); CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); - int32_t numberOfTables = ReadInt32(); - ReadTables(numberOfTables); + int32_t numberOfTables = ReadInt32(cdClientBuffer); + ReadTables(numberOfTables, cdClientBuffer); CDClientDatabase::ExecuteQuery("COMMIT;"); } catch (CppSQLite3Exception& e) { @@ -53,130 +51,130 @@ bool FdbToSqlite::Convert::ConvertDatabase() { return true; } -int32_t FdbToSqlite::Convert::ReadInt32() { +int32_t FdbToSqlite::Convert::ReadInt32(std::istream& cdClientBuffer) { int32_t nextInt{}; - BinaryIO::BinaryRead(m_Fdb, nextInt); + BinaryIO::BinaryRead(cdClientBuffer, nextInt); return nextInt; } -int64_t FdbToSqlite::Convert::ReadInt64() { - int32_t prevPosition = SeekPointer(); +int64_t FdbToSqlite::Convert::ReadInt64(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); int64_t value{}; - BinaryIO::BinaryRead(m_Fdb, value); + BinaryIO::BinaryRead(cdClientBuffer, value); - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); return value; } -std::string FdbToSqlite::Convert::ReadString() { - int32_t prevPosition = SeekPointer(); +std::string FdbToSqlite::Convert::ReadString(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); - auto readString = BinaryIO::ReadString(m_Fdb); + auto readString = BinaryIO::ReadString(cdClientBuffer); - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); return readString; } -int32_t FdbToSqlite::Convert::SeekPointer() { +int32_t FdbToSqlite::Convert::SeekPointer(std::istream& cdClientBuffer) { int32_t position{}; - BinaryIO::BinaryRead(m_Fdb, position); - int32_t prevPosition = m_Fdb.tellg(); - m_Fdb.seekg(position); + BinaryIO::BinaryRead(cdClientBuffer, position); + int32_t prevPosition = cdClientBuffer.tellg(); + cdClientBuffer.seekg(position); return prevPosition; } -std::string FdbToSqlite::Convert::ReadColumnHeader() { - int32_t prevPosition = SeekPointer(); +std::string FdbToSqlite::Convert::ReadColumnHeader(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); - int32_t numberOfColumns = ReadInt32(); - std::string tableName = ReadString(); + int32_t numberOfColumns = ReadInt32(cdClientBuffer); + std::string tableName = ReadString(cdClientBuffer); - auto columns = ReadColumns(numberOfColumns); + auto columns = ReadColumns(numberOfColumns, cdClientBuffer); std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");"; CDClientDatabase::ExecuteDML(newTable); - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); return tableName; } -void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables) { - int32_t prevPosition = SeekPointer(); +void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); for (int32_t i = 0; i < numberOfTables; i++) { - auto columnHeader = ReadColumnHeader(); - ReadRowHeader(columnHeader); + auto columnHeader = ReadColumnHeader(cdClientBuffer); + ReadRowHeader(columnHeader, cdClientBuffer); } - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); } -std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns) { +std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer) { std::stringstream columnsToCreate; - int32_t prevPosition = SeekPointer(); + int32_t prevPosition = SeekPointer(cdClientBuffer); std::string name{}; eSqliteDataType dataType{}; for (int32_t i = 0; i < numberOfColumns; i++) { if (i != 0) columnsToCreate << ", "; - dataType = static_cast(ReadInt32()); - name = ReadString(); + dataType = static_cast(ReadInt32(cdClientBuffer)); + name = ReadString(cdClientBuffer); columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType]; } - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); return columnsToCreate.str(); } -void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName) { - int32_t prevPosition = SeekPointer(); +void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); - int32_t numberOfAllocatedRows = ReadInt32(); + int32_t numberOfAllocatedRows = ReadInt32(cdClientBuffer); if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0); // assert power of 2 allocation size - ReadRows(numberOfAllocatedRows, tableName); + ReadRows(numberOfAllocatedRows, tableName, cdClientBuffer); - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); } -void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName) { - int32_t prevPosition = SeekPointer(); +void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); int32_t rowid = 0; for (int32_t row = 0; row < numberOfAllocatedRows; row++) { - int32_t rowPointer = ReadInt32(); + int32_t rowPointer = ReadInt32(cdClientBuffer); if (rowPointer == -1) rowid++; - else ReadRow(rowPointer, tableName); + else ReadRow(rowPointer, tableName, cdClientBuffer); } - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); } -void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName) { - int32_t prevPosition = m_Fdb.tellg(); - m_Fdb.seekg(position); +void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = cdClientBuffer.tellg(); + cdClientBuffer.seekg(position); while (true) { - ReadRowInfo(tableName); - int32_t linked = ReadInt32(); + ReadRowInfo(tableName, cdClientBuffer); + int32_t linked = ReadInt32(cdClientBuffer); if (linked == -1) break; - m_Fdb.seekg(linked); + cdClientBuffer.seekg(linked); } - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); } -void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName) { - int32_t prevPosition = SeekPointer(); +void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); - int32_t numberOfColumns = ReadInt32(); - ReadRowValues(numberOfColumns, tableName); + int32_t numberOfColumns = ReadInt32(cdClientBuffer); + ReadRowValues(numberOfColumns, tableName, cdClientBuffer); - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); } -void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName) { - int32_t prevPosition = SeekPointer(); +void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); int32_t emptyValue{}; int32_t intValue{}; @@ -190,26 +188,26 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& for (int32_t i = 0; i < numberOfColumns; i++) { if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row. - switch (static_cast(ReadInt32())) { + switch (static_cast(ReadInt32(cdClientBuffer))) { case eSqliteDataType::NONE: - BinaryIO::BinaryRead(m_Fdb, emptyValue); + BinaryIO::BinaryRead(cdClientBuffer, emptyValue); assert(emptyValue == 0); insertedRow << "NULL"; break; case eSqliteDataType::INT32: - intValue = ReadInt32(); + intValue = ReadInt32(cdClientBuffer); insertedRow << intValue; break; case eSqliteDataType::REAL: - BinaryIO::BinaryRead(m_Fdb, floatValue); + BinaryIO::BinaryRead(cdClientBuffer, floatValue); insertedRow << std::fixed << std::setprecision(34) << floatValue; // maximum precision of floating point number break; case eSqliteDataType::TEXT_4: case eSqliteDataType::TEXT_8: { - stringValue = ReadString(); + stringValue = ReadString(cdClientBuffer); size_t position = 0; // Need to escape quote with a double of ". @@ -225,12 +223,12 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& } case eSqliteDataType::INT_BOOL: - BinaryIO::BinaryRead(m_Fdb, boolValue); + BinaryIO::BinaryRead(cdClientBuffer, boolValue); insertedRow << static_cast(boolValue); break; case eSqliteDataType::INT64: - int64Value = ReadInt64(); + int64Value = ReadInt64(cdClientBuffer); insertedRow << std::to_string(int64Value); break; @@ -245,5 +243,5 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& auto copiedString = insertedRow.str(); CDClientDatabase::ExecuteDML(copiedString); - m_Fdb.seekg(prevPosition); + cdClientBuffer.seekg(prevPosition); } diff --git a/dCommon/FdbToSqlite.h b/dCommon/FdbToSqlite.h index cfa5263b..7aad2703 100644 --- a/dCommon/FdbToSqlite.h +++ b/dCommon/FdbToSqlite.h @@ -7,6 +7,8 @@ #include #include +class AssetMemoryBuffer; + enum class eSqliteDataType : int32_t; namespace FdbToSqlite { @@ -18,33 +20,28 @@ namespace FdbToSqlite { * @param inputFile The file which ends in .fdb to be converted * @param binaryPath The base path where the file will be saved */ - Convert(std::string inputFile, std::string binaryOutPath); - - /** - * Destroy the convert object and close the fdb file. - */ - ~Convert(); + Convert(std::string binaryOutPath); /** * Converts the input file to sqlite. Calling multiple times is safe. * * @return true if the database was converted properly, false otherwise. */ - bool ConvertDatabase(); + bool ConvertDatabase(AssetMemoryBuffer& buffer); /** * @brief Reads a 32 bit int from the fdb file. * * @return The read value */ - int32_t ReadInt32(); + int32_t ReadInt32(std::istream& cdClientBuffer); /** * @brief Reads a 64 bit integer from the fdb file. * * @return The read value */ - int64_t ReadInt64(); + int64_t ReadInt64(std::istream& cdClientBuffer); /** * @brief Reads a string from the fdb file. @@ -53,28 +50,28 @@ namespace FdbToSqlite { * * TODO This needs to be translated to latin-1! */ - std::string ReadString(); + std::string ReadString(std::istream& cdClientBuffer); /** * @brief Seeks to a pointer position. * * @return The previous position before the seek */ - int32_t SeekPointer(); + int32_t SeekPointer(std::istream& cdClientBuffer); /** * @brief Reads a column header from the fdb file and creates the table in the database * * @return The table name */ - std::string ReadColumnHeader(); + std::string ReadColumnHeader(std::istream& cdClientBuffer); /** * @brief Read the tables from the fdb file. * * @param numberOfTables The number of tables to read */ - void ReadTables(int32_t& numberOfTables); + void ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer); /** * @brief Reads the columns from the fdb file. @@ -82,14 +79,14 @@ namespace FdbToSqlite { * @param numberOfColumns The number of columns to read * @return All columns of the table formatted for a sql query */ - std::string ReadColumns(int32_t& numberOfColumns); + std::string ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer); /** * @brief Reads the row header from the fdb file. * * @param tableName The tables name */ - void ReadRowHeader(std::string& tableName); + void ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer); /** * @brief Read the rows from the fdb file., @@ -97,7 +94,7 @@ namespace FdbToSqlite { * @param numberOfAllocatedRows The number of rows that were allocated. Always a power of 2! * @param tableName The tables name. */ - void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName); + void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer); /** * @brief Reads a row from the fdb file. @@ -105,14 +102,14 @@ namespace FdbToSqlite { * @param position The position to seek in the fdb to * @param tableName The tables name */ - void ReadRow(int32_t& position, std::string& tableName); + void ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer); /** * @brief Reads the row info from the fdb file. * * @param tableName The tables name */ - void ReadRowInfo(std::string& tableName); + void ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer); /** * @brief Reads each row and its values from the fdb file and inserts them into the database @@ -120,7 +117,7 @@ namespace FdbToSqlite { * @param numberOfColumns The number of columns to read in * @param tableName The tables name */ - void ReadRowValues(int32_t& numberOfColumns, std::string& tableName); + void ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer); private: /** @@ -132,11 +129,6 @@ namespace FdbToSqlite { * Base path of the folder containing the fdb file */ std::string m_BasePath{}; - - /** - * ifstream containing the fdb file - */ - std::ifstream m_Fdb{}; /** * Whether or not a conversion was started. If one was started, do not attempt to convert the file again. diff --git a/dCommon/dClient/AssetManager.cpp b/dCommon/dClient/AssetManager.cpp index dc3db0a1..ed86d719 100644 --- a/dCommon/dClient/AssetManager.cpp +++ b/dCommon/dClient/AssetManager.cpp @@ -45,9 +45,6 @@ AssetManager::AssetManager(const std::filesystem::path& path) { switch (m_AssetBundleType) { case eAssetBundleType::Packed: { this->LoadPackIndex(); - - this->UnpackRequiredAssets(); - break; } } @@ -160,31 +157,6 @@ AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) { return AssetMemoryBuffer(buf, len, success); } -void AssetManager::UnpackRequiredAssets() { - if (std::filesystem::exists(m_ResPath / "cdclient.fdb")) return; - - char* data; - uint32_t size; - - bool success = this->GetFile("cdclient.fdb", &data, &size); - - if (!success) { - Game::logger->Log("AssetManager", "Failed to extract required files from the packs."); - - delete data; - - return; - } - - std::ofstream cdclientOutput(m_ResPath / "cdclient.fdb", std::ios::out | std::ios::binary); - cdclientOutput.write(data, size); - cdclientOutput.close(); - - delete data; - - return; -} - uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) { size_t i, j; uint32_t crc, msb; diff --git a/dCommon/dClient/AssetManager.h b/dCommon/dClient/AssetManager.h index 73b24f18..bc7e5ff7 100644 --- a/dCommon/dClient/AssetManager.h +++ b/dCommon/dClient/AssetManager.h @@ -60,7 +60,6 @@ public: private: void LoadPackIndex(); - void UnpackRequiredAssets(); // Modified crc algorithm (mpeg2) // Reference: https://stackoverflow.com/questions/54339800/how-to-modify-crc-32-to-crc-32-mpeg-2 diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 34ce59c7..82645797 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -156,22 +156,25 @@ int main(int argc, char** argv) { Game::logger->Log("MasterServer", "CDServer.sqlite is not located at resServer, but is located at res path. Copying file..."); std::filesystem::copy_file(Game::assetManager->GetResPath() / "CDServer.sqlite", BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); } else { - Game::logger->Log("WorldServer", + Game::logger->Log("MasterServer", "%s could not be found in resServer or res. Looking for %s to convert to sqlite.", (BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(), (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); - if (!fdbExists) { - Game::logger->Log("WorldServer", - "%s could not be opened. Please move cdclient.fdb to %s", - (Game::assetManager->GetResPath() / "cdclient.fdb").c_str(), - (Game::assetManager->GetResPath().c_str())); - return FinalizeShutdown(); + + AssetMemoryBuffer cdClientBuffer = Game::assetManager->GetFileAsBuffer("cdclient.fdb"); + if (!cdClientBuffer.m_Success) { + Game::logger->Log("MasterServer", "Failed to load %s", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + throw std::runtime_error("Aborting initialization due to missing cdclient.fdb."); } - Game::logger->Log("WorldServer", "Found cdclient.fdb. Converting to SQLite"); - if (FdbToSqlite::Convert(Game::assetManager->GetResPath().string(), (BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase() == false) { + + Game::logger->Log("MasterServer", "Found %s. Converting to SQLite", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + Game::logger->Flush(); + + if (FdbToSqlite::Convert((BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase(cdClientBuffer) == false) { Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite."); - return FinalizeShutdown(); + return EXIT_FAILURE; } + cdClientBuffer.close(); } } diff --git a/docker/Dockerfile b/docker/Dockerfile index 50f5b083..a7d91855 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,7 +6,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \ echo "Install build dependencies" && \ apt update && \ apt remove -y libmysqlcppconn7v5 libmysqlcppconn-dev && \ - apt install cmake zlib1g zlib1g-dev unzip -yqq --no-install-recommends && \ + apt install cmake zlib1g zlib1g-dev -yqq --no-install-recommends && \ rm -rf /var/lib/apt/lists/* COPY dAuthServer/ /build/dAuthServer @@ -35,12 +35,11 @@ ARG BUILD_VERSION=171022 RUN echo "Build server" && \ mkdir -p cmake_build && \ cd cmake_build && \ - sed -i -e "s/171022/${BUILD_VERSION}/g" ../CMakeVariables.txt && \ + sed -i -e "s/NET_VERSION=.*/NET_VERSION=${BUILD_VERSION}/g" ../CMakeVariables.txt && \ + sed -i -e "s/__maria_db_connector_compile_jobs__=.*/__maria_db_connector_compile_jobs__=${BUILD_THREADS}/g" ../CMakeVariables.txt && \ cmake .. -DCMAKE_BUILD_RPATH_USE_ORIGIN=TRUE && \ make -j $BUILD_THREADS -RUN unzip /build/resources/navmeshes.zip -d /build/cmake_build/res/maps - FROM gcc:11 as runtime RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \ diff --git a/docker/setup.Dockerfile b/docker/setup.Dockerfile index 2664e2fa..18bb2d06 100644 --- a/docker/setup.Dockerfile +++ b/docker/setup.Dockerfile @@ -1,23 +1,12 @@ -FROM rust:alpine3.14 as LUnpack - -WORKDIR /build_LUnpack - -COPY ./thirdparty/LUnpack . - -RUN apk add musl-dev --no-cache && cargo build --release - FROM python:3.10-alpine3.14 as prep -RUN apk add sqlite bash --no-cache +RUN apk add bash --no-cache WORKDIR /setup # copy needed files from repo COPY resources/ resources/ -COPY migrations/cdserver/ migrations/cdserver -COPY --from=LUnpack /build_LUnpack/target/release/lunpack /usr/local/bin/lunpack -ADD thirdparty/docker-utils/utils/*.py utils/ COPY docker/setup.sh /setup.sh -CMD [ "/setup.sh" ] \ No newline at end of file +CMD [ "/setup.sh" ] diff --git a/docker/setup.sh b/docker/setup.sh index 0f5c0d2e..ade67d2e 100755 --- a/docker/setup.sh +++ b/docker/setup.sh @@ -7,7 +7,7 @@ function update_ini() { FILE="/docker/configs/$1" KEY=$2 NEW_VALUE=$3 - sed -i "/^$KEY=/s/=.*/=$NEW_VALUE/" $FILE + sed -i "s~$2=.*~$2=$3~" $FILE } function update_database_ini_values_for() { @@ -32,62 +32,11 @@ function update_ini_values() { cp resources/worldconfig.ini /docker/configs/ cp resources/sharedconfig.ini /docker/configs/ - update_ini worldconfig.ini chat_server_port $CHAT_SERVER_PORT - update_ini worldconfig.ini max_clients $MAX_CLIENTS - # always use the internal docker hostname update_ini masterconfig.ini master_ip "darkflame" + update_ini sharedconfig.ini client_location "/client" update_database_ini_values_for sharedconfig.ini } -function fdb_to_sqlite() { - echo "Run fdb_to_sqlite" - python3 utils/fdb_to_sqlite.py /client/client/res/cdclient.fdb --sqlite_path /client/client/res/CDServer.sqlite - - ( - cd migrations/cdserver - readarray -d '' entries < <(printf '%s\0' *.sql | sort -zV) - for entry in "${entries[@]}"; do - echo "Execute $entry" - sqlite3 /client/client/res/CDServer.sqlite < $entry - done - ) -} - update_ini_values - -if [[ ! -d "/client" ]]; then - echo "Client not found." - echo "Did you forget to mount the client into the \"/client\" directory?" - exit 1 -fi - -if [[ ! -f "/client/extracted" ]]; then - echo "Start client resource extraction" - - touch globs.txt - - echo "client/res/macros/**" >> globs.txt - echo "client/res/BrickModels/**" >> globs.txt - echo "client/res/maps/**" >> globs.txt - echo "*.fdb" >> globs.txt - - lunpack -g ./globs.txt /client/ - - touch /client/extracted -else - echo "Client already extracted. Skip this step..." - echo "If you want to force a re-extract, just delete the file called \"extracted\" in the client directory" -fi - -if [[ ! -f "/client/migrated" ]]; then - echo "Start client db migration" - - fdb_to_sqlite - - touch /client/migrated -else - echo "Client db already migrated. Skip this step..." - echo "If you want to force a re-migrate, just delete the file called \"migrated\" in the client directory" -fi diff --git a/docker/start_server.sh b/docker/start_server.sh old mode 100644 new mode 100755 index 4fd6e2be..2e2e8c28 --- a/docker/start_server.sh +++ b/docker/start_server.sh @@ -1,25 +1,5 @@ #!/bin/bash -function symlink_client_files() { - echo "Creating symlinks for client files" - ln -s /client/client/res/macros/ /app/res/macros - ln -s /client/client/res/BrickModels/ /app/res/BrickModels - ln -s /client/client/res/chatplus_en_us.txt /app/res/chatplus_en_us.txt - ln -s /client/client/res/names/ /app/res/names - ln -s /client/client/res/CDServer.sqlite /app/res/CDServer.sqlite - - # need to create this file so the server knows the client is unpacked (see `dCommon/dClient/AssetManager.cpp`) - touch /app/res/cdclient.fdb - # need to iterate over entries in maps due to maps already being a directory with navmeshes/ in it - ( - cd /client/client/res/maps - readarray -d '' entries < <(printf '%s\0' * | sort -zV) - for entry in "${entries[@]}"; do - ln -s /client/client/res/maps/$entry /app/res/maps/ - done - ) -} - function symlink_config_files() { echo "Creating symlinks for config files" rm /app/*.ini @@ -30,15 +10,8 @@ function symlink_config_files() { ln -s /shared_configs/configs/sharedconfig.ini /app/sharedconfig.ini } -# check to make sure the setup has completed -while [ ! -f "/client/extracted" ] || [ ! -f "/client/migrated" ]; do - echo "Client setup not finished. Waiting for setup container to complete..." - sleep 5 -done - if [[ ! -f "/app/initialized" ]]; then # setup symlinks for volume files - symlink_client_files symlink_config_files # do not run symlinks more than once touch /app/initialized @@ -49,4 +22,4 @@ fi # start the server echo "Starting MasterServer" ./MasterServer -tail -f /dev/null \ No newline at end of file +tail -f /dev/null diff --git a/thirdparty/LUnpack b/thirdparty/LUnpack deleted file mode 160000 index f8d7e442..00000000 --- a/thirdparty/LUnpack +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f8d7e442a78910b298fe1cd5780f07c9c9285b8c diff --git a/thirdparty/docker-utils b/thirdparty/docker-utils deleted file mode 160000 index 3f0129e0..00000000 --- a/thirdparty/docker-utils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3f0129e0939ce5ccf41f0808dcbbe71a6243e37f From 8bcb4bd36d12282707776b3995dd946990768c81 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 6 Jan 2023 21:06:24 -0800 Subject: [PATCH 57/63] Fix smashables not counting towards whole team (#944) --- dGame/dComponents/DestroyableComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 8d8ed42a..1b127c41 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -701,7 +701,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* missions = owner->GetComponent(); if (missions != nullptr) { - if (team != nullptr && isEnemy) { + if (team != nullptr) { for (const auto memberId : team->members) { auto* member = EntityManager::Instance()->GetEntity(memberId); From fc75d6048fbd917586c5b7a75551dbe09288c495 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 6 Jan 2023 21:17:05 -0800 Subject: [PATCH 58/63] dGame Precompiled header improvements (#876) * moving branch * Add deleteinven slash command * Change name of BRICKS_IN_BBB * Use string_view instead of strcmp * Clean up include tree * Remove unneeded headers from PCH files Removes unneeded headers from pre-compiled headers. This increases compile time, however reduces development time for most files. * Update Entity.h * Update EntityManager.h * Update GameMessages.cpp * There it compiles now Co-authored-by: Aaron Kimbrell --- dCommon/dEnums/MissionState.h | 2 +- dCommon/{ => dEnums}/PermissionMap.h | 0 .../{ => dEnums}/eBlueprintSaveResponseType.h | 0 dCommon/dEnums/eMovementPlatformState.h | 16 + dGame/Entity.cpp | 5 + dGame/Entity.h | 25 +- dGame/EntityManager.cpp | 1 + dGame/EntityManager.h | 10 +- dGame/Player.cpp | 2 + dGame/UserManager.cpp | 1 + dGame/dBehaviors/BehaviorContext.cpp | 5 +- dGame/dBehaviors/SpawnBehavior.cpp | 2 + dGame/dComponents/CharacterComponent.cpp | 1 + dGame/dComponents/MovingPlatformComponent.cpp | 15 +- dGame/dComponents/MovingPlatformComponent.h | 17 +- dGame/dComponents/PetComponent.cpp | 1 + dGame/dComponents/PhantomPhysicsComponent.cpp | 1 + .../dComponents/PropertyEntranceComponent.cpp | 1 + dGame/dComponents/RacingControlComponent.cpp | 1 + dGame/dComponents/RebuildComponent.cpp | 1 + .../dComponents/ScriptedActivityComponent.cpp | 2 + dGame/dComponents/SkillComponent.cpp | 8 +- .../dGameMessages/DoClientProjectileImpact.h | 83 +++ dGame/dGameMessages/EchoStartSkill.h | 132 ++++ dGame/dGameMessages/EchoSyncSkill.h | 70 +++ dGame/dGameMessages/GameMessageHandler.cpp | 15 +- dGame/dGameMessages/GameMessages.cpp | 13 +- dGame/dGameMessages/GameMessages.h | 577 +----------------- .../RequestServerProjectileImpact.h | 74 +++ dGame/dGameMessages/StartSkill.h | 144 +++++ dGame/dGameMessages/SyncSkill.h | 68 +++ dGame/dInventory/Item.cpp | 1 + dGame/dMission/Mission.cpp | 1 + dGame/dMission/Mission.h | 6 +- dGame/dPropertyBehaviors/ControlBehaviors.cpp | 1 + dGame/dUtilities/BrickDatabase.cpp | 1 + dGame/dUtilities/SlashCommandHandler.cpp | 6 + dGame/dUtilities/VanityUtilities.cpp | 1 + dNet/ClientPackets.cpp | 2 +- .../02_server/Enemy/AM/AmDarklingDragon.cpp | 2 + .../02_server/Enemy/FV/FvMaelstromDragon.cpp | 2 + .../02_server/Enemy/General/BaseEnemyApe.cpp | 2 + .../02_server/Enemy/General/BaseEnemyMech.cpp | 1 + .../General/TreasureChestDragonServer.cpp | 1 + .../02_server/Equipment/BootyDigServer.cpp | 1 + dScripts/02_server/Map/AG/NpcPirateServer.cpp | 1 + dScripts/02_server/Map/AG/NpcWispServer.cpp | 1 + .../02_server/Map/AG/RemoveRentalGear.cpp | 1 + .../Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp | 1 + dScripts/02_server/Map/AM/AmBlueX.cpp | 1 + .../02_server/Map/AM/AmShieldGenerator.cpp | 1 + .../Map/AM/AmShieldGeneratorQuickbuild.cpp | 1 + dScripts/02_server/Map/AM/AmSkullkinDrill.cpp | 1 + dScripts/02_server/Map/AM/AmSkullkinTower.cpp | 1 + .../02_server/Map/FV/EnemyRoninSpawner.cpp | 1 + .../Map/General/BankInteractServer.cpp | 2 + .../02_server/Map/General/GrowingFlower.cpp | 1 + .../02_server/Map/General/PetDigServer.cpp | 1 + .../Map/General/PropertyPlatform.cpp | 5 +- dScripts/02_server/Map/General/QbSpawner.cpp | 2 +- .../Map/General/WishingWellServer.cpp | 2 + .../Map/NS/NsConcertChoiceBuildManager.cpp | 1 + dScripts/02_server/Map/NS/NsLegoClubDoor.h | 1 + dScripts/02_server/Map/NS/NsLupTeleport.h | 1 + .../Map/NT/NtCombatChallengeServer.cpp | 1 + dScripts/02_server/Map/NT/NtVandaServer.cpp | 1 + .../Property/AG_Small/EnemySpiderSpawner.cpp | 1 + .../Map/Property/PropertyBankInteract.cpp | 1 + dScripts/02_server/Map/VE/VeEpsilonServer.cpp | 2 + .../02_server/Map/VE/VeMissionConsole.cpp | 1 + .../Map/njhub/EnemySkeletonSpawner.cpp | 1 + .../Map/njhub/NjDragonEmblemChestServer.cpp | 3 + .../Map/njhub/NjNPCMissionSpinjitzuServer.cpp | 1 + dScripts/02_server/Map/njhub/RainOfArrows.cpp | 1 + .../General/MinigameTreasureChestServer.cpp | 1 + .../02_server/Objects/StinkyFishTarget.cpp | 1 + dScripts/ActivityManager.cpp | 1 + dScripts/CppScripts.h | 5 +- dScripts/NPCAddRemoveItem.cpp | 1 + dScripts/ScriptedPowerupSpawner.cpp | 1 + dScripts/SpawnPetBaseServer.cpp | 1 + dScripts/ai/AG/AgImagSmashable.cpp | 1 + dScripts/ai/AG/AgPicnicBlanket.cpp | 2 + dScripts/ai/AG/AgQbElevator.cpp | 6 +- dScripts/ai/AG/AgSpaceStuff.cpp | 1 + dScripts/ai/FV/FvPandaSpawnerServer.cpp | 1 + dScripts/ai/GF/GfBanana.cpp | 1 + dScripts/ai/GF/PetDigBuild.cpp | 1 + dScripts/ai/GF/PirateRep.cpp | 2 + .../ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp | 1 + dScripts/ai/NS/WH/RockHydrantSmashable.cpp | 1 + dScripts/ai/PETS/HydrantSmashable.cpp | 1 + dScripts/ai/PROPERTY/AgPropguards.cpp | 1 + dWorldServer/WorldServer.cpp | 5 + dZoneManager/LUTriggers.h | 30 + dZoneManager/Spawner.h | 1 + dZoneManager/Zone.cpp | 1 + dZoneManager/Zone.h | 41 +- tests/dGameTests/GameDependencies.h | 1 + 99 files changed, 821 insertions(+), 648 deletions(-) rename dCommon/{ => dEnums}/PermissionMap.h (100%) rename dCommon/{ => dEnums}/eBlueprintSaveResponseType.h (100%) create mode 100644 dCommon/dEnums/eMovementPlatformState.h create mode 100644 dGame/dGameMessages/DoClientProjectileImpact.h create mode 100644 dGame/dGameMessages/EchoStartSkill.h create mode 100644 dGame/dGameMessages/EchoSyncSkill.h create mode 100644 dGame/dGameMessages/RequestServerProjectileImpact.h create mode 100644 dGame/dGameMessages/StartSkill.h create mode 100644 dGame/dGameMessages/SyncSkill.h create mode 100644 dZoneManager/LUTriggers.h diff --git a/dCommon/dEnums/MissionState.h b/dCommon/dEnums/MissionState.h index fb1841d3..f040d33a 100644 --- a/dCommon/dEnums/MissionState.h +++ b/dCommon/dEnums/MissionState.h @@ -6,7 +6,7 @@ /** * Represents the possible states a mission can be in */ -enum class MissionState : int { +enum class MissionState : int32_t { /** * The mission state is unknown */ diff --git a/dCommon/PermissionMap.h b/dCommon/dEnums/PermissionMap.h similarity index 100% rename from dCommon/PermissionMap.h rename to dCommon/dEnums/PermissionMap.h diff --git a/dCommon/eBlueprintSaveResponseType.h b/dCommon/dEnums/eBlueprintSaveResponseType.h similarity index 100% rename from dCommon/eBlueprintSaveResponseType.h rename to dCommon/dEnums/eBlueprintSaveResponseType.h diff --git a/dCommon/dEnums/eMovementPlatformState.h b/dCommon/dEnums/eMovementPlatformState.h new file mode 100644 index 00000000..1df437d8 --- /dev/null +++ b/dCommon/dEnums/eMovementPlatformState.h @@ -0,0 +1,16 @@ +#ifndef __EMOVEMENTPLATFORMSTATE__H__ +#define __EMOVEMENTPLATFORMSTATE__H__ + +#include + +/** + * The different types of platform movement state, supposedly a bitmap + */ +enum class eMovementPlatformState : uint32_t +{ + Moving = 0b00010, + Stationary = 0b11001, + Stopped = 0b01100 +}; + +#endif //!__EMOVEMENTPLATFORMSTATE__H__ diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 16b2c5a1..c0f71324 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -17,6 +17,11 @@ #include "UserManager.h" #include "dpWorld.h" #include "Player.h" +#include "LUTriggers.h" +#include "User.h" +#include "EntityTimer.h" +#include "EntityCallbackTimer.h" +#include "Loot.h" //Component includes: #include "Component.h" diff --git a/dGame/Entity.h b/dGame/Entity.h index e0d38308..248018c0 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -4,30 +4,35 @@ #include #include #include +#include #include -#include "../thirdparty/raknet/Source/Replica.h" -#include "../thirdparty/raknet/Source/ReplicaManager.h" - -#include "dCommonVars.h" -#include "User.h" #include "NiPoint3.h" #include "NiQuaternion.h" #include "LDFFormat.h" -#include "Loot.h" -#include "Zone.h" -#include "EntityTimer.h" -#include "EntityCallbackTimer.h" -#include "EntityInfo.h" +namespace Loot { + class Info; +}; + +namespace tinyxml2 { + class XMLDocument; +}; +namespace LUTriggers { + struct Trigger; +}; class Player; +class EntityInfo; +class User; class Spawner; class ScriptComponent; class dpEntity; +class EntityTimer; class Component; class Item; class Character; +class EntityCallbackTimer; namespace CppScripts { class Script; diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 02b8b59e..99ead79d 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -17,6 +17,7 @@ #include "MissionComponent.h" #include "Game.h" #include "dLogger.h" +#include "MessageIdentifiers.h" EntityManager* EntityManager::m_Address = nullptr; diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index 40a98076..36bc5962 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -2,15 +2,17 @@ #define ENTITYMANAGER_H #include "dCommonVars.h" -#include "../thirdparty/raknet/Source/Replica.h" #include #include - -#include "Entity.h" #include +#include + +class Entity; +class EntityInfo; +class Player; +class User; struct SystemAddress; -class User; class EntityManager { public: diff --git a/dGame/Player.cpp b/dGame/Player.cpp index 5306584e..4f4bc951 100644 --- a/dGame/Player.cpp +++ b/dGame/Player.cpp @@ -13,7 +13,9 @@ #include "dZoneManager.h" #include "CharacterComponent.h" #include "Mail.h" +#include "User.h" #include "CppScripts.h" +#include "Loot.h" std::vector Player::m_Players = {}; diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 70e76016..93469daa 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -22,6 +22,7 @@ #include "SkillComponent.h" #include "AssetManager.h" #include "CDClientDatabase.h" +#include "dMessageIdentifiers.h" UserManager* UserManager::m_Address = nullptr; diff --git a/dGame/dBehaviors/BehaviorContext.cpp b/dGame/dBehaviors/BehaviorContext.cpp index ebed10ba..26d1e9e6 100644 --- a/dGame/dBehaviors/BehaviorContext.cpp +++ b/dGame/dBehaviors/BehaviorContext.cpp @@ -10,8 +10,9 @@ #include - +#include "dMessageIdentifiers.h" #include "DestroyableComponent.h" +#include "EchoSyncSkill.h" #include "PhantomPhysicsComponent.h" #include "RebuildComponent.h" @@ -216,7 +217,7 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) { } // Echo sync - GameMessages::EchoSyncSkill echo; + EchoSyncSkill echo; echo.bDone = true; echo.uiBehaviorHandle = entry.handle; diff --git a/dGame/dBehaviors/SpawnBehavior.cpp b/dGame/dBehaviors/SpawnBehavior.cpp index ac7bb797..8b2020b1 100644 --- a/dGame/dBehaviors/SpawnBehavior.cpp +++ b/dGame/dBehaviors/SpawnBehavior.cpp @@ -7,6 +7,8 @@ #include "dLogger.h" #include "DestroyableComponent.h" #include "RebuildComponent.h" +#include "Entity.h" +#include "EntityInfo.h" void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* origin = EntityManager::Instance()->GetEntity(context->originator); diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 424be0ac..ecd5e7b2 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -13,6 +13,7 @@ #include "VehiclePhysicsComponent.h" #include "GameMessages.h" #include "Item.h" +#include "AMFFormat.h" CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) { m_Character = character; diff --git a/dGame/dComponents/MovingPlatformComponent.cpp b/dGame/dComponents/MovingPlatformComponent.cpp index 42699672..2666c60c 100644 --- a/dGame/dComponents/MovingPlatformComponent.cpp +++ b/dGame/dComponents/MovingPlatformComponent.cpp @@ -12,11 +12,12 @@ #include "GameMessages.h" #include "CppScripts.h" #include "SimplePhysicsComponent.h" +#include "Zone.h" MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) { mPosition = {}; - mState = MovementPlatformState::Stopped; + mState = eMovementPlatformState::Stopped; mDesiredWaypointIndex = 0; // -1; mInReverse = false; mShouldStopAtDesiredWaypoint = false; @@ -127,7 +128,7 @@ void MovingPlatformComponent::OnCompleteRebuild() { StartPathing(); } -void MovingPlatformComponent::SetMovementState(MovementPlatformState value) { +void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) { auto* subComponent = static_cast(m_MoverSubComponent); subComponent->mState = value; @@ -152,7 +153,7 @@ void MovingPlatformComponent::StartPathing() { auto* subComponent = static_cast(m_MoverSubComponent); subComponent->mShouldStopAtDesiredWaypoint = true; - subComponent->mState = MovementPlatformState::Stationary; + subComponent->mState = eMovementPlatformState::Stationary; NiPoint3 targetPosition; @@ -174,7 +175,7 @@ void MovingPlatformComponent::StartPathing() { } m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] { - SetMovementState(MovementPlatformState::Moving); + SetMovementState(eMovementPlatformState::Moving); }); const auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5f; @@ -199,7 +200,7 @@ void MovingPlatformComponent::StartPathing() { void MovingPlatformComponent::ContinuePathing() { auto* subComponent = static_cast(m_MoverSubComponent); - subComponent->mState = MovementPlatformState::Stationary; + subComponent->mState = eMovementPlatformState::Stationary; subComponent->mCurrentWaypointIndex = subComponent->mNextWaypointIndex; @@ -282,7 +283,7 @@ void MovingPlatformComponent::ContinuePathing() { m_Parent->CancelCallbackTimers(); m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] { - SetMovementState(MovementPlatformState::Moving); + SetMovementState(eMovementPlatformState::Moving); }); auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5; @@ -313,7 +314,7 @@ void MovingPlatformComponent::StopPathing() { m_PathingStopped = true; - subComponent->mState = MovementPlatformState::Stopped; + subComponent->mState = eMovementPlatformState::Stopped; subComponent->mDesiredWaypointIndex = -1; subComponent->mShouldStopAtDesiredWaypoint = false; diff --git a/dGame/dComponents/MovingPlatformComponent.h b/dGame/dComponents/MovingPlatformComponent.h index efa3a4cf..38b15143 100644 --- a/dGame/dComponents/MovingPlatformComponent.h +++ b/dGame/dComponents/MovingPlatformComponent.h @@ -13,6 +13,9 @@ #include "dCommonVars.h" #include "EntityManager.h" #include "Component.h" +#include "eMovementPlatformState.h" + +class Path; /** * Different types of available platforms @@ -26,16 +29,6 @@ enum class eMoverSubComponentType : uint32_t { simpleMover = 5, }; -/** - * The different types of platform movement state, supposedly a bitmap - */ -enum class MovementPlatformState : uint32_t -{ - Moving = 0b00010, - Stationary = 0b11001, - Stopped = 0b01100 -}; - /** * Sub component for moving platforms that determine the actual current movement state */ @@ -49,7 +42,7 @@ public: /** * The state the platform is currently in */ - MovementPlatformState mState = MovementPlatformState::Stationary; + eMovementPlatformState mState = eMovementPlatformState::Stationary; /** * The waypoint this platform currently wants to traverse to @@ -133,7 +126,7 @@ public: * Updates the movement state for the moving platform * @param value the movement state to set */ - void SetMovementState(MovementPlatformState value); + void SetMovementState(eMovementPlatformState value); /** * Instructs the moving platform to go to some waypoint diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index d11331e7..771a9cc1 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -20,6 +20,7 @@ #include "dConfig.h" #include "dChatFilter.h" #include "Database.h" +#include "EntityInfo.h" std::unordered_map PetComponent::buildCache{}; std::unordered_map PetComponent::currentActivities{}; diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index cef9cc36..aa3ced46 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -19,6 +19,7 @@ #include "CDComponentsRegistryTable.h" #include "CDPhysicsComponentTable.h" #include "dServer.h" +#include "EntityInfo.h" #include "dpWorld.h" #include "dpEntity.h" diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index e6540417..9498a903 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -11,6 +11,7 @@ #include "CharacterComponent.h" #include "UserManager.h" #include "dLogger.h" +#include "AMFFormat.h" PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) { this->propertyQueries = {}; diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index 4b5743cd..f64dbc15 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -21,6 +21,7 @@ #include "dServer.h" #include "dZoneManager.h" #include "dConfig.h" +#include "Loot.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index c7c4e3a5..83ae818e 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -14,6 +14,7 @@ #include "Spawner.h" #include "MovingPlatformComponent.h" #include "Preconditions.h" +#include "Loot.h" #include "TeamManager.h" #include "CppScripts.h" diff --git a/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index ee7ca22e..a03dddbe 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -18,6 +18,8 @@ #include "dConfig.h" #include "InventoryComponent.h" #include "DestroyableComponent.h" +#include "dMessageIdentifiers.h" +#include "Loot.h" ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) { m_ActivityID = activityID; diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index 0608c63b..562c284a 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -19,7 +19,9 @@ #include "BaseCombatAIComponent.h" #include "ScriptComponent.h" #include "BuffComponent.h" - +#include "EchoStartSkill.h" +#include "dMessageIdentifiers.h" +#include "DoClientProjectileImpact.h" ProjectileSyncEntry::ProjectileSyncEntry() { } @@ -240,7 +242,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c if (!clientInitalized) { // Echo start skill - GameMessages::EchoStartSkill start; + EchoStartSkill start; start.iCastType = 0; start.skillID = skillId; @@ -384,7 +386,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) behavior->Calculate(entry.context, bitStream, entry.branchContext); - GameMessages::DoClientProjectileImpact projectileImpact; + DoClientProjectileImpact projectileImpact; projectileImpact.sBitStream.assign((char*)bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); projectileImpact.i64OwnerID = this->m_Parent->GetObjectID(); diff --git a/dGame/dGameMessages/DoClientProjectileImpact.h b/dGame/dGameMessages/DoClientProjectileImpact.h new file mode 100644 index 00000000..436e3dd2 --- /dev/null +++ b/dGame/dGameMessages/DoClientProjectileImpact.h @@ -0,0 +1,83 @@ +#ifndef __DOCLIENTPROJECTILEIMPACT__H__ +#define __DOCLIENTPROJECTILEIMPACT__H__ + +#include "dMessageIdentifiers.h" +#include "dCommonVars.h" + +/* Tell a client local projectile to impact */ +class DoClientProjectileImpact { + static const GAME_MSG MsgID = GAME_MSG_DO_CLIENT_PROJECTILE_IMPACT; + +public: + DoClientProjectileImpact() { + i64OrgID = LWOOBJID_EMPTY; + i64OwnerID = LWOOBJID_EMPTY; + i64TargetID = LWOOBJID_EMPTY; + } + + DoClientProjectileImpact(std::string _sBitStream, LWOOBJID _i64OrgID = LWOOBJID_EMPTY, LWOOBJID _i64OwnerID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { + i64OrgID = _i64OrgID; + i64OwnerID = _i64OwnerID; + i64TargetID = _i64TargetID; + sBitStream = _sBitStream; + } + + DoClientProjectileImpact(RakNet::BitStream* stream) : DoClientProjectileImpact() { + Deserialize(stream); + } + + ~DoClientProjectileImpact() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(i64OrgID != LWOOBJID_EMPTY); + if (i64OrgID != LWOOBJID_EMPTY) stream->Write(i64OrgID); + + stream->Write(i64OwnerID != LWOOBJID_EMPTY); + if (i64OwnerID != LWOOBJID_EMPTY) stream->Write(i64OwnerID); + + stream->Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + } + + bool Deserialize(RakNet::BitStream* stream) { + bool i64OrgIDIsDefault{}; + stream->Read(i64OrgIDIsDefault); + if (i64OrgIDIsDefault != 0) stream->Read(i64OrgID); + + bool i64OwnerIDIsDefault{}; + stream->Read(i64OwnerIDIsDefault); + if (i64OwnerIDIsDefault != 0) stream->Read(i64OwnerID); + + bool i64TargetIDIsDefault{}; + stream->Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + + return true; + } + + LWOOBJID i64OrgID; + LWOOBJID i64OwnerID; + LWOOBJID i64TargetID; + std::string sBitStream; +}; + +#endif //!__DOCLIENTPROJECTILEIMPACT__H__ diff --git a/dGame/dGameMessages/EchoStartSkill.h b/dGame/dGameMessages/EchoStartSkill.h new file mode 100644 index 00000000..6d912798 --- /dev/null +++ b/dGame/dGameMessages/EchoStartSkill.h @@ -0,0 +1,132 @@ +#ifndef __ECHOSTARTSKILL__H__ +#define __ECHOSTARTSKILL__H__ + +#include "dCommonVars.h" +#include "dMessageIdentifiers.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" + +/* Same as start skill but with different network options. An echo down to other clients that need to play the skill. */ +class EchoStartSkill { + static const GAME_MSG MsgID = GAME_MSG_ECHO_START_SKILL; + +public: + EchoStartSkill() { + bUsedMouse = false; + fCasterLatency = 0.0f; + iCastType = 0; + lastClickedPosit = NiPoint3::ZERO; + optionalTargetID = LWOOBJID_EMPTY; + originatorRot = NiQuaternion::IDENTITY; + uiSkillHandle = 0; + } + + EchoStartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, float _fCasterLatency = 0.0f, int32_t _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, uint32_t _uiSkillHandle = 0) { + bUsedMouse = _bUsedMouse; + fCasterLatency = _fCasterLatency; + iCastType = _iCastType; + lastClickedPosit = _lastClickedPosit; + optionalOriginatorID = _optionalOriginatorID; + optionalTargetID = _optionalTargetID; + originatorRot = _originatorRot; + sBitStream = _sBitStream; + skillID = _skillID; + uiSkillHandle = _uiSkillHandle; + } + + EchoStartSkill(RakNet::BitStream* stream) : EchoStartSkill() { + Deserialize(stream); + } + + ~EchoStartSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bUsedMouse); + + stream->Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + + stream->Write(iCastType != 0); + if (iCastType != 0) stream->Write(iCastType); + + stream->Write(lastClickedPosit != NiPoint3::ZERO); + if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); + + stream->Write(optionalOriginatorID); + + stream->Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + + stream->Write(originatorRot != NiQuaternion::IDENTITY); + if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(skillID); + + stream->Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bUsedMouse); + + bool fCasterLatencyIsDefault{}; + stream->Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + + bool iCastTypeIsDefault{}; + stream->Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream->Read(iCastType); + + bool lastClickedPositIsDefault{}; + stream->Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + + stream->Read(optionalOriginatorID); + + bool optionalTargetIDIsDefault{}; + stream->Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + + bool originatorRotIsDefault{}; + stream->Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream->Read(originatorRot); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(skillID); + + bool uiSkillHandleIsDefault{}; + stream->Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + + return true; + } + + bool bUsedMouse; + float fCasterLatency; + int32_t iCastType; + NiPoint3 lastClickedPosit; + LWOOBJID optionalOriginatorID; + LWOOBJID optionalTargetID; + NiQuaternion originatorRot; + std::string sBitStream; + TSkillID skillID; + uint32_t uiSkillHandle; +}; + +#endif //!__ECHOSTARTSKILL__H__ diff --git a/dGame/dGameMessages/EchoSyncSkill.h b/dGame/dGameMessages/EchoSyncSkill.h new file mode 100644 index 00000000..b56beae8 --- /dev/null +++ b/dGame/dGameMessages/EchoSyncSkill.h @@ -0,0 +1,70 @@ +#ifndef __ECHOSYNCSKILL__H__ +#define __ECHOSYNCSKILL__H__ + +#include + +#include "BitStream.h" + +#include "dMessageIdentifiers.h" + +/* Message to synchronize a skill cast */ +class EchoSyncSkill { + static const GAME_MSG MsgID = GAME_MSG_ECHO_SYNC_SKILL; + +public: + EchoSyncSkill() { + bDone = false; + } + + EchoSyncSkill(std::string _sBitStream, uint32_t _uiBehaviorHandle, uint32_t _uiSkillHandle, bool _bDone = false) { + bDone = _bDone; + sBitStream = _sBitStream; + uiBehaviorHandle = _uiBehaviorHandle; + uiSkillHandle = _uiSkillHandle; + } + + EchoSyncSkill(RakNet::BitStream* stream) : EchoSyncSkill() { + Deserialize(stream); + } + + ~EchoSyncSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bDone); + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(uiBehaviorHandle); + stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bDone); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (unsigned int k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(uiBehaviorHandle); + stream->Read(uiSkillHandle); + + return true; + } + + bool bDone{}; + std::string sBitStream{}; + uint32_t uiBehaviorHandle{}; + uint32_t uiSkillHandle{}; +}; + +#endif //!__ECHOSYNCSKILL__H__ diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index b7687c19..c03f58db 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -26,6 +26,11 @@ #include "CDSkillBehaviorTable.h" #include "SkillComponent.h" #include "RacingControlComponent.h" +#include "RequestServerProjectileImpact.h" +#include "SyncSkill.h" +#include "StartSkill.h" +#include "EchoStartSkill.h" +#include "EchoSyncSkill.h" using namespace std; @@ -251,7 +256,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System case GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT: { - auto message = GameMessages::RequestServerProjectileImpact(); + auto message = RequestServerProjectileImpact(); message.Deserialize(inStream); @@ -269,7 +274,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System } case GAME_MSG_START_SKILL: { - GameMessages::StartSkill startSkill = GameMessages::StartSkill(); + StartSkill startSkill = StartSkill(); startSkill.Deserialize(inStream); // inStream replaces &bitStream if (startSkill.skillID == 1561 || startSkill.skillID == 1562 || startSkill.skillID == 1541) return; @@ -309,7 +314,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System PacketUtils::WriteHeader(bitStreamLocal, CLIENT, MSG_CLIENT_GAME_MSG); bitStreamLocal.Write(entity->GetObjectID()); - GameMessages::EchoStartSkill echoStartSkill; + EchoStartSkill echoStartSkill; echoStartSkill.bUsedMouse = startSkill.bUsedMouse; echoStartSkill.fCasterLatency = startSkill.fCasterLatency; echoStartSkill.iCastType = startSkill.iCastType; @@ -333,7 +338,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System //bitStreamLocal.Write((unsigned short)GAME_MSG_ECHO_SYNC_SKILL); //bitStreamLocal.Write(inStream); - GameMessages::SyncSkill sync = GameMessages::SyncSkill(inStream); // inStream replaced &bitStream + SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream //sync.Serialize(&bitStreamLocal); ostringstream buffer; @@ -356,7 +361,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System delete bs; } - GameMessages::EchoSyncSkill echo = GameMessages::EchoSyncSkill(); + EchoSyncSkill echo = EchoSyncSkill(); echo.bDone = sync.bDone; echo.sBitStream = sync.sBitStream; echo.uiBehaviorHandle = sync.uiBehaviorHandle; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 2423915e..24f0816d 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -28,6 +28,10 @@ #include "GameConfig.h" #include "RocketLaunchLupComponent.h" #include "eUnequippableActiveType.h" +#include "eMovementPlatformState.h" +#include "LeaderboardManager.h" +#include "AMFFormat.h" +#include "Loot.h" #include "RacingTaskParam.h" #include @@ -73,6 +77,7 @@ #include "ControlBehaviors.h" #include "AMFDeserialize.h" #include "eBlueprintSaveResponseType.h" +#include "eAninmationFlags.h" void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) { CBITSTREAM; @@ -330,7 +335,7 @@ void GameMessages::SendStartPathing(Entity* entity) { void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint, int iIndex, int iDesiredWaypointIndex, int nextIndex, - MovementPlatformState movementState) { + eMovementPlatformState movementState) { CBITSTREAM; CMSGHEADER; @@ -341,7 +346,7 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd iIndex = 0; nextIndex = 0; bStopAtDesiredWaypoint = true; - movementState = MovementPlatformState::Stationary; + movementState = eMovementPlatformState::Stationary; } bitStream.Write(entity->GetObjectID()); @@ -575,7 +580,7 @@ void GameMessages::SendModifyLEGOScore(Entity* entity, const SystemAddress& sysA SEND_PACKET; } -void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, NDGFxValue args) { +void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFValue* args) { CBITSTREAM; CMSGHEADER; @@ -593,7 +598,7 @@ void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const Syste SEND_PACKET; } -void GameMessages::SendUIMessageServerToAllClients(const std::string& message, NDGFxValue args) { +void GameMessages::SendUIMessageServerToAllClients(const std::string& message, AMFValue* args) { CBITSTREAM; CMSGHEADER; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 8a1c2fe5..6575ad85 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -1,27 +1,26 @@ - #ifndef GAMEMESSAGES_H #define GAMEMESSAGES_H #include "dCommonVars.h" -#include "RakNetTypes.h" +#include #include -#include "dMessageIdentifiers.h" -#include "AMFFormat.h" -#include "AMFFormat_BitStream.h" -#include "NiQuaternion.h" -#include "PropertySelectQueryProperty.h" -#include "TradingManager.h" -#include "LeaderboardManager.h" -#include "MovingPlatformComponent.h" -#include "eAninmationFlags.h" +#include +#include "eMovementPlatformState.h" +#include "NiPoint3.h" +class AMFValue; +class Entity; +class Item; class NiQuaternion; class User; -class Entity; -class NiPoint3; +class Leaderboard; +class PropertySelectQueryProperty; +class TradeItem; + +enum class eAnimationFlags : uint32_t; + enum class eUnequippableActiveType; enum eInventoryType : uint32_t; -class Item; namespace GameMessages { class PropertyDataMessage; @@ -57,7 +56,7 @@ namespace GameMessages { void SendStartPathing(Entity* entity); void SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint = false, int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1, - MovementPlatformState movementState = MovementPlatformState::Moving); + eMovementPlatformState movementState = eMovementPlatformState::Moving); void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr); void SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr); @@ -74,8 +73,8 @@ namespace GameMessages { void NotifyLevelRewards(LWOOBJID objectID, const SystemAddress& sysAddr, int level, bool sending_rewards); void SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType); - void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, NDGFxValue args); - void SendUIMessageServerToAllClients(const std::string& message, NDGFxValue args); + void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFValue* args); + void SendUIMessageServerToAllClients(const std::string& message, AMFValue* args); void SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius); void SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority = 1, float scale = 1, bool serialize = true); @@ -589,550 +588,6 @@ namespace GameMessages { void HandleReportBug(RakNet::BitStream* inStream, Entity* entity); void SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId); - - /* Message to synchronize a skill cast */ - class EchoSyncSkill { - static const GAME_MSG MsgID = GAME_MSG_ECHO_SYNC_SKILL; - - public: - EchoSyncSkill() { - bDone = false; - } - - EchoSyncSkill(std::string _sBitStream, unsigned int _uiBehaviorHandle, unsigned int _uiSkillHandle, bool _bDone = false) { - bDone = _bDone; - sBitStream = _sBitStream; - uiBehaviorHandle = _uiBehaviorHandle; - uiSkillHandle = _uiSkillHandle; - } - - EchoSyncSkill(RakNet::BitStream* stream) { - bDone = false; - - Deserialize(stream); - } - - ~EchoSyncSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bDone); - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); - - return true; - } - - bool bDone{}; - std::string sBitStream{}; - unsigned int uiBehaviorHandle{}; - unsigned int uiSkillHandle{}; - }; - - /* Message to synchronize a skill cast */ - class SyncSkill { - static const GAME_MSG MsgID = GAME_MSG_SYNC_SKILL; - - public: - SyncSkill() { - bDone = false; - } - - SyncSkill(std::string _sBitStream, unsigned int _uiBehaviorHandle, unsigned int _uiSkillHandle, bool _bDone = false) { - bDone = _bDone; - sBitStream = _sBitStream; - uiBehaviorHandle = _uiBehaviorHandle; - uiSkillHandle = _uiSkillHandle; - } - - SyncSkill(RakNet::BitStream* stream) { - bDone = false; - Deserialize(stream); - } - - ~SyncSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bDone); - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); - - return true; - } - - bool bDone{}; - std::string sBitStream{}; - unsigned int uiBehaviorHandle{}; - unsigned int uiSkillHandle{}; - }; - - /* Notifying the server that a locally owned projectil impacted. Sent to the caster of the projectile - should always be the local char. */ - class RequestServerProjectileImpact { - static const GAME_MSG MsgID = GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT; - - public: - RequestServerProjectileImpact() { - i64LocalID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - } - - RequestServerProjectileImpact(std::string _sBitStream, LWOOBJID _i64LocalID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { - i64LocalID = _i64LocalID; - i64TargetID = _i64TargetID; - sBitStream = _sBitStream; - } - - RequestServerProjectileImpact(RakNet::BitStream* stream) { - i64LocalID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - - Deserialize(stream); - } - - ~RequestServerProjectileImpact() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(i64LocalID != LWOOBJID_EMPTY); - if (i64LocalID != LWOOBJID_EMPTY) stream->Write(i64LocalID); - - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - } - - bool Deserialize(RakNet::BitStream* stream) { - bool i64LocalIDIsDefault{}; - stream->Read(i64LocalIDIsDefault); - if (i64LocalIDIsDefault != 0) stream->Read(i64LocalID); - - bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - - return true; - } - - LWOOBJID i64LocalID; - LWOOBJID i64TargetID; - std::string sBitStream; - }; - - /* Tell a client local projectile to impact */ - class DoClientProjectileImpact { - static const GAME_MSG MsgID = GAME_MSG_DO_CLIENT_PROJECTILE_IMPACT; - - public: - DoClientProjectileImpact() { - i64OrgID = LWOOBJID_EMPTY; - i64OwnerID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - } - - DoClientProjectileImpact(std::string _sBitStream, LWOOBJID _i64OrgID = LWOOBJID_EMPTY, LWOOBJID _i64OwnerID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { - i64OrgID = _i64OrgID; - i64OwnerID = _i64OwnerID; - i64TargetID = _i64TargetID; - sBitStream = _sBitStream; - } - - DoClientProjectileImpact(RakNet::BitStream* stream) { - i64OrgID = LWOOBJID_EMPTY; - i64OwnerID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - - Deserialize(stream); - } - - ~DoClientProjectileImpact() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(i64OrgID != LWOOBJID_EMPTY); - if (i64OrgID != LWOOBJID_EMPTY) stream->Write(i64OrgID); - - stream->Write(i64OwnerID != LWOOBJID_EMPTY); - if (i64OwnerID != LWOOBJID_EMPTY) stream->Write(i64OwnerID); - - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - } - - bool Deserialize(RakNet::BitStream* stream) { - bool i64OrgIDIsDefault{}; - stream->Read(i64OrgIDIsDefault); - if (i64OrgIDIsDefault != 0) stream->Read(i64OrgID); - - bool i64OwnerIDIsDefault{}; - stream->Read(i64OwnerIDIsDefault); - if (i64OwnerIDIsDefault != 0) stream->Read(i64OwnerID); - - bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - - return true; - } - - LWOOBJID i64OrgID; - LWOOBJID i64OwnerID; - LWOOBJID i64TargetID; - std::string sBitStream; - }; - - /* Same as start skill but with different network options. An echo down to other clients that need to play the skill. */ - class EchoStartSkill { - static const GAME_MSG MsgID = GAME_MSG_ECHO_START_SKILL; - - public: - EchoStartSkill() { - bUsedMouse = false; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - } - - EchoStartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, float _fCasterLatency = 0.0f, int _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, unsigned int _uiSkillHandle = 0) { - bUsedMouse = _bUsedMouse; - fCasterLatency = _fCasterLatency; - iCastType = _iCastType; - lastClickedPosit = _lastClickedPosit; - optionalOriginatorID = _optionalOriginatorID; - optionalTargetID = _optionalTargetID; - originatorRot = _originatorRot; - sBitStream = _sBitStream; - skillID = _skillID; - uiSkillHandle = _uiSkillHandle; - } - - EchoStartSkill(RakNet::BitStream* stream) { - bUsedMouse = false; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - - Deserialize(stream); - } - - ~EchoStartSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bUsedMouse); - - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); - - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); - - stream->Write(lastClickedPosit != NiPoint3::ZERO); - if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); - - stream->Write(optionalOriginatorID); - - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); - - stream->Write(originatorRot != NiQuaternion::IDENTITY); - if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(skillID); - - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); - - bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); - - bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); - - bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); - - stream->Read(optionalOriginatorID); - - bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); - - bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(skillID); - - bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); - - return true; - } - - bool bUsedMouse; - float fCasterLatency; - int iCastType; - NiPoint3 lastClickedPosit; - LWOOBJID optionalOriginatorID; - LWOOBJID optionalTargetID; - NiQuaternion originatorRot; - std::string sBitStream; - TSkillID skillID; - unsigned int uiSkillHandle; - }; - - /* Same as sync skill but with different network options. An echo down to other clients that need to play the skill. */ - class StartSkill { - static const GAME_MSG MsgID = GAME_MSG_START_SKILL; - - public: - StartSkill() { - bUsedMouse = false; - consumableItemID = LWOOBJID_EMPTY; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - } - - StartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, LWOOBJID _consumableItemID = LWOOBJID_EMPTY, float _fCasterLatency = 0.0f, int _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, unsigned int _uiSkillHandle = 0) { - bUsedMouse = _bUsedMouse; - consumableItemID = _consumableItemID; - fCasterLatency = _fCasterLatency; - iCastType = _iCastType; - lastClickedPosit = _lastClickedPosit; - optionalOriginatorID = _optionalOriginatorID; - optionalTargetID = _optionalTargetID; - originatorRot = _originatorRot; - sBitStream = _sBitStream; - skillID = _skillID; - uiSkillHandle = _uiSkillHandle; - } - - StartSkill(RakNet::BitStream* stream) { - bUsedMouse = false; - consumableItemID = LWOOBJID_EMPTY; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - - Deserialize(stream); - } - - ~StartSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bUsedMouse); - - stream->Write(consumableItemID != LWOOBJID_EMPTY); - if (consumableItemID != LWOOBJID_EMPTY) stream->Write(consumableItemID); - - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); - - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); - - stream->Write(lastClickedPosit != NiPoint3::ZERO); - if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); - - stream->Write(optionalOriginatorID); - - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); - - stream->Write(originatorRot != NiQuaternion::IDENTITY); - if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(skillID); - - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); - - bool consumableItemIDIsDefault{}; - stream->Read(consumableItemIDIsDefault); - if (consumableItemIDIsDefault != 0) stream->Read(consumableItemID); - - bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); - - bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); - - bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); - - stream->Read(optionalOriginatorID); - - bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); - - bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(skillID); - - bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); - - return true; - } - - bool bUsedMouse = false; - LWOOBJID consumableItemID{}; - float fCasterLatency{}; - int iCastType{}; - NiPoint3 lastClickedPosit{}; - LWOOBJID optionalOriginatorID{}; - LWOOBJID optionalTargetID{}; - NiQuaternion originatorRot{}; - std::string sBitStream = ""; - TSkillID skillID = 0; - unsigned int uiSkillHandle = 0; - }; }; #endif // GAMEMESSAGES_H diff --git a/dGame/dGameMessages/RequestServerProjectileImpact.h b/dGame/dGameMessages/RequestServerProjectileImpact.h new file mode 100644 index 00000000..01426361 --- /dev/null +++ b/dGame/dGameMessages/RequestServerProjectileImpact.h @@ -0,0 +1,74 @@ +#ifndef __REQUESTSERVERPROJECTILEIMPACT__H__ +#define __REQUESTSERVERPROJECTILEIMPACT__H__ + +#include "dCommonVars.h" +#include "dMessageIdentifiers.h" + +/* Notifying the server that a locally owned projectile impacted. Sent to the caster of the projectile + should always be the local char. */ +class RequestServerProjectileImpact { + static const GAME_MSG MsgID = GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT; + +public: + RequestServerProjectileImpact() { + i64LocalID = LWOOBJID_EMPTY; + i64TargetID = LWOOBJID_EMPTY; + } + + RequestServerProjectileImpact(std::string _sBitStream, LWOOBJID _i64LocalID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { + i64LocalID = _i64LocalID; + i64TargetID = _i64TargetID; + sBitStream = _sBitStream; + } + + RequestServerProjectileImpact(RakNet::BitStream* stream) : RequestServerProjectileImpact() { + Deserialize(stream); + } + + ~RequestServerProjectileImpact() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(i64LocalID != LWOOBJID_EMPTY); + if (i64LocalID != LWOOBJID_EMPTY) stream->Write(i64LocalID); + + stream->Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + } + + bool Deserialize(RakNet::BitStream* stream) { + bool i64LocalIDIsDefault{}; + stream->Read(i64LocalIDIsDefault); + if (i64LocalIDIsDefault != 0) stream->Read(i64LocalID); + + bool i64TargetIDIsDefault{}; + stream->Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + + return true; + } + + LWOOBJID i64LocalID; + LWOOBJID i64TargetID; + std::string sBitStream; +}; + +#endif //!__REQUESTSERVERPROJECTILEIMPACT__H__ diff --git a/dGame/dGameMessages/StartSkill.h b/dGame/dGameMessages/StartSkill.h new file mode 100644 index 00000000..af82a9b4 --- /dev/null +++ b/dGame/dGameMessages/StartSkill.h @@ -0,0 +1,144 @@ +#ifndef __STARTSKILL__H__ +#define __STARTSKILL__H__ + +#include "dCommonVars.h" +#include "dMessageIdentifiers.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" + +/** + * Same as sync skill but with different network options. An echo down to other clients that need to play the skill. + */ +class StartSkill { + static const GAME_MSG MsgID = GAME_MSG_START_SKILL; + +public: + StartSkill() { + bUsedMouse = false; + consumableItemID = LWOOBJID_EMPTY; + fCasterLatency = 0.0f; + iCastType = 0; + lastClickedPosit = NiPoint3::ZERO; + optionalTargetID = LWOOBJID_EMPTY; + originatorRot = NiQuaternion::IDENTITY; + uiSkillHandle = 0; + } + + StartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, LWOOBJID _consumableItemID = LWOOBJID_EMPTY, float _fCasterLatency = 0.0f, int32_t _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, uint32_t _uiSkillHandle = 0) { + bUsedMouse = _bUsedMouse; + consumableItemID = _consumableItemID; + fCasterLatency = _fCasterLatency; + iCastType = _iCastType; + lastClickedPosit = _lastClickedPosit; + optionalOriginatorID = _optionalOriginatorID; + optionalTargetID = _optionalTargetID; + originatorRot = _originatorRot; + sBitStream = _sBitStream; + skillID = _skillID; + uiSkillHandle = _uiSkillHandle; + } + + StartSkill(RakNet::BitStream* stream) : StartSkill() { + Deserialize(stream); + } + + ~StartSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bUsedMouse); + + stream->Write(consumableItemID != LWOOBJID_EMPTY); + if (consumableItemID != LWOOBJID_EMPTY) stream->Write(consumableItemID); + + stream->Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + + stream->Write(iCastType != 0); + if (iCastType != 0) stream->Write(iCastType); + + stream->Write(lastClickedPosit != NiPoint3::ZERO); + if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); + + stream->Write(optionalOriginatorID); + + stream->Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + + stream->Write(originatorRot != NiQuaternion::IDENTITY); + if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(skillID); + + stream->Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bUsedMouse); + + bool consumableItemIDIsDefault{}; + stream->Read(consumableItemIDIsDefault); + if (consumableItemIDIsDefault != 0) stream->Read(consumableItemID); + + bool fCasterLatencyIsDefault{}; + stream->Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + + bool iCastTypeIsDefault{}; + stream->Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream->Read(iCastType); + + bool lastClickedPositIsDefault{}; + stream->Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + + stream->Read(optionalOriginatorID); + + bool optionalTargetIDIsDefault{}; + stream->Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + + bool originatorRotIsDefault{}; + stream->Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream->Read(originatorRot); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(skillID); + + bool uiSkillHandleIsDefault{}; + stream->Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + + return true; + } + + bool bUsedMouse = false; + LWOOBJID consumableItemID{}; + float fCasterLatency{}; + int32_t iCastType{}; + NiPoint3 lastClickedPosit{}; + LWOOBJID optionalOriginatorID{}; + LWOOBJID optionalTargetID{}; + NiQuaternion originatorRot{}; + std::string sBitStream = ""; + TSkillID skillID = 0; + uint32_t uiSkillHandle = 0; +}; + +#endif //!__STARTSKILL__H__ diff --git a/dGame/dGameMessages/SyncSkill.h b/dGame/dGameMessages/SyncSkill.h new file mode 100644 index 00000000..72a88839 --- /dev/null +++ b/dGame/dGameMessages/SyncSkill.h @@ -0,0 +1,68 @@ +#ifndef __SYNCSKILL__H__ +#define __SYNCSKILL__H__ + +#include +#include + +#include "BitStream.h" + +/* Message to synchronize a skill cast */ +class SyncSkill { + static const GAME_MSG MsgID = GAME_MSG_SYNC_SKILL; + +public: + SyncSkill() { + bDone = false; + } + + SyncSkill(std::string _sBitStream, uint32_t _uiBehaviorHandle, uint32_t _uiSkillHandle, bool _bDone = false) { + bDone = _bDone; + sBitStream = _sBitStream; + uiBehaviorHandle = _uiBehaviorHandle; + uiSkillHandle = _uiSkillHandle; + } + + SyncSkill(RakNet::BitStream* stream) : SyncSkill() { + Deserialize(stream); + } + + ~SyncSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bDone); + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (unsigned int k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(uiBehaviorHandle); + stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bDone); + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(uiBehaviorHandle); + stream->Read(uiSkillHandle); + + return true; + } + + bool bDone{}; + std::string sBitStream{}; + uint32_t uiBehaviorHandle{}; + uint32_t uiSkillHandle{}; +}; + +#endif //!__SYNCSKILL__H__ diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index 4f3626e3..d6721bdd 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -15,6 +15,7 @@ #include "eItemType.h" #include "AssetManager.h" #include "InventoryComponent.h" +#include "Loot.h" Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) { if (!Inventory::IsValidItem(lot)) { diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index a1ae724a..df1b16d7 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -17,6 +17,7 @@ #include "dServer.h" #include "dZoneManager.h" #include "InventoryComponent.h" +#include "User.h" #include "Database.h" #include "WorldConfig.h" diff --git a/dGame/dMission/Mission.h b/dGame/dMission/Mission.h index b8892f3d..f9902a06 100644 --- a/dGame/dMission/Mission.h +++ b/dGame/dMission/Mission.h @@ -13,6 +13,10 @@ #include "MissionState.h" #include "MissionLockState.h" +namespace tinyxml2 { + class XMLElement; +}; + class MissionComponent; /** @@ -223,7 +227,7 @@ public: /** * @brief Returns the unique mission order ID - * + * * @return The unique order ID */ uint32_t GetUniqueMissionOrderID() { return m_UniqueMissionID; }; diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.cpp b/dGame/dPropertyBehaviors/ControlBehaviors.cpp index d5b71a3a..278b6929 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviors.cpp @@ -7,6 +7,7 @@ #include "ModelComponent.h" #include "../../dWorldServer/ObjectIDManager.h" #include "dLogger.h" +#include "User.h" uint32_t GetBehaviorIDFromArgument(AMFArrayValue* arguments, const std::string& key = "BehaviorID") { auto* behaviorIDValue = arguments->FindValue(key); diff --git a/dGame/dUtilities/BrickDatabase.cpp b/dGame/dUtilities/BrickDatabase.cpp index 6d1e380c..a6c43d52 100644 --- a/dGame/dUtilities/BrickDatabase.cpp +++ b/dGame/dUtilities/BrickDatabase.cpp @@ -4,6 +4,7 @@ #include "BrickDatabase.h" #include "Game.h" #include "AssetManager.h" +#include "tinyxml2.h" std::vector BrickDatabase::emptyCache{}; BrickDatabase* BrickDatabase::m_Address = nullptr; diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 9a63f83c..2192fafb 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -50,6 +50,9 @@ #include "Item.h" #include "PropertyManagementComponent.h" #include "PacketUtils.h" +#include "Loot.h" +#include "EntityInfo.h" +#include "LUTriggers.h" #include "Player.h" #include "PhantomPhysicsComponent.h" #include "ProximityMonitorComponent.h" @@ -66,6 +69,9 @@ #include "AssetManager.h" #include "BinaryPathFinder.h" #include "dConfig.h" +#include "AMFFormat.h" +#include "MovingPlatformComponent.h" +#include "dMessageIdentifiers.h" void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) { std::string chatCommand; diff --git a/dGame/dUtilities/VanityUtilities.cpp b/dGame/dUtilities/VanityUtilities.cpp index 3a1259a2..74fd0f67 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -14,6 +14,7 @@ #include "Game.h" #include "dLogger.h" #include "BinaryPathFinder.h" +#include "EntityInfo.h" #include diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index 39e835d2..61267971 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -31,7 +31,7 @@ #include "dConfig.h" #include "CharacterComponent.h" #include "Database.h" - +#include "dMessageIdentifiers.h" void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* packet) { diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp index 9e0570ef..28ba0044 100644 --- a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp @@ -5,6 +5,8 @@ #include "GameMessages.h" #include "SkillComponent.h" #include "BaseCombatAIComponent.h" +#include "EntityInfo.h" +#include "eAninmationFlags.h" void AmDarklingDragon::OnStartup(Entity* self) { self->SetVar(u"weakspot", 0); diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp index ec513694..e78f537f 100644 --- a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp @@ -3,6 +3,8 @@ #include "SkillComponent.h" #include "BaseCombatAIComponent.h" #include "DestroyableComponent.h" +#include "eAninmationFlags.h" +#include "EntityInfo.h" void FvMaelstromDragon::OnStartup(Entity* self) { self->SetVar(u"weakspot", 0); diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp index 96419c08..d3c59448 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp @@ -3,7 +3,9 @@ #include "DestroyableComponent.h" #include "GameMessages.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "SkillComponent.h" +#include "eAninmationFlags.h" void BaseEnemyApe::OnStartup(Entity* self) { self->SetVar(u"timesStunned", 2); diff --git a/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp b/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp index 8017be2c..8c200566 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp @@ -3,6 +3,7 @@ #include "ControllablePhysicsComponent.h" #include "EntityManager.h" #include "dpWorld.h" +#include "EntityInfo.h" #include "GeneralUtils.h" #include "DestroyableComponent.h" diff --git a/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp index 15f0709c..19788677 100644 --- a/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp +++ b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp @@ -2,6 +2,7 @@ #include "ScriptedActivityComponent.h" #include "TeamManager.h" #include "EntityManager.h" +#include "Loot.h" void TreasureChestDragonServer::OnStartup(Entity* self) { diff --git a/dScripts/02_server/Equipment/BootyDigServer.cpp b/dScripts/02_server/Equipment/BootyDigServer.cpp index d38791d8..73d96b1f 100644 --- a/dScripts/02_server/Equipment/BootyDigServer.cpp +++ b/dScripts/02_server/Equipment/BootyDigServer.cpp @@ -3,6 +3,7 @@ #include "RenderComponent.h" #include "MissionComponent.h" #include "MissionTaskType.h" +#include "Loot.h" void BootyDigServer::OnStartup(Entity* self) { auto* zoneControlObject = EntityManager::Instance()->GetZoneControlEntity(); diff --git a/dScripts/02_server/Map/AG/NpcPirateServer.cpp b/dScripts/02_server/Map/AG/NpcPirateServer.cpp index 47571fa6..154fe2bc 100644 --- a/dScripts/02_server/Map/AG/NpcPirateServer.cpp +++ b/dScripts/02_server/Map/AG/NpcPirateServer.cpp @@ -1,4 +1,5 @@ #include "NpcPirateServer.h" +#include "MissionState.h" #include "InventoryComponent.h" void NpcPirateServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { diff --git a/dScripts/02_server/Map/AG/NpcWispServer.cpp b/dScripts/02_server/Map/AG/NpcWispServer.cpp index cd4a4d9c..d6eab34c 100644 --- a/dScripts/02_server/Map/AG/NpcWispServer.cpp +++ b/dScripts/02_server/Map/AG/NpcWispServer.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "Entity.h" #include "GameMessages.h" +#include "MissionState.h" void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { if (missionID != 1849 && missionID != 1883) diff --git a/dScripts/02_server/Map/AG/RemoveRentalGear.cpp b/dScripts/02_server/Map/AG/RemoveRentalGear.cpp index 06d964b9..fbb00c79 100644 --- a/dScripts/02_server/Map/AG/RemoveRentalGear.cpp +++ b/dScripts/02_server/Map/AG/RemoveRentalGear.cpp @@ -1,6 +1,7 @@ #include "RemoveRentalGear.h" #include "InventoryComponent.h" #include "Item.h" +#include "MissionState.h" #include "Character.h" /* diff --git a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp index ea517448..5996548f 100644 --- a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp +++ b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "ZoneAgProperty.h" #include "DestroyableComponent.h" +#include "EntityInfo.h" void ZoneAgSpiderQueen::SetGameVariables(Entity* self) { ZoneAgProperty::SetGameVariables(self); diff --git a/dScripts/02_server/Map/AM/AmBlueX.cpp b/dScripts/02_server/Map/AM/AmBlueX.cpp index 97f80e77..8e32694c 100644 --- a/dScripts/02_server/Map/AM/AmBlueX.cpp +++ b/dScripts/02_server/Map/AM/AmBlueX.cpp @@ -1,6 +1,7 @@ #include "AmBlueX.h" #include "SkillComponent.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "Character.h" void AmBlueX::OnUse(Entity* self, Entity* user) { diff --git a/dScripts/02_server/Map/AM/AmShieldGenerator.cpp b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp index d16acb87..5d1b7d08 100644 --- a/dScripts/02_server/Map/AM/AmShieldGenerator.cpp +++ b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EntityInfo.h" #include "MovementAIComponent.h" #include "BaseCombatAIComponent.h" #include "SkillComponent.h" diff --git a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp index 9f27b904..3188db33 100644 --- a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp +++ b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp @@ -5,6 +5,7 @@ #include "MovementAIComponent.h" #include "BaseCombatAIComponent.h" #include "SkillComponent.h" +#include "EntityInfo.h" #include "RebuildComponent.h" #include "MissionComponent.h" diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp index 321660e2..9b85cf85 100644 --- a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp +++ b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp @@ -4,6 +4,7 @@ #include "DestroyableComponent.h" #include "ProximityMonitorComponent.h" #include "MissionComponent.h" +#include "EntityInfo.h" void AmSkullkinDrill::OnStartup(Entity* self) { self->SetNetworkVar(u"bIsInUse", false); diff --git a/dScripts/02_server/Map/AM/AmSkullkinTower.cpp b/dScripts/02_server/Map/AM/AmSkullkinTower.cpp index 180bbdac..01acdeaf 100644 --- a/dScripts/02_server/Map/AM/AmSkullkinTower.cpp +++ b/dScripts/02_server/Map/AM/AmSkullkinTower.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "MovingPlatformComponent.h" +#include "EntityInfo.h" #include "GameMessages.h" #include "MissionComponent.h" diff --git a/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp b/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp index b6cae3bb..cfc58fa0 100644 --- a/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp +++ b/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp @@ -1,6 +1,7 @@ #include "EnemyRoninSpawner.h" #include "SkillComponent.h" #include "RenderComponent.h" +#include "EntityInfo.h" #include "EntityManager.h" void EnemyRoninSpawner::OnStartup(Entity* self) { diff --git a/dScripts/02_server/Map/General/BankInteractServer.cpp b/dScripts/02_server/Map/General/BankInteractServer.cpp index db5ebb98..b96187cf 100644 --- a/dScripts/02_server/Map/General/BankInteractServer.cpp +++ b/dScripts/02_server/Map/General/BankInteractServer.cpp @@ -1,5 +1,7 @@ #include "BankInteractServer.h" #include "GameMessages.h" +#include "Entity.h" +#include "AMFFormat.h" void BankInteractServer::OnUse(Entity* self, Entity* user) { AMFArrayValue args; diff --git a/dScripts/02_server/Map/General/GrowingFlower.cpp b/dScripts/02_server/Map/General/GrowingFlower.cpp index 7b495841..61bfbc30 100644 --- a/dScripts/02_server/Map/General/GrowingFlower.cpp +++ b/dScripts/02_server/Map/General/GrowingFlower.cpp @@ -1,5 +1,6 @@ #include "GrowingFlower.h" #include "MissionComponent.h" +#include "Loot.h" void GrowingFlower::OnSkillEventFired(Entity* self, Entity* target, const std::string& message) { if (!self->GetVar(u"blooming") && (message == "waterspray" || message == "shovelgrow")) { diff --git a/dScripts/02_server/Map/General/PetDigServer.cpp b/dScripts/02_server/Map/General/PetDigServer.cpp index e26b079a..0d62ff04 100644 --- a/dScripts/02_server/Map/General/PetDigServer.cpp +++ b/dScripts/02_server/Map/General/PetDigServer.cpp @@ -4,6 +4,7 @@ #include "EntityManager.h" #include "Character.h" #include "PetComponent.h" +#include "User.h" std::vector PetDigServer::treasures{}; diff --git a/dScripts/02_server/Map/General/PropertyPlatform.cpp b/dScripts/02_server/Map/General/PropertyPlatform.cpp index 89687ac3..902b9646 100644 --- a/dScripts/02_server/Map/General/PropertyPlatform.cpp +++ b/dScripts/02_server/Map/General/PropertyPlatform.cpp @@ -1,6 +1,7 @@ #include "PropertyPlatform.h" #include "RebuildComponent.h" #include "GameMessages.h" +#include "MovingPlatformComponent.h" void PropertyPlatform::OnRebuildComplete(Entity* self, Entity* target) { // auto* movingPlatform = self->GetComponent(); @@ -9,7 +10,7 @@ void PropertyPlatform::OnRebuildComplete(Entity* self, Entity* target) { // movingPlatform->SetNoAutoStart(true); // } GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, MovementPlatformState::Stationary); + 0, 0, eMovementPlatformState::Stationary); } void PropertyPlatform::OnUse(Entity* self, Entity* user) { @@ -20,7 +21,7 @@ void PropertyPlatform::OnUse(Entity* self, Entity* user) { // movingPlatform->GotoWaypoint(1); // } GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); + 1, 1, eMovementPlatformState::Moving); self->AddCallbackTimer(movementDelay + effectDelay, [self, this]() { self->SetNetworkVar(u"startEffect", dieDelay); diff --git a/dScripts/02_server/Map/General/QbSpawner.cpp b/dScripts/02_server/Map/General/QbSpawner.cpp index edee6148..d5c9d001 100644 --- a/dScripts/02_server/Map/General/QbSpawner.cpp +++ b/dScripts/02_server/Map/General/QbSpawner.cpp @@ -1,5 +1,6 @@ #include "QbSpawner.h" #include "BaseCombatAIComponent.h" +#include "EntityInfo.h" #include "MovementAIComponent.h" void QbSpawner::OnStartup(Entity* self) { @@ -133,4 +134,3 @@ void QbSpawner::AggroTargetObject(Entity* self, Entity* enemy) { } } - diff --git a/dScripts/02_server/Map/General/WishingWellServer.cpp b/dScripts/02_server/Map/General/WishingWellServer.cpp index 8ac9e0b2..fa3e13e0 100644 --- a/dScripts/02_server/Map/General/WishingWellServer.cpp +++ b/dScripts/02_server/Map/General/WishingWellServer.cpp @@ -1,6 +1,8 @@ #include "WishingWellServer.h" #include "ScriptedActivityComponent.h" #include "GameMessages.h" +#include "Loot.h" +#include "EntityManager.h" void WishingWellServer::OnStartup(Entity* self) { } diff --git a/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp index 33436525..a338d9c9 100644 --- a/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp +++ b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp @@ -1,4 +1,5 @@ #include "NsConcertChoiceBuildManager.h" +#include "EntityInfo.h" #include "EntityManager.h" const std::vector NsConcertChoiceBuildManager::crates{ diff --git a/dScripts/02_server/Map/NS/NsLegoClubDoor.h b/dScripts/02_server/Map/NS/NsLegoClubDoor.h index 0a7a6ee0..db1dcae4 100644 --- a/dScripts/02_server/Map/NS/NsLegoClubDoor.h +++ b/dScripts/02_server/Map/NS/NsLegoClubDoor.h @@ -2,6 +2,7 @@ #include "CppScripts.h" #include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" +#include "AMFFormat.h" class NsLegoClubDoor : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer { diff --git a/dScripts/02_server/Map/NS/NsLupTeleport.h b/dScripts/02_server/Map/NS/NsLupTeleport.h index 35edf0bc..28bab016 100644 --- a/dScripts/02_server/Map/NS/NsLupTeleport.h +++ b/dScripts/02_server/Map/NS/NsLupTeleport.h @@ -2,6 +2,7 @@ #include "CppScripts.h" #include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" +#include "AMFFormat.h" class NsLupTeleport : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer { diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp index 2b88ccf8..d27ac1f6 100644 --- a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp +++ b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp @@ -1,6 +1,7 @@ #include "NtCombatChallengeServer.h" #include "GameMessages.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "InventoryComponent.h" #include "MissionComponent.h" diff --git a/dScripts/02_server/Map/NT/NtVandaServer.cpp b/dScripts/02_server/Map/NT/NtVandaServer.cpp index bfc35203..e5653005 100644 --- a/dScripts/02_server/Map/NT/NtVandaServer.cpp +++ b/dScripts/02_server/Map/NT/NtVandaServer.cpp @@ -1,5 +1,6 @@ #include "NtVandaServer.h" #include "InventoryComponent.h" +#include "MissionState.h" void NtVandaServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { diff --git a/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp index 96302a33..695bd92f 100644 --- a/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp +++ b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp @@ -1,6 +1,7 @@ #include "EnemySpiderSpawner.h" #include "GameMessages.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "DestroyableComponent.h" //---------------------------------------------- diff --git a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp index 788768ca..9e727f39 100644 --- a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp +++ b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp @@ -1,6 +1,7 @@ #include "PropertyBankInteract.h" #include "EntityManager.h" #include "GameMessages.h" +#include "AMFFormat.h" void PropertyBankInteract::OnStartup(Entity* self) { auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); diff --git a/dScripts/02_server/Map/VE/VeEpsilonServer.cpp b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp index cc6ecafe..4a2f1bbf 100644 --- a/dScripts/02_server/Map/VE/VeEpsilonServer.cpp +++ b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp @@ -2,6 +2,8 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "MissionState.h" +#include "Entity.h" void VeEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { auto* character = target->GetCharacter(); diff --git a/dScripts/02_server/Map/VE/VeMissionConsole.cpp b/dScripts/02_server/Map/VE/VeMissionConsole.cpp index 2a424c4d..534f8c06 100644 --- a/dScripts/02_server/Map/VE/VeMissionConsole.cpp +++ b/dScripts/02_server/Map/VE/VeMissionConsole.cpp @@ -2,6 +2,7 @@ #include "InventoryComponent.h" #include "Character.h" #include "GameMessages.h" +#include "Loot.h" void VeMissionConsole::OnUse(Entity* self, Entity* user) { LootGenerator::Instance().DropActivityLoot(user, self, 12551); diff --git a/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp index 451fa1d5..0e2e4005 100644 --- a/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp +++ b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp @@ -2,6 +2,7 @@ #include "SkillComponent.h" #include "RenderComponent.h" #include "EntityManager.h" +#include "EntityInfo.h" void EnemySkeletonSpawner::OnStartup(Entity* self) { self->SetProximityRadius(15, "ronin"); diff --git a/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp index fa4d8556..be9fcbd9 100644 --- a/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp +++ b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp @@ -1,5 +1,8 @@ #include "NjDragonEmblemChestServer.h" #include "Character.h" +#include "EntityInfo.h" +#include "Loot.h" +#include "Entity.h" #include "DestroyableComponent.h" void NjDragonEmblemChestServer::OnUse(Entity* self, Entity* user) { diff --git a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp index 19f5f42a..69838dc8 100644 --- a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp +++ b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp @@ -1,6 +1,7 @@ #include "NjNPCMissionSpinjitzuServer.h" #include "Character.h" #include "EntityManager.h" +#include "MissionState.h" void NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { diff --git a/dScripts/02_server/Map/njhub/RainOfArrows.cpp b/dScripts/02_server/Map/njhub/RainOfArrows.cpp index 141cd3ab..b7c4c074 100644 --- a/dScripts/02_server/Map/njhub/RainOfArrows.cpp +++ b/dScripts/02_server/Map/njhub/RainOfArrows.cpp @@ -1,6 +1,7 @@ #include "RainOfArrows.h" #include "EntityManager.h" #include "SkillComponent.h" +#include "EntityInfo.h" #include "GameMessages.h" void RainOfArrows::OnStartup(Entity* self) { diff --git a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp index 66222d59..7df8fc12 100644 --- a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp +++ b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp @@ -3,6 +3,7 @@ #include "TeamManager.h" #include "EntityManager.h" #include "dZoneManager.h" +#include "Loot.h" void MinigameTreasureChestServer::OnUse(Entity* self, Entity* user) { auto* sac = self->GetComponent(); diff --git a/dScripts/02_server/Objects/StinkyFishTarget.cpp b/dScripts/02_server/Objects/StinkyFishTarget.cpp index 19dbce88..21d92fac 100644 --- a/dScripts/02_server/Objects/StinkyFishTarget.cpp +++ b/dScripts/02_server/Objects/StinkyFishTarget.cpp @@ -1,5 +1,6 @@ #include "StinkyFishTarget.h" #include "EntityManager.h" +#include "EntityInfo.h" void StinkyFishTarget::OnStartup(Entity* self) { auto position = self->GetPosition(); diff --git a/dScripts/ActivityManager.cpp b/dScripts/ActivityManager.cpp index 36e85b11..078a7a02 100644 --- a/dScripts/ActivityManager.cpp +++ b/dScripts/ActivityManager.cpp @@ -5,6 +5,7 @@ #include "GameMessages.h" #include #include "dLogger.h" +#include "Loot.h" bool ActivityManager::IsPlayerInActivity(Entity* self, LWOOBJID playerID) { const auto* sac = self->GetComponent(); diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index e4a6d655..eb9b7a04 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -1,12 +1,13 @@ #pragma once -#include "dCommonVars.h" -#include "MissionState.h" + +#include #include #include class User; class Entity; class NiPoint3; +enum class MissionState : int32_t; namespace CppScripts { /** diff --git a/dScripts/NPCAddRemoveItem.cpp b/dScripts/NPCAddRemoveItem.cpp index ce47b12a..1985a02b 100644 --- a/dScripts/NPCAddRemoveItem.cpp +++ b/dScripts/NPCAddRemoveItem.cpp @@ -1,5 +1,6 @@ #include "NPCAddRemoveItem.h" #include "InventoryComponent.h" +#include "MissionState.h" void NPCAddRemoveItem::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { auto* inventory = target->GetComponent(); diff --git a/dScripts/ScriptedPowerupSpawner.cpp b/dScripts/ScriptedPowerupSpawner.cpp index 730e65ba..3c1d1cca 100644 --- a/dScripts/ScriptedPowerupSpawner.cpp +++ b/dScripts/ScriptedPowerupSpawner.cpp @@ -1,6 +1,7 @@ #include "ScriptedPowerupSpawner.h" #include "RenderComponent.h" #include "EntityManager.h" +#include "Loot.h" void ScriptedPowerupSpawner::OnTemplateStartup(Entity* self) { self->SetVar(u"currentCycle", 1); diff --git a/dScripts/SpawnPetBaseServer.cpp b/dScripts/SpawnPetBaseServer.cpp index 1d73a5b8..d3c87288 100644 --- a/dScripts/SpawnPetBaseServer.cpp +++ b/dScripts/SpawnPetBaseServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EntityManager.h" #include "PetComponent.h" +#include "EntityInfo.h" void SpawnPetBaseServer::OnStartup(Entity* self) { SetVariables(self); diff --git a/dScripts/ai/AG/AgImagSmashable.cpp b/dScripts/ai/AG/AgImagSmashable.cpp index 593294e5..195f7b9a 100644 --- a/dScripts/ai/AG/AgImagSmashable.cpp +++ b/dScripts/ai/AG/AgImagSmashable.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "GeneralUtils.h" #include "GameMessages.h" +#include "EntityInfo.h" #include "DestroyableComponent.h" void AgImagSmashable::OnDie(Entity* self, Entity* killer) { diff --git a/dScripts/ai/AG/AgPicnicBlanket.cpp b/dScripts/ai/AG/AgPicnicBlanket.cpp index 30fb2950..d2a54d57 100644 --- a/dScripts/ai/AG/AgPicnicBlanket.cpp +++ b/dScripts/ai/AG/AgPicnicBlanket.cpp @@ -1,5 +1,7 @@ #include "AgPicnicBlanket.h" +#include "Loot.h" #include "GameMessages.h" +#include "Entity.h" void AgPicnicBlanket::OnUse(Entity* self, Entity* user) { GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); diff --git a/dScripts/ai/AG/AgQbElevator.cpp b/dScripts/ai/AG/AgQbElevator.cpp index ccb4d3b1..f1ac7bb5 100644 --- a/dScripts/ai/AG/AgQbElevator.cpp +++ b/dScripts/ai/AG/AgQbElevator.cpp @@ -15,7 +15,7 @@ void AgQbElevator::OnRebuildComplete(Entity* self, Entity* target) { if (delayTime < 1) delayTime = 1; GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, MovementPlatformState::Stationary); + 0, 0, eMovementPlatformState::Stationary); //add a timer that will kill the QB if no players get on in the killTime self->AddTimer("startKillTimer", killTime); @@ -33,7 +33,7 @@ void AgQbElevator::OnProximityUpdate(Entity* self, Entity* entering, std::string self->CancelTimer("StartElevator"); GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); + 1, 1, eMovementPlatformState::Moving); } else if (!self->GetBoolean(u"StartTimer")) { self->SetBoolean(u"StartTimer", true); self->AddTimer("StartElevator", startTime); @@ -45,7 +45,7 @@ void AgQbElevator::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "StartElevator") { GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); + 1, 1, eMovementPlatformState::Moving); } else if (timerName == "startKillTimer") { killTimerStartup(self); } else if (timerName == "KillTimer") { diff --git a/dScripts/ai/AG/AgSpaceStuff.cpp b/dScripts/ai/AG/AgSpaceStuff.cpp index 80a87e70..30929ebf 100644 --- a/dScripts/ai/AG/AgSpaceStuff.cpp +++ b/dScripts/ai/AG/AgSpaceStuff.cpp @@ -1,4 +1,5 @@ #include "AgSpaceStuff.h" +#include "EntityInfo.h" #include "GeneralUtils.h" #include "GameMessages.h" #include "EntityManager.h" diff --git a/dScripts/ai/FV/FvPandaSpawnerServer.cpp b/dScripts/ai/FV/FvPandaSpawnerServer.cpp index e1f3fb96..d7dcabcd 100644 --- a/dScripts/ai/FV/FvPandaSpawnerServer.cpp +++ b/dScripts/ai/FV/FvPandaSpawnerServer.cpp @@ -2,6 +2,7 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EntityInfo.h" #include "ScriptedActivityComponent.h" void FvPandaSpawnerServer::OnCollisionPhantom(Entity* self, Entity* target) { diff --git a/dScripts/ai/GF/GfBanana.cpp b/dScripts/ai/GF/GfBanana.cpp index 3a71eded..95a831cd 100644 --- a/dScripts/ai/GF/GfBanana.cpp +++ b/dScripts/ai/GF/GfBanana.cpp @@ -2,6 +2,7 @@ #include "Entity.h" #include "DestroyableComponent.h" +#include "EntityInfo.h" #include "EntityManager.h" void GfBanana::SpawnBanana(Entity* self) { diff --git a/dScripts/ai/GF/PetDigBuild.cpp b/dScripts/ai/GF/PetDigBuild.cpp index ae159575..32e5b2e3 100644 --- a/dScripts/ai/GF/PetDigBuild.cpp +++ b/dScripts/ai/GF/PetDigBuild.cpp @@ -1,5 +1,6 @@ #include "PetDigBuild.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "MissionComponent.h" void PetDigBuild::OnRebuildComplete(Entity* self, Entity* target) { diff --git a/dScripts/ai/GF/PirateRep.cpp b/dScripts/ai/GF/PirateRep.cpp index eb4cf510..81d69672 100644 --- a/dScripts/ai/GF/PirateRep.cpp +++ b/dScripts/ai/GF/PirateRep.cpp @@ -1,5 +1,7 @@ #include "PirateRep.h" #include "Character.h" +#include "MissionState.h" +#include "Entity.h" void PirateRep::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { if (missionID == m_PirateRepMissionID && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 47bca374..db914c7f 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -11,6 +11,7 @@ #include "MovementAIComponent.h" #include "../dWorldServer/ObjectIDManager.h" #include "MissionComponent.h" +#include "Loot.h" #include "InventoryComponent.h" void SGCannon::OnStartup(Entity* self) { diff --git a/dScripts/ai/NS/WH/RockHydrantSmashable.cpp b/dScripts/ai/NS/WH/RockHydrantSmashable.cpp index d76eca8d..b3a01567 100644 --- a/dScripts/ai/NS/WH/RockHydrantSmashable.cpp +++ b/dScripts/ai/NS/WH/RockHydrantSmashable.cpp @@ -1,5 +1,6 @@ #include "RockHydrantSmashable.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "GeneralUtils.h" void RockHydrantSmashable::OnDie(Entity* self, Entity* killer) { diff --git a/dScripts/ai/PETS/HydrantSmashable.cpp b/dScripts/ai/PETS/HydrantSmashable.cpp index 20baa58b..1ff082ea 100644 --- a/dScripts/ai/PETS/HydrantSmashable.cpp +++ b/dScripts/ai/PETS/HydrantSmashable.cpp @@ -1,5 +1,6 @@ #include "HydrantSmashable.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "GeneralUtils.h" void HydrantSmashable::OnDie(Entity* self, Entity* killer) { diff --git a/dScripts/ai/PROPERTY/AgPropguards.cpp b/dScripts/ai/PROPERTY/AgPropguards.cpp index 674c4bdd..2bcfcf94 100644 --- a/dScripts/ai/PROPERTY/AgPropguards.cpp +++ b/dScripts/ai/PROPERTY/AgPropguards.cpp @@ -3,6 +3,7 @@ #include "GameMessages.h" #include "EntityManager.h" #include "dZoneManager.h" +#include "MissionState.h" void AgPropguards::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { auto* character = target->GetCharacter(); diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 73157c09..b655bef3 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -42,6 +42,9 @@ #include "CharacterComponent.h" #include "EntityManager.h" +#include "EntityInfo.h" +#include "User.h" +#include "Loot.h" #include "Entity.h" #include "Character.h" #include "ChatPackets.h" @@ -58,6 +61,8 @@ #include "AssetManager.h" #include "LevelProgressionComponent.h" #include "eBlueprintSaveResponseType.h" +#include "AMFFormat.h" +#include "NiPoint3.h" #include "ZCompression.h" diff --git a/dZoneManager/LUTriggers.h b/dZoneManager/LUTriggers.h new file mode 100644 index 00000000..1869b4c3 --- /dev/null +++ b/dZoneManager/LUTriggers.h @@ -0,0 +1,30 @@ +#ifndef __LUTRIGGERS__H__ +#define __LUTRIGGERS__H__ + +#include +#include + +class Command; +class Event; + +namespace LUTriggers { + struct Command { + std::string id; + std::string target; + std::string targetName; + std::string args; + }; + + struct Event { + std::string eventID; + std::vector commands; + }; + + struct Trigger { + uint32_t id; + bool enabled; + std::vector events; + }; +}; + +#endif //!__LUTRIGGERS__H__ diff --git a/dZoneManager/Spawner.h b/dZoneManager/Spawner.h index 908bb3a3..a42c8a65 100644 --- a/dZoneManager/Spawner.h +++ b/dZoneManager/Spawner.h @@ -9,6 +9,7 @@ #include #include #include "LDFFormat.h" +#include "EntityInfo.h" struct SpawnerNode { NiPoint3 position = NiPoint3::ZERO; diff --git a/dZoneManager/Zone.cpp b/dZoneManager/Zone.cpp index ec73237e..79d940af 100644 --- a/dZoneManager/Zone.cpp +++ b/dZoneManager/Zone.cpp @@ -6,6 +6,7 @@ #include "dLogger.h" #include "GeneralUtils.h" #include "BinaryIO.h" +#include "LUTriggers.h" #include "AssetManager.h" #include "CDClientManager.h" diff --git a/dZoneManager/Zone.h b/dZoneManager/Zone.h index 978438aa..9c5322a1 100644 --- a/dZoneManager/Zone.h +++ b/dZoneManager/Zone.h @@ -1,35 +1,18 @@ #pragma once + #include "dZMCommon.h" #include "LDFFormat.h" -#include "../thirdparty/tinyxml2/tinyxml2.h" +#include "tinyxml2.h" #include #include #include -class Level; - -class LUTriggers { -public: - - struct Command { - std::string id; - std::string target; - std::string targetName; - std::string args; - }; - - struct Event { - std::string eventID; - std::vector commands; - }; - - struct Trigger { - uint32_t id; - bool enabled; - std::vector events; - }; +namespace LUTriggers { + struct Trigger; }; +class Level; + struct SceneRef { std::string filename; uint32_t id; @@ -110,11 +93,11 @@ enum class PropertyPathType : int32_t { GenetatedRectangle = 2 }; -enum class PropertyType : int32_t{ +enum class PropertyType : int32_t { Premiere = 0, - Prize = 1, - LUP = 2, - Headspace = 3 + Prize = 1, + LUP = 2, + Headspace = 3 }; enum class PropertyRentalTimeUnit : int32_t { @@ -222,7 +205,7 @@ public: uint32_t GetWorldID() const { return m_WorldID; } [[nodiscard]] std::string GetZoneName() const { return m_ZoneName; } - std::string GetZoneRawPath() const { return m_ZoneRawPath;} + std::string GetZoneRawPath() const { return m_ZoneRawPath; } std::string GetZonePath() const { return m_ZonePath; } const NiPoint3& GetSpawnPos() const { return m_Spawnpoint; } @@ -254,7 +237,7 @@ private: uint32_t m_PathDataLength; uint32_t m_PathChunkVersion; - std::vector m_Paths; + std::vector m_Paths; std::map m_MapRevisions; //rhs is the revision! diff --git a/tests/dGameTests/GameDependencies.h b/tests/dGameTests/GameDependencies.h index ee52dec6..81875ab6 100644 --- a/tests/dGameTests/GameDependencies.h +++ b/tests/dGameTests/GameDependencies.h @@ -4,6 +4,7 @@ #include "Game.h" #include "dLogger.h" #include "dServer.h" +#include "EntityInfo.h" #include "EntityManager.h" #include From 1ac898ba000b7a6e075163a64c1f94c8d3682a97 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 6 Jan 2023 21:21:40 -0800 Subject: [PATCH 59/63] Remove GameConfig (#874) * Remove GameConfig * Fully remove GmeConfig * Update worldconfig.ini Co-authored-by: Aaron Kimbrell --- dCommon/dConfig.h | 1 - dGame/dGameMessages/GameMessages.cpp | 3 +- dGame/dUtilities/CMakeLists.txt | 1 - dGame/dUtilities/GameConfig.cpp | 50 ------------------------ dGame/dUtilities/GameConfig.h | 38 ------------------ dGame/dUtilities/SlashCommandHandler.cpp | 20 ---------- docs/Commands.md | 2 - resources/worldconfig.ini | 3 ++ 8 files changed, 4 insertions(+), 114 deletions(-) delete mode 100644 dGame/dUtilities/GameConfig.cpp delete mode 100644 dGame/dUtilities/GameConfig.h diff --git a/dCommon/dConfig.h b/dCommon/dConfig.h index a6dd5df7..562c1ce9 100644 --- a/dCommon/dConfig.h +++ b/dCommon/dConfig.h @@ -24,7 +24,6 @@ public: * Reloads the config file to reset values */ void ReloadConfig(); - private: void ProcessLine(const std::string& line); diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 24f0816d..634e6a1e 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -25,7 +25,6 @@ #include "dConfig.h" #include "TeamManager.h" #include "ChatPackets.h" -#include "GameConfig.h" #include "RocketLaunchLupComponent.h" #include "eUnequippableActiveType.h" #include "eMovementPlatformState.h" @@ -1005,7 +1004,7 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& } void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos, int count) { - if (GameConfig::GetValue("no_drops") == 1) { + if (Game::config->GetValue("disable_drops") == "1") { return; } diff --git a/dGame/dUtilities/CMakeLists.txt b/dGame/dUtilities/CMakeLists.txt index 2c453a2e..55ca5797 100644 --- a/dGame/dUtilities/CMakeLists.txt +++ b/dGame/dUtilities/CMakeLists.txt @@ -1,5 +1,4 @@ set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp" - "GameConfig.cpp" "GUID.cpp" "Loot.cpp" "Mail.cpp" diff --git a/dGame/dUtilities/GameConfig.cpp b/dGame/dUtilities/GameConfig.cpp deleted file mode 100644 index ad201e6f..00000000 --- a/dGame/dUtilities/GameConfig.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "GameConfig.h" -#include - -std::map GameConfig::m_Config{}; -std::string GameConfig::m_EmptyString{}; - -void GameConfig::Load(const std::string& filepath) { - m_EmptyString = ""; - std::ifstream in(filepath); - if (!in.good()) return; - - std::string line; - while (std::getline(in, line)) { - if (line.length() > 0) { - if (line[0] != '#') ProcessLine(line); - } - } -} - -const std::string& GameConfig::GetValue(const std::string& key) { - const auto& it = m_Config.find(key); - - if (it != m_Config.end()) { - return it->second; - } - - return m_EmptyString; -} - -void GameConfig::SetValue(const std::string& key, const std::string& value) { - m_Config.insert_or_assign(key, value); -} - -void GameConfig::ProcessLine(const std::string& line) { - std::stringstream ss(line); - std::string segment; - std::vector seglist; - - while (std::getline(ss, segment, '=')) { - seglist.push_back(segment); - } - - if (seglist.size() != 2) return; - - //Make sure that on Linux, we remove special characters: - if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r') - seglist[1].erase(seglist[1].size() - 1); - - m_Config.insert_or_assign(seglist[0], seglist[1]); -} diff --git a/dGame/dUtilities/GameConfig.h b/dGame/dUtilities/GameConfig.h deleted file mode 100644 index 55089f89..00000000 --- a/dGame/dUtilities/GameConfig.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include "GeneralUtils.h" - -class GameConfig { -public: - static void Load(const std::string& filepath); - - static const std::string& GetValue(const std::string& key); - - static void SetValue(const std::string& key, const std::string& value); - - template - static T GetValue(const std::string& key) { - T value; - - if (GeneralUtils::TryParse(GetValue(key), value)) { - return value; - } - - return T(); - } - - template - static void SetValue(const std::string& key, const T& value) { - SetValue(key, std::to_string(value)); - } - -private: - static void ProcessLine(const std::string& line); - - static std::map m_Config; - static std::string m_EmptyString; -}; diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 2192fafb..9ee4c1e6 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -63,7 +63,6 @@ #include "BuffComponent.h" #include "SkillComponent.h" #include "VanityUtilities.h" -#include "GameConfig.h" #include "ScriptedActivityComponent.h" #include "LevelProgressionComponent.h" #include "AssetManager.h" @@ -1701,25 +1700,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "config-set" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 2) { - GameConfig::SetValue(args[0], args[1]); - - ChatPackets::SendSystemMessage( - sysAddr, u"Set config value: " + GeneralUtils::UTF8ToUTF16(args[0]) + u" to " + GeneralUtils::UTF8ToUTF16(args[1]) - ); - } - - if (chatCommand == "config-get" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { - const auto& value = GameConfig::GetValue(args[0]); - - std::u16string u16key = GeneralUtils::UTF8ToUTF16(args[0]); - if (value.empty()) { - ChatPackets::SendSystemMessage(sysAddr, u"No value found for " + u16key); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Value for " + u16key + u": " + GeneralUtils::UTF8ToUTF16(value)); - } - } - if (chatCommand == "metrics" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { for (const auto variable : Metrics::GetAllMetrics()) { auto* metric = Metrics::GetMetric(variable); diff --git a/docs/Commands.md b/docs/Commands.md index 060c2ba0..7c4f494f 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -36,8 +36,6 @@ |Command|Usage|Description|Admin Level Requirement| |--- |--- |--- |--- | |announce|`/announce`|Sends a announcement. `/setanntitle` and `/setannmsg` must be called first to configure the announcement.|8| -|config-set|`/config-set `|Set configuration item.|8| -|config-get|`/config-get `|Get current value of a configuration item.|8| |kill|`/kill `|Smashes the character whom the given user is playing.|8| |metrics|`/metrics`|Prints some information about the server's performance.|8| |setannmsg|`/setannmsg `|Sets the message of an announcement.|8| diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index ee6b6651..0c24c447 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -43,3 +43,6 @@ pets_take_imagination=1 # If you would like to increase the maximum number of best friends a player can have on the server # Change the value below to what you would like this to be (5 is live accurate) max_number_of_best_friends=5 + +# Disables loot drops +disable_drops=0 From 80f8dd800374e6cfd1597c17a8d493ca2b9cfa61 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell <aronwk.aaron@gmail.com> Date: Fri, 6 Jan 2023 23:59:19 -0600 Subject: [PATCH 60/63] Imminuty updates (#925) * WIP Immunities * Immunity getters * remove redundent variable replace it use with it's equivalent * remove unused lookups, fix typos * fix tests * added imunity test * address feedback * more immunity tests * explicit this --- dCommon/dEnums/dCommonVars.h | 2 +- dCommon/dEnums/dMessageIdentifiers.h | 2 + dGame/dBehaviors/ImmunityBehavior.cpp | 94 +++++-- dGame/dBehaviors/ImmunityBehavior.h | 23 +- .../ControllablePhysicsComponent.cpp | 58 ++++- .../ControllablePhysicsComponent.h | 35 +++ dGame/dComponents/DestroyableComponent.cpp | 77 +++++- dGame/dComponents/DestroyableComponent.h | 51 +++- dGame/dComponents/InventoryComponent.cpp | 2 +- dGame/dComponents/PossessorComponent.cpp | 2 +- dGame/dComponents/RailActivatorComponent.cpp | 4 +- dGame/dGameMessages/GameMessages.cpp | 67 ++++- dGame/dGameMessages/GameMessages.h | 31 ++- .../02_server/Enemy/General/BaseEnemyApe.cpp | 2 +- dScripts/02_server/Map/AM/AmSkullkinDrill.cpp | 6 +- .../02_server/Map/GF/GfCaptainsCannon.cpp | 4 +- dScripts/02_server/Map/GF/MastTeleport.cpp | 4 +- .../02_server/Map/NT/NtAssemblyTubeServer.cpp | 4 +- .../02_server/Map/NT/NtParadoxPanelServer.cpp | 4 +- .../02_server/Map/NT/NtParadoxTeleServer.cpp | 4 +- .../Map/NT/NtVentureCannonServer.cpp | 4 +- dScripts/BaseConsoleTeleportServer.cpp | 10 +- .../EquipmentScripts/PersonalFortress.cpp | 49 ++-- .../ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp | 2 +- .../DestroyableComponentTests.cpp | 239 +++++++++++++++++- 25 files changed, 681 insertions(+), 99 deletions(-) diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index 1fd5d071..9bf824e0 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -366,7 +366,7 @@ enum eControlSceme { SCHEME_WEAR_A_ROBOT //== freecam? }; -enum eStunState { +enum class eStateChangeType : uint32_t { PUSH, POP }; diff --git a/dCommon/dEnums/dMessageIdentifiers.h b/dCommon/dEnums/dMessageIdentifiers.h index 129585a0..ed4167c8 100644 --- a/dCommon/dEnums/dMessageIdentifiers.h +++ b/dCommon/dEnums/dMessageIdentifiers.h @@ -293,6 +293,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_POP_EQUIPPED_ITEMS_STATE = 192, GAME_MSG_SET_GM_LEVEL = 193, GAME_MSG_SET_STUNNED = 198, + GAME_MSG_SET_STUN_IMMUNITY = 200, GAME_MSG_KNOCKBACK = 202, GAME_MSG_REBUILD_CANCEL = 209, GAME_MSG_ENABLE_REBUILD = 213, @@ -512,6 +513,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_UPDATE_CHAT_MODE = 1395, GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE = 1396, GAME_MSG_SET_CONSUMABLE_ITEM = 1409, + GAME_MSG_SET_STATUS_IMMUNITY = 1435, GAME_MSG_SET_PET_NAME_MODERATED = 1448, GAME_MSG_MODIFY_LEGO_SCORE = 1459, GAME_MSG_RESTORE_TO_POST_LOAD_STATS = 1468, diff --git a/dGame/dBehaviors/ImmunityBehavior.cpp b/dGame/dBehaviors/ImmunityBehavior.cpp index 69c652f9..f4a41c52 100644 --- a/dGame/dBehaviors/ImmunityBehavior.cpp +++ b/dGame/dBehaviors/ImmunityBehavior.cpp @@ -6,28 +6,47 @@ #include "Game.h" #include "dLogger.h" #include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) { + if (!target) { Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); - return; } - auto* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - - if (destroyable == nullptr) { - return; + auto* destroyableComponent = target->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, + this->m_ImmuneToBasicAttack, + this->m_ImmuneToDamageOverTime, + this->m_ImmuneToKnockback, + this->m_ImmuneToInterrupt, + this->m_ImmuneToSpeed, + this->m_ImmuneToImaginationGain, + this->m_ImmuneToImaginationLoss, + this->m_ImmuneToQuickbuildInterrupt, + this->m_ImmuneToPullToPoint + ); } - if (!this->m_immuneBasicAttack) { - return; + auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, + context->caster, + this->m_ImmuneToStunAttack, + this->m_ImmuneToStunEquip, + this->m_ImmuneToStunInteract, + this->m_ImmuneToStunJump, + this->m_ImmuneToStunMove, + this->m_ImmuneToStunTurn, + this->m_ImmuneToStunUseItem + ); } - destroyable->PushImmunity(); - context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } @@ -38,21 +57,60 @@ void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bi void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(second); - if (target == nullptr) { + if (!target) { Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second); - return; } - auto* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - - if (destroyable == nullptr) { - return; + auto* destroyableComponent = target->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::POP, + this->m_ImmuneToBasicAttack, + this->m_ImmuneToDamageOverTime, + this->m_ImmuneToKnockback, + this->m_ImmuneToInterrupt, + this->m_ImmuneToSpeed, + this->m_ImmuneToImaginationGain, + this->m_ImmuneToImaginationLoss, + this->m_ImmuneToQuickbuildInterrupt, + this->m_ImmuneToPullToPoint + ); + } + + auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::POP, + context->caster, + this->m_ImmuneToStunAttack, + this->m_ImmuneToStunEquip, + this->m_ImmuneToStunInteract, + this->m_ImmuneToStunJump, + this->m_ImmuneToStunMove, + this->m_ImmuneToStunTurn, + this->m_ImmuneToStunUseItem + ); } - destroyable->PopImmunity(); } void ImmunityBehavior::Load() { - this->m_immuneBasicAttack = GetBoolean("immune_basic_attack"); + //Stun + this->m_ImmuneToStunAttack = GetBoolean("immune_stun_attack", false); + this->m_ImmuneToStunEquip = GetBoolean("immune_stun_equip", false); + this->m_ImmuneToStunInteract = GetBoolean("immune_stun_interact", false); + this->m_ImmuneToStunMove = GetBoolean("immune_stun_move", false); + this->m_ImmuneToStunTurn = GetBoolean("immune_stun_rotate", false); + + // Status + this->m_ImmuneToBasicAttack = GetBoolean("immune_basic_attack", false); + this->m_ImmuneToDamageOverTime = GetBoolean("immune_damage_over_time", false); + this->m_ImmuneToKnockback = GetBoolean("immune_knockback", false); + this->m_ImmuneToInterrupt = GetBoolean("immune_interrupt", false); + this->m_ImmuneToSpeed = GetBoolean("immune_speed", false); + this->m_ImmuneToImaginationGain = GetBoolean("immune_imagination_gain", false); + this->m_ImmuneToImaginationLoss = GetBoolean("immune_imagination_loss", false); + this->m_ImmuneToQuickbuildInterrupt = GetBoolean("immune_quickbuild_interrupts", false); + this->m_ImmuneToPullToPoint = GetBoolean("immune_pulltopoint", false); } diff --git a/dGame/dBehaviors/ImmunityBehavior.h b/dGame/dBehaviors/ImmunityBehavior.h index f9409e4c..02cc0fae 100644 --- a/dGame/dBehaviors/ImmunityBehavior.h +++ b/dGame/dBehaviors/ImmunityBehavior.h @@ -4,8 +4,6 @@ class ImmunityBehavior final : public Behavior { public: - uint32_t m_immuneBasicAttack; - /* * Inherited */ @@ -20,4 +18,25 @@ public: void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void Load() override; + +private: + // stuns + bool m_ImmuneToStunAttack = false; + bool m_ImmuneToStunEquip = false; + bool m_ImmuneToStunInteract = false; + bool m_ImmuneToStunJump = false; // Unused + bool m_ImmuneToStunMove = false; + bool m_ImmuneToStunTurn = false; + bool m_ImmuneToStunUseItem = false; // Unused + + //status + bool m_ImmuneToBasicAttack = false; + bool m_ImmuneToDamageOverTime = false; + bool m_ImmuneToKnockback = false; + bool m_ImmuneToInterrupt = false; + bool m_ImmuneToSpeed = false; + bool m_ImmuneToImaginationGain = false; + bool m_ImmuneToImaginationLoss = false; + bool m_ImmuneToQuickbuildInterrupt = false; + bool m_ImmuneToPullToPoint = false; // Unused in cdclient, but used in client }; diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index a5e447c8..2920a84f 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -35,6 +35,14 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com m_DirtyPickupRadiusScale = true; m_IsTeleporting = false; + m_ImmuneToStunAttackCount = 0; + m_ImmuneToStunEquipCount = 0; + m_ImmuneToStunInteractCount = 0; + m_ImmuneToStunJumpCount = 0; + m_ImmuneToStunMoveCount = 0; + m_ImmuneToStunTurnCount = 0; + m_ImmuneToStunUseItemCount = 0; + if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI return; @@ -71,7 +79,14 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo outBitStream->Write(m_JetpackBypassChecks); } - outBitStream->Write0(); //This contains info about immunities, but for now I'm leaving it out. + outBitStream->Write1(); // always write these on construction + outBitStream->Write(m_ImmuneToStunMoveCount); + outBitStream->Write(m_ImmuneToStunJumpCount); + outBitStream->Write(m_ImmuneToStunTurnCount); + outBitStream->Write(m_ImmuneToStunAttackCount); + outBitStream->Write(m_ImmuneToStunUseItemCount); + outBitStream->Write(m_ImmuneToStunEquipCount); + outBitStream->Write(m_ImmuneToStunInteractCount); } if (m_IgnoreMultipliers) m_DirtyCheats = false; @@ -298,3 +313,44 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) { SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed EntityManager::Instance()->SerializeEntity(m_Parent); } + +void ControllablePhysicsComponent::SetStunImmunity( + const eStateChangeType state, + const LWOOBJID originator, + const bool bImmuneToStunAttack, + const bool bImmuneToStunEquip, + const bool bImmuneToStunInteract, + const bool bImmuneToStunJump, + const bool bImmuneToStunMove, + const bool bImmuneToStunTurn, + const bool bImmuneToStunUseItem){ + + if (state == eStateChangeType::POP){ + if (bImmuneToStunAttack && m_ImmuneToStunAttackCount > 0) m_ImmuneToStunAttackCount -= 1; + if (bImmuneToStunEquip && m_ImmuneToStunEquipCount > 0) m_ImmuneToStunEquipCount -= 1; + if (bImmuneToStunInteract && m_ImmuneToStunInteractCount > 0) m_ImmuneToStunInteractCount -= 1; + if (bImmuneToStunJump && m_ImmuneToStunJumpCount > 0) m_ImmuneToStunJumpCount -= 1; + if (bImmuneToStunMove && m_ImmuneToStunMoveCount > 0) m_ImmuneToStunMoveCount -= 1; + if (bImmuneToStunTurn && m_ImmuneToStunTurnCount > 0) m_ImmuneToStunTurnCount -= 1; + if (bImmuneToStunUseItem && m_ImmuneToStunUseItemCount > 0) m_ImmuneToStunUseItemCount -= 1; + } else if (state == eStateChangeType::PUSH) { + if (bImmuneToStunAttack) m_ImmuneToStunAttackCount += 1; + if (bImmuneToStunEquip) m_ImmuneToStunEquipCount += 1; + if (bImmuneToStunInteract) m_ImmuneToStunInteractCount += 1; + if (bImmuneToStunJump) m_ImmuneToStunJumpCount += 1; + if (bImmuneToStunMove) m_ImmuneToStunMoveCount += 1; + if (bImmuneToStunTurn) m_ImmuneToStunTurnCount += 1; + if (bImmuneToStunUseItem) m_ImmuneToStunUseItemCount += 1; + } + + GameMessages::SendSetStunImmunity( + m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), originator, + bImmuneToStunAttack, + bImmuneToStunEquip, + bImmuneToStunInteract, + bImmuneToStunJump, + bImmuneToStunMove, + bImmuneToStunTurn, + bImmuneToStunUseItem + ); +} diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index e029d607..ba3e1bf4 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -264,6 +264,30 @@ public: std::vector<float> GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; }; + /** + * Push or Pop a layer of stun immunity to this entity + */ + void SetStunImmunity( + const eStateChangeType state, + const LWOOBJID originator = LWOOBJID_EMPTY, + const bool bImmuneToStunAttack = false, + const bool bImmuneToStunEquip = false, + const bool bImmuneToStunInteract = false, + const bool bImmuneToStunJump = false, + const bool bImmuneToStunMove = false, + const bool bImmuneToStunTurn = false, + const bool bImmuneToStunUseItem = false + ); + + // getters for stun immunities + const bool GetImmuneToStunAttack() { return m_ImmuneToStunAttackCount > 0;}; + const bool GetImmuneToStunEquip() { return m_ImmuneToStunEquipCount > 0;}; + const bool GetImmuneToStunInteract() { return m_ImmuneToStunInteractCount > 0;}; + const bool GetImmuneToStunJump() { return m_ImmuneToStunJumpCount > 0;}; + const bool GetImmuneToStunMove() { return m_ImmuneToStunMoveCount > 0;}; + const bool GetImmuneToStunTurn() { return m_ImmuneToStunTurnCount > 0;}; + const bool GetImmuneToStunUseItem() { return m_ImmuneToStunUseItemCount > 0;}; + private: /** * The entity that owns this component @@ -389,6 +413,17 @@ private: * The active speed boost for this entity */ float m_SpeedBoost; + + /** + * stun immunity counters + */ + int32_t m_ImmuneToStunAttackCount; + int32_t m_ImmuneToStunEquipCount; + int32_t m_ImmuneToStunInteractCount; + int32_t m_ImmuneToStunJumpCount; + int32_t m_ImmuneToStunMoveCount; + int32_t m_ImmuneToStunTurnCount; + int32_t m_ImmuneToStunUseItemCount; }; #endif // CONTROLLABLEPHYSICSCOMPONENT_H diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 1b127c41..3e146335 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -55,8 +55,17 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { m_LootMatrixID = 0; m_MinCoins = 0; m_MaxCoins = 0; - m_ImmuneStacks = 0; m_DamageReduction = 0; + + m_ImmuneToBasicAttackCount = 0; + m_ImmuneToDamageOverTimeCount = 0; + m_ImmuneToKnockbackCount = 0; + m_ImmuneToInterruptCount = 0; + m_ImmuneToSpeedCount = 0; + m_ImmuneToImaginationGainCount = 0; + m_ImmuneToImaginationLossCount = 0; + m_ImmuneToQuickbuildInterruptCount = 0; + m_ImmuneToPullToPointCount = 0; } DestroyableComponent::~DestroyableComponent() { @@ -106,7 +115,16 @@ void DestroyableComponent::Reinitialize(LOT templateID) { void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) { if (bIsInitialUpdate) { - outBitStream->Write0(); //Contains info about immunities this object has, but it's left out for now. + outBitStream->Write1(); // always write these on construction + outBitStream->Write(m_ImmuneToBasicAttackCount); + outBitStream->Write(m_ImmuneToDamageOverTimeCount); + outBitStream->Write(m_ImmuneToKnockbackCount); + outBitStream->Write(m_ImmuneToInterruptCount); + outBitStream->Write(m_ImmuneToSpeedCount); + outBitStream->Write(m_ImmuneToImaginationGainCount); + outBitStream->Write(m_ImmuneToImaginationLossCount); + outBitStream->Write(m_ImmuneToQuickbuildInterruptCount); + outBitStream->Write(m_ImmuneToPullToPointCount); } outBitStream->Write(m_DirtyHealth || bIsInitialUpdate); @@ -336,7 +354,7 @@ void DestroyableComponent::SetDamageReduction(int32_t value) { void DestroyableComponent::SetIsImmune(bool value) { m_DirtyHealth = true; - m_ImmuneStacks = value ? 1 : 0; + m_ImmuneToBasicAttackCount = value ? 1 : 0; } void DestroyableComponent::SetIsGMImmune(bool value) { @@ -439,7 +457,7 @@ void DestroyableComponent::SetAttacksToBlock(const uint32_t value) { } bool DestroyableComponent::IsImmune() const { - return m_ImmuneStacks > 0 || m_IsGMImmune; + return m_IsGMImmune || m_ImmuneToBasicAttackCount > 0; } bool DestroyableComponent::IsKnockbackImmune() const { @@ -804,12 +822,53 @@ void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) { AddFaction(factionID, ignoreChecks); } -void DestroyableComponent::PushImmunity(int32_t stacks) { - m_ImmuneStacks += stacks; -} +void DestroyableComponent::SetStatusImmunity( + const eStateChangeType state, + const bool bImmuneToBasicAttack, + const bool bImmuneToDamageOverTime, + const bool bImmuneToKnockback, + const bool bImmuneToInterrupt, + const bool bImmuneToSpeed, + const bool bImmuneToImaginationGain, + const bool bImmuneToImaginationLoss, + const bool bImmuneToQuickbuildInterrupt, + const bool bImmuneToPullToPoint) { -void DestroyableComponent::PopImmunity(int32_t stacks) { - m_ImmuneStacks -= stacks; + if (state == eStateChangeType::POP) { + if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1; + if (bImmuneToDamageOverTime && m_ImmuneToDamageOverTimeCount > 0) m_ImmuneToDamageOverTimeCount -= 1; + if (bImmuneToKnockback && m_ImmuneToKnockbackCount > 0) m_ImmuneToKnockbackCount -= 1; + if (bImmuneToInterrupt && m_ImmuneToInterruptCount > 0) m_ImmuneToInterruptCount -= 1; + if (bImmuneToSpeed && m_ImmuneToSpeedCount > 0) m_ImmuneToSpeedCount -= 1; + if (bImmuneToImaginationGain && m_ImmuneToImaginationGainCount > 0) m_ImmuneToImaginationGainCount -= 1; + if (bImmuneToImaginationLoss && m_ImmuneToImaginationLossCount > 0) m_ImmuneToImaginationLossCount -= 1; + if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1; + if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1; + + } else if (state == eStateChangeType::PUSH){ + if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1; + if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1; + if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1; + if (bImmuneToInterrupt) m_ImmuneToInterruptCount += 1; + if (bImmuneToSpeed) m_ImmuneToSpeedCount += 1; + if (bImmuneToImaginationGain) m_ImmuneToImaginationGainCount += 1; + if (bImmuneToImaginationLoss) m_ImmuneToImaginationLossCount += 1; + if (bImmuneToQuickbuildInterrupt) m_ImmuneToQuickbuildInterruptCount += 1; + if (bImmuneToPullToPoint) m_ImmuneToPullToPointCount += 1; + } + + GameMessages::SendSetStatusImmunity( + m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), + bImmuneToBasicAttack, + bImmuneToDamageOverTime, + bImmuneToKnockback, + bImmuneToInterrupt, + bImmuneToSpeed, + bImmuneToImaginationGain, + bImmuneToImaginationLoss, + bImmuneToQuickbuildInterrupt, + bImmuneToPullToPoint + ); } void DestroyableComponent::FixStats() { diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index 5bb990a7..2736f47c 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -396,16 +396,31 @@ public: void Smash(LWOOBJID source, eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"", uint32_t skillID = 0); /** - * Pushes a layer of immunity to this entity, making it immune for longer - * @param stacks the amount of immunity to add + * Push or Pop a layer of status immunity to this entity */ - void PushImmunity(int32_t stacks = 1); + void SetStatusImmunity( + const eStateChangeType state, + const bool bImmuneToBasicAttack = false, + const bool bImmuneToDamageOverTime = false, + const bool bImmuneToKnockback = false, + const bool bImmuneToInterrupt = false, + const bool bImmuneToSpeed = false, + const bool bImmuneToImaginationGain = false, + const bool bImmuneToImaginationLoss = false, + const bool bImmuneToQuickbuildInterrupt = false, + const bool bImmuneToPullToPoint = false + ); - /** - * Pops layers of immunity, making it immune for less longer - * @param stacks the number of layers of immunity to remove - */ - void PopImmunity(int32_t stacks = 1); + // Getters for status immunities + const bool GetImmuneToBasicAttack() {return m_ImmuneToBasicAttackCount > 0;}; + const bool GetImmuneToDamageOverTime() {return m_ImmuneToDamageOverTimeCount > 0;}; + const bool GetImmuneToKnockback() {return m_ImmuneToKnockbackCount > 0;}; + const bool GetImmuneToInterrupt() {return m_ImmuneToInterruptCount > 0;}; + const bool GetImmuneToSpeed() {return m_ImmuneToSpeedCount > 0;}; + const bool GetImmuneToImaginationGain() {return m_ImmuneToImaginationGainCount > 0;}; + const bool GetImmuneToImaginationLoss() {return m_ImmuneToImaginationLossCount > 0;}; + const bool GetImmuneToQuickbuildInterrupt() {return m_ImmuneToQuickbuildInterruptCount > 0;}; + const bool GetImmuneToPullToPoint() {return m_ImmuneToPullToPointCount > 0;}; /** * Utility to reset all stats to the default stats based on items and completed missions @@ -428,7 +443,7 @@ public: /** * Notify subscribed scripts of Damage actions. - * + * * @param attacker The attacking Entity * @param damage The amount of damage that was done */ @@ -493,11 +508,6 @@ private: */ uint32_t m_AttacksToBlock; - /** - * The layers of immunity this entity has left - */ - int32_t m_ImmuneStacks; - /** * The amount of damage that should be reduced from every attack */ @@ -577,6 +587,19 @@ private: * The list of scripts subscribed to this components actions */ std::map<LWOOBJID, CppScripts::Script*> m_SubscribedScripts; + + /** + * status immunity counters + */ + uint32_t m_ImmuneToBasicAttackCount; + uint32_t m_ImmuneToDamageOverTimeCount; + uint32_t m_ImmuneToKnockbackCount; + uint32_t m_ImmuneToInterruptCount; + uint32_t m_ImmuneToSpeedCount; + uint32_t m_ImmuneToImaginationGainCount; + uint32_t m_ImmuneToImaginationLossCount; + uint32_t m_ImmuneToQuickbuildInterruptCount; + uint32_t m_ImmuneToPullToPointCount; }; #endif // DESTROYABLECOMPONENT_H diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 6247f32d..e5ff2f2a 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -959,7 +959,7 @@ void InventoryComponent::HandlePossession(Item* item) { return; } - GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); // Set the mount Item ID so that we know what were handling possessorComponent->SetMountItemID(item->GetId()); diff --git a/dGame/dComponents/PossessorComponent.cpp b/dGame/dComponents/PossessorComponent.cpp index f0cad5ca..69046c3b 100644 --- a/dGame/dComponents/PossessorComponent.cpp +++ b/dGame/dComponents/PossessorComponent.cpp @@ -54,7 +54,7 @@ void PossessorComponent::Mount(Entity* mount) { // GM's to send GameMessages::SendSetJetPackMode(m_Parent, false); GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress()); - GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(mount); diff --git a/dGame/dComponents/RailActivatorComponent.cpp b/dGame/dComponents/RailActivatorComponent.cpp index 1b94fc4a..25fad26e 100644 --- a/dGame/dComponents/RailActivatorComponent.cpp +++ b/dGame/dComponents/RailActivatorComponent.cpp @@ -95,7 +95,7 @@ void RailActivatorComponent::OnUse(Entity* originator) { void RailActivatorComponent::OnRailMovementReady(Entity* originator) const { // Stun the originator - GameMessages::SendSetStunned(originator->GetObjectID(), PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -123,7 +123,7 @@ void RailActivatorComponent::OnRailMovementReady(Entity* originator) const { void RailActivatorComponent::OnCancelRailMovement(Entity* originator) { // Remove the stun from the originator - GameMessages::SendSetStunned(originator->GetObjectID(), POP, originator->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::POP, originator->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 634e6a1e..c6c7d2d1 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -2904,7 +2904,7 @@ void GameMessages::HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* en } } -void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr, +void GameMessages::SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator, bool bCantAttack, bool bCantEquip, bool bCantInteract, bool bCantJump, bool bCantMove, bool bCantTurn, bool bCantUseItem, bool bDontTerminateInteract, bool bIgnoreImmunity, @@ -2952,6 +2952,69 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, SEND_PACKET; } +void GameMessages::SendSetStunImmunity(LWOOBJID target, eStateChangeType state, const SystemAddress& sysAddr, + LWOOBJID originator, + bool bImmuneToStunAttack, + bool bImmuneToStunEquip, + bool bImmuneToStunInteract, + bool bImmuneToStunJump, + bool bImmuneToStunMove, + bool bImmuneToStunTurn, + bool bImmuneToStunUseItem) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(target); + bitStream.Write(GAME_MSG::GAME_MSG_SET_STUN_IMMUNITY); + + bitStream.Write(originator != LWOOBJID_EMPTY); + if (originator != LWOOBJID_EMPTY) bitStream.Write(originator); + + bitStream.Write(state); + + bitStream.Write(bImmuneToStunAttack); + bitStream.Write(bImmuneToStunEquip); + bitStream.Write(bImmuneToStunInteract); + bitStream.Write(bImmuneToStunJump); + bitStream.Write(bImmuneToStunMove); + bitStream.Write(bImmuneToStunTurn); + bitStream.Write(bImmuneToStunUseItem); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::SendSetStatusImmunity(LWOOBJID objectId, eStateChangeType state, const SystemAddress& sysAddr, + bool bImmuneToBasicAttack, + bool bImmuneToDamageOverTime, + bool bImmuneToKnockback, + bool bImmuneToInterrupt, + bool bImmuneToSpeed, + bool bImmuneToImaginationGain, + bool bImmuneToImaginationLoss, + bool bImmuneToQuickbuildInterrupt, + bool bImmuneToPullToPoint) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_SET_STATUS_IMMUNITY); + + bitStream.Write(state); + + bitStream.Write(bImmuneToBasicAttack); + bitStream.Write(bImmuneToDamageOverTime); + bitStream.Write(bImmuneToKnockback); + bitStream.Write(bImmuneToInterrupt); + bitStream.Write(bImmuneToSpeed); + bitStream.Write(bImmuneToImaginationGain); + bitStream.Write(bImmuneToImaginationLoss); + bitStream.Write(bImmuneToQuickbuildInterrupt); + bitStream.Write(bImmuneToPullToPoint); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) { CBITSTREAM; @@ -3991,7 +4054,7 @@ void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* e EntityManager::Instance()->SerializeEntity(entity); // We aren't mounted so remove the stun - GameMessages::SendSetStunned(entity->GetObjectID(), eStunState::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + GameMessages::SendSetStunned(entity->GetObjectID(), eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); } } } diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 6575ad85..6fa4e694 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -268,7 +268,7 @@ namespace GameMessages { float leadOut = -1.0f, bool leavePlayerLocked = false); void HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr, + void SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator = LWOOBJID_EMPTY, bool bCantAttack = false, bool bCantEquip = false, bool bCantInteract = false, bool bCantJump = false, bool bCantMove = false, bool bCantTurn = false, bool bCantUseItem = false, bool bDontTerminateInteract = false, bool bIgnoreImmunity = true, @@ -277,6 +277,35 @@ namespace GameMessages { bool bCantMoveOutChangeWasApplied = false, bool bCantTurnOutChangeWasApplied = false, bool bCantUseItemOutChangeWasApplied = false); + void SendSetStunImmunity( + LWOOBJID target, + eStateChangeType state, + const SystemAddress& sysAddr, + LWOOBJID originator = LWOOBJID_EMPTY, + bool bImmuneToStunAttack = false, + bool bImmuneToStunEquip = false, + bool bImmuneToStunInteract = false, + bool bImmuneToStunJump = false, + bool bImmuneToStunMove = false, + bool bImmuneToStunTurn = false, + bool bImmuneToStunUseItem = false + ); + + void SendSetStatusImmunity( + LWOOBJID objectId, + eStateChangeType state, + const SystemAddress& sysAddr, + bool bImmuneToBasicAttack = false, + bool bImmuneToDamageOverTime = false, + bool bImmuneToKnockback = false, + bool bImmuneToInterrupt = false, + bool bImmuneToSpeed = false, + bool bImmuneToImaginationGain = false, + bool bImmuneToImaginationLoss = false, + bool bImmuneToQuickbuildInterrupt = false, + bool bImmuneToPullToPoint = false + ); + void SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr); void SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr); diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp index d3c59448..ea3ce9b8 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp @@ -131,7 +131,7 @@ void BaseEnemyApe::StunApe(Entity* self, bool stunState) { skillComponent->Interrupt(); } - GameMessages::SendSetStunned(self->GetObjectID(), stunState ? PUSH : POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(), + GameMessages::SendSetStunned(self->GetObjectID(), stunState ? eStateChangeType::PUSH : eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(), true, true, true, true, true, true, true, true, true); diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp index 9b85cf85..da1954d6 100644 --- a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp +++ b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp @@ -147,21 +147,21 @@ void AmSkullkinDrill::OnUse(Entity* self, Entity* user) { } void AmSkullkinDrill::FreezePlayer(Entity* self, Entity* player, bool bFreeze) { - eStunState eChangeType = POP; + auto StateChangeType = eStateChangeType::POP; if (bFreeze) { if (player->GetIsDead()) { return; } - eChangeType = PUSH; + StateChangeType = eStateChangeType::PUSH; } else { if (player->GetIsDead()) { // } } - GameMessages::SendSetStunned(player->GetObjectID(), eChangeType, player->GetSystemAddress(), self->GetObjectID(), + GameMessages::SendSetStunned(player->GetObjectID(), StateChangeType, player->GetSystemAddress(), self->GetObjectID(), true, false, true, false, true, false, true ); } diff --git a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp index 7d67c781..eeabeef6 100644 --- a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp +++ b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp @@ -13,7 +13,7 @@ void GfCaptainsCannon::OnUse(Entity* self, Entity* user) { self->SetVar<bool>(u"bIsInUse", true); self->SetNetworkVar<bool>(u"bIsInUse", true); - GameMessages::SendSetStunned(user->GetObjectID(), PUSH, user->GetSystemAddress(), + GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true ); @@ -63,7 +63,7 @@ void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendPlay2DAmbientSound(player, "{7457d85c-4537-4317-ac9d-2f549219ea87}"); } else if (timerName == "cinematicTimer") { - GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(), + GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true ); diff --git a/dScripts/02_server/Map/GF/MastTeleport.cpp b/dScripts/02_server/Map/GF/MastTeleport.cpp index ebde7b20..dac5783c 100644 --- a/dScripts/02_server/Map/GF/MastTeleport.cpp +++ b/dScripts/02_server/Map/GF/MastTeleport.cpp @@ -16,7 +16,7 @@ void MastTeleport::OnRebuildComplete(Entity* self, Entity* target) { if (Preconditions::Check(target, 154) && Preconditions::Check(target, 44)) { self->SetVar<LWOOBJID>(u"userID", target->GetObjectID()); - GameMessages::SendSetStunned(target->GetObjectID(), PUSH, target->GetSystemAddress(), + GameMessages::SendSetStunned(target->GetObjectID(), eStateChangeType::PUSH, target->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -81,7 +81,7 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendTeleport(playerId, position, NiQuaternion::IDENTITY, player->GetSystemAddress()); - GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(), + GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); } diff --git a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp index f30f4fc7..5410047d 100644 --- a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp +++ b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp @@ -36,7 +36,7 @@ void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) { if (player->IsPlayer() && !bPlayerBeingTeleported) { auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -108,7 +108,7 @@ void NtAssemblyTubeServer::UnlockPlayer(Entity* self, Entity* player) { m_TeleportingPlayerTable[playerID] = false; - GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); } diff --git a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp index 06482c82..8d14050b 100644 --- a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp @@ -34,11 +34,11 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { GameMessages::SendPlayAnimation(player, u"rebuild-celebrate"); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "", player->GetSystemAddress()); - GameMessages::SendSetStunned(player->GetObjectID(), eStunState::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); + GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); self->SetVar(u"bActive", false); }); GameMessages::SendPlayAnimation(user, u"nexus-powerpanel", 6.0f); - GameMessages::SendSetStunned(user->GetObjectID(), eStunState::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); + GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); return; } diff --git a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp index 8003e93f..64af4d34 100644 --- a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp @@ -22,7 +22,7 @@ void NtParadoxTeleServer::OnProximityUpdate(Entity* self, Entity* entering, std: const auto bPlayerBeingTeleported = m_TeleportingPlayerTable[playerID]; if (player->IsPlayer() && !bPlayerBeingTeleported) { - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -100,7 +100,7 @@ void NtParadoxTeleServer::UnlockPlayer(Entity* self, Entity* player) { m_TeleportingPlayerTable[playerID] = false; - GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); diff --git a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp index d7f4cb99..e6cd2df6 100644 --- a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp +++ b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp @@ -14,7 +14,7 @@ void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { self->SetNetworkVar(u"bIsInUse", true); - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -92,7 +92,7 @@ void NtVentureCannonServer::ExitCannonEnded(Entity* self, Entity* player) { } void NtVentureCannonServer::UnlockCannonPlayer(Entity* self, Entity* player) { - GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index a8538de5..d0162e9c 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -15,7 +15,8 @@ void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* s if (button == 1) { - GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), player->GetObjectID(), + GameMessages::SendSetStunned( + player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), player->GetObjectID(), true, true, true, true, true, true, true ); @@ -82,11 +83,10 @@ void BaseConsoleTeleportServer::TransferPlayer(Entity* self, Entity* player, int return; } - // Ignoring extra effects for now - - /*GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), player->GetObjectID(), + GameMessages::SendSetStunned( + player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), player->GetObjectID(), true, true, true, true, true, true, true - );*/ + ); GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, player->GetObjectID()); diff --git a/dScripts/EquipmentScripts/PersonalFortress.cpp b/dScripts/EquipmentScripts/PersonalFortress.cpp index e7e89e80..f5062f9b 100644 --- a/dScripts/EquipmentScripts/PersonalFortress.cpp +++ b/dScripts/EquipmentScripts/PersonalFortress.cpp @@ -2,49 +2,56 @@ #include "GameMessages.h" #include "SkillComponent.h" #include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" #include "EntityManager.h" void PersonalFortress::OnStartup(Entity* self) { auto* owner = self->GetOwner(); self->AddTimer("FireSkill", 1.5); - GameMessages::SendSetStunned(owner->GetObjectID(), PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true, true, true - ); auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, + true, true, true, true, true, false, true, false, false + ); - if (destroyableComponent != nullptr) { - destroyableComponent->PushImmunity(); - } + auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, LWOOBJID_EMPTY, + true, true, true, true, true, true + ); + + GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true, true, true + ); EntityManager::Instance()->SerializeEntity(owner); } void PersonalFortress::OnDie(Entity* self, Entity* killer) { auto* owner = self->GetOwner(); - GameMessages::SendSetStunned(owner->GetObjectID(), POP, owner->GetSystemAddress(), LWOOBJID_EMPTY, + auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity( + eStateChangeType::POP, + true, true, true, true, true, false, true, false, false + ); + + auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::POP, LWOOBJID_EMPTY, + true, true, true, true, true, true + ); + + GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::POP, owner->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true, true ); - auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) { - destroyableComponent->PopImmunity(); - } - EntityManager::Instance()->SerializeEntity(owner); } void PersonalFortress::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "FireSkill") { - auto* owner = self->GetOwner(); - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) { - return; - } - - skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false); + if (skillComponent) skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false); } } diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index db914c7f..f9146ec4 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -77,7 +77,7 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); if (player != nullptr) { Game::logger->Log("SGCannon", "Player is ready"); - /*GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + /*GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true);*/ Game::logger->Log("SGCannon", "Sending ActivityEnter"); diff --git a/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp index 97288909..5448a4c2 100644 --- a/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp +++ b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp @@ -41,10 +41,19 @@ protected: TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) { destroyableComponent->Serialize(&bitStream, true, flags); // Assert that the full number of bits are present - ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 460); + ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 748); { // Now read in the full serialized construction BitStream - bool optionStatusImmunityInfo{}; // Values under this option are unused. + bool optionStatusImmunityInfo{}; + uint32_t ImmuneToBasicAttackCount{}; + uint32_t ImmuneToDamageOverTimeCount{}; + uint32_t ImmuneToKnockbackCount{}; + uint32_t ImmuneToInterruptCount{}; + uint32_t ImmuneToSpeedCount{}; + uint32_t ImmuneToImaginationGainCount{}; + uint32_t ImmuneToImaginationLossCount{}; + uint32_t ImmuneToQuickbuildInterruptCount{}; + uint32_t ImmuneToPullToPointCount{}; bool optionStatsInfo{}; uint32_t currentHealth{}; float maxHealth{}; @@ -70,7 +79,15 @@ TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) { bool optionIsOnThreatList{}; bool isThreatened{}; bitStream.Read(optionStatusImmunityInfo); - + bitStream.Read(ImmuneToBasicAttackCount); + bitStream.Read(ImmuneToDamageOverTimeCount); + bitStream.Read(ImmuneToKnockbackCount); + bitStream.Read(ImmuneToInterruptCount); + bitStream.Read(ImmuneToSpeedCount); + bitStream.Read(ImmuneToImaginationGainCount); + bitStream.Read(ImmuneToImaginationLossCount); + bitStream.Read(ImmuneToQuickbuildInterruptCount); + bitStream.Read(ImmuneToPullToPointCount); bitStream.Read(optionStatsInfo); bitStream.Read(currentHealth); bitStream.Read(maxHealth); @@ -101,7 +118,16 @@ TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) { bitStream.Read(optionIsOnThreatList); bitStream.Read(isThreatened); - EXPECT_EQ(optionStatusImmunityInfo, false); + EXPECT_EQ(optionStatusImmunityInfo, true); + EXPECT_EQ(ImmuneToBasicAttackCount, 0); + EXPECT_EQ(ImmuneToDamageOverTimeCount, 0); + EXPECT_EQ(ImmuneToKnockbackCount, 0); + EXPECT_EQ(ImmuneToInterruptCount, 0); + EXPECT_EQ(ImmuneToSpeedCount, 0); + EXPECT_EQ(ImmuneToImaginationGainCount, 0); + EXPECT_EQ(ImmuneToImaginationLossCount, 0); + EXPECT_EQ(ImmuneToQuickbuildInterruptCount, 0); + EXPECT_EQ(ImmuneToPullToPointCount, 0); EXPECT_EQ(optionStatsInfo, true); EXPECT_EQ(currentHealth, 23); @@ -298,3 +324,208 @@ TEST_F(DestroyableTest, DestroyableComponentValiditiyTest) { EXPECT_FALSE(destroyableComponent->IsFriend(enemyEntity)); delete enemyEntity; } + +TEST_F(DestroyableTest, DestroyableComponentImmunityTest) { + // assert to show that they are empty + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // set them all to true (count 1) and check + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, true, true, true, true, true, true, true, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint()); + + // remove them to check that they get removed properly + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + + // should not crash to remove them again + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + + // just do one + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // now stack it to 2 on basic attack + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // remove one and still shoudl be true + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // go back to 0 + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // check individual ones now + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, false, false, false, false, false, false, false, false); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, false, false, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, true, false, false, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, true, false, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, true, false, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, true, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, true, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, true, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, true, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, true, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, true, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, true, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, true, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, true, false, false); + + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, true, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, true, false); + + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, false, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, false, true); + +} + From 5374c555f549cc47dbedebf71dcdd9c47a9825f8 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell <aronwk.aaron@gmail.com> Date: Sat, 7 Jan 2023 00:14:51 -0600 Subject: [PATCH 61/63] Implement bubble seriliaztion in controllable physics (#942) * bubble * "Correct" serialization and enum * Enum update * figured out what things do * accurate types and cleanup * add sanity check add getter add slash command for testing * fix default * cleanup slash command * handle game message probably remove funny slash command add all bubble GM's Co-authored-by: Jett <55758076+Jettford@users.noreply.github.com> --- dCommon/dEnums/dMessageIdentifiers.h | 7 ++- dCommon/dEnums/eBubbleType.h | 14 +++++ .../ControllablePhysicsComponent.cpp | 49 ++++++++++++++--- .../ControllablePhysicsComponent.h | 53 +++++++++++++++++-- dGame/dGameMessages/GameMessageHandler.cpp | 9 +++- dGame/dGameMessages/GameMessages.cpp | 40 ++++++++++++++ dGame/dGameMessages/GameMessages.h | 9 ++++ dGame/dUtilities/SlashCommandHandler.cpp | 1 + 8 files changed, 168 insertions(+), 14 deletions(-) create mode 100644 dCommon/dEnums/eBubbleType.h diff --git a/dCommon/dEnums/dMessageIdentifiers.h b/dCommon/dEnums/dMessageIdentifiers.h index ed4167c8..c1afc497 100644 --- a/dCommon/dEnums/dMessageIdentifiers.h +++ b/dCommon/dEnums/dMessageIdentifiers.h @@ -374,6 +374,8 @@ enum GAME_MSG : unsigned short { GAME_MSG_PET_TAMING_TRY_BUILD_RESULT = 668, GAME_MSG_NOTIFY_TAMING_BUILD_SUCCESS = 673, GAME_MSG_NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674, + GAME_MSG_ACTIVATE_BUBBLE_BUFF = 678, + GAME_MSG_DEACTIVATE_BUBBLE_BUFF = 679, GAME_MSG_ADD_PET_TO_PLAYER = 681, GAME_MSG_REQUEST_SET_PET_NAME = 683, GAME_MSG_SET_PET_NAME = 684, @@ -386,7 +388,10 @@ enum GAME_MSG : unsigned short { GAME_MSG_QUERY_PROPERTY_DATA = 717, GAME_MSG_PROPERTY_EDITOR_BEGIN = 724, GAME_MSG_PROPERTY_EDITOR_END = 725, - GAME_MSG_START_PATHING = 735, + GAME_MSG_IS_MINIFIG_IN_A_BUBBLE = 729, + GAME_MSG_START_PATHING = 733, + GAME_MSG_ACTIVATE_BUBBLE_BUFF_FROM_SERVER = 734, + GAME_MSG_DEACTIVATE_BUBBLE_BUFF_FROM_SERVER = 735, GAME_MSG_NOTIFY_CLIENT_ZONE_OBJECT = 737, GAME_MSG_UPDATE_REPUTATION = 746, GAME_MSG_PROPERTY_RENTAL_RESPONSE = 750, diff --git a/dCommon/dEnums/eBubbleType.h b/dCommon/dEnums/eBubbleType.h new file mode 100644 index 00000000..4aa6fad1 --- /dev/null +++ b/dCommon/dEnums/eBubbleType.h @@ -0,0 +1,14 @@ +#pragma once + +#ifndef __EBUBBLETYPE__H__ +#define __EBUBBLETYPE__H__ + +#include <cstdint> + +enum class eBubbleType : uint32_t { + DEFAULT = 0, + ENERGY = 1, + SKUNK = 2, +}; + +#endif //!__EBUBBLETYPE__H__ diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index 2920a84f..6a6d69ce 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -31,8 +31,15 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com m_GravityScale = 1; m_DirtyCheats = false; m_IgnoreMultipliers = false; + + m_DirtyEquippedItemInfo = true; m_PickupRadius = 0.0f; - m_DirtyPickupRadiusScale = true; + + m_DirtyBubble = false; + m_IsInBubble = false; + m_SpecialAnims = false; + m_BubbleType = eBubbleType::DEFAULT; + m_IsTeleporting = false; m_ImmuneToStunAttackCount = 0; @@ -99,14 +106,22 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo m_DirtyCheats = false; } - outBitStream->Write(m_DirtyPickupRadiusScale); - if (m_DirtyPickupRadiusScale) { + outBitStream->Write(m_DirtyEquippedItemInfo); + if (m_DirtyEquippedItemInfo) { outBitStream->Write(m_PickupRadius); - outBitStream->Write0(); //No clue what this is so im leaving it false. - m_DirtyPickupRadiusScale = false; + outBitStream->Write(m_InJetpackMode); + m_DirtyEquippedItemInfo = false; } - outBitStream->Write0(); + outBitStream->Write(m_DirtyBubble); + if (m_DirtyBubble) { + outBitStream->Write(m_IsInBubble); + if (m_IsInBubble) { + outBitStream->Write(m_BubbleType); + outBitStream->Write(m_SpecialAnims); + } + m_DirtyBubble = false; + } outBitStream->Write(m_DirtyPosition || bIsInitialUpdate); if (m_DirtyPosition || bIsInitialUpdate) { @@ -263,7 +278,7 @@ void ControllablePhysicsComponent::AddPickupRadiusScale(float value) { m_ActivePickupRadiusScales.push_back(value); if (value > m_PickupRadius) { m_PickupRadius = value; - m_DirtyPickupRadiusScale = true; + m_DirtyEquippedItemInfo = true; } } @@ -279,7 +294,7 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) { // Recalculate pickup radius since we removed one by now m_PickupRadius = 0.0f; - m_DirtyPickupRadiusScale = true; + m_DirtyEquippedItemInfo = true; for (uint32_t i = 0; i < m_ActivePickupRadiusScales.size(); i++) { auto candidateRadius = m_ActivePickupRadiusScales[i]; if (m_PickupRadius < candidateRadius) m_PickupRadius = candidateRadius; @@ -314,6 +329,24 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) { EntityManager::Instance()->SerializeEntity(m_Parent); } +void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){ + if (m_IsInBubble) { + Game::logger->Log("ControllablePhysicsComponent", "Already in bubble"); + return; + } + m_BubbleType = bubbleType; + m_IsInBubble = true; + m_DirtyBubble = true; + m_SpecialAnims = specialAnims; + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void ControllablePhysicsComponent::DeactivateBubbleBuff(){ + m_DirtyBubble = true; + m_IsInBubble = false; + EntityManager::Instance()->SerializeEntity(m_Parent); +}; + void ControllablePhysicsComponent::SetStunImmunity( const eStateChangeType state, const LWOOBJID originator, diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index ba3e1bf4..a05a11fd 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -9,6 +9,7 @@ #include "Component.h" #include "dpCollisionChecks.h" #include "PhantomPhysicsComponent.h" +#include "eBubbleType.h" class Entity; class dpEntity; @@ -257,14 +258,40 @@ public: */ std::vector<float> GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; }; - + /** + * Add a Speed boost to the entity + * This will recalculate the speed boost based on what is being added + */ void AddSpeedboost(float value); + /** + * Remove speed boost from entity + * This will recalculate the speed boost based on what is the last one in te vector + */ void RemoveSpeedboost(float value); + /** + * The speed boosts of this component. + * @return All active Speed boosts for this component. + */ std::vector<float> GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; }; /** + * Activates the Bubble Buff + */ + void ActivateBubbleBuff(eBubbleType bubbleType = eBubbleType::DEFAULT, bool specialAnims = true); + + /** + * Deactivates the Bubble Buff + */ + void DeactivateBubbleBuff(); + + /** + * Gets if the Entity is in a bubble + */ + bool GetIsInBubble(){ return m_IsInBubble; }; + + /** * Push or Pop a layer of stun immunity to this entity */ void SetStunImmunity( @@ -387,7 +414,7 @@ private: /** * Whether the pickup scale is dirty. */ - bool m_DirtyPickupRadiusScale; + bool m_DirtyEquippedItemInfo; /** * The list of pickup radius scales for this entity @@ -414,7 +441,27 @@ private: */ float m_SpeedBoost; - /** + /* + * If Bubble info is dirty + */ + bool m_DirtyBubble; + + /* + * If the entity is in a bubble + */ + bool m_IsInBubble; + + /* + * The type of bubble the entity has + */ + eBubbleType m_BubbleType; + + /* + * If the entity should be using the special animations + */ + bool m_SpecialAnims; + + /** * stun immunity counters */ int32_t m_ImmuneToStunAttackCount; diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index c03f58db..a91a1e2a 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -665,9 +665,14 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System case GAME_MSG_DISMOUNT_COMPLETE: GameMessages::HandleDismountComplete(inStream, entity, sysAddr); break; - + case GAME_MSG_DEACTIVATE_BUBBLE_BUFF: + GameMessages::HandleDeactivateBubbleBuff(inStream, entity); + break; + case GAME_MSG_ACTIVATE_BUBBLE_BUFF: + GameMessages::HandleActivateBubbleBuff(inStream, entity); + break; default: - //Game::logger->Log("GameMessageHandler", "Unknown game message ID: %X", messageID); + // Game::logger->Log("GameMessageHandler", "Unknown game message ID: %i", messageID); break; } } diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index c6c7d2d1..7e9ea898 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -6084,3 +6084,43 @@ void GameMessages::HandleUpdatePlayerStatistic(RakNet::BitStream* inStream, Enti characterComponent->UpdatePlayerStatistic((StatisticID)updateID, (uint64_t)std::max(updateValue, int64_t(0))); } } + +void GameMessages::HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { + auto controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->DeactivateBubbleBuff(); +} + +void GameMessages::HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { + bool specialAnimations; + if (!inStream->Read(specialAnimations)) return; + + std::u16string type = GeneralUtils::ReadWString(inStream); + auto bubbleType = eBubbleType::DEFAULT; + if (type == u"skunk") bubbleType = eBubbleType::SKUNK; + else if (type == u"energy") bubbleType = eBubbleType::ENERGY; + + auto controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->ActivateBubbleBuff(bubbleType, specialAnimations); +} + +void GameMessages::SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_ACTIVATE_BUBBLE_BUFF_FROM_SERVER); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_DEACTIVATE_BUBBLE_BUFF_FROM_SERVER); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 6fa4e694..0675ae76 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -617,6 +617,15 @@ namespace GameMessages { void HandleReportBug(RakNet::BitStream* inStream, Entity* entity); void SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId); + + // bubble + void HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); + + void HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); + + void SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); + + void SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); }; #endif // GAMEMESSAGES_H diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 9ee4c1e6..e6e29ceb 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -68,6 +68,7 @@ #include "AssetManager.h" #include "BinaryPathFinder.h" #include "dConfig.h" +#include "eBubbleType.h" #include "AMFFormat.h" #include "MovingPlatformComponent.h" #include "dMessageIdentifiers.h" From a28a2e60cfaeef09394e8d46e49f75248d8b4f25 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 6 Jan 2023 22:16:43 -0800 Subject: [PATCH 62/63] Add property Teleport behavior (#846) * Add property Teleport behavior Untested. Will mark pr as ready for review when this has been tested * Fix issues --- dGame/dBehaviors/Behavior.cpp | 5 +- dGame/dBehaviors/CMakeLists.txt | 1 + dGame/dBehaviors/PropertyTeleportBehavior.cpp | 61 +++++++++++++++++++ dGame/dBehaviors/PropertyTeleportBehavior.h | 21 +++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 dGame/dBehaviors/PropertyTeleportBehavior.cpp create mode 100644 dGame/dBehaviors/PropertyTeleportBehavior.h diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 40c37a95..c8c1a1de 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -48,6 +48,7 @@ #include "PlayEffectBehavior.h" #include "DamageAbsorptionBehavior.h" #include "VentureVisionBehavior.h" +#include "PropertyTeleportBehavior.h" #include "BlockBehavior.h" #include "ClearTargetBehavior.h" #include "PullToPointBehavior.h" @@ -263,7 +264,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { case BehaviorTemplates::BEHAVIOR_DAMAGE_REDUCTION: behavior = new DamageReductionBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: break; + case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: + behavior = new PropertyTeleportBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_PROPERTY_CLEAR_TARGET: behavior = new ClearTargetBehavior(behaviorId); break; diff --git a/dGame/dBehaviors/CMakeLists.txt b/dGame/dBehaviors/CMakeLists.txt index e274872d..7b331fe0 100644 --- a/dGame/dBehaviors/CMakeLists.txt +++ b/dGame/dBehaviors/CMakeLists.txt @@ -35,6 +35,7 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "OverTimeBehavior.cpp" "PlayEffectBehavior.cpp" "ProjectileAttackBehavior.cpp" + "PropertyTeleportBehavior.cpp" "PullToPointBehavior.cpp" "RemoveBuffBehavior.cpp" "RepairBehavior.cpp" diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.cpp b/dGame/dBehaviors/PropertyTeleportBehavior.cpp new file mode 100644 index 00000000..447b085b --- /dev/null +++ b/dGame/dBehaviors/PropertyTeleportBehavior.cpp @@ -0,0 +1,61 @@ +#include "PropertyTeleportBehavior.h" + +#include "BehaviorBranchContext.h" +#include "BehaviorContext.h" +#include "Character.h" +#include "CharacterComponent.h" +#include "ChatPackets.h" +#include "WorldPackets.h" +#include "EntityManager.h" +#include "Game.h" +#include "ZoneInstanceManager.h" +#include "dZoneManager.h" + +void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* caster = EntityManager::Instance()->GetEntity(context->caster); + if (!caster) return; + + auto* character = caster->GetCharacter(); + if (!character) return; + + LWOOBJID objId = caster->GetObjectID(); + + LWOMAPID targetMapId = m_MapId; + LWOCLONEID targetCloneId = character->GetPropertyCloneID(); + + if (dZoneManager::Instance()->GetZoneID().GetCloneID() == character->GetPropertyCloneID()) { + targetMapId = character->GetLastNonInstanceZoneID(); + targetCloneId = 0; + } else { + character->SetLastNonInstanceZoneID(dZoneManager::Instance()->GetZoneID().GetMapID()); + } + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, targetMapId, targetCloneId, false, [objId](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + + auto* entity = EntityManager::Instance()->GetEntity(objId); + if (!entity) return; + + const auto sysAddr = entity->GetSystemAddress(); + + if (zoneClone != 0) ChatPackets::SendSystemMessage(sysAddr, u"Transfering to your property!"); + else ChatPackets::SendSystemMessage(sysAddr, u"Transfering back to previous world!"); + + Game::logger->Log("PropertyTeleportBehavior", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + entity->GetComponent<CharacterComponent>()->SetLastRocketConfig(u""); + } + + entity->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + return; + }); +} + +void PropertyTeleportBehavior::Load() { + this->m_CancelIfInteracting = GetBoolean("cancel_if_interacting"); // TODO unused + this->m_MapId = LWOMAPID(GetInt("mapID")); +} diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.h b/dGame/dBehaviors/PropertyTeleportBehavior.h new file mode 100644 index 00000000..74eed03b --- /dev/null +++ b/dGame/dBehaviors/PropertyTeleportBehavior.h @@ -0,0 +1,21 @@ +#pragma once +#include "Behavior.h" + +class PropertyTeleportBehavior final : public Behavior +{ +public: + /* + * Inherited + */ + + explicit PropertyTeleportBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; + +private: + LWOMAPID m_MapId; + bool m_CancelIfInteracting; +}; From a580e3a2f5edd0e2b90b693b036f9e66dad760df Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 6 Jan 2023 22:17:09 -0800 Subject: [PATCH 63/63] Update lookup command (#909) * Update lookup command * Fix bugs Update SlashCommandHandler.cpp --- dGame/dUtilities/SlashCommandHandler.cpp | 10 ++++++++-- docs/Commands.md | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index e6e29ceb..cc1c82a9 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -1198,11 +1198,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "lookup" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "lookup" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { auto query = CDClientDatabase::CreatePreppedStmt( "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); + // Concatenate all of the arguments into a single query so a multi word query can be used properly. + std::string conditional = args[0]; + args.erase(args.begin()); + for (auto& argument : args) { + conditional += ' ' + argument; + } - const std::string query_text = "%" + args[0] + "%"; + const std::string query_text = "%" + conditional + "%"; query.bind(1, query_text.c_str()); auto tables = query.execQuery(); diff --git a/docs/Commands.md b/docs/Commands.md index 7c4f494f..7dc11ff1 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -78,7 +78,7 @@ These commands are primarily for development and testing. The usage of many of t |inspect|`/inspect <component> (-m <waypoint> \| -a <animation> \| -s \| -p \| -f (faction) \| -t)`|Finds the closest entity with the given component or LDF variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. See [Detailed `/inspect` Usage](#detailed-inspect-usage) below.|8| |list-spawns|`/list-spawns`|Lists all the character spawn points in the zone. Additionally, this command will display the current scene that plays when the character lands in the next zone, if there is one.|8| |locrow|`/locrow`|Prints the your current position and rotation information to the console.|8| -|lookup|`/lookup <query>`|Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query.|8| +|lookup|`/lookup <query>`|Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query. Query can be multiple words delimited by spaces.|8| |playanimation|`/playanimation <id>`|Plays animation with given ID. Alias: `/playanim`.|8| |playeffect|`/playeffect <effect id> <effect type> <effect name>`|Plays an effect.|8| |playlvlfx|`/playlvlfx`|Plays the level up animation on your character.|8|