mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-24 06:27:24 +00:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
9d4d618e63
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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$\<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.
|
||||
|
@ -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<eSqliteDataType, std::string> 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<eSqliteDataType>(ReadInt32());
|
||||
name = ReadString();
|
||||
dataType = static_cast<eSqliteDataType>(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<eSqliteDataType>(ReadInt32())) {
|
||||
switch (static_cast<eSqliteDataType>(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<bool>(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);
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
|
||||
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:
|
||||
|
||||
/**
|
||||
@ -133,11 +130,6 @@ namespace FdbToSqlite {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
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;
|
||||
@ -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;
|
||||
@ -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:
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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(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;
|
||||
|
||||
|
@ -243,6 +243,12 @@ private:
|
||||
*/
|
||||
std::vector<LWOOBJID> 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
|
||||
|
@ -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;
|
||||
@ -700,7 +701,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
||||
auto* missions = owner->GetComponent<MissionComponent>();
|
||||
|
||||
if (missions != nullptr) {
|
||||
if (team != nullptr && isEnemy) {
|
||||
if (team != nullptr) {
|
||||
for (const auto memberId : team->members) {
|
||||
auto* member = EntityManager::Instance()->GetEntity(memberId);
|
||||
|
||||
@ -763,22 +764,17 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
||||
if (dZoneManager::Instance()->GetPlayerLoseCoinOnDeath()) {
|
||||
auto* character = m_Parent->GetCharacter();
|
||||
uint64_t coinsTotal = character->GetCoins();
|
||||
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;
|
||||
|
||||
if (coinsTotal > 0) {
|
||||
uint64_t coinsToLoose = 1;
|
||||
uint64_t coinsToLose = std::max(static_cast<uint64_t>(coinsTotal * coinPercentageToLose), minCoinsToLose);
|
||||
coinsToLose = std::min(maxCoinsToLose, coinsToLose);
|
||||
|
||||
if (coinsTotal >= 200) {
|
||||
float hundreth = (coinsTotal / 100.0f);
|
||||
coinsToLoose = static_cast<int>(hundreth);
|
||||
}
|
||||
coinsTotal -= coinsToLose;
|
||||
|
||||
if (coinsToLoose > 10000) {
|
||||
coinsToLoose = 10000;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd
|
||||
outBitStream->Write(m_Owner);
|
||||
}
|
||||
|
||||
if (bIsInitialUpdate) {
|
||||
outBitStream->Write(tamed);
|
||||
if (tamed) {
|
||||
outBitStream->Write(m_ModerationStatus);
|
||||
@ -136,6 +137,7 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PetComponent::OnUse(Entity* originator) {
|
||||
if (m_Owner != LWOOBJID_EMPTY) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<uint32_t>(attachmentID);
|
||||
LOT itemLOT = 0;
|
||||
//Inventory::InventoryType itemType;
|
||||
int mailCost = 25;
|
||||
int mailCost = dZoneManager::Instance()->GetWorldConfig()->mailBaseFee;
|
||||
int stackSize = 0;
|
||||
auto inv = static_cast<InventoryComponent*>(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 {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
67
dZoneManager/WorldConfig.h
Normal file
67
dZoneManager/WorldConfig.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef __WORLDCONFIG__H__
|
||||
#define __WORLDCONFIG__H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
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__
|
@ -8,6 +8,7 @@
|
||||
#include "DestroyableComponent.h"
|
||||
#include "GameMessages.h"
|
||||
#include "VanityUtilities.h"
|
||||
#include "WorldConfig.h"
|
||||
#include <chrono>
|
||||
|
||||
#include "../dWorldServer/ObjectIDManager.h"
|
||||
@ -53,6 +54,8 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) {
|
||||
|
||||
endTime = std::chrono::duration_cast<std::chrono::milliseconds>(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");
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "Spawner.h"
|
||||
#include <map>
|
||||
|
||||
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<LWOOBJID, Spawner*> m_Spawners;
|
||||
WorldConfig* m_WorldConfig = nullptr;
|
||||
|
||||
Entity* m_ZoneControlObject;
|
||||
Entity* m_ZoneControlObject = nullptr;
|
||||
};
|
||||
|
@ -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 \
|
||||
|
@ -1,22 +1,11 @@
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
|
27
docker/start_server.sh
Normal file → Executable file
27
docker/start_server.sh
Normal file → Executable file
@ -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
|
||||
|
1
thirdparty/LUnpack
vendored
1
thirdparty/LUnpack
vendored
@ -1 +0,0 @@
|
||||
Subproject commit f8d7e442a78910b298fe1cd5780f07c9c9285b8c
|
1
thirdparty/docker-utils
vendored
1
thirdparty/docker-utils
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 3f0129e0939ce5ccf41f0808dcbbe71a6243e37f
|
Loading…
Reference in New Issue
Block a user