Merge branch 'main' into npc-pathing

This commit is contained in:
Aaron Kimbre 2022-11-03 15:39:17 -05:00
commit aee8075375
603 changed files with 1775 additions and 350 deletions

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.18)
project(Darkflame)
include(CTest)
@ -58,7 +58,7 @@ if(UNIX)
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC -lstdc++fs")
endif()
if (__dynamic AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
@ -101,6 +101,17 @@ foreach(resource_file ${RESOURCE_FILES})
endif()
endforeach()
# Copy navmesh data on first build and extract it
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/)
configure_file(
${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip
COPYONLY
)
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
endif()
# Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
foreach(file ${VANITY_FILES})
@ -143,7 +154,9 @@ set(INCLUDED_DIRECTORIES
"dGame/dInventory"
"dGame/dMission"
"dGame/dEntity"
"dGame/dPropertyBehaviors"
"dGame/dUtilities"
"dCommon/dClient"
"dPhysics"
"dNavigation"
"dNavigation/dTerrain"
@ -152,6 +165,74 @@ set(INCLUDED_DIRECTORIES
"dDatabase/Tables"
"dNet"
"dScripts"
"dScripts/02_server"
"dScripts/ai"
"dScripts/client"
"dScripts/EquipmentScripts"
"dScripts/zone"
"dScripts/02_server/DLU"
"dScripts/02_server/Enemy"
"dScripts/02_server/Equipment"
"dScripts/02_server/Map"
"dScripts/02_server/Minigame"
"dScripts/02_server/Objects"
"dScripts/02_server/Pets"
"dScripts/02_server/Enemy/AG"
"dScripts/02_server/Enemy/AM"
"dScripts/02_server/Enemy/FV"
"dScripts/02_server/Enemy/General"
"dScripts/02_server/Enemy/Survival"
"dScripts/02_server/Enemy/VE"
"dScripts/02_server/Enemy/Waves"
"dScripts/02_server/Map/AG"
"dScripts/02_server/Map/AG_Spider_Queen"
"dScripts/02_server/Map/AM"
"dScripts/02_server/Map/FV"
"dScripts/02_server/Map/General"
"dScripts/02_server/Map/GF"
"dScripts/02_server/Map/njhub"
"dScripts/02_server/Map/NS"
"dScripts/02_server/Map/NT"
"dScripts/02_server/Map/PR"
"dScripts/02_server/Map/Property"
"dScripts/02_server/Map/SS"
"dScripts/02_server/Map/VE"
"dScripts/02_server/Map/FV/Racing"
"dScripts/02_server/Map/General/Ninjago"
"dScripts/02_server/Map/njhub/boss_instance"
"dScripts/02_server/Map/NS/Waves"
"dScripts/02_server/Map/Property/AG_Med"
"dScripts/02_server/Map/Property/AG_Small"
"dScripts/02_server/Map/Property/NS_Med"
"dScripts/02_server/Minigame/General"
"dScripts/ai/ACT"
"dScripts/ai/AG"
"dScripts/ai/FV"
"dScripts/ai/GENERAL"
"dScripts/ai/GF"
"dScripts/ai/MINIGAME"
"dScripts/ai/NP"
"dScripts/ai/NS"
"dScripts/ai/PETS"
"dScripts/ai/PROPERTY"
"dScripts/ai/RACING"
"dScripts/ai/SPEC"
"dScripts/ai/WILD"
"dScripts/ai/ACT/FootRace"
"dScripts/ai/MINIGAME/SG_GF"
"dScripts/ai/MINIGAME/SG_GF/SERVER"
"dScripts/ai/NS/NS_PP_01"
"dScripts/ai/NS/WH"
"dScripts/ai/PROPERTY/AG"
"dScripts/ai/RACING/OBJECTS"
"dScripts/client/ai"
"dScripts/client/ai/PR"
"dScripts/zone/AG"
"dScripts/zone/LUPs"
"dScripts/zone/PROPERTY"
"dScripts/zone/PROPERTY/FV"
"dScripts/zone/PROPERTY/GF"
"dScripts/zone/PROPERTY/NS"
"thirdparty/raknet/Source"
"thirdparty/tinyxml2"

View File

@ -12,6 +12,7 @@
#include "dMessageIdentifiers.h"
#include "dChatFilter.h"
#include "Diagnostics.h"
#include "AssetManager.h"
#include "PlayerContainer.h"
#include "ChatPacketHandler.h"
@ -22,6 +23,7 @@ namespace Game {
dServer* server;
dConfig* config;
dChatFilter* chatFilter;
AssetManager* assetManager;
}
//RakNet includes:
@ -50,6 +52,16 @@ int main(int argc, char** argv) {
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
try {
std::string client_path = config.GetValue("client_location");
if (client_path.empty()) client_path = "./res";
Game::assetManager = new AssetManager(client_path);
} catch (std::runtime_error& ex) {
Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what());
return EXIT_FAILURE;
}
//Connect to the MySQL Database
std::string mysql_host = config.GetValue("mysql_host");
std::string mysql_database = config.GetValue("mysql_database");
@ -87,7 +99,7 @@ int main(int argc, char** argv) {
Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat);
Game::chatFilter = new dChatFilter("./res/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf"))));
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf"))));
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();

View File

