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] 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());