mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-22 13:33:35 +00:00
initial implementation
This commit is contained in:
parent
afc2966507
commit
427b7c1047
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@ RelWithDebInfo/
|
||||
docker/configs
|
||||
|
||||
# Third party libraries
|
||||
thirdparty/magic_enum
|
||||
thirdparty/mysql/
|
||||
thirdparty/mysql_linux/
|
||||
CMakeVariables.txt
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -14,6 +14,3 @@
|
||||
path = thirdparty/mariadb-connector-cpp
|
||||
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
|
||||
ignore = dirty
|
||||
[submodule "thirdparty/magic_enum"]
|
||||
path = thirdparty/magic_enum
|
||||
url = https://github.com/Neargye/magic_enum.git
|
||||
|
@ -110,6 +110,23 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
find_package(MariaDB)
|
||||
|
||||
# Fetch third party dependencies
|
||||
set(DLU_THIRDPARTY_SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
magic_enum
|
||||
SYSTEM
|
||||
# SOURCE_DIR ${DLU_THIRDPARTY_SOURCE_DIR}/magic_enum
|
||||
GIT_REPOSITORY https://github.com/Neargye/magic_enum.git
|
||||
GIT_TAG v0.9.7
|
||||
)
|
||||
FetchContent_MakeAvailable(magic_enum)
|
||||
|
||||
include(CMakePrintHelpers)
|
||||
cmake_print_properties(TARGETS magic_enum::magic_enum PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
|
||||
# Create a /resServer directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
||||
|
||||
@ -252,7 +269,6 @@ include_directories(
|
||||
"tests/dGameTests/dComponentsTests"
|
||||
|
||||
SYSTEM
|
||||
"thirdparty/magic_enum/include/magic_enum"
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation"
|
||||
@ -314,7 +330,7 @@ add_subdirectory(dPhysics)
|
||||
add_subdirectory(dServer)
|
||||
|
||||
# Create a list of common libraries shared between all binaries
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "magic_enum")
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "magic_enum::magic_enum")
|
||||
|
||||
# Add platform specific common libraries
|
||||
if(UNIX)
|
||||
|
@ -70,5 +70,6 @@ else ()
|
||||
endif ()
|
||||
|
||||
target_link_libraries(dCommon
|
||||
PUBLIC magic_enum::magic_enum
|
||||
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
|
||||
INTERFACE dDatabase)
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
#include "magic_enum.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
namespace MessageType {
|
||||
enum class Game : uint16_t {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
#include "magic_enum.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
namespace MessageType {
|
||||
enum class World : uint32_t {
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define __STRINGIFIEDENUM_H__
|
||||
|
||||
#include <string>
|
||||
#include "magic_enum.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
namespace StringifiedEnum {
|
||||
template<typename T>
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "magic_enum.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
static const uint8_t NUMBER_OF_INVENTORIES = 17;
|
||||
/**
|
||||
|
@ -2,12 +2,6 @@ add_subdirectory(CDClientDatabase)
|
||||
add_subdirectory(GameDatabase)
|
||||
|
||||
add_library(dDatabase STATIC "MigrationRunner.cpp")
|
||||
|
||||
add_custom_target(conncpp_dylib
|
||||
${CMAKE_COMMAND} -E copy $<TARGET_FILE:MariaDB::ConnCpp> ${PROJECT_BINARY_DIR})
|
||||
|
||||
add_dependencies(dDatabase conncpp_dylib)
|
||||
|
||||
target_include_directories(dDatabase PUBLIC ".")
|
||||
target_link_libraries(dDatabase
|
||||
PUBLIC dDatabaseCDClient dDatabaseGame)
|
||||
PUBLIC magic_enum::magic_enum dDatabaseCDClient dDatabaseGame)
|
||||
|
@ -1,4 +1,7 @@
|
||||
add_library(dECS STATIC "ECS.cpp")
|
||||
add_library(dECS STATIC
|
||||
"Core.h"
|
||||
"Core.cpp"
|
||||
)
|
||||
target_include_directories(dECS PUBLIC .)
|
||||
target_link_libraries(dECS PRIVATE dCommon)
|
||||
target_link_libraries(dECS PRIVATE dCommon magic_enum::magic_enum)
|
||||
target_compile_options(dECS PRIVATE "-Wall")
|
||||
|
70
dECS/Core.cpp
Normal file
70
dECS/Core.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include <atomic>
|
||||
#include <magic_enum/magic_enum_containers.hpp>
|
||||
#include <eReplicaComponentType.h>
|
||||
#include "Core.h"
|
||||
|
||||
namespace dECS {
|
||||
struct WorldData {
|
||||
using CompSignature = magic_enum::containers::bitset<eReplicaComponentType>;
|
||||
using CompMap = std::unordered_map<LWOOBJID, CompSignature>;
|
||||
using CompStorage = std::unordered_map<eReplicaComponentType, std::unique_ptr<IStorage>>;
|
||||
|
||||
std::atomic<LWOOBJID> nextId = 1;
|
||||
CompMap map;
|
||||
CompStorage data;
|
||||
};
|
||||
|
||||
World::World() : m_World{ std::make_shared<WorldData>() } {};
|
||||
|
||||
Entity World::MakeEntity() {
|
||||
return Entity{ m_World->nextId.fetch_add(1, std::memory_order::relaxed),
|
||||
m_World };
|
||||
}
|
||||
|
||||
void* Entity::AddComponent(const eReplicaComponentType kind, const StorageConstructor storageConstructor) {
|
||||
if (auto w = m_World.lock()) {
|
||||
// add to kind signature
|
||||
w->map[m_Id].set(kind, true);
|
||||
|
||||
// get or add storage
|
||||
auto storageIt = w->data.find(kind);
|
||||
if (storageIt == w->data.cend()) {
|
||||
bool inserted = false;
|
||||
std::tie(storageIt, inserted) = w->data.try_emplace(kind, storageConstructor());
|
||||
if (!inserted) throw "storage emplacement failure";
|
||||
}
|
||||
auto& storage = *storageIt->second;
|
||||
|
||||
// return reference if already mapped, otherwise add component
|
||||
auto compIt = storage.rowMap.find(m_Id);
|
||||
if (compIt == storage.rowMap.cend()) {
|
||||
const auto curSize = storage.rowMap.size();
|
||||
storage.rowMap.emplace(m_Id, curSize);
|
||||
return storage.emplace_back();
|
||||
}
|
||||
const auto row = compIt->second;
|
||||
return storage.at(row);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const void* Entity::GetComponent(const eReplicaComponentType kind) const {
|
||||
if (auto const w = m_World.lock()) {
|
||||
const auto& compSig = w->map.at(m_Id);
|
||||
if (!compSig.test(kind)) return nullptr;
|
||||
|
||||
const auto& storage = *w->data.at(kind);
|
||||
const auto it = storage.rowMap.find(m_Id);
|
||||
if (it == storage.rowMap.cend()) return nullptr;
|
||||
|
||||
const auto row = it->second;
|
||||
return storage.at(row);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* Entity::GetComponent(const eReplicaComponentType kind) {
|
||||
// Casting away const for this overload is safe, if not at all pretty
|
||||
return const_cast<void*>(std::as_const(*this).GetComponent(kind));
|
||||
}
|
||||
}
|
124
dECS/Core.h
Normal file
124
dECS/Core.h
Normal file
@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class Component;
|
||||
enum class eReplicaComponentType : uint32_t;
|
||||
using LWOOBJID = int64_t;
|
||||
|
||||
namespace dECS {
|
||||
// template <typename C>
|
||||
// concept IsComponent = std::derived_from<C, Component>;
|
||||
|
||||
struct WorldData;
|
||||
struct World;
|
||||
struct Entity;
|
||||
struct IStorage;
|
||||
|
||||
template <typename C>
|
||||
class Storage;
|
||||
|
||||
using WorldPtr = std::shared_ptr<WorldData>;
|
||||
using WeakWorldPtr = std::weak_ptr<WorldData>;
|
||||
|
||||
class World {
|
||||
public:
|
||||
World();
|
||||
|
||||
[[nodiscard]]
|
||||
Entity MakeEntity();
|
||||
|
||||
private:
|
||||
WorldPtr m_World;
|
||||
};
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
friend Entity World::MakeEntity();
|
||||
|
||||
using StorageConstructor = std::function<std::unique_ptr<IStorage>()>;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr LWOOBJID Id() const noexcept {
|
||||
return m_Id;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void* AddComponent(eReplicaComponentType, StorageConstructor);
|
||||
|
||||
template <typename C>
|
||||
[[maybe_unused]]
|
||||
C* AddComponent() {
|
||||
return static_cast<C*>(AddComponent(C::ComponentType, std::make_unique<Storage<C>>));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const void* GetComponent(eReplicaComponentType) const;
|
||||
|
||||
[[nodiscard]]
|
||||
void* GetComponent(eReplicaComponentType);
|
||||
|
||||
template <typename C>
|
||||
[[nodiscard]]
|
||||
const C* GetComponent() const {
|
||||
return static_cast<const C*>(GetComponent(C::ComponentType));
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
[[nodiscard]]
|
||||
C* GetComponent() {
|
||||
return static_cast<C*>(GetComponent(C::ComponentType));
|
||||
}
|
||||
|
||||
private:
|
||||
Entity(const LWOOBJID id, const WeakWorldPtr world)
|
||||
: m_Id{ id }
|
||||
, m_World { world }
|
||||
{}
|
||||
|
||||
LWOOBJID m_Id;
|
||||
|
||||
WeakWorldPtr m_World;
|
||||
};
|
||||
|
||||
struct IStorage {
|
||||
using RowMap = std::unordered_map<LWOOBJID, size_t>;
|
||||
|
||||
virtual ~IStorage() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual void* at(size_t) = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const void* at(size_t) const = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual void* emplace_back() = 0;
|
||||
|
||||
RowMap rowMap;
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
class Storage : public IStorage {
|
||||
public:
|
||||
[[nodiscard]]
|
||||
void* at(const size_t index) override {
|
||||
return static_cast<void*>(&m_Vec.at(index));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const void* at(const size_t index) const override {
|
||||
return static_cast<const void*>(&m_Vec.at(index));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
void* emplace_back() override {
|
||||
return static_cast<void*>(&m_Vec.emplace_back());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<C> m_Vec;
|
||||
};
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#include "ECS.h"
|
||||
#include "dCommonVars.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Component {
|
||||
|
||||
}
|
65
dECS/ECS.h
65
dECS/ECS.h
@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "dCommonVars.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
namespace Component {
|
||||
constexpr size_t MAX_KINDS { 32 };
|
||||
|
||||
enum class Kind : uint32_t {
|
||||
NONE = 0,
|
||||
DESTROYABLE = 7,
|
||||
PET = 26,
|
||||
};
|
||||
|
||||
using Signature = std::bitset<MAX_KINDS>;
|
||||
|
||||
// Components
|
||||
struct Destroyable;
|
||||
struct Pet {
|
||||
static constexpr Kind KIND_ID = Kind::PET;
|
||||
|
||||
// The ID under which this pet is stored in the database (if it's tamed)
|
||||
LWOOBJID m_DatabaseId;
|
||||
|
||||
// The ID of the item from which this pet was creat
|
||||
LWOOBJID m_ItemId;
|
||||
|
||||
// The name of this pet
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class IStorage {
|
||||
public:
|
||||
constexpr IStorage(const Kind kind) : m_Kind{ kind } {}
|
||||
virtual ~IStorage() = default;
|
||||
constexpr virtual void Remove(const size_t index) = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr Kind GetKind() const {
|
||||
return m_Kind;
|
||||
}
|
||||
|
||||
protected:
|
||||
Kind m_Kind;
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
class Storage : public IStorage {
|
||||
public:
|
||||
constexpr Storage() : IStorage{ C::KIND_ID } {}
|
||||
|
||||
constexpr void Remove(const size_t index) override {
|
||||
auto& elementToDelete = m_Vec.at(index);
|
||||
auto& lastElement = m_Vec.back();
|
||||
std::swap(elementToDelete, lastElement);
|
||||
m_Vec.pop_back();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<C> m_Vec;
|
||||
};
|
||||
}
|
@ -55,7 +55,7 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp"
|
||||
"VerifyBehavior.cpp")
|
||||
|
||||
add_library(dBehaviors OBJECT ${DGAME_DBEHAVIORS_SOURCES})
|
||||
target_link_libraries(dBehaviors PUBLIC dDatabaseCDClient dPhysics)
|
||||
target_link_libraries(dBehaviors PUBLIC dDatabaseCDClient dPhysics magic_enum::magic_enum tinyxml2)
|
||||
target_include_directories(dBehaviors PUBLIC "."
|
||||
"${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # via BehaviorContext.h
|
||||
PRIVATE
|
||||
|
@ -79,4 +79,4 @@ target_include_directories(dComponents PUBLIC "."
|
||||
)
|
||||
target_precompile_headers(dComponents REUSE_FROM dGameBase)
|
||||
|
||||
target_link_libraries(dComponents INTERFACE dBehaviors)
|
||||
target_link_libraries(dComponents PUBLIC magic_enum::magic_enum tinyxml2 INTERFACE dBehaviors)
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
#include "tinyxml2.h"
|
||||
|
||||
namespace RakNet {
|
||||
class BitStream;
|
||||
};
|
||||
|
||||
class Entity;
|
||||
|
||||
/**
|
||||
|
@ -6,7 +6,7 @@ set(DGAME_DGAMEMESSAGES_SOURCES
|
||||
|
||||
add_library(dGameMessages OBJECT ${DGAME_DGAMEMESSAGES_SOURCES})
|
||||
target_link_libraries(dGameMessages
|
||||
PUBLIC dDatabase
|
||||
PUBLIC magic_enum::magic_enum tinyxml2 dDatabase
|
||||
INTERFACE dGameBase # TradingManager
|
||||
)
|
||||
target_include_directories(dGameMessages PUBLIC "."
|
||||
|
@ -24,6 +24,7 @@ target_include_directories(dInventory PUBLIC "."
|
||||
"${PROJECT_SOURCE_DIR}/dGame/dMission" # via MissionComponent.h
|
||||
"${PROJECT_SOURCE_DIR}/dZoneManager" # via Item.cpp
|
||||
)
|
||||
target_link_libraries(dInventory PUBLIC magic_enum::magic_enum tinyxml2)
|
||||
target_precompile_headers(dInventory REUSE_FROM dGameBase)
|
||||
# Workaround for compiler bug where the optimized code could result in a memcpy of 0 bytes, even though that isnt possible.
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97185
|
||||
|
@ -4,7 +4,7 @@
|
||||
#define _VARIADIC_MAX 10
|
||||
#include "dCommonVars.h"
|
||||
#include "dNetCommon.h"
|
||||
#include "magic_enum.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
enum class ServerType : uint32_t;
|
||||
enum class eLoginResponse : uint8_t;
|
||||
|
@ -8,7 +8,7 @@ set(DNET_SOURCES "AuthPackets.cpp"
|
||||
"ZoneInstanceManager.cpp")
|
||||
|
||||
add_library(dNet STATIC ${DNET_SOURCES})
|
||||
target_link_libraries(dNet PRIVATE bcrypt MD5)
|
||||
target_link_libraries(dNet PUBLIC magic_enum::magic_enum PRIVATE bcrypt MD5)
|
||||
target_include_directories(dNet PRIVATE
|
||||
"${PROJECT_SOURCE_DIR}/dCommon"
|
||||
"${PROJECT_SOURCE_DIR}/dCommon/dEnums"
|
||||
|
@ -13,7 +13,7 @@ target_include_directories(WorldServer PRIVATE
|
||||
"${PROJECT_SOURCE_DIR}/dServer" # BinaryPathFinder.h
|
||||
)
|
||||
|
||||
target_link_libraries(WorldServer ${COMMON_LIBRARIES}
|
||||
target_link_libraries(WorldServer PUBLIC ${COMMON_LIBRARIES}
|
||||
dScripts
|
||||
dGameBase
|
||||
dComponents
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "Game.h"
|
||||
#include "MessageType/Game.h"
|
||||
#include "MessageType/World.h"
|
||||
#include "magic_enum.hpp"
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#define ENUM_EQ(e, y, z)\
|
||||
LOG("%s %s", StringifiedEnum::ToString(static_cast<e>(y)).data(), #z);\
|
||||
|
@ -3,7 +3,7 @@ add_executable(dECSTests
|
||||
)
|
||||
|
||||
# Link needed libraries
|
||||
target_link_libraries(dECSTests PRIVATE dCommon dECS GTest::gtest_main)
|
||||
target_link_libraries(dECSTests PRIVATE dCommon dGame dECS GTest::gtest_main)
|
||||
|
||||
# Discover the tests
|
||||
gtest_discover_tests(dECSTests)
|
||||
|
@ -1,10 +1,67 @@
|
||||
#include <cstdio>
|
||||
#include <gtest/gtest.h>
|
||||
#include "ECS.h"
|
||||
#include "Core.h"
|
||||
#include <dComponents/Component.h>
|
||||
#include <eReplicaComponentType.h>
|
||||
|
||||
TEST(ECSTest, MakeStorage) {
|
||||
const auto storage = Component::Storage<Component::Pet>();
|
||||
const Component::IStorage* const storagePtr = &storage;
|
||||
using namespace dECS;
|
||||
|
||||
ASSERT_EQ(storagePtr->GetKind(), Component::Kind::PET);
|
||||
ASSERT_NE(storagePtr->GetKind(), Component::Kind::DESTROYABLE);
|
||||
struct TestComponent {
|
||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::CHOICE_BUILD;
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
// Test that entity IDs increment correctly
|
||||
TEST(ECSTest, IncrementEntityIdsSingleThread) {
|
||||
auto w = World{};
|
||||
|
||||
auto ea = w.MakeEntity();
|
||||
ASSERT_EQ(ea.Id(), 1);
|
||||
|
||||
auto eb = w.MakeEntity();
|
||||
ASSERT_EQ(eb.Id(), 2);
|
||||
|
||||
auto ec = w.MakeEntity();
|
||||
ASSERT_EQ(ec.Id(), 3);
|
||||
}
|
||||
|
||||
// Test adding and getting components
|
||||
TEST(ECSTest, MakeOneEntityAndAddComponents) {
|
||||
auto w = World{};
|
||||
auto e = w.MakeEntity();
|
||||
ASSERT_EQ(e.Id(), 1);
|
||||
|
||||
// add component
|
||||
auto* const testCompPtr = e.AddComponent<TestComponent>();
|
||||
ASSERT_NE(testCompPtr, nullptr);
|
||||
ASSERT_EQ(testCompPtr->ComponentType, eReplicaComponentType::CHOICE_BUILD);
|
||||
ASSERT_EQ(testCompPtr->value, 0);
|
||||
testCompPtr->value = 15;
|
||||
|
||||
// try getting the same component we just added
|
||||
auto* const getTestCompPtr = e.GetComponent<TestComponent>();
|
||||
ASSERT_NE(getTestCompPtr, nullptr);
|
||||
ASSERT_EQ(testCompPtr, getTestCompPtr);
|
||||
ASSERT_NE(getTestCompPtr->value, 0);
|
||||
ASSERT_EQ(getTestCompPtr->value, 15);
|
||||
}
|
||||
|
||||
// Test world scoping
|
||||
TEST(ECSTest, WorldScope) {
|
||||
auto e = std::optional<dECS::Entity>{};
|
||||
|
||||
{
|
||||
auto w = World{};
|
||||
e.emplace(w.MakeEntity());
|
||||
ASSERT_EQ(e->Id(), 1);
|
||||
|
||||
// add component within scope
|
||||
auto* const cPtr = e->AddComponent<TestComponent>();
|
||||
ASSERT_NE(cPtr, nullptr);
|
||||
}
|
||||
|
||||
// Attempting to access this component now that the world has gone
|
||||
// out of scope should return nullptr
|
||||
ASSERT_EQ(e->GetComponent<TestComponent>(), nullptr);
|
||||
}
|
||||
|
3
thirdparty/CMakeLists.txt
vendored
3
thirdparty/CMakeLists.txt
vendored
@ -34,9 +34,6 @@ target_include_directories(bcrypt PRIVATE "libbcrypt/src")
|
||||
# Source code for sqlite
|
||||
add_subdirectory(SQLite)
|
||||
|
||||
# Source code for magic_enum
|
||||
add_subdirectory(magic_enum)
|
||||
|
||||
# Create our third party library objects
|
||||
add_subdirectory(raknet)
|
||||
|
||||
|
1
thirdparty/magic_enum
vendored
1
thirdparty/magic_enum
vendored
@ -1 +0,0 @@
|
||||
Subproject commit e55b9b54d5cf61f8e117cafb17846d7d742dd3b4
|
Loading…
Reference in New Issue
Block a user