@ -10,7 +10,7 @@ void BinaryIO::WriteString(const std::string& stringToWrite, std::ofstream& outs
}
//For reading null-terminated strings
std::string BinaryIO::ReadString(std::ifstream& instream) {
std::string BinaryIO::ReadString(std::istream& instream) {
std::string toReturn;
char buffer;
@ -25,7 +25,7 @@ std::string BinaryIO::ReadString(std::ifstream& instream) {
}
//For reading strings of a specific size
std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) {
std::string BinaryIO::ReadString(std::istream& instream, size_t size) {
std::string toReturn;
char buffer;
@ -37,7 +37,7 @@ std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) {
return toReturn;
}
std::string BinaryIO::ReadWString(std::ifstream& instream) {
std::string BinaryIO::ReadWString(std::istream& instream) {
size_t size;
BinaryRead(instream, size);
//toReturn.resize(size);

View File

@ -10,16 +10,15 @@ namespace BinaryIO {
template<typename T>
std::istream& BinaryRead(std::istream& stream, T& value) {
if (!stream.good())
printf("bla");
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
}
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
std::string ReadString(std::ifstream& instream);
std::string ReadString(std::ifstream& instream, size_t size);
std::string ReadWString(std::ifstream& instream);
std::string ReadString(std::istream& instream);
std::string ReadString(std::istream& instream, size_t size);
std::string ReadWString(std::istream& instream);
inline bool DoesFileExist(const std::string& name) {
std::ifstream f(name.c_str());

View File

@ -49,10 +49,10 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
}
// Ignore the valgrind warning about uninitialized values. These are discarded later when we know the actual uncompressed size.
std::unique_ptr<uint8_t[]> uncompressedChunk(new uint8_t[MAX_SD0_CHUNK_SIZE]);
std::unique_ptr<uint8_t[]> uncompressedChunk(new uint8_t[ZCompression::MAX_SD0_CHUNK_SIZE]);
int32_t err{};
int32_t actualUncompressedSize = ZCompression::Decompress(
compressedChunk.get(), chunkSize, uncompressedChunk.get(), MAX_SD0_CHUNK_SIZE, err);
compressedChunk.get(), chunkSize, uncompressedChunk.get(), ZCompression::MAX_SD0_CHUNK_SIZE, err);
if (actualUncompressedSize != -1) {
uint32_t previousSize = completeUncompressedModel.size();

View File

@ -17,10 +17,4 @@ namespace BrickByBrickFix {
* @return The number of BrickByBrick models that were updated
*/
uint32_t UpdateBrickByBrickModelsToSd0();
/**
* @brief Max size of an inflated sd0 zlib chunk
*
*/
constexpr uint32_t MAX_SD0_CHUNK_SIZE = 1024 * 256;
};

View File

@ -17,6 +17,12 @@ set(DCOMMON_SOURCES "AMFFormat.cpp"
"BrickByBrickFix.cpp"
)
add_subdirectory(dClient)
foreach(file ${DCOMMON_DCLIENT_SOURCES})
set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}")
endforeach()
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
add_library(dCommon STATIC ${DCOMMON_SOURCES})

View File

@ -10,6 +10,7 @@ class dChatFilter;
class dConfig;
class dLocale;
class RakPeerInterface;
class AssetManager;
struct SystemAddress;
namespace Game {
@ -22,5 +23,6 @@ namespace Game {
extern dLocale* locale;
extern std::mt19937 randomEngine;
extern RakPeerInterface* chatServer;
extern AssetManager* assetManager;
extern SystemAddress chatSysAddr;
}

View File

@ -50,6 +50,7 @@ bool _IsSuffixChar(uint8_t c) {
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
size_t rem = slice.length();
if (slice.empty()) return false;
const uint8_t* bytes = (const uint8_t*)&slice.front();
if (rem > 0) {
uint8_t first = bytes[0];

View File

@ -8,5 +8,11 @@ namespace ZCompression {
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst);
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr);
/**
* @brief Max size of an inflated sd0 zlib chunk
*
*/
constexpr uint32_t MAX_SD0_CHUNK_SIZE = 1024 * 256;
}

View File

@ -0,0 +1,203 @@
#include "AssetManager.h"
#include "Game.h"
#include "dLogger.h"
#include <zlib.h>
AssetManager::AssetManager(const std::string& path) {
if (!std::filesystem::is_directory(path)) {
throw std::runtime_error("Attempted to load asset bundle (" + path + ") however it is not a valid directory.");
}
m_Path = std::filesystem::path(path);
if (std::filesystem::exists(m_Path / "client") && std::filesystem::exists(m_Path / "versions")) {
m_AssetBundleType = eAssetBundleType::Packed;
m_RootPath = m_Path;
m_ResPath = (m_Path / "client" / "res");
} else if (std::filesystem::exists(m_Path / ".." / "versions") && std::filesystem::exists(m_Path / "res")) {
m_AssetBundleType = eAssetBundleType::Packed;
m_RootPath = (m_Path / "..");
m_ResPath = (m_Path / "res");
} else if (std::filesystem::exists(m_Path / "pack") && std::filesystem::exists(m_Path / ".." / ".." / "versions")) {
m_AssetBundleType = eAssetBundleType::Packed;
m_RootPath = (m_Path / ".." / "..");
m_ResPath = m_Path;
} else if (std::filesystem::exists(m_Path / "res" / "cdclient.fdb") && !std::filesystem::exists(m_Path / "res" / "pack")) {
m_AssetBundleType = eAssetBundleType::Unpacked;
m_ResPath = (m_Path / "res");
} else if (std::filesystem::exists(m_Path / "cdclient.fdb") && !std::filesystem::exists(m_Path / "pack")) {
m_AssetBundleType = eAssetBundleType::Unpacked;
m_ResPath = m_Path;
}
if (m_AssetBundleType == eAssetBundleType::None) {
throw std::runtime_error("Failed to identify client type, cannot read client data.");
}
switch (m_AssetBundleType) {
case eAssetBundleType::Packed: {
this->LoadPackIndex();
this->UnpackRequiredAssets();
break;
}
}
}
void AssetManager::LoadPackIndex() {
m_PackIndex = new PackIndex(m_RootPath);
}
std::filesystem::path AssetManager::GetResPath() {
return m_ResPath;
}
eAssetBundleType AssetManager::GetAssetBundleType() {
return m_AssetBundleType;
}
bool AssetManager::HasFile(const char* name) {
auto fixedName = std::string(name);
std::transform(fixedName.begin(), fixedName.end(), fixedName.begin(), [](uint8_t c) { return std::tolower(c); });
std::replace(fixedName.begin(), fixedName.end(), '/', '\\');
auto realPathName = fixedName;
if (fixedName.rfind("client\\res\\", 0) != 0) {
fixedName = "client\\res\\" + fixedName;
}
if (std::filesystem::exists(m_ResPath / realPathName)) {
return true;
}
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
if (item.m_Crc == crc) {
return true;
}
}
return false;
}
bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
auto fixedName = std::string(name);
std::transform(fixedName.begin(), fixedName.end(), fixedName.begin(), [](uint8_t c) { return std::tolower(c); });
std::replace(fixedName.begin(), fixedName.end(), '\\', '/'); // On the off chance someone has the wrong slashes, force forward slashes
auto realPathName = fixedName;
if (std::filesystem::exists(m_ResPath / realPathName)) {
FILE* file;
#ifdef _WIN32
fopen_s(&file, (m_ResPath / realPathName).string().c_str(), "rb");
#elif __APPLE__
// macOS has 64bit file IO by default
file = fopen((m_ResPath / realPathName).string().c_str(), "rb");
#else
file = fopen64((m_ResPath / realPathName).string().c_str(), "rb");
#endif
fseek(file, 0, SEEK_END);
*len = ftell(file);
*data = (char*)malloc(*len);
fseek(file, 0, SEEK_SET);
fread(*data, sizeof(uint8_t), *len, file);
fclose(file);
return true;
}
if (this->m_AssetBundleType == eAssetBundleType::Unpacked) return false;
// The crc in side of the pack always uses backslashes, so we need to convert them again...
std::replace(fixedName.begin(), fixedName.end(), '/', '\\');
if (fixedName.rfind("client\\res\\", 0) != 0) {
fixedName = "client\\res\\" + fixedName;
}
int32_t packIndex = -1;
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
if (item.m_Crc == crc) {
packIndex = item.m_PackFileIndex;
crc = item.m_Crc;
break;
}
}
if (packIndex == -1 || !crc) {
return false;
}
auto packs = this->m_PackIndex->GetPacks();
auto* pack = packs.at(packIndex);
bool success = pack->ReadFileFromPack(crc, data, len);
return success;
}
AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) {
char* buf;
uint32_t len;
bool success = this->GetFile(name, &buf, &len);
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;
crc = base;
for (i = 0; i < l; i++) {
// xor next byte to upper bits of crc
crc ^= (((unsigned int)message[i]) << 24);
for (j = 0; j < 8; j++) { // Do eight times.
msb = crc >> 31;
crc <<= 1;
crc ^= (0 - msb) & 0x04C11DB7;
}
}
return crc; // don't complement crc on output
}
AssetManager::~AssetManager() {
delete m_PackIndex;
}

View File

@ -0,0 +1,78 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <filesystem>
#include "Pack.h"
#include "PackIndex.h"
enum class eAssetBundleType {
None,
Unpacked,
Packed
};
struct AssetMemoryBuffer : std::streambuf {
char* m_Base;
bool m_Success;
AssetMemoryBuffer(char* base, std::ptrdiff_t n, bool success) {
m_Base = base;
m_Success = success;
if (!m_Success) return;
this->setg(base, base, base + n);
}
pos_type seekpos(pos_type sp, std::ios_base::openmode which) override {
return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
}
pos_type seekoff(off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which = std::ios_base::in) override {
if (dir == std::ios_base::cur)
gbump(off);
else if (dir == std::ios_base::end)
setg(eback(), egptr() + off, egptr());
else if (dir == std::ios_base::beg)
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
void close() {
delete m_Base;
}
};
class AssetManager {
public:
AssetManager(const std::string& path);
~AssetManager();
std::filesystem::path GetResPath();
eAssetBundleType GetAssetBundleType();
bool HasFile(const char* name);
bool GetFile(const char* name, char** data, uint32_t* len);
AssetMemoryBuffer GetFileAsBuffer(const char* name);
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
inline uint32_t crc32b(uint32_t base, uint8_t* message, size_t l);
bool m_SuccessfullyLoaded;
std::filesystem::path m_Path;
std::filesystem::path m_RootPath;
std::filesystem::path m_ResPath;
eAssetBundleType m_AssetBundleType = eAssetBundleType::None;
PackIndex* m_PackIndex;
};

View File

@ -0,0 +1,6 @@
set(DCOMMON_DCLIENT_SOURCES
"PackIndex.cpp"
"Pack.cpp"
"AssetManager.cpp"
PARENT_SCOPE
)

119
dCommon/dClient/Pack.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "Pack.h"
#include "BinaryIO.h"
#include "ZCompression.h"
Pack::Pack(const std::filesystem::path& filePath) {
m_FilePath = filePath;
if (!std::filesystem::exists(filePath)) {
return;
}
m_FileStream = std::ifstream(filePath, std::ios::in | std::ios::binary);
m_FileStream.read(m_Version, 7);
m_FileStream.seekg(-8, std::ios::end); // move file pointer to 8 bytes before the end (location of the address of the record count)
uint32_t recordCountPos = 0;
BinaryIO::BinaryRead<uint32_t>(m_FileStream, recordCountPos);
m_FileStream.seekg(recordCountPos, std::ios::beg);
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_RecordCount);
for (int i = 0; i < m_RecordCount; i++) {
PackRecord record;
BinaryIO::BinaryRead<PackRecord>(m_FileStream, record);
m_Records.push_back(record);
}
m_FileStream.close();
}
bool Pack::HasFile(uint32_t crc) {
for (const auto& record : m_Records) {
if (record.m_Crc == crc) {
return true;
}
}
return false;
}
bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
// Time for some wacky C file reading for speed reasons
PackRecord pkRecord{};
for (const auto& record : m_Records) {
if (record.m_Crc == crc) {
pkRecord = record;
break;
}
}
if (pkRecord.m_Crc == 0) return false;
size_t pos = 0;
pos += pkRecord.m_FilePointer;
bool isCompressed = (pkRecord.m_IsCompressed & 0xff) > 0;
auto inPackSize = isCompressed ? pkRecord.m_CompressedSize : pkRecord.m_UncompressedSize;
FILE* file;
#ifdef _WIN32
fopen_s(&file, m_FilePath.string().c_str(), "rb");
#elif __APPLE__
// macOS has 64bit file IO by default
file = fopen(m_FilePath.string().c_str(), "rb");
#else
file = fopen64(m_FilePath.string().c_str(), "rb");
#endif
fseek(file, pos, SEEK_SET);
if (!isCompressed) {
char* tempData = (char*)malloc(pkRecord.m_UncompressedSize);
fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file);
*data = tempData;
*len = pkRecord.m_UncompressedSize;
fclose(file);
return true;
}
pos += 5; // skip header
fseek(file, pos, SEEK_SET);
char* decompressedData = (char*)malloc(pkRecord.m_UncompressedSize);
uint32_t currentReadPos = 0;
while (true) {
if (currentReadPos >= pkRecord.m_UncompressedSize) break;
uint32_t size;
fread(&size, sizeof(uint32_t), 1, file);
pos += 4; // Move pointer position 4 to the right
char* chunk = (char*)malloc(size);
fread(chunk, sizeof(int8_t), size, file);
pos += size; // Move pointer position the amount of bytes read to the right
int32_t err;
currentReadPos += ZCompression::Decompress((uint8_t*)chunk, size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
free(chunk);
}
*data = decompressedData;
*len = pkRecord.m_UncompressedSize;
fclose(file);
return true;
}

