imgration 14/12/2025
This commit is contained in:
120
include/asset_base.hpp
Normal file
120
include/asset_base.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <ryml.hpp>
|
||||
|
||||
#include "type_info.hpp"
|
||||
|
||||
|
||||
struct AssetGUID
|
||||
{
|
||||
AssetGUID() = default;
|
||||
AssetGUID(const char* data) : AssetGUID(std::string_view(data, 32)) {};
|
||||
AssetGUID(std::string_view data)
|
||||
{
|
||||
for (size_t i = 0; i < 16; ++i) Data[0] = (Data[0] << 4) | hexToVal(data[i]);
|
||||
for (size_t i = 16; i < 32; ++i) Data[1] = (Data[1] << 4) | hexToVal(data[i]);
|
||||
}
|
||||
|
||||
static uint64_t hexToVal(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') ? (c - '0') : (c - 'a' + 10);
|
||||
}
|
||||
|
||||
bool operator==(const AssetGUID& other) const
|
||||
{
|
||||
return Data[0] == other.Data[0] && Data[1] == other.Data[1];
|
||||
}
|
||||
|
||||
static constexpr uint64_t DefaultVal = 0xe000000000000000;
|
||||
|
||||
std::array<uint64_t, 2> Data{ 0, DefaultVal };
|
||||
};
|
||||
|
||||
struct AssetPath
|
||||
{
|
||||
std::filesystem::path path{};
|
||||
AssetGUID GUID{};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using unordered_map_guid = std::unordered_map<AssetGUID, T>;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<AssetGUID> {
|
||||
size_t operator()(const AssetGUID& v) const noexcept
|
||||
{
|
||||
auto h1 = std::hash<uint64_t>{}(v.Data[0]);
|
||||
auto h2 = std::hash<uint64_t>{}(v.Data[1]);
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
inline AssetGUID ParseAssetGUID(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
auto guidStringSpan2 = node["guid"].val();
|
||||
|
||||
assert(guidStringSpan2.size() == 32);
|
||||
|
||||
return AssetGUID{std::string_view(guidStringSpan2.data(), guidStringSpan2.size())};
|
||||
}
|
||||
|
||||
struct AssetBase
|
||||
{
|
||||
std::filesystem::path Path{};
|
||||
AssetGUID GUID{};
|
||||
|
||||
// static std::span<std::string_view> GetExtensions();
|
||||
};
|
||||
|
||||
struct AssetCollectionBase
|
||||
{
|
||||
std::vector<std::unordered_map<AssetGUID, AssetBase*>*> AssetsInterface{};
|
||||
std::vector<std::string_view> AssetNames{};
|
||||
|
||||
template <typename AssetType>
|
||||
AssetType* GetAsset(AssetGUID guid)
|
||||
{
|
||||
for (size_t i = 0; i < AssetNames.size(); i++)
|
||||
if (AssetNames[i] == type_name<AssetType>())
|
||||
{
|
||||
auto& assetMap = (*AssetsInterface[i]);
|
||||
auto it = assetMap.find(guid);
|
||||
if (it != assetMap.end())
|
||||
{
|
||||
return static_cast<AssetType*>(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename AssetTypes = TypeCollection<>>
|
||||
struct AssetCollection : public AssetCollectionBase
|
||||
{
|
||||
using AssetsT = typename AssetTypes::template AsContainedType<unordered_map_guid>;
|
||||
|
||||
AssetsT Assets;
|
||||
|
||||
AssetCollection(AssetsT&& assets)
|
||||
: AssetNames(AssetTypes::get_names())
|
||||
, AssetsInterface(sizeof...(AssetTypes))
|
||||
, Assets(std::move(assets))
|
||||
{
|
||||
size_t index = 0;
|
||||
AssetTypes::ForEachT([this, &index]<typename AssetT>()
|
||||
{
|
||||
AssetsInterface[index++] = &std::get<std::unordered_map<AssetGUID, AssetT>>(Assets);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <span>
|
||||
|
||||
#include <ryml.hpp>
|
||||
#include <ryml_std.hpp>
|
||||
#include <c4/format.hpp>
|
||||
|
||||
struct AssetBase
|
||||
{
|
||||
public:
|
||||
int64_t ID;
|
||||
};
|
||||
|
||||
struct AssetGUID
|
||||
{
|
||||
AssetGUID() = default;
|
||||
AssetGUID(const char* data) : AssetGUID(std::string_view(data, 32)) {};
|
||||
AssetGUID(std::string_view data)
|
||||
{
|
||||
for (size_t i = 0; i < 16; ++i) Data[0] = (Data[0] << 4) | hexToVal(data[i]);
|
||||
for (size_t i = 16; i < 32; ++i) Data[1] = (Data[1] << 4) | hexToVal(data[i]);
|
||||
}
|
||||
|
||||
static uint64_t hexToVal(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') ? (c - '0') : (c - 'a' + 10);
|
||||
}
|
||||
|
||||
bool operator==(const AssetGUID& other) const
|
||||
{
|
||||
return Data[0] == other.Data[0] && Data[1] == other.Data[1];
|
||||
}
|
||||
|
||||
static constexpr uint64_t DefaultVal = 0xe000000000000000;
|
||||
|
||||
std::array<uint64_t, 2> Data{ 0, DefaultVal };
|
||||
};
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<AssetGUID> {
|
||||
size_t operator()(const AssetGUID& v) const noexcept
|
||||
{
|
||||
auto h1 = std::hash<uint64_t>{}(v.Data[0]);
|
||||
auto h2 = std::hash<uint64_t>{}(v.Data[1]);
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* ParseAssetRef(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
T* asset;
|
||||
node["fileID"] >> asset;
|
||||
return asset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool LinkAssetRef(const std::unordered_map<int64_t, AssetBase*>& assetsMap, T*& asset)
|
||||
{
|
||||
auto it = assetsMap.find(reinterpret_cast<int64_t>(asset));
|
||||
if (it != assetsMap.end())
|
||||
{
|
||||
asset = reinterpret_cast<T*>(it->second);
|
||||
return true;
|
||||
}
|
||||
asset = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline AssetGUID ParseAssetGUID(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
auto guidStringSpan2 = node["guid"].val();
|
||||
|
||||
assert(guidStringSpan2.size() == 32);
|
||||
|
||||
return AssetGUID{std::string_view(guidStringSpan2.data(), guidStringSpan2.size())};
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset_base.hpp"
|
||||
|
||||
struct Drop
|
||||
{
|
||||
int itemId;
|
||||
int minAmount;
|
||||
int maxAmount;
|
||||
int dropChance;
|
||||
};
|
||||
|
||||
struct Interactable_Resource : public AssetBase
|
||||
{
|
||||
int maxHealth;
|
||||
int respawnTime;
|
||||
std::vector<Drop> drops;
|
||||
std::vector<int> requiredTools;
|
||||
int xp;
|
||||
int typeId;
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <ryml_std.hpp>
|
||||
|
||||
#include "asset_base.hpp"
|
||||
#include "transform.hpp"
|
||||
|
||||
struct GameObjectAsset : public AssetBase
|
||||
{
|
||||
std::string name;
|
||||
uint8_t layer{ 0 };
|
||||
uint8_t namMeshLayer{ 0 };
|
||||
std::string tag;
|
||||
|
||||
TransformAsset* transform{ nullptr };
|
||||
std::vector<AssetBase*> Components;
|
||||
};
|
||||
|
||||
inline GameObjectAsset ParseGameObject(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
GameObjectAsset gameObject;
|
||||
|
||||
node["m_Name"] >> gameObject.name;
|
||||
node["m_Layer"] >> gameObject.layer;
|
||||
node["m_TagString"] >> gameObject.tag;
|
||||
|
||||
auto components = node["m_Component"];
|
||||
auto it = components.begin();
|
||||
|
||||
gameObject.transform = ParseAssetRef<TransformAsset>((*it)["component"]);
|
||||
++it;
|
||||
for (; it != components.end(); ++it)
|
||||
{
|
||||
gameObject.Components.push_back(ParseAssetRef<AssetBase>((*it)["component"]));
|
||||
}
|
||||
|
||||
return gameObject;
|
||||
}
|
||||
|
||||
inline void LinkGameObject(const std::unordered_map<int64_t, AssetBase*>& assetsMap, GameObjectAsset& gameObject)
|
||||
{
|
||||
LinkAssetRef<TransformAsset>(assetsMap, gameObject.transform);
|
||||
for (int i = static_cast<int>(gameObject.Components.size()) - 1; i >= 0; i--)
|
||||
{
|
||||
if (!LinkAssetRef<AssetBase>(assetsMap, gameObject.Components[i]))
|
||||
{
|
||||
std::swap(gameObject.Components[i], gameObject.Components.back());
|
||||
gameObject.Components.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
0
include/assets/image.h
Normal file
0
include/assets/image.h
Normal file
0
include/assets/mesh.h
Normal file
0
include/assets/mesh.h
Normal file
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "asset_base.hpp"
|
||||
|
||||
|
||||
struct GameObjectAsset;
|
||||
|
||||
struct MeshFilterAsset : AssetBase
|
||||
{
|
||||
AssetGUID Mesh;
|
||||
GameObjectAsset* GameObject{ nullptr };
|
||||
};
|
||||
|
||||
inline MeshFilterAsset ParseMeshFilter(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
MeshFilterAsset meshFilter;
|
||||
|
||||
meshFilter.Mesh = ParseAssetGUID(node["m_Mesh"]);
|
||||
meshFilter.GameObject = ParseAssetRef<GameObjectAsset>(node["m_GameObject"]);
|
||||
|
||||
return meshFilter;
|
||||
}
|
||||
|
||||
inline void LinkMeshFilter(const std::unordered_map<int64_t, AssetBase*>& assetsMap, MeshFilterAsset& meshFilter)
|
||||
{
|
||||
LinkAssetRef<GameObjectAsset>(assetsMap, meshFilter.GameObject);
|
||||
}
|
||||
29
include/assets/prefab.h
Normal file
29
include/assets/prefab.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset_base.hpp"
|
||||
|
||||
#include <ryml_std.hpp>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
|
||||
struct Prefab : public AssetBase
|
||||
{
|
||||
public:
|
||||
static constexpr std::array<std::string_view, 1> Extensions = { ".prefab" };
|
||||
|
||||
public:
|
||||
std::unordered_map<int64_t, ryml::Tree> Data;
|
||||
|
||||
public:
|
||||
template <typename ParsedProject>
|
||||
void Parse(ParsedProject& project, std::string& content)
|
||||
{
|
||||
using ObjectTypesT = typename ParsedProject::ObjectTypes;
|
||||
|
||||
auto names = ObjectTypesT::get_names();
|
||||
ParseSceneYaml(content, false, names, [this](std::string_view componentName, int64_t ID, ryml::Tree&& tree)
|
||||
{
|
||||
Data.emplace(ID, std::move(tree));
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset_base.hpp"
|
||||
|
||||
//struct PrefabInstanceAsset : AssetBase
|
||||
//{
|
||||
// AssetGUID prefabGUID;
|
||||
// ryml::Tree Data{};
|
||||
//};
|
||||
|
||||
struct PrefabAsset
|
||||
{
|
||||
std::filesystem::path path;
|
||||
std::string name;
|
||||
|
||||
std::unordered_map<int64_t, ryml::Tree> Data;
|
||||
};
|
||||
|
||||
//inline PrefabInstanceAsset ParsePrefabInstance(const ryml::ConstNodeRef& node)
|
||||
//{
|
||||
// PrefabInstanceAsset prefabInstance;
|
||||
// prefabInstance.prefabGUID = ParseAssetGUID(node["m_SourcePrefab"]);
|
||||
// // prefabInstance.Data = node;
|
||||
// return prefabInstance;
|
||||
//}
|
||||
118
include/assets/scene.h
Normal file
118
include/assets/scene.h
Normal file
@@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
|
||||
#include "asset_base.hpp"
|
||||
#include "type_base.hpp"
|
||||
|
||||
struct Scene : public AssetBase
|
||||
{
|
||||
public:
|
||||
static constexpr std::array<std::string_view, 1> Extensions = { ".unity" };
|
||||
|
||||
private:
|
||||
std::unordered_map<int64_t, void*> IDtoAsset;
|
||||
|
||||
public:
|
||||
int64_t GetNewID(int64_t lastID = 0)
|
||||
{
|
||||
for (;; ++lastID)
|
||||
{
|
||||
if (IDtoAsset.find(lastID) == IDtoAsset.end())
|
||||
return lastID;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ParsedProject>
|
||||
void Parse(ParsedProject& project, std::string& content)
|
||||
{
|
||||
using ObjectTypesT = typename ParsedProject::ObjectTypes;
|
||||
|
||||
auto& sceneData = project.CreateSceneData(GUID);
|
||||
|
||||
// Create ParseContext for component parsing
|
||||
ParseContext context(*this, project.Assets);
|
||||
|
||||
auto names = ObjectTypesT::get_names();
|
||||
ParseSceneYaml(content, true, names, [&sceneData, &context](std::string_view componentName, int64_t ID, ryml::Tree&& tree)
|
||||
{
|
||||
sceneData.AddComponent(componentName, ID, std::move(tree), context);
|
||||
});
|
||||
|
||||
// Link all components after parsing
|
||||
LinkAssets(project);
|
||||
}
|
||||
|
||||
template <typename ParsedProject>
|
||||
void LinkAssets(ParsedProject& project)
|
||||
{
|
||||
using ObjectTypesT = typename ParsedProject::ObjectTypes;
|
||||
|
||||
auto& sceneData = project.GetSceneData(GUID);
|
||||
|
||||
// Build the assets map (ID -> pointer)
|
||||
std::unordered_map<int64_t, TypeBase*> assetsMap;
|
||||
ObjectTypesT::ForEachT([&]<typename T>() -> void
|
||||
{
|
||||
auto& components = sceneData.template GetComponents<T>();
|
||||
for (auto& component : components)
|
||||
{
|
||||
assetsMap.emplace(component.ID, &component);
|
||||
}
|
||||
});
|
||||
|
||||
// Link all components
|
||||
ObjectTypesT::ForEachT([&]<typename T>() -> void
|
||||
{
|
||||
auto& components = sceneData.template GetComponents<T>();
|
||||
for (auto& component : components)
|
||||
{
|
||||
component.Link(assetsMap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ParsedProject>
|
||||
void MergeComponents(const ParsedProject& project, const Scene& otherScene)
|
||||
{
|
||||
using ObjectTypesT = typename ParsedProject::ObjectTypes;
|
||||
|
||||
auto& thisSceneData = project.GetSceneData(GUID);
|
||||
auto& otherSceneData = project.GetSceneData(otherScene.GUID);
|
||||
|
||||
std::unordered_map<int64_t, int64_t> newIDMap{};
|
||||
int64_t lastID = std::random_device{}();
|
||||
|
||||
ObjectTypesT::ForEachT([&]<typename T>() -> void
|
||||
{
|
||||
auto& thisComponents = thisSceneData.template GetComponents<T>();
|
||||
auto& otherComponents = otherSceneData.template GetComponents<T>();
|
||||
|
||||
for (auto otherComponentCopy : otherComponents)
|
||||
{
|
||||
int64_t originalID = otherComponentCopy.ID;
|
||||
lastID = GetNewID(lastID);
|
||||
otherComponentCopy.ID = lastID;
|
||||
|
||||
// register the new ID to the scene
|
||||
newIDMap.emplace(originalID, lastID);
|
||||
|
||||
// add the component to the scene
|
||||
thisComponents.emplace_back(std::move(otherComponentCopy));
|
||||
}
|
||||
});
|
||||
|
||||
auto& IDMapLinked = reinterpret_cast<std::unordered_map<int64_t, TypeBase*>&>(newIDMap);
|
||||
ObjectTypesT::ForEachT([&]<typename T>() -> void
|
||||
{
|
||||
auto& thisComponents = thisSceneData.template GetComponents<T>();
|
||||
for (auto& component : thisComponents)
|
||||
{
|
||||
component.Link(IDMapLinked);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "game_object.hpp"
|
||||
#include "transform.hpp"
|
||||
#include "mesh_filter.hpp"
|
||||
#include "prefab_instance.hpp"
|
||||
|
||||
struct SceneAsset
|
||||
{
|
||||
public:
|
||||
std::filesystem::path path;
|
||||
std::string name;
|
||||
|
||||
std::vector<GameObjectAsset> gameObjects;
|
||||
std::vector<TransformAsset> transforms;
|
||||
std::vector<MeshFilterAsset> meshFilters;
|
||||
// std::vector<PrefabInstanceAsset> prefabInstances;
|
||||
|
||||
std::unordered_map<int64_t, void*> IDtoAsset;
|
||||
|
||||
|
||||
};
|
||||
16
include/assets/scripts.h
Normal file
16
include/assets/scripts.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset_base.hpp"
|
||||
|
||||
struct Scripts : public AssetBase
|
||||
{
|
||||
public:
|
||||
static constexpr std::array<std::string_view, 1> Extensions = { ".cs" };
|
||||
|
||||
public:
|
||||
template <typename ParsedProject>
|
||||
void Parse(const ParsedProject& project, std::string& content)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include "asset_base.hpp"
|
||||
|
||||
struct GameObjectAsset;
|
||||
|
||||
struct TransformAsset : public AssetBase
|
||||
{
|
||||
glm::quat Rotation;
|
||||
glm::vec3 Position;
|
||||
glm::vec3 Scale;
|
||||
|
||||
glm::mat4 GlobalMatrix;
|
||||
|
||||
GameObjectAsset* GameObject{ nullptr };
|
||||
std::vector<TransformAsset*> Children;
|
||||
TransformAsset* Parent{ nullptr };
|
||||
};
|
||||
|
||||
inline glm::vec3 ParseVector3(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
glm::vec3 vector;
|
||||
node["x"] >> vector.x;
|
||||
node["y"] >> vector.y;
|
||||
node["z"] >> vector.z;
|
||||
return vector;
|
||||
}
|
||||
|
||||
inline glm::quat ParseQuaternion(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
glm::quat quaternion;
|
||||
node["x"] >> quaternion.x;
|
||||
node["y"] >> quaternion.y;
|
||||
node["z"] >> quaternion.z;
|
||||
node["w"] >> quaternion.w;
|
||||
return quaternion;
|
||||
}
|
||||
|
||||
inline TransformAsset ParseTransform(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
TransformAsset transform;
|
||||
transform.Rotation = ParseQuaternion(node["m_LocalRotation"]);
|
||||
transform.Position = ParseVector3(node["m_LocalPosition"]);
|
||||
transform.Scale = ParseVector3(node["m_LocalScale"]);
|
||||
|
||||
transform.Parent = ParseAssetRef<TransformAsset>(node["m_Father"]);
|
||||
transform.GameObject = ParseAssetRef<GameObjectAsset>(node["m_GameObject"]);
|
||||
|
||||
auto children = node["m_Children"];
|
||||
for (const auto& child : children)
|
||||
{
|
||||
transform.Children.push_back(ParseAssetRef<TransformAsset>(child));
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
inline void LinkTransform(const std::unordered_map<int64_t, AssetBase*>& assetsMap, TransformAsset& transform)
|
||||
{
|
||||
LinkAssetRef<TransformAsset>(assetsMap, transform.Parent);
|
||||
for (int i = static_cast<int>(transform.Children.size()) - 1; i >= 0; i--)
|
||||
{
|
||||
if (!LinkAssetRef<TransformAsset>(assetsMap, transform.Children[i]))
|
||||
{
|
||||
std::swap(transform.Children[i], transform.Children.back());
|
||||
transform.Children.pop_back();
|
||||
}
|
||||
}
|
||||
LinkAssetRef<GameObjectAsset>(assetsMap, transform.GameObject);
|
||||
}
|
||||
@@ -34,8 +34,8 @@ struct Achievement
|
||||
};
|
||||
|
||||
// Achievements configuration functions
|
||||
bool loadAchievementsFromXML(const std::string& filepath);
|
||||
const Achievement* getAchievementById(uint16_t id);
|
||||
const std::unordered_map<uint16_t, Achievement>& getAllAchievements();
|
||||
bool loadAchievementsFromXML(const std::string& filepath, std::unordered_map<uint16_t, Achievement>& achievements);
|
||||
const Achievement* getAchievementById(uint16_t id, const std::unordered_map<uint16_t, Achievement>& achievements);
|
||||
const std::unordered_map<uint16_t, Achievement>& getAllAchievements(const std::unordered_map<uint16_t, Achievement>& achievements);
|
||||
|
||||
} // namespace cursebreaker
|
||||
@@ -34,8 +34,8 @@ struct Harvestable
|
||||
};
|
||||
|
||||
// Harvestables configuration functions
|
||||
bool loadHarvestablesFromXML(const std::string& filepath);
|
||||
const Harvestable* getHarvestableById(uint16_t id);
|
||||
const std::unordered_map<uint16_t, Harvestable>& getAllHarvestables();
|
||||
bool loadHarvestablesFromXML(const std::string& filepath, std::unordered_map<uint16_t, Harvestable>& harvestables);
|
||||
const Harvestable* getHarvestableById(uint16_t id, const std::unordered_map<uint16_t, Harvestable>& harvestables);
|
||||
const std::unordered_map<uint16_t, Harvestable>& getAllHarvestables(const std::unordered_map<uint16_t, Harvestable>& harvestables);
|
||||
|
||||
} // namespace cursebreaker
|
||||
@@ -63,8 +63,8 @@ struct Item {
|
||||
};
|
||||
|
||||
// Items configuration functions
|
||||
bool loadItemsFromXML(const std::string& filepath);
|
||||
const Item* getItemById(uint16_t id);
|
||||
const std::unordered_map<uint16_t, Item>& getAllItems();
|
||||
bool loadItemsFromXML(const std::string& filepath, std::unordered_map<uint16_t, Item>& items);
|
||||
const Item* getItemById(uint16_t id, const std::unordered_map<uint16_t, Item>& items);
|
||||
const std::unordered_map<uint16_t, Item>& getAllItems(const std::unordered_map<uint16_t, Item>& items);
|
||||
|
||||
} // namespace cursebreaker
|
||||
|
||||
@@ -31,8 +31,8 @@ struct LootTable
|
||||
};
|
||||
|
||||
// Loot configuration functions
|
||||
bool loadLootTablesFromXML(const std::string& filepath);
|
||||
const LootTable* getLootTableById(uint16_t id);
|
||||
const std::unordered_map<uint16_t, LootTable>& getAllLootTables();
|
||||
bool loadLootTablesFromXML(const std::string& filepath, std::unordered_map<uint16_t, LootTable>& lootTables);
|
||||
const LootTable* getLootTableById(uint16_t id, const std::unordered_map<uint16_t, LootTable>& lootTables);
|
||||
const std::unordered_map<uint16_t, LootTable>& getAllLootTables(const std::unordered_map<uint16_t, LootTable>& lootTables);
|
||||
|
||||
} // namespace cursebreaker
|
||||
@@ -36,8 +36,8 @@ struct NPC
|
||||
};
|
||||
|
||||
// NPCs configuration functions
|
||||
bool loadNPCsFromXML(const std::string& filepath);
|
||||
const NPC* getNPCById(uint16_t id);
|
||||
const std::unordered_map<uint16_t, NPC>& getAllNPCs();
|
||||
bool loadNPCsFromXML(const std::string& filepath, std::unordered_map<uint16_t, NPC>& npcs);
|
||||
const NPC* getNPCById(uint16_t id, const std::unordered_map<uint16_t, NPC>& npcs);
|
||||
const std::unordered_map<uint16_t, NPC>& getAllNPCs(const std::unordered_map<uint16_t, NPC>& npcs);
|
||||
|
||||
} // namespace cursebreaker
|
||||
@@ -31,8 +31,8 @@ struct Shop
|
||||
};
|
||||
|
||||
// Shops configuration functions
|
||||
bool loadShopsFromXML(const std::string& filepath);
|
||||
const Shop* getShopById(uint16_t id);
|
||||
const std::unordered_map<uint16_t, Shop>& getAllShops();
|
||||
bool loadShopsFromXML(const std::string& filepath, std::unordered_map<uint16_t, Shop>& shops);
|
||||
const Shop* getShopById(uint16_t id, const std::unordered_map<uint16_t, Shop>& shops);
|
||||
const std::unordered_map<uint16_t, Shop>& getAllShops(const std::unordered_map<uint16_t, Shop>& shops);
|
||||
|
||||
} // namespace cursebreaker
|
||||
@@ -5,53 +5,295 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
#include <span>
|
||||
#include <bitset>
|
||||
#include <type_traits>
|
||||
|
||||
#include <SQLiteCpp/SQLiteCpp.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <ryml.hpp>
|
||||
#include <ryml_std.hpp>
|
||||
|
||||
#include "assets/asset_base.hpp"
|
||||
#include "assets/scene.hpp"
|
||||
#include "type_base.hpp"
|
||||
#include "assets/scene.h"
|
||||
#include "configs/items.h"
|
||||
#include "configs/loot.h"
|
||||
#include "configs/harvestables.h"
|
||||
#include "configs/npcs.h"
|
||||
#include "configs/shops.h"
|
||||
#include "configs/achievements.h"
|
||||
#include "types/prefab_instance.h"
|
||||
|
||||
struct AssetPath
|
||||
{
|
||||
std::filesystem::path path{};
|
||||
AssetGUID GUID{};
|
||||
};
|
||||
|
||||
namespace cursebreaker {
|
||||
|
||||
struct ParsedProject
|
||||
#include "type_info.hpp"
|
||||
#include "asset_base.hpp"
|
||||
|
||||
// Forward declarations for ForEachObj
|
||||
struct GameObject;
|
||||
struct Transform;
|
||||
|
||||
|
||||
|
||||
class ParsedProjectBase
|
||||
{
|
||||
public:
|
||||
std::filesystem::path m_projectRoot;
|
||||
|
||||
std::vector<AssetPath> m_scriptFiles;
|
||||
std::vector<AssetPath> m_imageFiles;
|
||||
std::vector<AssetPath> m_meshFiles;
|
||||
std::vector<AssetPath> m_sceneFiles;
|
||||
std::vector<AssetPath> m_prefabFiles;
|
||||
public:
|
||||
ParsedProjectBase(const std::filesystem::path& projectRoot) : m_projectRoot{ projectRoot } {}
|
||||
|
||||
bool HasAssetType(std::string_view name) { return std::find(m_assetNames.begin(), m_assetNames.end(), name) != m_assetNames.end(); }
|
||||
bool HasMonobehaviourType(std::string_view name) { return std::find(m_monobehaviourNames.begin(), m_monobehaviourNames.end(), name) != m_monobehaviourNames.end(); }
|
||||
bool HasUnityType(std::string_view name) { return std::find(m_unityNames.begin(), m_unityNames.end(), name) != m_unityNames.end(); }
|
||||
|
||||
std::vector<PrefabAsset> m_prefabAssets;
|
||||
std::vector<SceneAsset> m_sceneAssets;
|
||||
protected:
|
||||
std::vector<std::string_view> m_assetNames;
|
||||
std::vector<std::string_view> m_monobehaviourNames;
|
||||
std::vector<std::string_view> m_unityNames;
|
||||
|
||||
std::unordered_map<AssetGUID, PrefabAsset*> m_prefabsMap;
|
||||
std::unordered_map<AssetGUID, uint32_t> m_scriptToClassHash;
|
||||
|
||||
std::unordered_map<uint16_t, Item> m_items;
|
||||
std::unordered_map<uint16_t, LootTable> m_lootTables;
|
||||
std::unordered_map<uint16_t, Harvestable> m_harvestables;
|
||||
std::unordered_map<uint16_t, NPC> m_npcs;
|
||||
std::unordered_map<uint16_t, Shop> m_shops;
|
||||
std::unordered_map<uint16_t, Achievement> m_achievements;
|
||||
public:
|
||||
AssetCollectionBase* AssetsInterface;
|
||||
};
|
||||
|
||||
void ParseProject(const std::filesystem::path& projectRoot);
|
||||
template <
|
||||
typename UnityTypes = TypeCollection<>,
|
||||
typename MonobehaviourTypes = TypeCollection<>
|
||||
>
|
||||
class SceneData final
|
||||
{
|
||||
public:
|
||||
using UnityTypesT = UnityTypes;
|
||||
using MonobehaviourTypesT = MonobehaviourTypes;
|
||||
using AllTypes = typename UnityTypes::template MergeWith<MonobehaviourTypes>;
|
||||
using AllTypesContainer = typename AllTypes::template AsContainedType<std::vector>;
|
||||
|
||||
extern ParsedProject g_parsedProject;
|
||||
private:
|
||||
AllTypesContainer m_Data{};
|
||||
|
||||
public:
|
||||
void AddComponent(std::string_view ComponentName, int64_t ID, ryml::Tree&& tree, ParseContext& context)
|
||||
{
|
||||
auto it = AddObjectFunctions.find(ComponentName);
|
||||
assert(it != AddObjectFunctions.end());
|
||||
auto nodeRef = tree.rootref();
|
||||
it->second(static_cast<void*>(&m_Data), static_cast<const void*>(&nodeRef), ID, static_cast<void*>(&context));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const std::vector<T>& GetComponents() const
|
||||
{
|
||||
return std::get<std::vector<T>>(m_Data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T>& GetComponents()
|
||||
{
|
||||
return std::get<std::vector<T>>(m_Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all GameObjects that have ALL of the specified component types.
|
||||
*
|
||||
* This function uses a bitset-based component mask for efficient filtering,
|
||||
* only checking components on GameObjects that have all required types.
|
||||
*
|
||||
* Usage:
|
||||
* sceneData.ForEachObj<Transform>([](GameObject& go, Transform& t) { ... });
|
||||
* sceneData.ForEachObj<Transform, MeshFilter>([](GameObject& go, Transform& t, MeshFilter& m) { ... });
|
||||
*
|
||||
* @tparam ComponentTypes The component types to filter by
|
||||
* @param func Lambda/function taking GameObject reference followed by references to the specified component types
|
||||
*/
|
||||
template <typename... ComponentTypes, typename Func>
|
||||
void ForEachObj(Func&& func)
|
||||
{
|
||||
ForEachObjImpl<ComponentTypes...>(*this, std::forward<Func>(func));
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all GameObjects that have ALL of the specified component types (const version).
|
||||
*
|
||||
* @tparam ComponentTypes The component types to filter by
|
||||
* @param func Lambda/function taking const GameObject reference followed by const references to the specified component types
|
||||
*/
|
||||
template <typename... ComponentTypes, typename Func>
|
||||
void ForEachObj(Func&& func) const
|
||||
{
|
||||
ForEachObjImpl<ComponentTypes...>(*this, std::forward<Func>(func));
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper implementation for ForEachObj that works with both const and non-const
|
||||
template <typename... ComponentTypes, typename SceneDataRef, typename Func>
|
||||
static void ForEachObjImpl(SceneDataRef&& sceneData, Func&& func)
|
||||
{
|
||||
static_assert(sizeof...(ComponentTypes) > 0, "At least one component type must be specified");
|
||||
|
||||
// Build the required component mask
|
||||
std::bitset<64> requiredMask;
|
||||
((requiredMask.set(AllTypes::template GetTypeIndex<ComponentTypes>())), ...);
|
||||
|
||||
// Get the GameObjects vector (const or non-const depending on sceneData)
|
||||
auto& gameObjects = sceneData.template GetComponents<GameObject>();
|
||||
|
||||
// Iterate through all game objects
|
||||
for (auto& gameObject : gameObjects)
|
||||
{
|
||||
// Check if this GameObject has all required components
|
||||
if ((gameObject.ComponentMask & requiredMask) == requiredMask)
|
||||
{
|
||||
// Use conditional const for pointer types based on whether sceneData is const
|
||||
using GameObjectT = std::remove_reference_t<decltype(gameObject)>;
|
||||
using TransformPtrT = std::conditional_t<std::is_const_v<GameObjectT>,
|
||||
const Transform*, Transform*>;
|
||||
|
||||
// Extract the components
|
||||
std::tuple<std::conditional_t<std::is_const_v<GameObjectT>,
|
||||
const ComponentTypes*, ComponentTypes*>...> components;
|
||||
bool allFound = true;
|
||||
|
||||
// Try to extract each required component type
|
||||
([&]()
|
||||
{
|
||||
using ComponentPtrT = std::conditional_t<std::is_const_v<GameObjectT>,
|
||||
const ComponentTypes*, ComponentTypes*>;
|
||||
|
||||
if constexpr (std::is_same_v<ComponentTypes, Transform>)
|
||||
{
|
||||
std::get<ComponentPtrT>(components) = gameObject.transform;
|
||||
if (!gameObject.transform) allFound = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ComponentPtrT found = nullptr;
|
||||
for (auto* comp : gameObject.Components)
|
||||
{
|
||||
if (comp && comp->TypeID == AllTypes::template GetTypeIndex<ComponentTypes>())
|
||||
{
|
||||
found = static_cast<ComponentPtrT>(comp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::get<ComponentPtrT>(components) = found;
|
||||
if (!found) allFound = false;
|
||||
}
|
||||
}(), ...);
|
||||
|
||||
// If all components were found, call the function with GameObject first, then components
|
||||
if (allFound)
|
||||
{
|
||||
std::apply([&](auto*... comps)
|
||||
{
|
||||
func(gameObject, *comps...);
|
||||
}, components);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using AddObjectFunctionT = void*(*)(void*, const void*, int64_t, void*);
|
||||
|
||||
static auto GetAddObjectFunctions()
|
||||
{
|
||||
std::unordered_map<std::string_view, AddObjectFunctionT> functions;
|
||||
AllTypes::ForEachT([&functions]<typename T>()
|
||||
{
|
||||
functions[type_name<T>()] = +[](void* pSceneData, const void* pComponentYaml, int64_t ID, void* pContext) -> void*
|
||||
{
|
||||
SceneData& sceneData = *static_cast<SceneData*>(pSceneData);
|
||||
const ryml::ConstNodeRef& componentYaml = *static_cast<const ryml::ConstNodeRef*>(pComponentYaml);
|
||||
ParseContext& context = *static_cast<ParseContext*>(pContext);
|
||||
|
||||
T component{};
|
||||
component.ID = ID;
|
||||
component.TypeID = AllTypes::template GetTypeIndex<T>(); // Set the TypeID for bitset operations
|
||||
|
||||
// Parse the component with context
|
||||
component.Parse(componentYaml.child(0).child(0), context);
|
||||
|
||||
return &std::get<std::vector<T>>(sceneData.m_Data).emplace_back(std::move(component));
|
||||
};
|
||||
});
|
||||
return functions;
|
||||
}
|
||||
|
||||
private:
|
||||
inline static std::unordered_map<std::string_view, AddObjectFunctionT> AddObjectFunctions = GetAddObjectFunctions();
|
||||
};
|
||||
|
||||
template <
|
||||
typename UnityTypes = TypeCollection<>,
|
||||
typename MonobehaviourTypes = TypeCollection<>,
|
||||
typename AssetTypes = TypeCollection<>
|
||||
>
|
||||
class ParsedProject final : public ParsedProjectBase
|
||||
{
|
||||
public:
|
||||
using UnityTypesT = UnityTypes;
|
||||
using MonobehaviourTypesT = MonobehaviourTypes;
|
||||
using AssetTypesT = AssetTypes;
|
||||
|
||||
using ObjectTypes = typename UnityTypes::template MergeWith<MonobehaviourTypes>;
|
||||
using AllTypes = typename UnityTypes::template MergeWith<MonobehaviourTypes>;
|
||||
|
||||
public:
|
||||
AssetCollection<AssetTypes> Assets;
|
||||
|
||||
private:
|
||||
std::unordered_map<AssetGUID, SceneData<UnityTypes, MonobehaviourTypes>> m_sceneData;
|
||||
|
||||
public:
|
||||
ParsedProject(const std::filesystem::path& projectRoot) : ParsedProjectBase(projectRoot)
|
||||
{
|
||||
auto asset_names = AssetTypes::get_names();
|
||||
m_assetNames.assign(asset_names.begin(), asset_names.end());
|
||||
|
||||
auto monobehaviour_names = MonobehaviourTypes::get_names();
|
||||
m_monobehaviourNames.assign(monobehaviour_names.begin(), monobehaviour_names.end());
|
||||
|
||||
auto unity_names = UnityTypes::get_names();
|
||||
m_unityNames.assign(unity_names.begin(), unity_names.end());
|
||||
|
||||
Assets = AssetCollectionBase{ asset_names };
|
||||
AssetsInterface = &Assets;
|
||||
}
|
||||
|
||||
auto& CreateSceneData(AssetGUID guid)
|
||||
{
|
||||
return m_sceneData[guid];
|
||||
}
|
||||
|
||||
auto& GetSceneData(AssetGUID guid)
|
||||
{
|
||||
auto it = m_sceneData.find(guid);
|
||||
assert(it != m_sceneData.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto& GetSceneData(AssetGUID guid) const
|
||||
{
|
||||
auto it = m_sceneData.find(guid);
|
||||
assert(it != m_sceneData.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template <typename Asset>
|
||||
std::unordered_map<AssetGUID, Asset>& GetAssets() { return std::get<std::unordered_map<AssetGUID, Asset>>(Assets); }
|
||||
template <typename Asset>
|
||||
const std::unordered_map<AssetGUID, Asset>& GetAssets() const { return std::get<std::unordered_map<AssetGUID, Asset>>(Assets); }
|
||||
|
||||
template <typename Function>
|
||||
void ForEachAsset(Function func)
|
||||
{
|
||||
AssetTypes::ForEachT([&]<typename T>() {
|
||||
func(GetAssets<T>());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
AssetGUID GetAssetGUIDFromFile(const std::filesystem::path& path);
|
||||
void ParseSceneYaml(std::string& content, bool in_place, std::span<std::string_view> assetNames = {}, std::function<void(std::string_view, int64_t, ryml::Tree&&)> callback = {});
|
||||
|
||||
} // namespace cursebreaker
|
||||
77
include/project_parser.hpp
Normal file
77
include/project_parser.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "project_parser.h"
|
||||
|
||||
|
||||
|
||||
template <typename AssetTypes = TypeCollection<>>
|
||||
auto FindAssetFiles(std::string_view project_root)
|
||||
{
|
||||
using AssetsContainer = typename AssetTypes::template AsContainedType<unordered_map_guid>;
|
||||
AssetsContainer Assets{};
|
||||
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(project_root))
|
||||
{
|
||||
if (entry.is_directory()) continue;
|
||||
|
||||
std::string extension = entry.path().extension().string();
|
||||
|
||||
if (extension == std::string_view(".meta")) continue;
|
||||
|
||||
AssetTypes::ForEachT([&Assets, &extension, &entry]<typename AssetT>()
|
||||
{
|
||||
constexpr auto assetExtensions = AssetT::Extensions;
|
||||
|
||||
for (auto assetExtension : assetExtensions)
|
||||
{
|
||||
if (extension == assetExtension)
|
||||
{
|
||||
static_assert(std::is_base_of_v<AssetBase, AssetT>, "Asset Type must derive from AssetBase");
|
||||
|
||||
AssetT asset{};
|
||||
asset.Path = entry.path();
|
||||
asset.GUID = GetAssetGUIDFromFile(entry.path().string() + ".meta");
|
||||
std::get<std::unordered_map<AssetGUID, AssetT>>(Assets).emplace(asset.GUID, std::move(asset));
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Assets;
|
||||
}
|
||||
|
||||
template <typename AssetTypes = TypeCollection<>, typename ProjectType>
|
||||
void InitializeAssetFiles(ProjectType& project)
|
||||
{
|
||||
AssetTypes::ForEachT([&project]<typename AssetT>()
|
||||
{
|
||||
std::string buffer{};
|
||||
|
||||
auto& assetMap = std::get<std::unordered_map<AssetGUID, AssetT>>(project.Assets);
|
||||
for (auto& [guid, asset] : assetMap)
|
||||
{
|
||||
buffer.clear();
|
||||
std::ifstream file(asset.Path);
|
||||
buffer.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
|
||||
|
||||
asset.Parse(project, buffer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <
|
||||
typename AssetTypes = TypeCollection<>,
|
||||
typename UnityTypes = TypeCollection<>,
|
||||
typename MonobehaviourTypes = TypeCollection<>
|
||||
>
|
||||
ParsedProject<UnityTypes, MonobehaviourTypes, AssetTypes> ParseProject(const std::filesystem::path& projectRoot)
|
||||
{
|
||||
auto project = ParsedProject<UnityTypes, MonobehaviourTypes, AssetTypes>{projectRoot};
|
||||
|
||||
project.Assets = FindAssetFiles<AssetTypes>(projectRoot.generic_string());
|
||||
|
||||
InitializeAssetFiles<AssetTypes>(project);
|
||||
|
||||
return project;
|
||||
}
|
||||
@@ -1,5 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "assets/scene.hpp"
|
||||
|
||||
void BuildTree(SceneAsset& sceneAsset);
|
||||
#pragma once
|
||||
|
||||
#include "assets/scene.h"
|
||||
#include "types/transform.h"
|
||||
#include <vector>
|
||||
|
||||
void BuildTreeHelper(Transform& transform, const glm::mat4& parentMatrix);
|
||||
|
||||
template <typename ParsedProject>
|
||||
void BuildTree(ParsedProject& project, Scene& scene)
|
||||
{
|
||||
// Get the scene data which contains the components
|
||||
auto& sceneData = project.GetSceneData(scene.GUID);
|
||||
|
||||
// Get all transforms from the scene data
|
||||
auto& transforms = sceneData.template GetComponents<Transform>();
|
||||
|
||||
// Find transforms with no parent (root transforms)
|
||||
std::vector<Transform*> rootTransforms;
|
||||
|
||||
for (auto& transform : transforms)
|
||||
{
|
||||
if (transform.Parent == nullptr)
|
||||
{
|
||||
rootTransforms.push_back(&transform);
|
||||
}
|
||||
}
|
||||
|
||||
// Build tree for each root transform
|
||||
for (auto rootTransform : rootTransforms)
|
||||
{
|
||||
BuildTreeHelper(*rootTransform, glm::mat4(1.0f));
|
||||
}
|
||||
}
|
||||
56
include/type_base.hpp
Normal file
56
include/type_base.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <span>
|
||||
|
||||
#include <ryml.hpp>
|
||||
#include <ryml_std.hpp>
|
||||
#include <c4/format.hpp>
|
||||
|
||||
#include "asset_base.hpp"
|
||||
|
||||
// Forward declarations
|
||||
struct Scene;
|
||||
|
||||
struct TypeBase
|
||||
{
|
||||
public:
|
||||
int64_t ID;
|
||||
int32_t TypeID{ -1 }; // Runtime type identification for bitset operations
|
||||
};
|
||||
|
||||
struct ParseContext
|
||||
{
|
||||
template <typename AssetsT>
|
||||
ParseContext(Scene& mainScene, AssetsT& assets)
|
||||
: MainScene(mainScene)
|
||||
, Assets(&assets)
|
||||
{}
|
||||
|
||||
Scene& MainScene;
|
||||
AssetCollectionBase& Assets;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool LinkObjectRef(const std::unordered_map<int64_t, TypeBase*>& assetsMap, T*& asset)
|
||||
{
|
||||
auto it = assetsMap.find(reinterpret_cast<int64_t>(asset));
|
||||
if (it != assetsMap.end())
|
||||
{
|
||||
asset = reinterpret_cast<T*>(it->second);
|
||||
return true;
|
||||
}
|
||||
asset = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* ParseObjectRef(const ryml::ConstNodeRef& node)
|
||||
{
|
||||
T* asset;
|
||||
node["fileID"] >> asset;
|
||||
return asset;
|
||||
}
|
||||
107
include/type_info.hpp
Normal file
107
include/type_info.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/*
|
||||
* Get the type name of a template parameter
|
||||
*/
|
||||
template<typename T>
|
||||
consteval std::string_view type_name() {
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
constexpr std::string_view full = __PRETTY_FUNCTION__;
|
||||
constexpr std::string_view prefix = "std::string_view type_name() [T = ";
|
||||
constexpr std::string_view suffix = "]";
|
||||
#elif defined(_MSC_VER)
|
||||
constexpr std::string_view full = __FUNCSIG__;
|
||||
constexpr std::string_view prefix = "class std::basic_string_view<char,struct std::char_traits<char> > __cdecl type_name<";
|
||||
constexpr std::string_view suffix = ">(void)";
|
||||
#endif
|
||||
|
||||
constexpr auto start = full.find(prefix) + prefix.size();
|
||||
constexpr auto end = full.rfind(suffix);
|
||||
constexpr std::string_view raw_name = full.substr(start, end - start);
|
||||
|
||||
// Remove "class " or "struct " prefix
|
||||
constexpr std::string_view class_prefix = "class ";
|
||||
constexpr std::string_view struct_prefix = "struct ";
|
||||
|
||||
constexpr std::string_view without_keyword =
|
||||
raw_name.starts_with(class_prefix) ? raw_name.substr(class_prefix.size()) :
|
||||
raw_name.starts_with(struct_prefix) ? raw_name.substr(struct_prefix.size()) :
|
||||
raw_name;
|
||||
|
||||
// Remove namespace - keep only the part after the last "::"
|
||||
constexpr auto last_colon = without_keyword.rfind("::");
|
||||
constexpr std::string_view final_name =
|
||||
(last_colon != std::string_view::npos)
|
||||
? without_keyword.substr(last_colon + 2)
|
||||
: without_keyword;
|
||||
|
||||
return final_name;
|
||||
}
|
||||
|
||||
template <typename ... Ts>
|
||||
struct TypeCollection
|
||||
{
|
||||
using Tuple = std::tuple<Ts...>;
|
||||
|
||||
template <typename ... OtherTs>
|
||||
using Merge = TypeCollection<Ts..., OtherTs...>;
|
||||
|
||||
template <typename OtherTypeCollection>
|
||||
struct MergeWithImpl;
|
||||
|
||||
template <typename ... OtherTs>
|
||||
struct MergeWithImpl<TypeCollection<OtherTs...>>
|
||||
{
|
||||
using type = TypeCollection<Ts..., OtherTs...>;
|
||||
};
|
||||
|
||||
template <typename OtherTypeCollection>
|
||||
using MergeWith = typename MergeWithImpl<OtherTypeCollection>::type;
|
||||
|
||||
template <template <typename> typename ContainerType>
|
||||
using AsContainedType = std::tuple<ContainerType<Ts>...>;
|
||||
|
||||
static constexpr std::array<std::string_view, sizeof...(Ts)> get_names()
|
||||
{
|
||||
return std::array<std::string_view, sizeof...(Ts)>{ type_name<Ts>()... };
|
||||
}
|
||||
|
||||
static constexpr bool has_duplicate_names()
|
||||
{
|
||||
constexpr auto names = get_names();
|
||||
for (size_t i = 0; i < names.size(); i++)
|
||||
for (size_t j = i + 1; j < names.size(); j++)
|
||||
if (names[i] == names[j])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for duplicates
|
||||
static_assert(!has_duplicate_names());
|
||||
|
||||
template <typename Func>
|
||||
static constexpr void ForEachT(Func&& func)
|
||||
{
|
||||
(func.template operator()<Ts>(), ...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static constexpr bool HasT()
|
||||
{
|
||||
return (std::is_same_v<T, Ts> || ...);
|
||||
}
|
||||
|
||||
// Get the index of a type in the collection
|
||||
template <typename T>
|
||||
static constexpr int32_t GetTypeIndex()
|
||||
{
|
||||
int32_t index = 0;
|
||||
bool found = false;
|
||||
((std::is_same_v<T, Ts> ? (found = true, false) : (found ? false : (++index, false))), ...);
|
||||
return found ? index : -1;
|
||||
}
|
||||
|
||||
// Get the type index at runtime by comparing type IDs
|
||||
static constexpr size_t Count() { return sizeof...(Ts); }
|
||||
};
|
||||
11
include/types/Interactable_resource.h
Normal file
11
include/types/Interactable_resource.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "type_base.hpp"
|
||||
|
||||
struct Interactable_Resource : public TypeBase
|
||||
{
|
||||
uint16_t ResourceID;
|
||||
|
||||
void Parse(const ryml::ConstNodeRef& node, ParseContext& context);
|
||||
void Link(const std::unordered_map<int64_t, TypeBase*>& assetsMap) {};
|
||||
};
|
||||
65
include/types/game_object.h
Normal file
65
include/types/game_object.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
#include <ryml_std.hpp>
|
||||
|
||||
#include "type_base.hpp"
|
||||
#include "transform.h"
|
||||
|
||||
struct GameObject : public TypeBase
|
||||
{
|
||||
std::string name;
|
||||
uint8_t layer{ 0 };
|
||||
uint8_t namMeshLayer{ 0 };
|
||||
std::string tag;
|
||||
|
||||
Transform* transform{ nullptr };
|
||||
std::vector<TypeBase*> Components;
|
||||
|
||||
/**
|
||||
* ComponentMask is a bitset where each bit corresponds to a component type index.
|
||||
* This allows for extremely fast checking of whether a GameObject has specific components.
|
||||
* The bit is set during the Link() phase when components are resolved.
|
||||
* Max 64 different component types are supported.
|
||||
*/
|
||||
std::bitset<64> ComponentMask;
|
||||
|
||||
void Parse(const ryml::ConstNodeRef& node, ParseContext& context);
|
||||
void Link(const std::unordered_map<int64_t, TypeBase*>& assetsMap);
|
||||
|
||||
// Check if this GameObject has a specific component type
|
||||
template <typename T>
|
||||
bool HasComponent() const
|
||||
{
|
||||
// Type index must be set by the system
|
||||
for (auto* comp : Components)
|
||||
{
|
||||
if (comp && comp->TypeID >= 0 && comp->TypeID < 64)
|
||||
{
|
||||
if (ComponentMask.test(comp->TypeID))
|
||||
{
|
||||
// Additional runtime check could be added here
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get a component of a specific type
|
||||
template <typename T>
|
||||
T* GetComponent()
|
||||
{
|
||||
for (auto* comp : Components)
|
||||
{
|
||||
if (auto* typedComp = dynamic_cast<T*>(comp))
|
||||
{
|
||||
return typedComp;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
18
include/types/mesh_filter.h
Normal file
18
include/types/mesh_filter.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "type_base.hpp"
|
||||
|
||||
|
||||
struct GameObject;
|
||||
|
||||
struct MeshFilter : TypeBase
|
||||
{
|
||||
AssetGUID Mesh;
|
||||
GameObject* GameObject{ nullptr };
|
||||
|
||||
void Parse(const ryml::ConstNodeRef& node, ParseContext& context);
|
||||
void Link(const std::unordered_map<int64_t, TypeBase*>& assetsMap);
|
||||
};
|
||||
|
||||
13
include/types/prefab_instance.h
Normal file
13
include/types/prefab_instance.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "type_base.hpp"
|
||||
|
||||
struct PrefabInstance : public TypeBase
|
||||
{
|
||||
public:
|
||||
void Parse(const ryml::ConstNodeRef& node, ParseContext& context);
|
||||
void Link(const std::unordered_map<int64_t, TypeBase*>& assetsMap) {};
|
||||
|
||||
public:
|
||||
std::unordered_map<int64_t, ryml::Tree> Data;
|
||||
};
|
||||
27
include/types/transform.h
Normal file
27
include/types/transform.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include "type_base.hpp"
|
||||
|
||||
struct GameObject;
|
||||
|
||||
struct Transform : public TypeBase
|
||||
{
|
||||
glm::quat Rotation;
|
||||
glm::vec3 Position;
|
||||
glm::vec3 Scale;
|
||||
|
||||
glm::mat4 GlobalMatrix;
|
||||
|
||||
GameObject* GameObject{ nullptr };
|
||||
std::vector<Transform*> Children;
|
||||
Transform* Parent{ nullptr };
|
||||
|
||||
void Parse(const ryml::ConstNodeRef& node, ParseContext& context);
|
||||
void Link(const std::unordered_map<int64_t, TypeBase*>& assetsMap);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user