From 2ba3103a0c69252976f5114c67197be38753fabb Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 5 Dec 2022 00:57:58 -0800 Subject: [PATCH 1/3] Implement FDB to SQLite (#872) --- dCommon/CMakeLists.txt | 1 + dCommon/FdbToSqlite.cpp | 248 +++++++++++++++++++++++++++++++ dCommon/FdbToSqlite.h | 49 ++++++ dCommon/dEnums/eSqliteDataType.h | 16 ++ dDatabase/MigrationRunner.cpp | 2 + dMasterServer/MasterServer.cpp | 14 +- 6 files changed, 319 insertions(+), 11 deletions(-) create mode 100644 dCommon/FdbToSqlite.cpp create mode 100644 dCommon/FdbToSqlite.h create mode 100644 dCommon/dEnums/eSqliteDataType.h diff --git a/dCommon/CMakeLists.txt b/dCommon/CMakeLists.txt index 8d02186b..549acfb2 100644 --- a/dCommon/CMakeLists.txt +++ b/dCommon/CMakeLists.txt @@ -16,6 +16,7 @@ set(DCOMMON_SOURCES "AMFFormat.cpp" "ZCompression.cpp" "BrickByBrickFix.cpp" "BinaryPathFinder.cpp" + "FdbToSqlite.cpp" ) add_subdirectory(dClient) diff --git a/dCommon/FdbToSqlite.cpp b/dCommon/FdbToSqlite.cpp new file mode 100644 index 00000000..d98d4962 --- /dev/null +++ b/dCommon/FdbToSqlite.cpp @@ -0,0 +1,248 @@ +#include "FdbToSqlite.h" + +#include +#include +#include +#include + +#include "BinaryIO.h" +#include "CDClientDatabase.h" +#include "GeneralUtils.h" +#include "Game.h" +#include "dLogger.h" + +#include "eSqliteDataType.h" + +std::map FdbToSqlite::Convert::sqliteType = { + { eSqliteDataType::NONE, "none"}, + { eSqliteDataType::INT32, "int32"}, + { eSqliteDataType::REAL, "real"}, + { eSqliteDataType::TEXT_4, "text_4"}, + { eSqliteDataType::INT_BOOL, "int_bool"}, + { eSqliteDataType::INT64, "int64"}, + { eSqliteDataType::TEXT_8, "text_8"} +}; + +FdbToSqlite::Convert::Convert(std::string basePath) { + this->basePath = basePath; +} + +bool FdbToSqlite::Convert::ConvertDatabase() { + fdb.open(basePath + "/cdclient.fdb", std::ios::binary); + + try { + CDClientDatabase::Connect(basePath + "/CDServer.sqlite"); + + CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); + + int32_t numberOfTables = ReadInt32(); + ReadTables(numberOfTables); + + CDClientDatabase::ExecuteQuery("COMMIT;"); + } catch (CppSQLite3Exception& e) { + Game::logger->Log("FdbToSqlite", "Encountered error %s converting FDB to SQLite", e.errorMessage()); + return false; + } + + fdb.close(); + return true; +} + +int32_t FdbToSqlite::Convert::ReadInt32() { + uint32_t numberOfTables{}; + BinaryIO::BinaryRead(fdb, numberOfTables); + return numberOfTables; +} + +int64_t FdbToSqlite::Convert::ReadInt64() { + int32_t prevPosition = SeekPointer(); + + int64_t value{}; + BinaryIO::BinaryRead(fdb, value); + + fdb.seekg(prevPosition); + return value; +} + +std::string FdbToSqlite::Convert::ReadString() { + int32_t prevPosition = SeekPointer(); + + auto readString = BinaryIO::ReadString(fdb); + + 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); + return prevPosition; +} + +std::string FdbToSqlite::Convert::ReadColumnHeader() { + int32_t prevPosition = SeekPointer(); + + int32_t numberOfColumns = ReadInt32(); + std::string tableName = ReadString(); + + auto columns = ReadColumns(numberOfColumns); + std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");"; + CDClientDatabase::ExecuteDML(newTable); + + fdb.seekg(prevPosition); + + return tableName; +} + +void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables) { + int32_t prevPosition = SeekPointer(); + + for (int32_t i = 0; i < numberOfTables; i++) { + auto columnHeader = ReadColumnHeader(); + ReadRowHeader(columnHeader); + } + + fdb.seekg(prevPosition); +} + +std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns) { + std::stringstream columnsToCreate; + int32_t prevPosition = SeekPointer(); + + std::string name{}; + eSqliteDataType dataType{}; + for (int32_t i = 0; i < numberOfColumns; i++) { + if (i != 0) columnsToCreate << ", "; + dataType = static_cast(ReadInt32()); + name = ReadString(); + columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::sqliteType[dataType]; + } + + fdb.seekg(prevPosition); + return columnsToCreate.str(); +} + +void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName) { + int32_t prevPosition = SeekPointer(); + + int32_t numberOfAllocatedRows = ReadInt32(); + if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0); // assert power of 2 allocation size + ReadRows(numberOfAllocatedRows, tableName); + + fdb.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName) { + int32_t prevPosition = SeekPointer(); + + int32_t rowid = 0; + for (int32_t row = 0; row < numberOfAllocatedRows; row++) { + int32_t rowPointer = ReadInt32(); + if (rowPointer == -1) rowid++; + else ReadRow(rowid, rowPointer, tableName); + } + + fdb.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRow(int32_t& rowid, int32_t& position, std::string& tableName) { + int32_t prevPosition = fdb.tellg(); + fdb.seekg(position); + + while (true) { + ReadRowInfo(tableName); + int32_t linked = ReadInt32(); + + rowid += 1; + + if (linked == -1) break; + + fdb.seekg(linked); + } + + fdb.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName) { + int32_t prevPosition = SeekPointer(); + + int32_t numberOfColumns = ReadInt32(); + ReadRowValues(numberOfColumns, tableName); + + fdb.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName) { + int32_t prevPosition = SeekPointer(); + + int32_t emptyValue{}; + int32_t intValue{}; + float_t floatValue{}; + std::string stringValue{}; + int32_t boolValue{}; + int64_t int64Value{}; + bool insertedFirstEntry = false; + std::stringstream insertedRow; + insertedRow << "INSERT INTO " << tableName << " values ("; + + 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())) { + case eSqliteDataType::NONE: + BinaryIO::BinaryRead(fdb, emptyValue); + assert(emptyValue == 0); + insertedRow << "\"\""; + break; + + case eSqliteDataType::INT32: + intValue = ReadInt32(); + insertedRow << intValue; + break; + + case eSqliteDataType::REAL: + BinaryIO::BinaryRead(fdb, 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(); + size_t position = 0; + + // Need to escape quote with a double of ". + while (position < stringValue.size()) { + if (stringValue.at(position) == '\"') { + stringValue.insert(position, "\""); + position++; + } + position++; + } + insertedRow << "\"" << stringValue << "\""; + break; + } + + case eSqliteDataType::INT_BOOL: + BinaryIO::BinaryRead(fdb, boolValue); + insertedRow << static_cast(boolValue); + break; + + case eSqliteDataType::INT64: + int64Value = ReadInt64(); + insertedRow << std::to_string(int64Value); + break; + + default: + throw std::invalid_argument("Unsupported SQLite type encountered."); + break; + + } + } + + insertedRow << ");"; + + auto copiedString = insertedRow.str(); + CDClientDatabase::ExecuteDML(copiedString); + fdb.seekg(prevPosition); +} diff --git a/dCommon/FdbToSqlite.h b/dCommon/FdbToSqlite.h new file mode 100644 index 00000000..a9611220 --- /dev/null +++ b/dCommon/FdbToSqlite.h @@ -0,0 +1,49 @@ +#ifndef __FDBTOSQLITE__H__ +#define __FDBTOSQLITE__H__ + +#pragma once + +#include +#include +#include + +enum class eSqliteDataType : int32_t; + +namespace FdbToSqlite { + class Convert { + public: + Convert(std::string inputFile); + + bool ConvertDatabase(); + + int32_t ReadInt32(); + + int64_t ReadInt64(); + + std::string ReadString(); + + int32_t SeekPointer(); + + std::string ReadColumnHeader(); + + void ReadTables(int32_t& numberOfTables); + + std::string ReadColumns(int32_t& numberOfColumns); + + void ReadRowHeader(std::string& tableName); + + void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName); + + void ReadRow(int32_t& rowid, int32_t& position, std::string& tableName); + + void ReadRowInfo(std::string& tableName); + + void ReadRowValues(int32_t& numberOfColumns, std::string& tableName); + private: + static std::map sqliteType; + std::string basePath{}; + std::ifstream fdb{}; + }; // class FdbToSqlite +}; //! namespace FdbToSqlite + +#endif //!__FDBTOSQLITE__H__ diff --git a/dCommon/dEnums/eSqliteDataType.h b/dCommon/dEnums/eSqliteDataType.h new file mode 100644 index 00000000..26e1233b --- /dev/null +++ b/dCommon/dEnums/eSqliteDataType.h @@ -0,0 +1,16 @@ +#ifndef __ESQLITEDATATYPE__H__ +#define __ESQLITEDATATYPE__H__ + +#include + +enum class eSqliteDataType : int32_t { + NONE = 0, + INT32, + REAL = 3, + TEXT_4, + INT_BOOL, + INT64, + TEXT_8 = 8 +}; + +#endif //!__ESQLITEDATATYPE__H__ diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp index 31fb9148..d39201b2 100644 --- a/dDatabase/MigrationRunner.cpp +++ b/dDatabase/MigrationRunner.cpp @@ -136,6 +136,7 @@ void MigrationRunner::RunSQLiteMigrations() { // Doing these 1 migration at a time since one takes a long time and some may think it is crashing. // This will at the least guarentee that the full migration needs to be run in order to be counted as "migrated". Game::logger->Log("MigrationRunner", "Executing migration: %s. This may take a while. Do not shut down server.", migration.name.c_str()); + CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); for (const auto& dml : GeneralUtils::SplitString(migration.data, ';')) { if (dml.empty()) continue; try { @@ -150,6 +151,7 @@ void MigrationRunner::RunSQLiteMigrations() { cdstmt.bind((int32_t) 1, migration.name.c_str()); cdstmt.execQuery().finalize(); cdstmt.finalize(); + CDClientDatabase::ExecuteQuery("COMMIT;"); } Game::logger->Log("MigrationRunner", "CDServer database is up to date."); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 0a387d8e..0329d9a0 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -40,6 +40,7 @@ #include "ObjectIDManager.h" #include "PacketUtils.h" #include "dMessageIdentifiers.h" +#include "FdbToSqlite.h" namespace Game { dLogger* logger; @@ -126,18 +127,9 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - Game::logger->Log("WorldServer", "Found cdclient.fdb. Clearing cdserver migration_history then copying and converting to sqlite."); - auto stmt = Database::CreatePreppedStmt(R"#(DELETE FROM migration_history WHERE name LIKE "%cdserver%";)#"); - stmt->executeUpdate(); - delete stmt; + Game::logger->Log("WorldServer", "Found cdclient.fdb. Converting to SQLite"); - std::string res = "python3 " - + (BinaryPathFinder::GetBinaryDir() / "../thirdparty/docker-utils/utils/fdb_to_sqlite.py").string() - + " --sqlite_path " + (Game::assetManager->GetResPath() / "CDServer.sqlite").string() - + " " + (Game::assetManager->GetResPath() / "cdclient.fdb").string(); - - int result = system(res.c_str()); - if (result != 0) { + if (FdbToSqlite::Convert(Game::assetManager->GetResPath().string()).ConvertDatabase() == false) { Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite"); return EXIT_FAILURE; } From 0a616f891fd4e09bd52c5d68f56099cf62ea7954 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 5 Dec 2022 07:04:59 -0800 Subject: [PATCH 2/3] Change File Finder (#873) --- dCommon/GeneralUtils.cpp | 65 +++++++++++++---------------------- dCommon/GeneralUtils.h | 3 +- dDatabase/MigrationRunner.cpp | 4 +-- 3 files changed, 27 insertions(+), 45 deletions(-) diff --git a/dCommon/GeneralUtils.cpp b/dCommon/GeneralUtils.cpp index 24ea72a0..54ef5661 100644 --- a/dCommon/GeneralUtils.cpp +++ b/dCommon/GeneralUtils.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include template inline size_t MinSize(size_t size, const std::basic_string_view& string) { @@ -290,51 +292,30 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) { return string; } -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include - -std::vector GeneralUtils::GetFileNamesFromFolder(const std::string& folder) { - std::vector names; - std::string search_path = folder + "/*.*"; - WIN32_FIND_DATA fd; - HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - names.push_back(fd.cFileName); - } - } while (::FindNextFile(hFind, &fd)); - ::FindClose(hFind); - } - return names; -} -#else -#include -#include -#include -#include -#include -#include - -std::vector GeneralUtils::GetFileNamesFromFolder(const std::string& folder) { - std::vector names; - struct dirent* entry; - DIR* dir = opendir(folder.c_str()); - if (dir == NULL) { - return names; +std::vector GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) { + // Because we dont know how large the initial number before the first _ is we need to make it a map like so. + std::map filenames{}; + for (auto& t : std::filesystem::directory_iterator(folder)) { + auto filename = t.path().filename().string(); + auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0)); + filenames.insert(std::make_pair(index, filename)); } - while ((entry = readdir(dir)) != NULL) { - std::string value(entry->d_name, strlen(entry->d_name)); - if (value == "." || value == "..") { - continue; + // Now sort the map by the oldest migration. + std::vector sortedFiles{}; + auto fileIterator = filenames.begin(); + std::map::iterator oldest = filenames.begin(); + while (!filenames.empty()) { + if (fileIterator == filenames.end()) { + sortedFiles.push_back(oldest->second); + filenames.erase(oldest); + fileIterator = filenames.begin(); + oldest = filenames.begin(); + continue; } - names.push_back(value); + if (oldest->first > fileIterator->first) oldest = fileIterator; + fileIterator++; } - closedir(dir); - - return names; + return sortedFiles; } -#endif diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index 898616d2..af7c7012 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -12,6 +12,7 @@ #include #include "Game.h" +#include "dLogger.h" /*! \file GeneralUtils.hpp @@ -138,7 +139,7 @@ namespace GeneralUtils { std::vector SplitString(const std::string& str, char delimiter); - std::vector GetFileNamesFromFolder(const std::string& folder); + std::vector GetSqlFileNamesFromFolder(const std::string& folder); template T Parse(const char* value); diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp index d39201b2..54def9e2 100644 --- a/dDatabase/MigrationRunner.cpp +++ b/dDatabase/MigrationRunner.cpp @@ -38,7 +38,7 @@ void MigrationRunner::RunMigrations() { sql::SQLString finalSQL = ""; bool runSd0Migrations = false; - for (const auto& entry : GeneralUtils::GetFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) { + for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) { auto migration = LoadMigration("dlu/" + entry); if (migration.data.empty()) { @@ -102,7 +102,7 @@ void MigrationRunner::RunSQLiteMigrations() { stmt->execute(); delete stmt; - for (const auto& entry : GeneralUtils::GetFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "migrations/cdserver/").string())) { + for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "migrations/cdserver/").string())) { auto migration = LoadMigration("cdserver/" + entry); if (migration.data.empty()) continue; From 18a0ae599bcf3976b01e5550607a9d3abf04b9df Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:08:47 -0800 Subject: [PATCH 3/3] Add bandwidth limit of 10kb/s(#863) --- dAuthServer/AuthServer.cpp | 2 +- dChatServer/ChatServer.cpp | 2 +- dGame/dUtilities/SlashCommandHandler.cpp | 1 + dMasterServer/MasterServer.cpp | 2 +- dNet/dServer.cpp | 11 +++++++++-- dNet/dServer.h | 5 ++++- dWorldServer/WorldServer.cpp | 2 +- resources/sharedconfig.ini | 3 +++ 8 files changed, 21 insertions(+), 7 deletions(-) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 9621f683..a9f02f53 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -83,7 +83,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::Auth); + Game::server = new dServer(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(); diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index e0073747..e3c6d6e9 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -103,7 +103,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::server = new dServer(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")))); diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 60862c1a..9b37d4b8 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -1778,6 +1778,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit scriptedActivityComponent->ReloadConfig(); } + Game::server->UpdateBandwidthLimit(); ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); } diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 0329d9a0..4acb9b26 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -216,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::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config); //Query for the database for a server labeled "master" auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index c46b156c..481667b8 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -2,6 +2,7 @@ #include "dServer.h" #include "dNetCommon.h" #include "dLogger.h" +#include "dConfig.h" #include "RakNetworkFactory.h" #include "MessageIdentifiers.h" @@ -35,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, 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, unsigned int zoneID) { mIP = ip; mPort = port; mZoneID = zoneID; @@ -50,6 +51,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect mNetIDManager = nullptr; mReplicaManager = nullptr; mServerType = serverType; + mConfig = config; //Attempt to start our server here: mIsOkay = Startup(); @@ -181,7 +183,7 @@ bool dServer::Startup() { if (mIsInternal) { mPeer->SetIncomingPassword("3.25 DARKFLAME1", 15); } else { - //mPeer->SetPerConnectionOutgoingBandwidthLimit(800000); //100Kb/s + UpdateBandwidthLimit(); mPeer->SetIncomingPassword("3.25 ND1", 8); } @@ -191,6 +193,11 @@ bool dServer::Startup() { return true; } +void dServer::UpdateBandwidthLimit() { + auto newBandwidth = mConfig->GetValue("maximum_outgoing_bandwidth"); + mPeer->SetPerConnectionOutgoingBandwidthLimit(!newBandwidth.empty() ? std::stoi(newBandwidth) : 0); +} + void dServer::Shutdown() { if (mPeer) { mPeer->Shutdown(1000); diff --git a/dNet/dServer.h b/dNet/dServer.h index 264932ee..0fbdecce 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -5,6 +5,7 @@ #include "NetworkIDManager.h" class dLogger; +class dConfig; enum class ServerType : uint32_t { Master, @@ -17,7 +18,7 @@ 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, 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, unsigned int zoneID = 0); ~dServer(); Packet* ReceiveFromMaster(); @@ -42,6 +43,7 @@ public: const int GetInstanceID() const { return mInstanceID; } ReplicaManager* GetReplicaManager() { return mReplicaManager; } void UpdateReplica(); + void UpdateBandwidthLimit(); int GetPing(const SystemAddress& sysAddr) const; int GetLatestPing(const SystemAddress& sysAddr) const; @@ -58,6 +60,7 @@ private: private: dLogger* mLogger = nullptr; + dConfig* mConfig = nullptr; RakPeerInterface* mPeer = nullptr; ReplicaManager* mReplicaManager = nullptr; NetworkIDManager* mNetIDManager = nullptr; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index b4be7511..acd38ad3 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, zoneID); + 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; diff --git a/resources/sharedconfig.ini b/resources/sharedconfig.ini index 847a6b7c..439ffe2f 100644 --- a/resources/sharedconfig.ini +++ b/resources/sharedconfig.ini @@ -25,3 +25,6 @@ dump_folder= # The location of the client # Either the folder with /res or with /client and /versions client_location= + +# The maximum outgoing bandwidth in bits +maximum_outgoing_bandwidth=80000