mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-05-23 15:22:28 +00:00
Merge branch 'main' into npc-pathing
This commit is contained in:
commit
aee8075375
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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})
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
203
dCommon/dClient/AssetManager.cpp
Normal file
203
dCommon/dClient/AssetManager.cpp
Normal 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;
|
||||
}
|
78
dCommon/dClient/AssetManager.h
Normal file
78
dCommon/dClient/AssetManager.h
Normal 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;
|
||||
};
|
6
dCommon/dClient/CMakeLists.txt
Normal file
6
dCommon/dClient/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(DCOMMON_DCLIENT_SOURCES
|
||||
"PackIndex.cpp"
|
||||
"Pack.cpp"
|
||||
"AssetManager.cpp"
|
||||
PARENT_SCOPE
|
||||
)
|
119
dCommon/dClient/Pack.cpp
Normal file
119
dCommon/dClient/Pack.cpp
Normal 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
38
dCommon/dClient/Pack.h
Normal 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;
|
||||
};
|
54
dCommon/dClient/PackIndex.cpp
Normal file
54
dCommon/dClient/PackIndex.cpp
Normal 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;
|
||||
}
|
||||
}
|
40
dCommon/dClient/PackIndex.h
Normal file
40
dCommon/dClient/PackIndex.h
Normal 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;
|
||||
};
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
4
dGame/dPropertyBehaviors/CMakeLists.txt
Normal file
4
dGame/dPropertyBehaviors/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
set(DGAME_DPROPERTYBEHAVIORS_SOURCES
|
||||
"ControlBehaviors.cpp"
|
||||
PARENT_SCOPE
|
||||
)
|
81
dGame/dPropertyBehaviors/ControlBehaviors.cpp
Normal file
81
dGame/dPropertyBehaviors/ControlBehaviors.cpp
Normal 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);
|
||||
}
|
35
dGame/dPropertyBehaviors/ControlBehaviors.h
Normal file
35
dGame/dPropertyBehaviors/ControlBehaviors.h
Normal 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__
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
45
dScripts/02_server/CMakeLists.txt
Normal file
45
dScripts/02_server/CMakeLists.txt
Normal 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)
|
3
dScripts/02_server/DLU/CMakeLists.txt
Normal file
3
dScripts/02_server/DLU/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_DLU
|
||||
"DLUVanityNPC.cpp"
|
||||
PARENT_SCOPE)
|
3
dScripts/02_server/Enemy/AG/CMakeLists.txt
Normal file
3
dScripts/02_server/Enemy/AG/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_AG
|
||||
"BossSpiderQueenEnemyServer.cpp"
|
||||
PARENT_SCOPE)
|
5
dScripts/02_server/Enemy/AM/CMakeLists.txt
Normal file
5
dScripts/02_server/Enemy/AM/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_AM
|
||||
"AmDarklingMech.cpp"
|
||||
"AmSkeletonEngineer.cpp"
|
||||
"AmDarklingDragon.cpp"
|
||||
PARENT_SCOPE)
|
45
dScripts/02_server/Enemy/CMakeLists.txt
Normal file
45
dScripts/02_server/Enemy/CMakeLists.txt
Normal 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)
|
4
dScripts/02_server/Enemy/FV/CMakeLists.txt
Normal file
4
dScripts/02_server/Enemy/FV/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_FV
|
||||
"FvMaelstromCavalry.cpp"
|
||||
"FvMaelstromDragon.cpp"
|
||||
PARENT_SCOPE)
|
7
dScripts/02_server/Enemy/General/CMakeLists.txt
Normal file
7
dScripts/02_server/Enemy/General/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_GENERAL
|
||||
"BaseEnemyMech.cpp"
|
||||
"BaseEnemyApe.cpp"
|
||||
"GfApeSmashingQB.cpp"
|
||||
"TreasureChestDragonServer.cpp"
|
||||
"EnemyNjBuff.cpp"
|
||||
PARENT_SCOPE)
|
5
dScripts/02_server/Enemy/Survival/CMakeLists.txt
Normal file
5
dScripts/02_server/Enemy/Survival/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_SURVIVAL
|
||||
"AgSurvivalStromling.cpp"
|
||||
"AgSurvivalMech.cpp"
|
||||
"AgSurvivalSpiderling.cpp"
|
||||
PARENT_SCOPE)
|
3
dScripts/02_server/Enemy/VE/CMakeLists.txt
Normal file
3
dScripts/02_server/Enemy/VE/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_VE
|
||||
"VeMech.cpp"
|
||||
PARENT_SCOPE)
|
6
dScripts/02_server/Enemy/Waves/CMakeLists.txt
Normal file
6
dScripts/02_server/Enemy/Waves/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_WAVES
|
||||
"WaveBossHammerling.cpp"
|
||||
"WaveBossApe.cpp"
|
||||
"WaveBossSpiderling.cpp"
|
||||
"WaveBossHorsemen.cpp"
|
||||
PARENT_SCOPE)
|
4
dScripts/02_server/Equipment/CMakeLists.txt
Normal file
4
dScripts/02_server/Equipment/CMakeLists.txt
Normal 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
Loading…
x
Reference in New Issue
Block a user