38
dCommon/dClient/Pack.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <vector>
#include <string>
#include <filesystem>
#pragma pack(push, 1)
struct PackRecord {
uint32_t m_Crc;
int32_t m_LowerCrc;
int32_t m_UpperCrc;
uint32_t m_UncompressedSize;
char m_UncompressedHash[32];
uint32_t m_Padding1;
uint32_t m_CompressedSize;
char m_CompressedHash[32];
uint32_t m_Padding2;
uint32_t m_FilePointer;
uint32_t m_IsCompressed; // u32 bool
};
#pragma pack(pop)
class Pack {
public:
Pack(const std::filesystem::path& filePath);
~Pack() = default;
bool HasFile(uint32_t crc);
bool ReadFileFromPack(uint32_t crc, char** data, uint32_t* len);
private:
std::ifstream m_FileStream;
std::filesystem::path m_FilePath;
char m_Version[7];
uint32_t m_RecordCount;
std::vector<PackRecord> m_Records;
};

View File

@ -0,0 +1,54 @@
#include "PackIndex.h"
#include "BinaryIO.h"
#include "Game.h"
#include "dLogger.h"
PackIndex::PackIndex(const std::filesystem::path& filePath) {
m_FileStream = std::ifstream(filePath / "versions" / "primary.pki", std::ios::in | std::ios::binary);
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_Version);
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackPathCount);
for (int i = 0; i < m_PackPathCount; i++) {
uint32_t stringLen = 0;
BinaryIO::BinaryRead<uint32_t>(m_FileStream, stringLen);
std::string path;
for (int j = 0; j < stringLen; j++) {
char inChar;
BinaryIO::BinaryRead<char>(m_FileStream, inChar);
path += inChar;
}
m_PackPaths.push_back(path);
}
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackFileIndexCount);
for (int i = 0; i < m_PackFileIndexCount; i++) {
PackFileIndex packFileIndex;
BinaryIO::BinaryRead<PackFileIndex>(m_FileStream, packFileIndex);
m_PackFileIndices.push_back(packFileIndex);
}
Game::logger->Log("PackIndex", "Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size());
for (auto& item : m_PackPaths) {
std::replace(item.begin(), item.end(), '\\', '/');
auto* pack = new Pack(filePath / item);
m_Packs.push_back(pack);
}
m_FileStream.close();
}
PackIndex::~PackIndex() {
for (const auto* item : m_Packs) {
delete item;
}
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <filesystem>
#include "Pack.h"
#pragma pack(push, 1)
struct PackFileIndex {
uint32_t m_Crc;
int32_t m_LowerCrc;
int32_t m_UpperCrc;
uint32_t m_PackFileIndex;
uint32_t m_IsCompressed; // u32 bool?
};
#pragma pack(pop)
class PackIndex {
public:
PackIndex(const std::filesystem::path& filePath);
~PackIndex();
const std::vector<std::string>& GetPackPaths() { return m_PackPaths; }
const std::vector<PackFileIndex>& GetPackFileIndices() { return m_PackFileIndices; }
const std::vector<Pack*>& GetPacks() { return m_Packs; }
private:
std::ifstream m_FileStream;
uint32_t m_Version;
uint32_t m_PackPathCount;
std::vector<std::string> m_PackPaths;
uint32_t m_PackFileIndexCount;
std::vector<PackFileIndex> m_PackFileIndices;
std::vector<Pack*> m_Packs;
};

View File

@ -35,8 +35,8 @@ void Database::Connect(const string& host, const string& database, const string&
}
void Database::Connect() {
con = driver->connect(Database::props);
con->setSchema(Database::database);
con = driver->connect(Database::props["hostName"].c_str(), Database::props["user"].c_str(), Database::props["password"].c_str());
con->setSchema(Database::database.c_str());
}
void Database::Destroy(std::string source, bool log) {

View File

@ -45,7 +45,7 @@ void MigrationRunner::RunMigrations() {
}
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name);
stmt->setString(1, migration.name.c_str());
auto* res = stmt->executeQuery();
bool doExit = res->next();
delete res;
@ -56,11 +56,11 @@ void MigrationRunner::RunMigrations() {
if (migration.name == "5_brick_model_sd0.sql") {
runSd0Migrations = true;
} else {
finalSQL.append(migration.data);
finalSQL.append(migration.data.c_str());
}
stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
stmt->setString(1, migration.name);
stmt->setString(1, migration.name.c_str());
stmt->execute();
delete stmt;
}
@ -76,7 +76,7 @@ void MigrationRunner::RunMigrations() {
for (auto& query : migration) {
try {
if (query.empty()) continue;
simpleStatement->execute(query);
simpleStatement->execute(query.c_str());
} catch (sql::SQLException& e) {
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
}
@ -103,7 +103,7 @@ void MigrationRunner::RunSQLiteMigrations() {
if (migration.data.empty()) continue;
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name);
stmt->setString(1, migration.name.c_str());
auto* res = stmt->executeQuery();
bool doExit = res->next();
delete res;

View File

@ -44,13 +44,19 @@ foreach(file ${DGAME_DMISSION_SOURCES})
set(DGAME_SOURCES ${DGAME_SOURCES} "dMission/${file}")
endforeach()
add_subdirectory(dPropertyBehaviors)
foreach(file ${DGAME_DPROPERTYBEHAVIORS_SOURCES})
set(DGAME_SOURCES ${DGAME_SOURCES} "dPropertyBehaviors/${file}")
endforeach()
add_subdirectory(dUtilities)
foreach(file ${DGAME_DUTILITIES_SOURCES})
set(DGAME_SOURCES ${DGAME_SOURCES} "dUtilities/${file}")
endforeach()
foreach(file ${DSCRIPT_SOURCES})
foreach(file ${DSCRIPTS_SOURCES})
set(DGAME_SOURCES ${DGAME_SOURCES} "${PROJECT_SOURCE_DIR}/dScripts/${file}")
endforeach()

View File

@ -656,7 +656,7 @@ void PropertyManagementComponent::Save() {
return;
}
auto* insertion = Database::CreatePreppedStmt("INSERT INTO properties_contents VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
auto* insertion = Database::CreatePreppedStmt("INSERT INTO properties_contents VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
auto* update = Database::CreatePreppedStmt("UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ? WHERE id = ?;");
auto* lookup = Database::CreatePreppedStmt("SELECT id FROM properties_contents WHERE property_id = ?;");
auto* remove = Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE id = ?;");
@ -706,6 +706,13 @@ void PropertyManagementComponent::Save() {
insertion->setDouble(9, rotation.y);
insertion->setDouble(10, rotation.z);
insertion->setDouble(11, rotation.w);
insertion->setString(12, "Objects_" + std::to_string(entity->GetLOT()) + "_name"); // Model name. TODO make this customizable
insertion->setString(13, ""); // Model description. TODO implement this.
insertion->setDouble(14, 0); // behavior 1. TODO implement this.
insertion->setDouble(15, 0); // behavior 2. TODO implement this.
insertion->setDouble(16, 0); // behavior 3. TODO implement this.
insertion->setDouble(17, 0); // behavior 4. TODO implement this.
insertion->setDouble(18, 0); // behavior 5. TODO implement this.
try {
insertion->execute();
} catch (sql::SQLException& ex) {

View File

@ -68,6 +68,8 @@
#include "PropertyVendorComponent.h"
#include "PropertySelectQueryProperty.h"
#include "TradingManager.h"
#include "ControlBehaviors.h"
#include "AMFDeserialize.h"
void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) {
CBITSTREAM;
@ -2396,8 +2398,24 @@ void GameMessages::SendUnSmash(Entity* entity, LWOOBJID builderID, float duratio
}
void GameMessages::HandleControlBehaviors(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
// TODO
Game::logger->Log("GameMessages", "Recieved Control Behavior GameMessage, but property behaviors are unimplemented.");
AMFDeserialize reader;
std::unique_ptr<AMFValue> amfArguments(reader.Read(inStream));
if (amfArguments->GetValueType() != AMFValueType::AMFArray) return;
uint32_t commandLength{};
inStream->Read(commandLength);
std::string command;
for (uint32_t i = 0; i < commandLength; i++) {
unsigned char character;
inStream->Read(character);
command.push_back(character);
}
auto owner = PropertyManagementComponent::Instance()->GetOwner();
if (!owner) return;
ControlBehaviors::ProcessCommand(entity, sysAddr, static_cast<AMFArrayValue*>(amfArguments.get()), command, owner);
}
void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
@ -2545,7 +2563,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent
delete ugcs;
//Insert into the db as a BBB model:
auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents`(`id`, `property_id`, `ugc_id`, `lot`, `x`, `y`, `z`, `rx`, `ry`, `rz`, `rw`) VALUES (?,?,?,?,?,?,?,?,?,?,?)");
auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents` VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
stmt->setUInt64(1, newIDL);
stmt->setUInt64(2, propertyId);
stmt->setUInt(3, blueprintIDSmall);
@ -2557,6 +2575,13 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent
stmt->setDouble(9, 0.0f); // ry
stmt->setDouble(10, 0.0f); // rz
stmt->setDouble(11, 0.0f); // rw
stmt->setString(12, "Objects_14_name"); // Model name. TODO make this customizable
stmt->setString(13, ""); // Model description. TODO implement this.
stmt->setDouble(14, 0); // behavior 1. TODO implement this.
stmt->setDouble(15, 0); // behavior 2. TODO implement this.
stmt->setDouble(16, 0); // behavior 3. TODO implement this.
stmt->setDouble(17, 0); // behavior 4. TODO implement this.
stmt->setDouble(18, 0); // behavior 5. TODO implement this.
stmt->execute();
delete stmt;

View File

@ -13,6 +13,7 @@
#include "PossessableComponent.h"
#include "CharacterComponent.h"
#include "eItemType.h"
#include "AssetManager.h"
class Inventory;
@ -340,18 +341,23 @@ void Item::DisassembleModel() {
std::string renderAsset = result.fieldIsNull(0) ? "" : std::string(result.getStringField(0));
std::vector<std::string> renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\');
std::string lxfmlPath = "res/BrickModels/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.')[0] + ".lxfml";
std::ifstream file(lxfmlPath);
std::string lxfmlPath = "BrickModels/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.').at(0) + ".lxfml";
auto buffer = Game::assetManager->GetFileAsBuffer(lxfmlPath.c_str());
std::istream file(&buffer);
result.finalize();
if (!file.good()) {
buffer.close();
return;
}
std::stringstream data;
data << file.rdbuf();
buffer.close();
if (data.str().empty()) {
return;
}

View File

@ -0,0 +1,4 @@
set(DGAME_DPROPERTYBEHAVIORS_SOURCES
"ControlBehaviors.cpp"
PARENT_SCOPE
)

View File

@ -0,0 +1,81 @@
#include "ControlBehaviors.h"
#include "AMFFormat.h"
#include "Entity.h"
#include "Game.h"
#include "GameMessages.h"
#include "ModelComponent.h"
#include "dLogger.h"
void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) {
if (!modelEntity || !modelOwner || !arguments) return;
if (command == "sendBehaviorListToClient")
SendBehaviorListToClient(modelEntity, sysAddr, modelOwner);
else if (command == "modelTypeChanged")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "toggleExecutionUpdates")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "addStrip")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "removeStrip")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "mergeStrips")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "splitStrip")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "updateStripUI")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "addAction")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "migrateActions")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "rearrangeStrip")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "add")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "removeActions")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "rename")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "sendBehaviorBlocksToClient")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "moveToInventory")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else if (command == "updateAction")
Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str());
else
Game::logger->Log("ControlBehaviors", "Unknown behavior command (%s)\n", command.c_str());
}
void ControlBehaviors::SendBehaviorListToClient(
Entity* modelEntity,
const SystemAddress& sysAddr,
Entity* modelOwner
) {
auto* modelComponent = modelEntity->GetComponent<ModelComponent>();
if (!modelComponent) return;
AMFArrayValue behaviorsToSerialize;
AMFArrayValue* behaviors = new AMFArrayValue(); // Empty for now
/**
* The behaviors AMFArray will have up to 5 elements in the dense portion.
* Each element in the dense portion will be made up of another AMFArray
* with the following information mapped in the associative portion
* "id": Behavior ID cast to an AMFString
* "isLocked": AMFTrue or AMFFalse of whether or not the behavior is locked
* "isLoot": AMFTrue or AMFFalse of whether or not the behavior is a custom behavior (true if custom)
* "name": The name of the behavior formatted as an AMFString
*/
behaviorsToSerialize.InsertValue("behaviors", behaviors);
AMFStringValue* amfStringValueForObjectID = new AMFStringValue();
amfStringValueForObjectID->SetStringValue(std::to_string(modelComponent->GetParent()->GetObjectID()));
behaviorsToSerialize.InsertValue("objectID", amfStringValueForObjectID);
GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorList", &behaviorsToSerialize);
}

