发现了链接错误,先备份一下

This commit is contained in:
ouczbs 2024-08-01 15:38:54 +08:00
parent 7e2712848c
commit f5e2424f0f
61 changed files with 1675 additions and 118 deletions

View File

@ -0,0 +1,2 @@
#pragma once
EDITOR_API extern int editor_v;

View File

@ -0,0 +1,2 @@
#include "asset/module.h"
#include "module/module_manager.h"

View File

@ -0,0 +1,21 @@
#pragma once
#include "resource_system.h"
namespace api {
class Asset : public Resource<Asset> {
public:
using Base = Resource<Asset>;
const refl::UClass* meta;
Asset(const refl::UClass* meta): Base(), meta(meta){}
refl::Any Meta() {
return refl::Any{ this, meta };
}
};
template<>
inline void MetaBundle::Add(RscHandle<Asset> h)
{
if (h)
{
metadatas.emplace_back(SerializedMeta{ h.guid, h->Name(), refl::type_name<Asset>().View(), h->Meta()});
}
}
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "asset.h"
#include "os/package_path.h"
namespace api {
class AssetLoader :public IFileLoader{
public:
static void Init();
ResourceBundle LoadFile(PackagePath path, const MetaBundle& meta) override;
void SaveFile(PackagePath path, const ResourceBundle& bundle) override;
};
}

View File

@ -0,0 +1,11 @@
#include "module/module_manager.h"
namespace api {
class AssetModule : public IStaticModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
void InitMetaData(void) override {};
};
IMPLEMENT_STATIC_MODULE(AssetModule, asset)
}

View File

@ -0,0 +1,78 @@
#pragma once
#include "refl/pch.h"
#include <objbase.h>
#include <string>
namespace api
{
using pmr::Name;
using std::string_view;
using std::span;
struct Guid
{
unsigned int Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
Guid() noexcept
: Data1{ 0 }, Data2{ 0 }, Data3{ 0 }, Data4{ 0,0,0,0,0,0,0,0 }
{}
USING_OVERLOAD_CTOR(Guid, string_view)
UFUNCTION({}, ref = USING_CTOR_NAME)
Guid(string_view str) noexcept
: Guid{}
{
sscanf_s(str.data(),
"%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
&Data1, &Data2, &Data3,
&Data4[0], &Data4[1], &Data4[2], &Data4[3],
&Data4[4], &Data4[5], &Data4[6], &Data4[7]);
}
constexpr Guid(unsigned int a, unsigned short b, unsigned short c, unsigned long long d)
: Data1{ a }
, Data2{ b }
, Data3{ c }
, Data4{
(unsigned char)(d >> 56 & 0xFF)
, (unsigned char)(d >> 48 & 0xFF)
, (unsigned char)(d >> 40 & 0xFF)
, (unsigned char)(d >> 32 & 0xFF)
, (unsigned char)(d >> 24 & 0xFF)
, (unsigned char)(d >> 16 & 0xFF)
, (unsigned char)(d >> 8 & 0xFF)
, (unsigned char)(d >> 0 & 0xFF)
}
{};
UFUNCTION({})
std::string ToString()const {
char guid_cstr[39];
snprintf(guid_cstr, sizeof(guid_cstr),
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
Data1, Data2, Data3,
Data4[0], Data4[1], Data4[2], Data4[3],
Data4[4], Data4[5], Data4[6], Data4[7]);
return std::string{ guid_cstr };
}
public:
auto operator<=>(const Guid&) const noexcept = default;
operator bool() const noexcept
{
return *reinterpret_cast<const GUID*>(this) != GUID_NULL;
}
operator std::string() const
{
return ToString();
}
public:
UFUNCTION({})
static Guid Make()
{
Guid guid;
const auto res = CoCreateGuid((GUID*)&guid);
return guid;
}
};
}
#include "guid.inl"

View File

@ -0,0 +1,15 @@
#pragma once
namespace std
{
template<> struct hash<api::Guid>
{
size_t operator()(const api::Guid& guid) const noexcept
{
const size_t* p = reinterpret_cast<const size_t*>(&guid);
size_t seed = 0;
::pmr::hash_combine(seed, p[0]);
::pmr::hash_combine(seed, p[1]);
return seed;
}
};
}

View File

@ -0,0 +1,42 @@
#pragma once
#include "type.h"
#include "guid.h"
#include "resource_bundle.h"
namespace api
{
struct SerializedMeta
{
UPROPERTY({})
Guid guid;
UPROPERTY({})
Name name;
UPROPERTY({})
Name t_hash;
UPROPERTY({})
refl::Any meta;
bool operator==(const SerializedMeta& other)const{
return guid == other.guid && name == other.name && t_hash == other.t_hash;
}
};
struct ResourceBundle;
struct MetaBundle
{
UPROPERTY({})
vector<SerializedMeta> metadatas;
UPROPERTY({})
vector<Name> includes;
MetaBundle() = default;
const SerializedMeta* FetchMeta(const Guid& guid) const;
template<typename T>
const SerializedMeta* FetchMeta() const;
template<typename T>
const SerializedMeta* FetchMeta(string_view asset_name) const;
template<typename T>
void Add(RscHandle<T>);
bool operator==(const MetaBundle& other)const;
bool operator!=(const MetaBundle& other)const;
};
}
#include "meta_bundle.inl"
#include "meta_bundle_gen.inl"

View File

