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
This commit is contained in:
David Markowitz 2023-01-06 21:04:20 -08:00 committed by GitHub
parent 7fcc8a6e84
commit bad3845d83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 109 additions and 243 deletions

6
.gitmodules vendored
View File

@ -14,12 +14,6 @@
path = thirdparty/mariadb-connector-cpp path = thirdparty/mariadb-connector-cpp
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
ignore = dirty 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"] [submodule "thirdparty/AccountManager"]
path = thirdparty/AccountManager path = thirdparty/AccountManager
url = https://github.com/DarkflameUniverse/AccountManager url = https://github.com/DarkflameUniverse/AccountManager

View File

@ -4,7 +4,7 @@
- [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker) - [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) - [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 ## Run server inside Docker

View File

@ -25,7 +25,7 @@
11. Once the command has completed (you can see you path again and can enter commands), close the window. 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` 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_. 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$\<your linux OS>\...` 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). > If you need the extra performance, place the client files in `\\wsl$\<your linux OS>\...` 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. 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.

View File

@ -10,6 +10,7 @@
#include "GeneralUtils.h" #include "GeneralUtils.h"
#include "Game.h" #include "Game.h"
#include "dLogger.h" #include "dLogger.h"
#include "AssetManager.h"
#include "eSqliteDataType.h" #include "eSqliteDataType.h"
@ -23,26 +24,23 @@ std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::m_SqliteType = {
{ eSqliteDataType::TEXT_8, "text_8"} { eSqliteDataType::TEXT_8, "text_8"}
}; };
FdbToSqlite::Convert::Convert(std::string basePath, std::string binaryOutPath) { FdbToSqlite::Convert::Convert(std::string binaryOutPath) {
this->m_BasePath = basePath;
this->m_BinaryOutPath = binaryOutPath; this->m_BinaryOutPath = binaryOutPath;
m_Fdb.open(m_BasePath + "/cdclient.fdb", std::ios::binary);
} }
FdbToSqlite::Convert::~Convert() { bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
this->m_Fdb.close();
}
bool FdbToSqlite::Convert::ConvertDatabase() {
if (m_ConversionStarted) return false; if (m_ConversionStarted) return false;
std::istream cdClientBuffer(&buffer);
this->m_ConversionStarted = true; this->m_ConversionStarted = true;
try { try {
CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite"); CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite");
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
int32_t numberOfTables = ReadInt32(); int32_t numberOfTables = ReadInt32(cdClientBuffer);
ReadTables(numberOfTables); ReadTables(numberOfTables, cdClientBuffer);
CDClientDatabase::ExecuteQuery("COMMIT;"); CDClientDatabase::ExecuteQuery("COMMIT;");
} catch (CppSQLite3Exception& e) { } catch (CppSQLite3Exception& e) {
@ -53,130 +51,130 @@ bool FdbToSqlite::Convert::ConvertDatabase() {
return true; return true;
} }
int32_t FdbToSqlite::Convert::ReadInt32() { int32_t FdbToSqlite::Convert::ReadInt32(std::istream& cdClientBuffer) {
int32_t nextInt{}; int32_t nextInt{};
BinaryIO::BinaryRead(m_Fdb, nextInt); BinaryIO::BinaryRead(cdClientBuffer, nextInt);
return nextInt; return nextInt;
} }
int64_t FdbToSqlite::Convert::ReadInt64() { int64_t FdbToSqlite::Convert::ReadInt64(std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); int32_t prevPosition = SeekPointer(cdClientBuffer);
int64_t value{}; int64_t value{};
BinaryIO::BinaryRead(m_Fdb, value); BinaryIO::BinaryRead(cdClientBuffer, value);
m_Fdb.seekg(prevPosition); cdClientBuffer.seekg(prevPosition);
return value; return value;
} }
std::string FdbToSqlite::Convert::ReadString() { std::string FdbToSqlite::Convert::ReadString(std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); 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; return readString;
} }
int32_t FdbToSqlite::Convert::SeekPointer() { int32_t FdbToSqlite::Convert::SeekPointer(std::istream& cdClientBuffer) {
int32_t position{}; int32_t position{};
BinaryIO::BinaryRead(m_Fdb, position); BinaryIO::BinaryRead(cdClientBuffer, position);
int32_t prevPosition = m_Fdb.tellg(); int32_t prevPosition = cdClientBuffer.tellg();
m_Fdb.seekg(position); cdClientBuffer.seekg(position);
return prevPosition; return prevPosition;
} }
std::string FdbToSqlite::Convert::ReadColumnHeader() { std::string FdbToSqlite::Convert::ReadColumnHeader(std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t numberOfColumns = ReadInt32(); int32_t numberOfColumns = ReadInt32(cdClientBuffer);
std::string tableName = ReadString(); std::string tableName = ReadString(cdClientBuffer);
auto columns = ReadColumns(numberOfColumns); auto columns = ReadColumns(numberOfColumns, cdClientBuffer);
std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");"; std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");";
CDClientDatabase::ExecuteDML(newTable); CDClientDatabase::ExecuteDML(newTable);
m_Fdb.seekg(prevPosition); cdClientBuffer.seekg(prevPosition);
return tableName; return tableName;
} }
void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables) { void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); int32_t prevPosition = SeekPointer(cdClientBuffer);
for (int32_t i = 0; i < numberOfTables; i++) { for (int32_t i = 0; i < numberOfTables; i++) {
auto columnHeader = ReadColumnHeader(); auto columnHeader = ReadColumnHeader(cdClientBuffer);
ReadRowHeader(columnHeader); 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; std::stringstream columnsToCreate;
int32_t prevPosition = SeekPointer(); int32_t prevPosition = SeekPointer(cdClientBuffer);
std::string name{}; std::string name{};
eSqliteDataType dataType{}; eSqliteDataType dataType{};
for (int32_t i = 0; i < numberOfColumns; i++) { for (int32_t i = 0; i < numberOfColumns; i++) {
if (i != 0) columnsToCreate << ", "; if (i != 0) columnsToCreate << ", ";
dataType = static_cast<eSqliteDataType>(ReadInt32()); dataType = static_cast<eSqliteDataType>(ReadInt32(cdClientBuffer));
name = ReadString(); name = ReadString(cdClientBuffer);
columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType]; columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType];
} }
m_Fdb.seekg(prevPosition); cdClientBuffer.seekg(prevPosition);
return columnsToCreate.str(); return columnsToCreate.str();
} }
void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName) { void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); 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 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) { void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t rowid = 0; int32_t rowid = 0;
for (int32_t row = 0; row < numberOfAllocatedRows; row++) { for (int32_t row = 0; row < numberOfAllocatedRows; row++) {
int32_t rowPointer = ReadInt32(); int32_t rowPointer = ReadInt32(cdClientBuffer);
if (rowPointer == -1) rowid++; 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) { void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = m_Fdb.tellg(); int32_t prevPosition = cdClientBuffer.tellg();
m_Fdb.seekg(position); cdClientBuffer.seekg(position);
while (true) { while (true) {
ReadRowInfo(tableName); ReadRowInfo(tableName, cdClientBuffer);
int32_t linked = ReadInt32(); int32_t linked = ReadInt32(cdClientBuffer);
if (linked == -1) break; 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) { void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t numberOfColumns = ReadInt32(); int32_t numberOfColumns = ReadInt32(cdClientBuffer);
ReadRowValues(numberOfColumns, tableName); ReadRowValues(numberOfColumns, tableName, cdClientBuffer);
m_Fdb.seekg(prevPosition); cdClientBuffer.seekg(prevPosition);
} }
void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName) { void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(); int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t emptyValue{}; int32_t emptyValue{};
int32_t intValue{}; int32_t intValue{};
@ -190,26 +188,26 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string&
for (int32_t i = 0; i < numberOfColumns; i++) { for (int32_t i = 0; i < numberOfColumns; i++) {
if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row. if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row.
switch (static_cast<eSqliteDataType>(ReadInt32())) { switch (static_cast<eSqliteDataType>(ReadInt32(cdClientBuffer))) {
case eSqliteDataType::NONE: case eSqliteDataType::NONE:
BinaryIO::BinaryRead(m_Fdb, emptyValue); BinaryIO::BinaryRead(cdClientBuffer, emptyValue);
assert(emptyValue == 0); assert(emptyValue == 0);
insertedRow << "NULL"; insertedRow << "NULL";
break; break;
case eSqliteDataType::INT32: case eSqliteDataType::INT32:
intValue = ReadInt32(); intValue = ReadInt32(cdClientBuffer);
insertedRow << intValue; insertedRow << intValue;
break; break;
case eSqliteDataType::REAL: 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 insertedRow << std::fixed << std::setprecision(34) << floatValue; // maximum precision of floating point number
break; break;
case eSqliteDataType::TEXT_4: case eSqliteDataType::TEXT_4:
case eSqliteDataType::TEXT_8: { case eSqliteDataType::TEXT_8: {
stringValue = ReadString(); stringValue = ReadString(cdClientBuffer);
size_t position = 0; size_t position = 0;
// Need to escape quote with a double of ". // 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: case eSqliteDataType::INT_BOOL:
BinaryIO::BinaryRead(m_Fdb, boolValue); BinaryIO::BinaryRead(cdClientBuffer, boolValue);
insertedRow << static_cast<bool>(boolValue); insertedRow << static_cast<bool>(boolValue);
break; break;
case eSqliteDataType::INT64: case eSqliteDataType::INT64:
int64Value = ReadInt64(); int64Value = ReadInt64(cdClientBuffer);
insertedRow << std::to_string(int64Value); insertedRow << std::to_string(int64Value);
break; break;
@ -245,5 +243,5 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string&
auto copiedString = insertedRow.str(); auto copiedString = insertedRow.str();
CDClientDatabase::ExecuteDML(copiedString); CDClientDatabase::ExecuteDML(copiedString);
m_Fdb.seekg(prevPosition); cdClientBuffer.seekg(prevPosition);
} }

View File

@ -7,6 +7,8 @@
#include <iosfwd> #include <iosfwd>
#include <map> #include <map>
class AssetMemoryBuffer;
enum class eSqliteDataType : int32_t; enum class eSqliteDataType : int32_t;
namespace FdbToSqlite { namespace FdbToSqlite {
@ -18,33 +20,28 @@ namespace FdbToSqlite {
* @param inputFile The file which ends in .fdb to be converted * @param inputFile The file which ends in .fdb to be converted
* @param binaryPath The base path where the file will be saved * @param binaryPath The base path where the file will be saved
*/ */
Convert(std::string inputFile, std::string binaryOutPath); Convert(std::string binaryOutPath);
/**
* Destroy the convert object and close the fdb file.
*/
~Convert();
/** /**
* Converts the input file to sqlite. Calling multiple times is safe. * Converts the input file to sqlite. Calling multiple times is safe.
* *
* @return true if the database was converted properly, false otherwise. * @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. * @brief Reads a 32 bit int from the fdb file.
* *
* @return The read value * @return The read value
*/ */
int32_t ReadInt32(); int32_t ReadInt32(std::istream& cdClientBuffer);
/** /**
* @brief Reads a 64 bit integer from the fdb file. * @brief Reads a 64 bit integer from the fdb file.
* *
* @return The read value * @return The read value
*/ */
int64_t ReadInt64(); int64_t ReadInt64(std::istream& cdClientBuffer);
/** /**
* @brief Reads a string from the fdb file. * @brief Reads a string from the fdb file.
@ -53,28 +50,28 @@ namespace FdbToSqlite {
* *
* TODO This needs to be translated to latin-1! * TODO This needs to be translated to latin-1!
*/ */
std::string ReadString(); std::string ReadString(std::istream& cdClientBuffer);
/** /**
* @brief Seeks to a pointer position. * @brief Seeks to a pointer position.
* *
* @return The previous position before the seek * @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 * @brief Reads a column header from the fdb file and creates the table in the database
* *
* @return The table name * @return The table name
*/ */
std::string ReadColumnHeader(); std::string ReadColumnHeader(std::istream& cdClientBuffer);
/** /**
* @brief Read the tables from the fdb file. * @brief Read the tables from the fdb file.
* *
* @param numberOfTables The number of tables to read * @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. * @brief Reads the columns from the fdb file.
@ -82,14 +79,14 @@ namespace FdbToSqlite {
* @param numberOfColumns The number of columns to read * @param numberOfColumns The number of columns to read
* @return All columns of the table formatted for a sql query * @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. * @brief Reads the row header from the fdb file.
* *
* @param tableName The tables name * @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., * @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 numberOfAllocatedRows The number of rows that were allocated. Always a power of 2!
* @param tableName The tables name. * @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. * @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 position The position to seek in the fdb to
* @param tableName The tables name * @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. * @brief Reads the row info from the fdb file.
* *
* @param tableName The tables name * @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 * @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 numberOfColumns The number of columns to read in
* @param tableName The tables name * @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: private:
/** /**
@ -132,11 +129,6 @@ namespace FdbToSqlite {
* Base path of the folder containing the fdb file * Base path of the folder containing the fdb file
*/ */
std::string m_BasePath{}; 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. * Whether or not a conversion was started. If one was started, do not attempt to convert the file again.

View File

@ -45,9 +45,6 @@ AssetManager::AssetManager(const std::filesystem::path& path) {
switch (m_AssetBundleType) { switch (m_AssetBundleType) {
case eAssetBundleType::Packed: { case eAssetBundleType::Packed: {
this->LoadPackIndex(); this->LoadPackIndex();
this->UnpackRequiredAssets();
break; break;
} }
} }
@ -160,31 +157,6 @@ AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) {
return AssetMemoryBuffer(buf, len, success); 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) { uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
size_t i, j; size_t i, j;
uint32_t crc, msb; uint32_t crc, msb;

View File

@ -60,7 +60,6 @@ public:
private: private:
void LoadPackIndex(); void LoadPackIndex();
void UnpackRequiredAssets();
// Modified crc algorithm (mpeg2) // Modified crc algorithm (mpeg2)
// Reference: https://stackoverflow.com/questions/54339800/how-to-modify-crc-32-to-crc-32-mpeg-2 // Reference: https://stackoverflow.com/questions/54339800/how-to-modify-crc-32-to-crc-32-mpeg-2

View File

@ -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..."); 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"); std::filesystem::copy_file(Game::assetManager->GetResPath() / "CDServer.sqlite", BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite");
} else { } 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.", "%s could not be found in resServer or res. Looking for %s to convert to sqlite.",
(BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(), (BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(),
(Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); (Game::assetManager->GetResPath() / "cdclient.fdb").c_str());
if (!fdbExists) {
Game::logger->Log("WorldServer", AssetMemoryBuffer cdClientBuffer = Game::assetManager->GetFileAsBuffer("cdclient.fdb");
"%s could not be opened. Please move cdclient.fdb to %s", if (!cdClientBuffer.m_Success) {
(Game::assetManager->GetResPath() / "cdclient.fdb").c_str(), Game::logger->Log("MasterServer", "Failed to load %s", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str());
(Game::assetManager->GetResPath().c_str())); throw std::runtime_error("Aborting initialization due to missing cdclient.fdb.");
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", "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."); Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite.");
return FinalizeShutdown(); return EXIT_FAILURE;
} }
cdClientBuffer.close();
} }
} }

View File

@ -6,7 +6,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
echo "Install build dependencies" && \ echo "Install build dependencies" && \
apt update && \ apt update && \
apt remove -y libmysqlcppconn7v5 libmysqlcppconn-dev && \ 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/* rm -rf /var/lib/apt/lists/*
COPY dAuthServer/ /build/dAuthServer COPY dAuthServer/ /build/dAuthServer
@ -35,12 +35,11 @@ ARG BUILD_VERSION=171022
RUN echo "Build server" && \ RUN echo "Build server" && \
mkdir -p cmake_build && \ mkdir -p cmake_build && \
cd 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 && \ cmake .. -DCMAKE_BUILD_RPATH_USE_ORIGIN=TRUE && \
make -j $BUILD_THREADS make -j $BUILD_THREADS
RUN unzip /build/resources/navmeshes.zip -d /build/cmake_build/res/maps
FROM gcc:11 as runtime FROM gcc:11 as runtime
RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \ RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \

View File

@ -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 FROM python:3.10-alpine3.14 as prep
RUN apk add sqlite bash --no-cache RUN apk add bash --no-cache
WORKDIR /setup WORKDIR /setup
# copy needed files from repo # copy needed files from repo
COPY resources/ resources/ 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 COPY docker/setup.sh /setup.sh
CMD [ "/setup.sh" ] CMD [ "/setup.sh" ]

View File

@ -7,7 +7,7 @@ function update_ini() {
FILE="/docker/configs/$1" FILE="/docker/configs/$1"
KEY=$2 KEY=$2
NEW_VALUE=$3 NEW_VALUE=$3
sed -i "/^$KEY=/s/=.*/=$NEW_VALUE/" $FILE sed -i "s~$2=.*~$2=$3~" $FILE
} }
function update_database_ini_values_for() { function update_database_ini_values_for() {
@ -32,62 +32,11 @@ function update_ini_values() {
cp resources/worldconfig.ini /docker/configs/ cp resources/worldconfig.ini /docker/configs/
cp resources/sharedconfig.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 # always use the internal docker hostname
update_ini masterconfig.ini master_ip "darkflame" update_ini masterconfig.ini master_ip "darkflame"
update_ini sharedconfig.ini client_location "/client"
update_database_ini_values_for sharedconfig.ini 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 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

29
docker/start_server.sh Normal file → Executable file
View File

@ -1,25 +1,5 @@
#!/bin/bash #!/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() { function symlink_config_files() {
echo "Creating symlinks for config files" echo "Creating symlinks for config files"
rm /app/*.ini rm /app/*.ini
@ -30,15 +10,8 @@ function symlink_config_files() {
ln -s /shared_configs/configs/sharedconfig.ini /app/sharedconfig.ini 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 if [[ ! -f "/app/initialized" ]]; then
# setup symlinks for volume files # setup symlinks for volume files
symlink_client_files
symlink_config_files symlink_config_files
# do not run symlinks more than once # do not run symlinks more than once
touch /app/initialized touch /app/initialized
@ -49,4 +22,4 @@ fi
# start the server # start the server
echo "Starting MasterServer" echo "Starting MasterServer"
./MasterServer ./MasterServer
tail -f /dev/null tail -f /dev/null

1
thirdparty/LUnpack vendored

@ -1 +0,0 @@
Subproject commit f8d7e442a78910b298fe1cd5780f07c9c9285b8c

@ -1 +0,0 @@
Subproject commit 3f0129e0939ce5ccf41f0808dcbbe71a6243e37f