View File

@ -0,0 +1,35 @@
#pragma once
#ifndef __CONTROLBEHAVIORS__H__
#define __CONTROLBEHAVIORS__H__
#include <string>
#include "RakNetTypes.h"
class Entity;
class AMFArrayValue;
namespace ControlBehaviors {
/**
* @brief Main driver for processing Property Behavior commands
*
* @param modelEntity The model that sent this command
* @param sysAddr The SystemAddress to respond to
* @param arguments The arguments formatted as an AMFArrayValue
* @param command The command to perform
* @param modelOwner The owner of the model which sent this command
*/
void ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner);
/**
* @brief Helper function to send the behavior list to the client
*
* @param modelEntity The model that sent this command
* @param sysAddr The SystemAddress to respond to
* @param modelOwner The owner of the model which sent this command
*/
void SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner);
};
#endif //!__CONTROLBEHAVIORS__H__

View File

@ -3,6 +3,7 @@
#include "BrickDatabase.h"
#include "Game.h"
#include "AssetManager.h"
std::vector<Brick> BrickDatabase::emptyCache{};
BrickDatabase* BrickDatabase::m_Address = nullptr;
@ -17,7 +18,8 @@ std::vector<Brick>& BrickDatabase::GetBricks(const std::string& lxfmlPath) {
return cached->second;
}
std::ifstream file(lxfmlPath);
AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer(("client/" + lxfmlPath).c_str());
std::istream file(&buffer);
if (!file.good()) {
return emptyCache;
}
@ -25,9 +27,12 @@ std::vector<Brick>& BrickDatabase::GetBricks(const std::string& lxfmlPath) {
std::stringstream data;
data << file.rdbuf();
if (data.str().empty()) {
buffer.close();
return emptyCache;
}
buffer.close();
auto* doc = new tinyxml2::XMLDocument();
if (doc->Parse(data.str().c_str(), data.str().size()) != 0) {
delete doc;

View File

@ -63,6 +63,7 @@
#include "GameConfig.h"
#include "ScriptedActivityComponent.h"
#include "LevelProgressionComponent.h"
#include "AssetManager.h"
void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) {
std::string chatCommand;
@ -582,7 +583,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (args[0].find("/") != std::string::npos) return;
if (args[0].find("\\") != std::string::npos) return;
std::ifstream infile("./res/macros/" + args[0] + ".scm");
auto buf = Game::assetManager->GetFileAsBuffer(("macros/" + args[0] + ".scm").c_str());
std::istream infile(&buf);
if (infile.good()) {
std::string line;
@ -593,6 +595,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?");
}
buf.close();
return;
}
@ -1904,10 +1908,7 @@ bool SlashCommandHandler::CheckIfAccessibleZone(const unsigned int zoneID) {
CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable");
const CDZoneTable* zone = zoneTable->Query(zoneID);
if (zone != nullptr) {
std::string zonePath = "./res/maps/" + zone->zoneName;
std::transform(zonePath.begin(), zonePath.end(), zonePath.begin(), ::tolower);
std::ifstream f(zonePath.c_str());
return f.good();
return Game::assetManager->HasFile(("maps/" + zone->zoneName).c_str());
} else {
return false;
}

View File

@ -25,6 +25,7 @@
#include "dConfig.h"
#include "dLogger.h"
#include "dServer.h"
#include "AssetManager.h"
//RakNet includes:
#include "RakNetDefines.h"
@ -44,6 +45,7 @@ namespace Game {
dServer* server;
InstanceManager* im;
dConfig* config;
AssetManager* assetManager;
} //namespace Game
bool shutdownSequenceStarted = false;
@ -99,44 +101,49 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
try {
std::string client_path = config.GetValue("client_location");
if (client_path.empty()) client_path = "./res";
Game::assetManager = new AssetManager(client_path);
} catch (std::runtime_error& ex) {
Game::logger->Log("MasterServer", "Got an error while setting up assets: %s", ex.what());
return EXIT_FAILURE;
}
MigrationRunner::RunMigrations();
//Check CDClient exists
const std::string cdclient_path = "./res/CDServer.sqlite";
std::ifstream cdclient_fd(cdclient_path);
if (!cdclient_fd.good()) {
Game::logger->Log("WorldServer", "%s could not be opened. Looking for cdclient.fdb to convert to sqlite.", cdclient_path.c_str());
cdclient_fd.close();
// 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 std::string cdclientFdbPath = "./res/cdclient.fdb";
cdclient_fd.open(cdclientFdbPath);
if (!cdclient_fd.good()) {
Game::logger->Log(
"WorldServer", "%s could not be opened."
"Please move a cdclient.fdb or an already converted database to build/res.", cdclientFdbPath.c_str());
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 %s. Clearing cdserver migration_history then copying and converting to sqlite.", cdclientFdbPath.c_str());
Game::logger->Log("WorldServer", "Found cdclient.fdb. Clearing cdserver migration_history then copying and converting to sqlite.");
auto stmt = Database::CreatePreppedStmt(R"#(DELETE FROM migration_history WHERE name LIKE "%cdserver%";)#");
stmt->executeUpdate();
delete stmt;
cdclient_fd.close();
std::string res = "python3 ../thirdparty/docker-utils/utils/fdb_to_sqlite.py " + cdclientFdbPath;
int r = system(res.c_str());
if (r != 0) {
std::string res = "python3 ../thirdparty/docker-utils/utils/fdb_to_sqlite.py " + (Game::assetManager->GetResPath() / "cdclient.fdb").string();
int result = system(res.c_str());
if (result != 0) {
Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite");
return EXIT_FAILURE;
}
if (std::rename("./cdclient.sqlite", "./res/CDServer.sqlite") != 0) {
Game::logger->Log("MasterServer", "failed to move cdclient file.");
if (std::rename("./cdclient.sqlite", (Game::assetManager->GetResPath() / "CDServer.sqlite").string().c_str()) != 0) {
Game::logger->Log("MasterServer", "Failed to move cdclient file.");
return EXIT_FAILURE;
}
}
//Connect to CDClient
try {
CDClientDatabase::Connect(cdclient_path);
CDClientDatabase::Connect((Game::assetManager->GetResPath() / "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());
@ -152,7 +159,7 @@ int main(int argc, char** argv) {
CDClientManager::Instance()->Initialize();
} catch (CppSQLite3Exception& e) {
Game::logger->Log("WorldServer", "Failed to initialize CDServer SQLite Database");
Game::logger->Log("WorldServer", "May be caused by corrupted file: %s", cdclient_path.c_str());
Game::logger->Log("WorldServer", "May be caused by corrupted file: %s", (Game::assetManager->GetResPath() / "CDServer.sqlite").string().c_str());
Game::logger->Log("WorldServer", "Error: %s", e.errorMessage());
Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode());
return EXIT_FAILURE;
@ -230,7 +237,7 @@ int main(int argc, char** argv) {
//If we found a server, update it's IP and port to the current one.
if (result->next()) {
auto* updateStatement = Database::CreatePreppedStmt("UPDATE `servers` SET `ip` = ?, `port` = ? WHERE `id` = ?");
updateStatement->setString(1, master_server_ip);
updateStatement->setString(1, master_server_ip.c_str());
updateStatement->setInt(2, Game::server->GetPort());
updateStatement->setInt(3, result->getInt("id"));
updateStatement->execute();
@ -238,7 +245,7 @@ int main(int argc, char** argv) {
} else {
//If we didn't find a server, create one.
auto* insertStatement = Database::CreatePreppedStmt("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171023)");
insertStatement->setString(1, master_server_ip);
insertStatement->setString(1, master_server_ip.c_str());
insertStatement->setInt(2, Game::server->GetPort());
insertStatement->execute();
delete insertStatement;

View File

@ -43,7 +43,7 @@ dNavMesh::~dNavMesh() {
void dNavMesh::LoadNavmesh() {
std::string path = "./res/maps/navmeshes/" + std::to_string(m_ZoneId) + ".bin";
std::string path = "./navmeshes/" + std::to_string(m_ZoneId) + ".bin";
if (!BinaryIO::DoesFileExist(path)) {
return;

View File

@ -34,7 +34,6 @@ dpEntity::dpEntity(const LWOOBJID& objectID, NiPoint3 boxDimensions, bool isStat
m_CollisionGroup = COLLISION_GROUP_ALL;
m_CollisionShape = new dpShapeBox(this, boxDimensions.x, boxDimensions.y, boxDimensions.z);
if (boxDimensions.x > 100.0f) m_IsGargantuan = true;
}
dpEntity::dpEntity(const LWOOBJID& objectID, float width, float height, float depth, bool isStatic) {
@ -45,7 +44,6 @@ dpEntity::dpEntity(const LWOOBJID& objectID, float width, float height, float de
m_CollisionGroup = COLLISION_GROUP_ALL;
m_CollisionShape = new dpShapeBox(this, width, height, depth);
if (width > 100.0f) m_IsGargantuan = true;
}
dpEntity::dpEntity(const LWOOBJID& objectID, float radius, bool isStatic) {
@ -56,7 +54,6 @@ dpEntity::dpEntity(const LWOOBJID& objectID, float radius, bool isStatic) {
m_CollisionGroup = COLLISION_GROUP_ALL;
m_CollisionShape = new dpShapeSphere(this, radius);
if (radius > 200.0f) m_IsGargantuan = true;
}
dpEntity::~dpEntity() {
@ -146,5 +143,12 @@ void dpEntity::SetAngularVelocity(const NiPoint3& newAngularVelocity) {
void dpEntity::SetGrid(dpGrid* grid) {
m_Grid = grid;
if (m_CollisionShape->GetShapeType() == dpShapeType::Sphere && static_cast<dpShapeSphere*>(m_CollisionShape)->GetRadius() * 2.0f > static_cast<float>(m_Grid->CELL_SIZE)) {
m_IsGargantuan = true;
} else if (m_CollisionShape->GetShapeType() == dpShapeType::Box && static_cast<dpShapeBox*>(m_CollisionShape)->GetWidth() > static_cast<float>(m_Grid->CELL_SIZE)) {
m_IsGargantuan = true;
}
m_Grid->Add(this);
}

View File

@ -0,0 +1,45 @@
set(DSCRIPTS_SOURCES_02_SERVER)
add_subdirectory(DLU)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_DLU})
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "DLU/${file}")
endforeach()
add_subdirectory(Enemy)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY})
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Enemy/${file}")
endforeach()
add_subdirectory(Equipment)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_EQUIPMENT})
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Equipment/${file}")
endforeach()
add_subdirectory(Map)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP})
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Map/${file}")
endforeach()
add_subdirectory(Minigame)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MINIGAME})
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Minigame/${file}")
endforeach()
add_subdirectory(Objects)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_OBJECTS})
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Objects/${file}")
endforeach()
add_subdirectory(Pets)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_PETS})
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} "Pets/${file}")
endforeach()
set(DSCRIPTS_SOURCES_02_SERVER ${DSCRIPTS_SOURCES_02_SERVER} PARENT_SCOPE)

View File

@ -0,0 +1,3 @@
set(DSCRIPTS_SOURCES_02_SERVER_DLU
"DLUVanityNPC.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,3 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_AG
"BossSpiderQueenEnemyServer.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,5 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_AM
"AmDarklingMech.cpp"
"AmSkeletonEngineer.cpp"
"AmDarklingDragon.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,45 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY)
add_subdirectory(AG)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_AG})
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "AG/${file}")
endforeach()
add_subdirectory(AM)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_AM})
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "AM/${file}")
endforeach()
add_subdirectory(FV)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_FV})
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "FV/${file}")
endforeach()
add_subdirectory(General)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_GENERAL})
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "General/${file}")
endforeach()
add_subdirectory(Survival)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_SURVIVAL})
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "Survival/${file}")
endforeach()
add_subdirectory(VE)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_VE})
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "VE/${file}")
endforeach()
add_subdirectory(Waves)
foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_WAVES})
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "Waves/${file}")
endforeach()
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} PARENT_SCOPE)

View File

@ -0,0 +1,4 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_FV
"FvMaelstromCavalry.cpp"
"FvMaelstromDragon.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,7 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_GENERAL
"BaseEnemyMech.cpp"
"BaseEnemyApe.cpp"
"GfApeSmashingQB.cpp"
"TreasureChestDragonServer.cpp"
"EnemyNjBuff.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,5 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_SURVIVAL
"AgSurvivalStromling.cpp"
"AgSurvivalMech.cpp"
"AgSurvivalSpiderling.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,3 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_VE
"VeMech.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,6 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_WAVES
"WaveBossHammerling.cpp"
"WaveBossApe.cpp"
"WaveBossSpiderling.cpp"
"WaveBossHorsemen.cpp"
PARENT_SCOPE)

View File

@ -0,0 +1,4 @@
set(DSCRIPTS_SOURCES_02_SERVER_EQUIPMENT
"MaestromExtracticatorServer.cpp"
"BootyDigServer.cpp"
PARENT_SCOPE)

Some files were not shown because too many files have changed in this diff Show More