@ -0,0 +1,34 @@
#pragma once
namespace api
{
template<typename T>
inline const SerializedMeta* MetaBundle::FetchMeta() const
{
string_view name = type_name<typename T::BaseResource>().View();
for (auto& elem : metadatas)
{
if (elem.t_hash == name)
return &elem;
}
return nullptr;
}
template<typename T>
inline const SerializedMeta* MetaBundle::FetchMeta(string_view asset_name) const
{
string_view name = type_name<typename T::BaseResource>().View();
for (auto& elem : metadatas)
{
if (elem.t_hash == name && asset_name == elem.name)
return &elem;
}
return nullptr;
}
template<typename T>
void MetaBundle::Add(RscHandle<T> h)
{
if (h)
{
metadatas.emplace_back(SerializedMeta{ h.guid, h->Name(), type_name<T>().View() });
}
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "resource_handle.h"
namespace api
{
struct GenericResourceHandle;
struct ResourceBundle
{
ResourceBundle() = default;
template<typename Res> // conversion from single resource
ResourceBundle(const RscHandle<Res>& handle);
operator bool();
// will reshuffle vector and invalidate span, but you shouldn't be accessing vector directly anyway so this is ok
template<typename T> void Add(RscHandle<T> handle);
template<typename T> RscHandle<T> Get() const; // get a resource from the bundle
span<const GenericResourceHandle> GetAll() const; // gets absolutely all resources
template<typename T> span<const GenericResourceHandle> GetAll() const; // get all resources of one type
private:
struct sub_array { short index = 0, count = 0; };
vector<GenericResourceHandle> handles; // always sorted so that we can simply span
array<sub_array, ResourceCount> subarrays;
};
}
#include "resource_bundle.inl"

View File

@ -0,0 +1,47 @@
#include "resource_bundle.h"
#pragma once
namespace api
{
template<typename Res>
inline ResourceBundle::ResourceBundle(const RscHandle<Res>& handle)
{
Add(handle);
}
template<typename T>
inline void ResourceBundle::Add(RscHandle<T> handle)
{
auto& sub_arr = subarrays[ResourceID<T>];
auto new_ind = sub_arr.index + sub_arr.count++;
// make space for new resource
handles.emplace_back();
std::move_backward(handles.data() + new_ind, handles.data() + handles.size() - 1, handles.data() + handles.size());
// assign new resource
handles[new_ind] = handle;
// push back all subsequent resources
for (auto& elem : span<sub_array>{ &sub_arr + 1, subarrays.data() + subarrays.size() })
++elem.index;
}
inline ResourceBundle::operator bool()
{
return !handles.empty();
}
inline span<const GenericResourceHandle> ResourceBundle::GetAll() const
{
return span<const GenericResourceHandle>(handles);
}
template<typename T>
inline RscHandle<T> ResourceBundle::Get() const
{
auto& subarray = subarrays[ResourceID<T>];
return subarray.count > 0 ? handles[subarray.index].template AsHandle<T>() : RscHandle<T>();
}
template<typename T> span<const GenericResourceHandle> ResourceBundle::GetAll() const {
auto& subarray = subarrays[ResourceID<T>];
return span<const GenericResourceHandle>{handles.data() + subarray.index, handles.data() + subarray.index + subarray.count};
}
}

View File

@ -0,0 +1,46 @@
#pragma once
#include "type.h"
namespace api {
class Guid;
template<typename Res>
struct RscHandle;
template<typename Res>
class Resource
{
public:
using BaseResource = Res;
Guid GetGuid()const;
RscHandle<Res> GetHandle() const { return mHandle; }
Resource() = default;
pmr::Name Name() const { return mName; }
void Name(pmr::Name n) { mName = n; }
private:
RscHandle<Res> mHandle;
pmr::Name mName;
friend class RscHandle<Res>;
friend class ResourceSystem;
};
using Resources = std::tuple<
class ShaderProgram
, class Model
, class Asset
>;
template<typename Resource>
concept is_resource_v = requires { typename Resource::BaseResource; };
template<typename Resource, typename Enable = void>
struct ResourceID_impl {
static constexpr auto value() { return index_in_tuple_v<Resource, Resources>; }
};
template<typename Resource>
struct ResourceID_impl<Resource, std::enable_if_t<is_resource_v<Resource>>> {
static constexpr auto value() { return index_in_tuple_v<typename Resource::BaseResource, Resources>; }
};
template<typename Resource>
constexpr auto ResourceID = ResourceID_impl<Resource>::value();
constexpr auto ResourceCount = std::tuple_size_v<Resources>;
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "guid.h"
#include "resource_config.h"
namespace api
{
struct RscHandleBase {
UPROPERTY({})
Guid guid;
void* res{nullptr};
};
template<typename Res>
struct RscHandle : public RscHandleBase
{
constexpr size_t RscID()const { return ResourceID<Res>; }
constexpr RscHandle() noexcept = default;
template<typename T>
constexpr RscHandle(const RscHandle<T>& other) noexcept : RscHandleBase(other.guid, other.res) {};
constexpr RscHandle(const Guid& guid, Res* res) noexcept : RscHandleBase(guid, res) {}
void Init();
void Clear() { res = nullptr; };
Res* Ptr() {
return (Res*)res;
}
Res* operator->() { if (!res && guid) Init(); return (Res*)res; }
Res& operator*() { if (!res && guid) Init(); return *(Res*)res; }
operator bool() { if (!res && guid) Init(); return res; }
Res* operator->() const { return (Res*)res; }
Res& operator*()const { return *(Res*)res; }
operator bool() const { return res; }
};
}
#include "resource_handle.inl"
#include "resource_handle_gen.inl"

View File

@ -0,0 +1,43 @@
#pragma once
namespace api{
template<typename Res>
inline Guid Resource<Res>::GetGuid() const
{
return GetHandle().guid;
}
struct GenericResourceHandle
: variant_wrap_t<tuple_to_variant_t<Resources>, RscHandle>
{
private:
using Base = variant_wrap_t<tuple_to_variant_t<Resources>, RscHandle>;
public:
using Base::Base;
using Base::operator=;
template<typename T>
GenericResourceHandle(RscHandle<T> handle) : Base(RscHandle<typename T::BaseResource>{handle}) {}
GenericResourceHandle(string_view type_name, Guid guid);
template<typename T> RscHandle<T> AsHandle() const {
return std::get<ResourceID<T>>(*this);
}
Guid guid() const;
size_t resource_id() const;
};
}
// hashtable support
namespace std
{
template<typename Res>
struct hash <api::RscHandle<Res>>
{
size_t operator()(const api::RscHandle<Res>& res) const noexcept
{
return std::hash<api::Guid>()(res.guid);
}
};
}
namespace refl::detail {
template<typename T>
struct real_type<api::RscHandle<T>> {
using type = api::RscHandleBase;
};
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "pmr/name.h"
#include "meta/variant.h"
#include "meta/tuple.h"
#include "meta/comparable.h"
#include <vector>
#include <optional>
namespace api {
using namespace meta;
using std::vector;
using std::array;
using pmr::table;
template<typename T>
using opt = std::optional<T>;
template<bool val>
using sfinae = std::enable_if_t<val>;
}

View File

@ -0,0 +1,130 @@
#pragma once
#include "module/module.h"
#include "res/resource_config.h"
#include "res/resource_bundle.h"
#include "res/meta_bundle.h"
#include "os/package_path.h"
#include "meta/result.h"
#include <memory>
#include <optional>
namespace api {
using std::array;
using std::shared_ptr;
class IFileLoader;
enum class ResourceLoadError : char
{
ExtensionNotRegistered,
FileDoesNotExist,
FailedToLoadResource,
};
struct ResourceFileFlag{
enum Value : uint32_t {
File_Default = 0,
File_Dirty = 1 << 0,
File_Meta_Dirty = 1 << 1,
File_Loaded = 1 << 2,
};
Value val{ File_Default };
// 构造函数和操作符重载,使类实例像整数一样使用
ResourceFileFlag(Value v = File_Default) : val(v) {}
operator uint32_t() const { return val; }
ResourceFileFlag& operator=(Value v) {
val = v;
return *this;
}
};
template<typename Res>
using LoadResult = result<Res, ResourceLoadError>;
class ResourceSystem : public ISystem<ResourceSystem>
{
public:
struct ResourceFileBlock;
template<typename R>
struct ResourceBlock;
template<typename R>
using ResourceStorage = table<Guid, ResourceBlock<R>>;
using GenericPtr = shared_ptr<void>;
private:
uint32_t mFileFlag;
array<GenericPtr, ResourceCount> mResourceTable;
table<Guid, FileBlock*> mResourceFile;
table<Name, IFileLoader*> mFileLoader;
table<Name, std::pair<std::string, uint32_t>> mFileFlags;
table<Name, ResourceFileBlock> mFileBlock;
vector<ResourceFileBlock*> mDirtyBlock;
public:
ResourceSystem();
void Initialize() override;
void Finalize() override;
public:
template<typename Res>
Res* Get(const RscHandle<Res>& handle,bool sync = true);
template<typename Res>
auto& GetTable() {
return *reinterpret_cast<ResourceStorage<Res>*> (mResourceTable[ResourceID<Res>].get());
}
template<typename Res>
ResourceBlock<Res>* GetBlock(const RscHandle<Res>& handle);
ResourceFileBlock& GetFileBlock(PackagePath path);
FileBlock* GetResourceFile(const Guid& guid);
template<typename Res>
[[nodiscard]] RscHandle<Res> LoadFromMeta(const Guid& ,const SerializedMeta& meta);
template<typename Res, typename ... Args>
[[nodiscard]] RscHandle<Res> LoadEmplaceResource(Args&& ... args) {
return LoadEmplaceResource<Res>(Guid::Make(), args...);
};
template<typename Res, typename ... Args>
[[nodiscard]] RscHandle<Res> LoadEmplaceResource(Guid, Args&& ... args);
IFileLoader* GetLoader(Name extension);
template<typename FLoader, typename ... Args>
FLoader& RegisterLoader(Name ext, Args&& ... args);
template<typename Res>
RscHandle<Res> Load(PackagePath path, bool reload_resource = true);
ResourceBundle& Load(PackagePath path, bool reload_resource = true, int deep = 0);
MetaBundle GetMeta(PackagePath path);
MetaBundle GetVisitMeta(const ResourceBundle& bundle);
void SaveMeta(PackagePath path, const MetaBundle& bundle);
void SaveDirtyFile();
void SaveFile(PackagePath path, const ResourceBundle& bundle);
void LoadFileFlags();
void SaveFileFlags();
void LoadResourceFile();
void SaveResourceFile();
uint32_t GetFileFlag(Name name);
void SetFileFlag(Name name, uint32_t flag);
};
struct ResourceSystem::ResourceFileBlock
{
ResourceBundle bundle;
PackagePath path;
uint32_t flag{0};
ResourceFileBlock& SetFlag(bool is, ResourceFileFlag _flag) {
if (is)
flag |= _flag;
else
flag &= ~_flag;
return *this;
}
operator bool() {
return IsLoaded();
}
ResourceFileBlock& Loaded(bool is) { return SetFlag(is, ResourceFileFlag::File_Loaded); }
ResourceFileBlock& Dirty(bool is) { return SetFlag(is, ResourceFileFlag::File_Dirty); }
ResourceFileBlock& MetaDirty(bool is) { return SetFlag(is, ResourceFileFlag::File_Meta_Dirty); }
bool IsLoaded() { return flag & ResourceFileFlag::File_Loaded; }
bool IsDirty() { return flag & ResourceFileFlag::File_Dirty; }
bool IsMetaDirty() { return flag & ResourceFileFlag::File_Meta_Dirty; }
};
template<typename R>
struct ResourceSystem::ResourceBlock
{
R* resource{nullptr};
ResourceFileBlock* file{ nullptr };
bool valid() const { return resource; }
};
}
#include "resource_system.inl"

View File

@ -0,0 +1,145 @@
#include "resource_system.h"
#pragma once
namespace api {
class IFileLoader
{
protected:
uint32_t mFileFlag = 0;
public:
void SetFileFlag(uint32_t flag) {
mFileFlag = flag;
}
virtual ResourceBundle LoadFile(PackagePath handle, const MetaBundle& meta) = 0;
virtual void SaveFile(PackagePath handle, const ResourceBundle& bundle) {};
virtual ~IFileLoader() = default;
};
namespace detail {
template<typename T> struct ResourceSystem_detail;
template<typename ... Rs>
struct ResourceSystem_detail<std::tuple<Rs...>>
{
constexpr static array<shared_ptr<void>, sizeof...(Rs)> GenResourceTables()
{
return array<shared_ptr<void>, sizeof...(Rs)>{
std::make_shared<ResourceSystem::ResourceStorage<Rs>>()...
};
}
constexpr static array<void(*)(ResourceSystem*), sizeof...(Rs)> ReleaseTableResources()
{
return array<void(*)(ResourceSystem*), sizeof...(Rs)>{
[](ResourceSystem* resource_man)
{
if (auto table = &resource_man->GetTable<Rs>())
table->clear();
}...
};
}
};
using ResourceHelper = ResourceSystem_detail<Resources>;
}
template<typename Res>
inline RscHandle<Res> ResourceSystem::LoadFromMeta(const Guid& guid, const SerializedMeta& meta)
{
if (!guid || !meta.meta) {
return {};
}
Res* res = meta.meta.CastTo<Res*>();
auto& table = GetTable<Res>();
auto& control_block = table[guid]; // don't care just replace
if (control_block.resource) {
//meta.meta.MoveTo(control_block.resource);
res = control_block.resource;
}
else {
control_block.resource = res;
res->mHandle.guid = guid;
}
res->Name(meta.name);
return RscHandle<Res>{guid, res};
}
template<typename Res, typename ...Args>
inline RscHandle<Res> ResourceSystem::LoadEmplaceResource(Guid guid, Args&& ...args)
{
auto& table = GetTable<Res>();
auto& control_block = table[guid]; // don't care just replace
// attempt to put on other thread
Res* res = new Res(std::forward<Args>(args)...);
res->mHandle.guid = guid;
control_block.resource = res;
return RscHandle<Res>{guid, res};
}
template<typename FLoader, typename ...Args>
inline FLoader& ResourceSystem::RegisterLoader(Name ext, Args&& ...args)
{
auto& ptr = mFileLoader[ext];
if (ptr) {
delete ptr;
}
ptr = new FLoader(std::forward<Args>(args)...);
ptr->SetFileFlag(GetFileFlag(ext));
return *(FLoader*)ptr;
}
template<typename Res>
inline RscHandle<Res> ResourceSystem::Load(PackagePath path, bool reload_resource)
{
auto& res = Load(path, reload_resource);
return res.Get<Res>();
}
template<typename Res>
inline Res* ResourceSystem::Get(const RscHandle<Res>& handle, bool sync)
{
auto& table = GetTable<Res>();
auto itr = table.find(handle.guid);
if (itr == table.end()) {
FileBlock* file = sync ? GetResourceFile(handle.guid) : nullptr;
if (file) {
Load(file->path);
return Get<Res>(handle, false);
}
return nullptr;
}
return itr->second.resource;
}
inline uint32_t ResourceSystem::GetFileFlag(Name name)
{
auto it = mFileFlags.find(name);
if (it == mFileFlags.end()) {
return 0;
}
return it->second.second;
}
inline void ResourceSystem::SetFileFlag(Name name, uint32_t flag)
{
auto it = mFileFlags.find(name);
if (it == mFileFlags.end()) {
mFileFlags.emplace(name, std::make_pair(std::string(name.ToStringView()), flag));
}
else {
it->second.second = flag;
}
}
template<typename Res>
inline ResourceSystem::ResourceBlock<Res>* ResourceSystem::GetBlock(const RscHandle<Res>& handle)
{
auto& table = GetTable<Res>();
return &table[handle.guid];
}
inline ResourceSystem::ResourceFileBlock& ResourceSystem::GetFileBlock(PackagePath path) {
return mFileBlock[Name(path())];
}
inline FileBlock* ResourceSystem::GetResourceFile(const Guid& guid)
{
auto it = mResourceFile.find(guid);
if(it == mResourceFile.end())
return nullptr;
return it->second;
}
template<typename Res>
inline void RscHandle<Res>::Init()
{
res = ResourceSystem::Ptr()->Get(*this);
}
}

View File

@ -0,0 +1,13 @@
#include "assert.h"
#include "asset_loader.h"
#include "resource_system.h"
namespace api {
void FindIncludes(MetaBundle& bundle, Asset* asset) {
}
MetaBundle ResourceSystem::GetVisitMeta(const ResourceBundle& bundle)
{
MetaBundle new_meta = MetaBundle{};
return new_meta;
}
}

View File

@ -0,0 +1,25 @@
#include "asset_loader.h"
#include "os/file_manager.h"
#include "os/file_handle.h"
#include <fstream>
namespace api {
void AssetLoader::Init() {
ResourceSystem::Ptr()->RegisterLoader<AssetLoader>(".asset");
}
ResourceBundle AssetLoader::LoadFile(PackagePath path, const MetaBundle& metas)
{
ResourceBundle bundle;
for (auto meta : metas.metadatas) {
if (!meta.meta)
continue;
auto rsc = ResourceSystem::Ptr()->LoadFromMeta<Asset>(meta.guid, meta);
bundle.Add(rsc);
}
return bundle;
}
void AssetLoader::SaveFile(PackagePath path, const ResourceBundle& bundle)
{
MetaBundle new_meta = ResourceSystem::Ptr()->GetVisitMeta(bundle);
ResourceSystem::Ptr()->SaveMeta(path, new_meta);
}
}

View File

@ -0,0 +1,14 @@
#include "module.h"
#include "resource_system.h"
#include "asset_loader.h"
namespace api {
void AssetModule::OnLoad(int argc, char** argv)
{
AddSystem<ResourceSystem>();
AssetLoader::Init();
}
void AssetModule::OnUnload()
{
}
}

View File

@ -0,0 +1,23 @@
#include "res/meta_bundle.h"
#include <algorithm>
namespace api
{
const SerializedMeta* MetaBundle::FetchMeta(const Guid& guid) const
{
for (auto& elem : metadatas)
{
if (elem.guid == guid)
return &elem;
}
return nullptr;
}
bool MetaBundle::operator==(const MetaBundle& other)const
{
return metadatas == other.metadatas && includes == other.includes;
}
bool MetaBundle::operator!=(const MetaBundle& other)const
{
return !(*this == other);
}
}

View File

@ -0,0 +1,17 @@
#include "res/resource_handle.h"
namespace api
{
GenericResourceHandle::GenericResourceHandle(string_view type_name, Guid guid)
{
}
Guid GenericResourceHandle::guid() const
{
return std::visit([](const auto& handle) { return handle.guid; }, *this);
}
size_t GenericResourceHandle::resource_id() const
{
return std::visit([](const auto& handle) { return handle.RscID(); }, *this);
}
}

View File

@ -0,0 +1,137 @@
#include "resource_system.h"
#include "os/file_manager.h"
#include "os/file_handle.h"
#include "archive/json.h"
namespace api {
ResourceSystem::ResourceSystem()
{
mResourceTable = detail::ResourceHelper::GenResourceTables();
LoadFileFlags();
LoadResourceFile();
}
void ResourceSystem::Initialize()
{
SaveFileFlags();
SaveDirtyFile();
}
void ResourceSystem::Finalize()
{
constexpr static auto release_tables = detail::ResourceHelper::ReleaseTableResources();
for (auto& elem : release_tables)
elem(this);
SaveFileFlags();
SaveDirtyFile();
SaveResourceFile();
}
IFileLoader* ResourceSystem::GetLoader(Name extension)
{
auto itr = mFileLoader.find(extension);
if (itr == mFileLoader.end())
return nullptr;
return itr->second;
}
ResourceBundle& ResourceSystem::Load(PackagePath path, bool reload_resource, int deep)
{
Name name = path();
auto it = mFileBlock.find(name);
auto& res = mFileBlock[name];
if (deep > 5 || (!reload_resource && res && it != mFileBlock.end())) {
return res.bundle;
}
Name ext = path.GetExtension();
IFileLoader* loader = GetLoader(ext);
MetaBundle meta = GetMeta(path);
ResourceBundle bundle = loader->LoadFile(path, meta);
MetaBundle new_meta = GetVisitMeta(bundle);
bool is_dirty_meta = meta != new_meta;
for (auto& elem : bundle.GetAll()) {
std::visit([&](auto& handle) {
using T = std::decay_t<decltype(*handle)>;
GetBlock<T>(handle)->file = &res;
mResourceFile[handle.guid] = FileManager::Ptr()->FindPathBlock(path);
}, elem);
}
if (is_dirty_meta || res.IsDirty()) {
mDirtyBlock.push_back(&res);
}
res.path = path.SafePath();
res.bundle = bundle;
res.Loaded(true).MetaDirty(is_dirty_meta);
res.bundle = bundle;
if (!new_meta.includes.empty()) {
for (auto include : new_meta.includes) {
Load(include, false, deep + 1);
}
}
return res.bundle;
}
MetaBundle ResourceSystem::GetMeta(PackagePath path)
{
FileHandle handle(path + ".meta");
if (!handle.Open(FILE_OP::READ, mFileFlag & FileFlag::File_Binary)) {
return {};
}
meta::result<MetaBundle, SerializeError> res;
if (mFileFlag & FileFlag::File_Binary) {
}
else {
pmr::string text = handle.ReadAll<pmr::string>();
res = JsonDeserialize<MetaBundle>(text);
}
if (!res) {
return {};
}
return res.value();
}
void ResourceSystem::SaveMeta(PackagePath path, const MetaBundle& bundle)
{
FileHandle handle(path + ".meta");
handle.Open(FILE_OP::WRITE, mFileFlag & FileFlag::File_Binary);
if (mFileFlag & FileFlag::File_Binary) {
}
else {
handle.Write(JsonSerialize(bundle));
}
}
void ResourceSystem::SaveDirtyFile()
{
for (auto block : mDirtyBlock) {
if (block->IsMetaDirty()) {
block->MetaDirty(false);
MetaBundle new_meta = GetVisitMeta(block->bundle);
SaveMeta(block->path, new_meta);
}
if (block->IsDirty()) {
block->Dirty(false);
auto loader = GetLoader(block->path.GetExtension());
loader->SaveFile(block->path, block->bundle);
}
}
mDirtyBlock.clear();
}
void ResourceSystem::SaveFile(PackagePath path, const ResourceBundle& bundle)
{
auto loader = GetLoader(path.GetExtension());
loader->SaveFile(path, bundle);
}
void ResourceSystem::LoadFileFlags()
{
}
void ResourceSystem::SaveFileFlags()
{
}
void ResourceSystem::LoadResourceFile()
{
}
void ResourceSystem::SaveResourceFile()
{
}
}

View File

@ -1,5 +1,8 @@
static_component("asset","engine")
add_rules("c++.codegen",{
files = {"include/asset/res/*.h"}
})
add_includedirs("include/asset")
add_headerfiles("include/**.h")
add_headerfiles("include/**.h","include/**.inl")
add_files("src/**.cpp")
add_deps("core", {public = true})

View File

@ -1,3 +1,4 @@
#pragma once
template <typename T>
class Singleton{
protected:

View File

@ -7,8 +7,8 @@ namespace api {
using std::string_view;
enum class SerializeError : char
{
EMPTY,
ERROR,
SERDE_EMPTY,
SERDE_ERROR,
};
template<typename T>
inline bool JsonDeserialize(string_view text, T* obj) {
@ -27,12 +27,12 @@ namespace api {
template<typename T, typename... Args>
inline result<T, SerializeError> JsonDeserialize(string_view text, Args&& ...args) {
if (text.empty()) {
return SerializeError::EMPTY;
return SerializeError::SERDE_EMPTY;
}
T* obj = new(FramePool)T(std::forward<Args>(args)...);
bool bsuccess = JsonDeserialize<T>(text, obj);
using ResultType = result<T, SerializeError>;
return bsuccess ? ResultType{ *obj } : ResultType{ SerializeError::ERROR };
return bsuccess ? ResultType{ *obj } : ResultType{ SerializeError::SERDE_ERROR };
}
template<has_json_specialization_v T>
inline string_view JsonSerialize(const T& t) {

View File

@ -5,19 +5,15 @@ namespace api {
using refl::Any;
using refl::UClass;
using refl::TypeInfo;
using pmr::string_hash;
struct JsonVTable {
bool(*Read)(yyjson_val*, const void*) = nullptr;
yyjson_mut_val*(*Write)(yyjson_mut_doc*, const void*) = nullptr;
template<typename T>
static JsonVTable Make() {
return { &gen::JsonSerde<T>::Read, &gen::JsonSerde<T>::Write };
}
using Read = bool(*)(yyjson_val*, const void*);
using Write = yyjson_mut_val*(*)(yyjson_mut_doc*, const void*);
};
using JsonFuncTable = std::pmr::unordered_map<const UClass*, JsonVTable>;
struct JsonArchive {
private:
static JsonFuncTable BuildFuncTable();
inline static JsonFuncTable FuncTable = BuildFuncTable();
static bool InitJsonSerde();
inline static bool HasInit = InitJsonSerde();
public:
template<typename T>
static void Register();

View File

@ -27,28 +27,38 @@ namespace api {
alc.ctx = mr;
return alc;
}
inline JsonFuncTable JsonArchive::BuildFuncTable()
inline bool JsonArchive::InitJsonSerde()
{
JsonFuncTable funcTable{ MemPool };
using std::string_view;
#define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>())
#define RegisterAny(T) Register<T>();
#include "../register.inl"
#undef RegisterAny
return funcTable;
return true;
}
constexpr size_t VJsonSerdeRead() {
return string_hash("JsonSerdeRead");
}
constexpr size_t VJsonSerdeWrite() {
return string_hash("JsonSerdeWrite");
}
template<typename T>
inline void JsonArchive::Register()
{
FuncTable.emplace(&TypeInfo<T>::StaticClass, JsonVTable::Make<T>());
auto uclass = &TypeInfo<T>::StaticClass;
auto [bfind, it] = uclass->vtable.FindLast(VJsonSerdeRead());
if (!bfind && it) {
it = it->Insert(VJsonSerdeRead(), (void*) &gen::JsonSerde<T>::Read);
it = it->Insert(VJsonSerdeWrite(), (void*) &gen::JsonSerde<T>::Write);
}
}
inline yyjson_mut_val* JsonArchive::Serialize(yyjson_mut_doc* doc, Any any)
{
if (!any) {
return {};
}
auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) {
return it->second.Write(doc, any.ptr);
auto it = any.FindVtable<JsonVTable::Write>(VJsonSerdeWrite());
if (it) {
return it(doc, any.ptr);
}
return {};
}
@ -57,9 +67,9 @@ namespace api {
if (!any) {
return false;
}
auto it = FuncTable.find(any.cls);
if (it != FuncTable.end()) {
return it->second.Read(res, any.ptr);
auto it = any.FindVtable<JsonVTable::Read>(VJsonSerdeRead());
if (it) {
return it(res, any.ptr);
}
return false;
}

View File

@ -3,6 +3,14 @@
#include "enum_macro.h"
#include "os/shared_library.h"
#include "refl/pch.h"
//可变生命周期,回收内存
inline thread_local pmr::unsynchronized_pool_resource MemPool;
// 默认对齐方式 new
void* operator new(std::size_t size);
// 默认对齐方式 delete
void operator delete(void* ptr) noexcept;
// 自定义对齐 align
void* operator new(std::size_t size, std::align_val_t align);
namespace api {
using pmr::Name;
enum class EModuleFlag : uint32_t {
@ -38,20 +46,17 @@ namespace api {
Name copyright; //!< copyright of the plugin
UPROPERTY()
pmr::vector<ModuleDependency> dependencies;
ModuleInfo(pmr::memory_resource* mr = MemPool) : dependencies(mr){};
public:
bool IsReload() {
return !!(flag & EModuleFlag::Reload);
}
};
struct IModuleSubsystem
struct ISubSystem
{
using CreatePFN = IModuleSubsystem* (*)();
virtual ~IModuleSubsystem() = default;
using CreatePFN = ISubSystem* (*)();
virtual ~ISubSystem() = default;
virtual void Initialize() = 0;
virtual void Finalize() = 0;
virtual void BeginLoad() {}
virtual void EndLoad() {}
};
struct IModule {
public:
@ -60,20 +65,26 @@ namespace api {
IModule() = default;
IModule(const IModule& rhs) = delete;
IModule& operator=(const IModule& rhs) = delete;
virtual ~IModule() {};
virtual ~IModule();
virtual void OnLoad(int argc, char** argv) = 0;
virtual void OnUnload() = 0;
virtual void InitMetaData(void) = 0;
virtual int Main(int argc, char** argv) { return 0; }
virtual const ModuleInfo* GetModuleInfo()
virtual void Initialize();
virtual void Finalize();
template<typename T, typename ... Args>
T* AddSystem(Args&&... args) {
T* ptr = new (GlobalPool) T(std::forward<Args>(args)...);
mSystems.push_back(ptr);
return ptr;
}
const ModuleInfo* GetModuleInfo()
{
return &mInfo;
}
protected:
ModuleInfo mInfo;
pmr::vector<IModuleSubsystem*> mSubSystems;
pmr::vector<ISubSystem*> mSystems;
};
}
#include "module.inl"

View File

@ -1,4 +1,21 @@
namespace api {
template <typename T>
class ISystem : public ISubSystem {
protected:
inline static T* ms_system = nullptr;
public:
explicit ISystem() {
ms_system = static_cast<T*>(this);
}
~ISystem() override{
ms_system = nullptr;
}
static constexpr T* Ptr(void) {
return ms_system;
}
};
template <typename ModuleClass>
struct ModuleRegistrantImpl;
struct IDynamicModule : public IModule {
virtual ~IDynamicModule() override
{
@ -20,11 +37,11 @@ namespace api {
};
}
#define IMPLEMENT_STATIC_MODULE(ModuleImplClass, ModuleName) \
inline const api::ModuleRegistrantImpl<ModuleImplClass> __RegisterModule__##ModuleName(#ModuleName);
inline static const api::ModuleRegistrantImpl<ModuleImplClass> __RegisterModule__##ModuleName(#ModuleName);
#define IMPLEMENT_DYNAMIC_MODULE(DLL_APL, ModuleImplClass, ModuleName) \
using __##ModuleName##__module = ModuleImplClass; \
extern "C" DLL_APL api::IModule* __newDynamicModule__##ModuleName() \
{ \
return new(MemPool) ModuleImplClass(); \
return new(GlobalPool) ModuleImplClass(); \
}

View File

@ -1,12 +1,13 @@
#pragma once
#include "module.h"
namespace api {
class ModuleManager
class DLL_API ModuleManager
{
friend struct IModule;
private:
struct ModuleBlock {
bool isActive;
bool isLoad;
bool isInit;
};
struct ExecuteInfo {
Name name;
@ -16,18 +17,21 @@ namespace api {
};
ExecuteInfo mInfo;
SharedLibrary mProcessLib;
pmr::table<Name, ModuleBlock> mModuleBlocks{ GetMemPool() };
pmr::table<Name, IModule*> mModuleTable{GetMemPool()};
pmr::table<Name, IModule::CreatePFN> mInitializeTable{ GetMemPool() };
pmr::table<Name, ModuleBlock> mModuleBlocks;
pmr::table<Name, IModule*> mModuleTable;
pmr::table<Name, IModule::CreatePFN> mInitializeTable;
pmr::table<Name, pmr::vector<ISubSystem::CreatePFN>> mInitializeSubSystems;;
public:
static ModuleManager* Ptr();
public:
ModuleManager();
~ModuleManager();
IModule* GetModule(Name name);
void RegisterModule(Name name, IModule::CreatePFN fn) { mInitializeTable[name] = fn; }
void RegisterModule(Name name, IModule::CreatePFN fn);
void CreateModule(Name name, bool shared);
void DestroyModule(Name name);
void InitModule(Name name);
void ShutModule(Name name);
void MakeGraph(Name name, bool shared, int argc, char** argv);
void DestroyGraph();
protected:

View File

@ -0,0 +1,61 @@
#include "package_path.h"
#include <vector>
#include <fstream>
#include <variant>
namespace api {
using std::vector;
enum class FILE_OP
{
READ,
WRITE,
APPEND,
NONE
};
class FileHandle : PackagePath{
protected:
uint32_t flag{0};
FILE_OP op{ FILE_OP::NONE};
size_t size{0};
pmr::memory_resource* pool;
std::variant<std::ifstream, std::ofstream, nullptr_t> vfile{nullptr};
public:
using PackagePath::PackagePath;
FileHandle(PackagePath path, pmr::memory_resource* pool = FramePool) : PackagePath(path) , pool(pool) {}
uint32_t Flag() {
return flag;
}
operator bool() {
return flag & File_Success;
}
std::ifstream& Reader() {
return std::get<std::ifstream>(vfile);
}
std::ofstream& Writer() {
return std::get<std::ofstream>(vfile);
}
FileHandle& Open(FILE_OP op, bool is_binarry = false);
int Read(void* data, int size);
template<typename T = pmr::vector<char>>
T ReadAll() {
Reader().seekg(0);
return ReadLeft<T>();
}
template<typename T = pmr::vector<char>>
T ReadLeft();
bool FindNext(const char* begin, const char* end, size_t& stop);
//这里出问题了,二进制的\r\n会被读取成\n,大小对不上
template<typename T>
T ReadUntil(const T& token);
void Write(const char* data, size_t size){ Writer().write(data, size); }
template<typename T = pmr::string>
void Write(const T& data) {
Write(data.data(), data.size());
}
template<typename T = pmr::string>
void WriteLine(const T& data) {
Write<T>(data);
Write<T>(T{ "\n"});
}
};
}
#include "file_handle.inl"

View File

@ -0,0 +1,39 @@
namespace api{
template<typename T>
inline T FileHandle::ReadLeft()
{
T data{pool};
auto& fi = Reader();
size_t read_size = size - fi.tellg();
data.resize(read_size, '\0');
fi.read(data.data(), read_size);
// 检查实际读取的字节数
size_t count = (size_t)fi.gcount();
if (count != read_size) {
data.resize(count);
}
return data;
}
template<typename T>
inline T FileHandle::ReadUntil(const T& token)
{
auto& fi = Reader();
size_t start = fi.tellg();
size_t stop = size;
size_t skip_to = 0;
if (FindNext(token.data(), &token.back(), stop)) {
skip_to = stop + token.size();
}
T buffer{pool};
buffer.resize(stop - start);
fi.read(buffer.data(), stop - start);
size_t count = (size_t)fi.gcount();
if (count != stop - start) {
buffer.resize(count);
}
if (skip_to) {
fi.seekg(skip_to);
}
return buffer;
}
}

View File

@ -9,23 +9,24 @@ namespace api
FileManager();
~FileManager();
public:
void Mount(Name name, const string& path) {
void Mount(Name name, const std::string& path) {
MountMap.emplace(name, std::make_pair(name, path));
}
std::pair<string, string> FindMount(Name id) {
std::pair<std::string, std::string>* FindMount(Name id) {
auto it = MountMap.find(id);
if (it != MountMap.end()) {
return it->second;
return &it->second;
}
return {};
static std::pair<std::string, std::string> pair("", "");
return &pair;
}
string_view FindMountName(Name id) {
auto pair = FindMount(id);
return pair.first;
return pair->first;
}
string_view FindMountPath(Name id) {
auto pair = FindMount(id);
return pair.second;
return pair->second;
}
string_view FindPathView(Name name) {
auto it = FileMap.find(name);
@ -42,14 +43,14 @@ namespace api
auto res = FileMap.emplace(name, FileBlock{ FileFlag::File_Default, name.ToString()});
return res.first->second.path;
}
uint32_t FindPathFlag(const PackagePath& pack_path) {
uint32_t FindPathFlag(PackagePath pack_path) {
auto it = FileMap.find(pack_path());
if (it == FileMap.end()) {
return FileFlag::File_Not_Exist;
}
return it->second.flag;
}
FileBlock* FindPathBlock(const PackagePath& pack_path) {
FileBlock* FindPathBlock(PackagePath pack_path) {
auto it = FileMap.find(pack_path());
if (it == FileMap.end()) {
return nullptr;
@ -60,10 +61,10 @@ namespace api
void LoadFileMap();
void SaveFileMap();
private:
pmr::table<Name, std::pair<string, string>> MountMap{GetMemPool()};
pmr::table<Name, FileBlock> FileMap{GetMemPool()};
pmr::table<Name, std::pair<std::string, std::string>> MountMap;
pmr::table<Name, FileBlock> FileMap;
public:
//外界不应该使用绝对路径
pmr::string RealPath(const PackagePath& pack_path);
pmr::string RealPath(PackagePath pack_path);
};
}

View File

@ -3,7 +3,6 @@
#include "pmr/name.h"
namespace api
{
using std::string;
using std::string_view;
using pmr::Name;
enum FileFlag : uint32_t {
@ -18,8 +17,8 @@ namespace api
//占位符浪费了四个字节
struct FileBlock {
uint32_t flag{ 0 };
string path;
string addr;
std::string path;
std::string addr;
operator bool() {
return !(flag & FileFlag::File_Not_Exist);
}
@ -29,8 +28,9 @@ namespace api
PackagePath() {};
PackagePath(const char* path) : path(path) {}
PackagePath(string_view path) : path(path) {}
PackagePath(const string& path) : path(path) {}
PackagePath(const std::string& path) : path(path) {}
PackagePath(const pmr::string& path) : path(path) {}
PackagePath(pmr::Name name) : path(name.ToStringView()) {}
operator bool() {
return path != "";
}
@ -41,13 +41,13 @@ namespace api
return path.size();
}
pmr::string operator+(const char* suffix) const {
return pmr::string(path, FramePool) + suffix;
return pmr::string(path) + suffix;
}
string_view ParsePackage()const {
string_view name;
if (path[0] == '/') {
size_t pos = path.find('/', 1);
if (pos != string::npos) {
if (pos != std::string::npos) {
return path.substr(1, pos - 1);
}
}

View File

@ -1,5 +1,28 @@
#include "module/module_manager.h"
#include "os/file_manager.h"
struct MemDetail {
int count{ 0 };
int new_count{ 0 };
int del_count{ 0 };
};
thread_local MemDetail detail;
void* operator new(std::size_t size) {
std::size_t alignment = alignof(std::max_align_t);
detail.count++;
detail.new_count++;
return MemPool.allocate(size, alignment);
}
// 默认对齐方式 delete
void operator delete(void* ptr) noexcept {
detail.count--;
detail.del_count++;
MemPool.deallocate(ptr, 0);
}
// 自定义对齐 align
void* operator new(std::size_t size, std::align_val_t align) {
std::size_t alignment = static_cast<std::size_t>(align);
return MemPool.allocate(size, alignment);
}
namespace api {
void CoreModule::OnLoad(int argc, char** argv)
{
@ -13,4 +36,22 @@ namespace api {
{
}
IModule::~IModule()
{
for (auto system : mSystems) {
delete system;
}
}
void IModule::Initialize()
{
for (auto system : mSystems) {
system->Initialize();
}
}
void IModule::Finalize()
{
for (auto system : mSystems) {
system->Finalize();
}
}
}

View File

@ -8,7 +8,7 @@ namespace api {
}
ModuleManager::ModuleManager()
{
GetMemPool();
GetGlobalPool();
GetFramePool();
mProcessLib.Load();
new FileManager();
@ -17,8 +17,8 @@ namespace api {
{
DestroyGraph();
delete FileManager::Ptr();
delete GetFramePool();
delete GetMemPool();
delete FramePool;
delete GlobalPool;
}
void ModuleManager::CreateModule(Name name, bool shared)
{
@ -27,7 +27,7 @@ namespace api {
spawnDynamicModule(name, hotfix) :
spawnStaticModule(name);
if (!module) { return; }
mModuleBlocks[name] = ModuleBlock{false};
mModuleBlocks[name] = ModuleBlock{false, false};
ModuleBlock& block = mModuleBlocks[name];
auto& moduleInfo = module->mInfo;
for (auto& dep : moduleInfo.dependencies) {
@ -35,12 +35,12 @@ namespace api {
CreateModule(dep.name, dep.kind == pmr::FName("shared"));
}
module->OnLoad(mInfo.argc, mInfo.argv);
block.isActive = true;
block.isLoad = true;
}
void ModuleManager::DestroyModule(Name name)
{
auto it = mModuleBlocks.find(name);
if (it == mModuleBlocks.end() || !it->second.isActive) {
if (it == mModuleBlocks.end() || !it->second.isLoad) {
return;
}
IModule* module = mModuleTable[name];
@ -48,17 +48,49 @@ namespace api {
for (auto& dep : moduleInfo.dependencies) {
DestroyModule(dep.name);
}
it->second.isActive = false;
module->OnUnload();
it->second.isLoad = false;
}
void ModuleManager::InitModule(Name name)
{
auto it = mModuleBlocks.find(name);
if (it == mModuleBlocks.end() || it->second.isInit) {
return;
}
IModule* module = mModuleTable[name];
auto& moduleInfo = module->mInfo;
for (auto& dep : moduleInfo.dependencies) {
InitModule(dep.name);
}
module->Initialize();
it->second.isInit = true;
}
void ModuleManager::ShutModule(Name name)
{
auto it = mModuleBlocks.find(name);
if (it == mModuleBlocks.end() || !it->second.isInit) {
return;
}
IModule* module = mModuleTable[name];
auto& moduleInfo = module->mInfo;
for (auto& dep : moduleInfo.dependencies) {
ShutModule(dep.name);
}
module->Finalize();
it->second.isInit = false;
}
void ModuleManager::MakeGraph(Name name, bool shared, int argc, char** argv)
{
mInfo = { name, argc, argv , true};
CreateModule(name, shared);
InitModule(name);
}
void ModuleManager::DestroyGraph()
{
if(mInfo.isActive)
if(mInfo.isActive){
ShutModule(mInfo.name);
DestroyModule(mInfo.name);
}
}
IModule* ModuleManager::spawnDynamicModule(Name name, bool hotfix)
{
@ -67,11 +99,11 @@ namespace api {
}
SharedLibrary sharedLib;
string_view name_view = name.ToStringView();
pmr::string newFuncName("__newDynamicModule__", FramePool);
pmr::string newFuncName("__newDynamicModule__");
newFuncName.append(name_view);
void* newFuncAddr = mProcessLib.GetSymbol(newFuncName.data());
if (!newFuncAddr) {
pmr::string libPath("/exe/", FramePool);
pmr::string libPath("/exe/");
libPath.reserve(10 + name_view.size());
libPath.append(name_view);
libPath.append(SharedLibrary::GetExtensionName());
@ -79,7 +111,7 @@ namespace api {
newFuncAddr = sharedLib.GetSymbol(newFuncName.data());
}
}
IDynamicModule* module = newFuncAddr ? (IDynamicModule*)((IModule::CreatePFN)newFuncAddr)() : new(MemPool) DefaultDynamicModule(name);
IDynamicModule* module = newFuncAddr ? (IDynamicModule*)((IModule::CreatePFN)newFuncAddr)() : new(GlobalPool) DefaultDynamicModule(name);
mModuleTable[name] = module;
module->mSharedLib = sharedLib;
module->InitMetaData();
@ -107,4 +139,8 @@ namespace api {
}
return it->second;
}
void ModuleManager::RegisterModule(Name name, IModule::CreatePFN fn)
{
mInitializeTable[name] = fn;
}
}

View File

@ -0,0 +1,75 @@
#include "os/file_handle.h"
#include <algorithm>
#define READ_DATA_SIZE 100
#define TOKEN_SIZE 100
namespace api {
FileHandle& FileHandle::Open(FILE_OP _op, bool is_binarry)
{
op = _op;
pmr::string file_path = RealPath();
switch (op)
{
case api::FILE_OP::READ:
{
vfile = std::ifstream(file_path.c_str(), is_binarry ? std::ios::binary | std::ios::ate : std::ios::ate);
auto& fi = Reader();
if (!fi.is_open()) {
return *this;
}
size = fi.tellg();
fi.seekg(0);
break;
}
case api::FILE_OP::WRITE:
vfile = std::ofstream(file_path.c_str(), is_binarry ? std::ios::binary : 0);
break;
case api::FILE_OP::APPEND:
vfile = std::ofstream(file_path.c_str(), is_binarry ? std::ios::app | std::ios::binary : std::ios::app);
break;
default:
break;
}
flag = FileFlag::File_Success | (is_binarry ? FileFlag::File_Binary : 0);
return *this;
}
int FileHandle::Read(void* data, int size)
{
auto& fi = Reader();
if (!fi) {
return -1;
}
fi.read((char*)data, size);
return fi.gcount();
}
bool FileHandle::FindNext(const char* begin, const char* end, size_t& stop)
{
auto& fi = Reader();
size_t start = fi.tellg();
size_t cur = start;
char chunk[READ_DATA_SIZE + TOKEN_SIZE];
const char* last = chunk + READ_DATA_SIZE + TOKEN_SIZE;
while (cur < stop) {
fi.read(chunk + TOKEN_SIZE, READ_DATA_SIZE);
size_t count = fi.gcount();
if (count < READ_DATA_SIZE || cur + count > stop) {
fi.clear();
}
const char* first = cur == start ? chunk + TOKEN_SIZE : chunk;
const char* it = std::search(first, last, begin, end);
if (it != last) {
fi.seekg(start);
stop = cur + (it - first) - TOKEN_SIZE;
return true;
}
if (count < READ_DATA_SIZE) {
fi.seekg(start);
stop = cur + count;
return false;
}
cur += count;
memcpy(chunk, chunk + READ_DATA_SIZE, TOKEN_SIZE);
}
fi.seekg(start);
return false;
}
}

View File

@ -26,14 +26,14 @@ namespace api {
{
}
pmr::string FileManager::RealPath(const PackagePath& pack_path)
pmr::string FileManager::RealPath(PackagePath pack_path)
{
string_view name = pack_path.ParsePackage();
string_view pre_path = FindMountPath(name);
if (name.empty() || pre_path.empty()) {
return pmr::string(pack_path(), FramePool);
return pmr::string(pack_path());
}
pmr::string path{FramePool};
pmr::string path{};
path.reserve(pre_path.size() + pack_path.size() - name.size() - 1);
path.append(pre_path);
path.append(pack_path().substr(name.size() + 1));

View File

@ -6,7 +6,7 @@ namespace api {
string_view name = ParsePackage();
if (name.empty() || suffix.empty())
return *this;
string suffixPath;
pmr::string suffixPath;
suffixPath.reserve(path.size() + suffix.size());
suffixPath.append(name);
suffixPath.append(suffix);

View File

@ -0,0 +1,18 @@
#pragma once
#include <utility>
namespace meta
{
template<typename T>
struct comparable
{
bool operator>(const T&) const;
bool operator<=(const T&) const;
bool operator>=(const T&) const;
bool operator==(const T&) const;
bool operator!=(const T&) const;
private:
T& me();
const T& me() const;
};
}
#include "comparable.inl"

View File

@ -0,0 +1,43 @@
#pragma once
namespace meta
{
template<typename T>
inline bool comparable<T>::operator>(const T& rhs) const
{
static_assert(std::is_same_v<decltype(std::declval<const T&>() < std::declval<const T&>()), bool>, "type must be override bool operator<(const T&) const");
return rhs < me();
}
template<typename T>
inline bool comparable<T>::operator<=(const T& rhs) const
{
return !(rhs > me());
}
template<typename T>
inline bool comparable<T>::operator>=(const T& rhs) const
{
return !(me() < rhs);
}
template<typename T>
inline bool comparable<T>::operator==(const T& rhs) const
{
return !operator!=(rhs);
}
template<typename T>
inline bool comparable<T>::operator!=(const T& rhs) const
{
return me() < rhs || rhs < me();
}
template<typename T>
inline T& comparable<T>::me()
{
return *static_cast<T*>(this);
}
template<typename T>
inline const T& comparable<T>::me() const
{
return *static_cast<const T*>(this);
}
}

View File

@ -0,0 +1,43 @@
#pragma once
// tuple utils
#include <tuple>
namespace meta
{
template<typename Tuple, template<typename ...> typename Wrap>
struct tuple_wrap;
template<typename Tuple, template<typename ...> typename Wrap>
using tuple_wrap_t = typename tuple_wrap<Tuple, Wrap>::type;
template<typename...Ts>
using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
template<typename T1, typename T2>
struct tuple_join;
template<typename T1, typename T2>
using tuple_join_t = typename tuple_join<T1, T2>::type;
template <typename T, typename Tuple, std::size_t Index = 0>
consteval std::size_t index_in_tuple() {
if constexpr (Index == std::tuple_size_v<Tuple>) {
return Index; // 如果没有找到,返回元组的大小作为标志
}
else if constexpr (std::is_same_v<T, std::tuple_element_t<Index, Tuple>>) {
return Index; // 找到匹配的类型,返回当前索引
}
else {
return index_in_tuple<T, Tuple, Index + 1>(); // 递归检查下一个索引
}
}
template<typename FindMe, typename Tuple>
constexpr uint8_t index_in_tuple_v = index_in_tuple<FindMe, Tuple>();
template<typename T, typename ... Args>
constexpr auto tuple_construct(const std::tuple<Args...>&) noexcept;
}
#include "tuple.inl"

View File

@ -0,0 +1,30 @@
#pragma once
#include <utility>
namespace meta
{
namespace detail
{
template<typename T, typename ... Args, unsigned ... Indexes>
auto tuple_construct_helper(const std::tuple<Args...>& arg_tuple, std::index_sequence<Indexes...>)
{
return T{(std::get<Indexes>(arg_tuple))...};
}
}
template<typename T, typename ... Args>
constexpr auto tuple_construct(const std::tuple<Args...>& arg_tuple) noexcept
{
return detail::tuple_construct_helper<T>(arg_tuple, std::make_index_sequence < std::tuple_size_v<std::decay_t<decltype(arg_tuple)> >> {});
}
template<typename ... T1s, typename ...T2s>
struct tuple_join<std::tuple<T1s...>, std::tuple<T2s...>>
{
using type = std::tuple<T1s..., T2s...>;
};
template<typename ... Ts, template<typename ...> typename Wrap>
struct tuple_wrap<std::tuple<Ts...>, Wrap>
{
using type = std::tuple<Wrap<Ts>...>;
};
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <tuple>
#include <variant>
namespace meta
{
template<typename Variant, template<class T> typename Template>
struct variant_wrap;
template<typename Variant, template<class T> typename Template>
using variant_wrap_t = typename variant_wrap<Variant, Template>::type;
template<typename T>
struct tuple_to_variant;
template<typename T>
using tuple_to_variant_t = typename tuple_to_variant<T>::type;
template<typename T>
constexpr auto variant_construct(size_t) noexcept;
template<typename FindMe, typename Variant>
struct index_in_variant;
template<typename FindMe, typename Variant>
constexpr auto index_in_variant_v = index_in_variant<FindMe, Variant>::value;
}
#include "variant.inl"

View File

@ -0,0 +1,64 @@
#pragma once
namespace meta
{
namespace detail
{
template<typename T>
struct variant_helper;
template<typename ... Ts>
struct variant_helper<std::variant<Ts...>>
{
static constexpr auto ConstructJT()
{
using T = std::variant<Ts...>;
return std::array<T(*)(), sizeof...(Ts)>
{
[]() -> T
{
return Ts{};
} ...
};
}
};
}
template<template<class T> typename Template, typename ...Ts>
struct variant_wrap <std::variant<Ts...>, Template>
{
using type = std::variant<Template<Ts>...>;
};
template<typename ... Ts>
struct tuple_to_variant <std::tuple<Ts...>>
{
using type = std::variant<Ts...>;
};
template<typename T>
constexpr auto variant_construct(size_t i) noexcept
{
constexpr auto jt = detail::variant_helper<T>::ConstructJT();
return jt[i]();
}
template<typename FindMe>
struct index_in_variant<FindMe, std::variant<>>
{
static constexpr uint8_t value = 0;
};
template<typename FindMe, typename ... Ts>
struct index_in_variant<FindMe, std::variant<FindMe, Ts...>>
{
static constexpr uint8_t value = 0;
};
template<typename FindMe, typename First, typename ... Ts>
struct index_in_variant<FindMe, std::variant<First, Ts...>>
{
static constexpr uint8_t value = index_in_variant<FindMe, std::variant<Ts...>>::value + 1;
};
}

View File

@ -2,6 +2,7 @@
#include <vector>
#include <memory_resource>
namespace pmr {
using std::pmr::unsynchronized_pool_resource;
using std::pmr::memory_resource;
using std::pmr::vector;
class FrameAllocator : public memory_resource {
@ -47,18 +48,28 @@ inline void* operator new(size_t size, pmr::FrameAllocatorPool* pool, size_t ali
return pool->allocate(size, alignment);
}
#include "frame_allocator.inl"
inline pmr::FrameAllocatorPool* MemPool{};
inline pmr::FrameAllocatorPool* FramePool{};
inline pmr::FrameAllocatorPool* GetMemPool(){
if(!MemPool){
MemPool = new pmr::FrameAllocatorPool();
#ifdef DLL_API_VALUE
//全局生命周期,不回收内存
extern DLL_API inline pmr::FrameAllocatorPool* GlobalPool;
//局部生命周期,每帧回收内存
extern DLL_API inline pmr::FrameAllocatorPool* FramePool;
DLL_API pmr::FrameAllocatorPool* GetGlobalPool();
DLL_API pmr::FrameAllocatorPool* GetFramePool();
#else
//全局生命周期,不回收内存
inline pmr::FrameAllocatorPool* GlobalPool;
//局部生命周期,每帧回收内存
inline pmr::FrameAllocatorPool* FramePool;
inline pmr::FrameAllocatorPool* GetGlobalPool() {
if (!GlobalPool) {
GlobalPool = new pmr::FrameAllocatorPool();
}
return MemPool;
return GlobalPool;
}
inline pmr::FrameAllocatorPool* GetFramePool(){
if(!FramePool){
FramePool = new(GetMemPool()) pmr::FrameAllocatorPool();
inline pmr::FrameAllocatorPool* GetFramePool() {
if (!FramePool) {
FramePool = new(GetGlobalPool()) pmr::FrameAllocatorPool();
}
return FramePool;
}
}
#endif // DLL_API

View File

@ -55,6 +55,12 @@ namespace pmr
inline bool operator==(const CName& cname, const Name& name) {
return cname.Hash() == name.Hash();
}
template <class T>
constexpr inline void hash_combine(size_t& seed, const T& v) noexcept
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
constexpr inline size_t string_hash(std::string_view str) noexcept
{
constexpr size_t fnv_offset_basis = 0xcbf29ce484222325;

View File

@ -6,7 +6,7 @@ namespace pmr {
template<typename T>
static std::string_view MakePair(size_t id, T&& str);
static NameTable_t& TableRef() {
static NameTable_t Table{GetMemPool()};
static NameTable_t Table{GetGlobalPool()};
return Table;
}
};

View File

@ -32,5 +32,7 @@ namespace refl {
public:
operator bool()const { return cls && ptr; }
bool Check(const UClass* parent) const;
template<typename T>
T FindVtable(size_t name)const;
};
}

View File

@ -11,4 +11,9 @@ namespace refl{
}
return cls->IsChildOf(parent);
}
template<typename T>
inline T Any::FindVtable(size_t name) const
{
return (T)cls->vtable.Find(name);
}
}

View File

@ -24,18 +24,70 @@ namespace refl {
FIND_METHODS,//函数重载 特别是构造函数
};
struct vtable_uclass
{
{
struct Node {
size_t name;
void* method;
Node* next;
Node(size_t name, void* ptr) :name(name), method(ptr), next(nullptr) {}
Node* Insert(size_t name, void* ptr) {
Node* it = new Node(name, ptr);
next = it;
return it;
}
};
Node* header{nullptr};
operator bool() { return header; }
void Add(Name name, void* ptr) {
Add(name.Hash(), ptr);
}
void Add(size_t name, void* ptr) {
auto [bfind, it] = FindLast(name);
if (bfind) {
return;
}
Node* next = new Node(name, ptr);
Node** prev= it ? &(it->next) : &header;
*prev = next;
}
std::pair<bool,Node*> FindLast(size_t name) const{
Node *prev = nullptr, *it = header;
while (it) {
if (it->name == name) {
return std::make_pair(true, it);
}
prev = it;
it = it->next;
}
return std::make_pair(false, prev);
}
void* Find(size_t name) const {
Node* it = header;
while (it) {
if (it->name == name) {
return it->method;
}
it = it->next;
}
return nullptr;
}
//class
span<const FieldPtr>(*GetFields)(const UClass*, EFieldFind find, Name name);
using GetFields_t = span<const FieldPtr>(*)(const UClass*, EFieldFind find, Name name);
//class meta
using GetMeta_t = const UClass* (*)(Name);
//function
span<const UClass>(*GetParams)(const UClass*);
//function
void (*Call)(const FieldPtr*, span<Any> ArgsList);
//meta
const UClass* (*GetMeta)(Name);
using GetParams_t = span<const UClass>(*)(const UClass*);
//function args
using Call_t = void (*)(const FieldPtr*, span<Any> ArgsList);
//object
bool (*Construct)(void* ptr, const UClass* cls, span<Any> ArgsList);
void (*Destruct)(void*);
using Construct_t = bool (*)(void* ptr, const UClass* cls, span<Any> ArgsList);
using Destruct_t = void (*)(void*);
GetFields_t GetFields() const { return (GetFields_t) Find(string_hash("GetFields")); }
GetMeta_t GetMeta() const { return (GetMeta_t) Find(string_hash("GetMeta")); }
GetParams_t GetParams() const { return (GetParams_t) Find(string_hash("GetParams")); }
Call_t Call() const { return (Call_t) Find(string_hash("Call")); }
Construct_t Construct() const { return (Construct_t) Find(string_hash("Construct")); }
Destruct_t Destruct() const { return (Destruct_t) Find(string_hash("Destruct")); }
};
class UClass {
public:
@ -43,7 +95,7 @@ namespace refl {
uint32_t size;
uint32_t flag{0};
const UClass* parent;
vtable_uclass* vtable{nullptr};
vtable_uclass vtable;
UClass(const UClass*) = delete;
UClass& operator=(const UClass*) = delete;
public:

View File

@ -24,9 +24,8 @@ namespace refl{
parent = &TypeInfo<RT>::StaticClass;
}
else {
vtable = new(MemPool)vtable_uclass();
vtable->Construct = &UClass::Construct<T>;
vtable->Destruct = &UClass::Destruct<T>;
vtable.Add(string_hash("Construct"), (void*) &UClass::Construct<T>);
vtable.Add(string_hash("Destruct"), (void*) &UClass::Destruct<T>);
}
}
};
@ -44,15 +43,15 @@ namespace refl{
template<typename T>
struct TypeInfoImpl {
using MyUClass = UClass_Auto<T>;
inline static MyUClass StaticClass{};
const inline static MyUClass StaticClass{};
};
template<>
struct TypeInfoImpl<void> {
inline static UClass StaticClass{ type_name<void>().View(), 0 };
const inline static UClass StaticClass{ type_name<void>().View(), 0 };
};
template<is_meta_v T>
struct TypeInfoImpl<T> {
using MyUClass = UClass_Meta<T, meta_t<T>>;
inline static MyUClass StaticClass{};
const inline static MyUClass StaticClass{};
};
}

View File

@ -2,4 +2,4 @@ shared_module("vulkan","engine")
add_includedirs("include/vulkan")
add_headerfiles("include/**.h")
add_files("src/**.cpp")
add_dependency("core", "asset", {public = true})
add_dependency("engine", {public = true})

View File

@ -9,12 +9,16 @@ function header_component(name, owner, opt)
end
function static_component(name, owner, opt)
target(owner)
add_deps(name, { public = opt and opt.public or true })
add_deps(name)
add_defines("DLL_API_VALUE", {public = true})
add_includedirs("include", {public = true})
target_end()
target(name)
set_kind("static")
set_group("Engine/"..owner.."__comp")
add_includedirs("include", {public = true})
add_rules("engine.api")
add_defines("DLL_API=")
add_includedirs("include")
end
function shared_module(name, owner, opt)
target(name)

View File

@ -0,0 +1,2 @@
#include "api.h"
int editor_v;

14
engine/src/engine/api.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "api.h"
class ENGINE_API EngineModule : public api::IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override {};
void OnUnload() override {};
void InitMetaData(void) override {
mInfo.dependencies = {
{"core", "1.0.1", "static" },
{"asset", "1.0.1", "static" },
};
};
};
IMPLEMENT_DYNAMIC_MODULE(ENGINE_API, EngineModule, engine)

View File

@ -48,7 +48,7 @@ void genPlugin(const char* file_path, ParseData& pd) {
}
else if (md.macro == PUBLIC_MODULE_DEPENDENCY) {
for (auto& args : md.args) {
std::pmr::string upname{ args, FramePool};
std::pmr::string upname{ args};
std::transform(upname.begin(), upname.end(), upname.begin(), std::toupper);
info.dependencies.push_back({args, upname + "_VERSION", upname + "_KIND"});
}

View File

@ -1,9 +1,18 @@
target("editor")
set_kind("static")
set_kind("shared")
set_group("Engine")
add_rules("engine.api", {targets = {"dll", "editor"}})
add_headerfiles("include/editor/*.h")
add_includedirs("include/editor")
add_files("src/editor/*.cpp")
target("engine")
set_kind("static")
add_includedirs("include", {public = true})
set_kind("shared")
set_group("Engine")
add_rules("engine.api", {targets = {"dll", "engine"}})
add_headerfiles("include/engine/*.h")
add_includedirs("include/engine")
add_files("src/engine/*.cpp")
includes("xmake/xmake.lua")
includes("3rdparty/xmake.lua")
includes("tools/xmake.lua")

View File

@ -9,7 +9,11 @@ rule("engine.tool")
end)
rule("engine.api")
on_load(function (target)
local api = string.upper(target:name()) .. "_API"
target:add("defines", api.."=__declspec(dllimport)", {interface=true})
target:add("defines", api.."=__declspec(dllexport)", {public=false})
local deps = target:extraconf("rules", "engine.api", "targets")
deps = deps or {target:name()}
for k,v in ipairs(deps) do
local api = string.upper(v) .. "_API"
target:add("defines", api.."=__declspec(dllimport)", {interface=true})
target:add("defines", api.."=__declspec(dllexport)", {public=false})
end
end)

View File

@ -1,10 +1,7 @@
#include <iostream>
#include <array>
#include <charconv>
#include "pmr/frame_allocator.h"
#include "pmr/name.h"
#include "refl/pch.h"
#include "module/module_manager.h"
#include "engine/api.h"
void test(std::string_view str = "") {
std::cout << "test " << str << std::endl;
}