发现了链接错误,先备份一下
This commit is contained in:
parent
7e2712848c
commit
f5e2424f0f
2
engine/include/editor/api.h
Normal file
2
engine/include/editor/api.h
Normal file
@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
EDITOR_API extern int editor_v;
|
||||
2
engine/include/engine/api.h
Normal file
2
engine/include/engine/api.h
Normal file
@ -0,0 +1,2 @@
|
||||
#include "asset/module.h"
|
||||
#include "module/module_manager.h"
|
||||
@ -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()});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
engine/modules/engine/asset/include/asset/asset_loader.h
Normal file
11
engine/modules/engine/asset/include/asset/asset_loader.h
Normal 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;
|
||||
};
|
||||
}
|
||||
11
engine/modules/engine/asset/include/asset/module.h
Normal file
11
engine/modules/engine/asset/include/asset/module.h
Normal 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)
|
||||
}
|
||||
78
engine/modules/engine/asset/include/asset/res/guid.h
Normal file
78
engine/modules/engine/asset/include/asset/res/guid.h
Normal 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"
|
||||
15
engine/modules/engine/asset/include/asset/res/guid.inl
Normal file
15
engine/modules/engine/asset/include/asset/res/guid.inl
Normal 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
42
engine/modules/engine/asset/include/asset/res/meta_bundle.h
Normal file
42
engine/modules/engine/asset/include/asset/res/meta_bundle.h
Normal 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"
|
||||
@ -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() });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
@ -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};
|
||||
}
|
||||
}
|
||||
@ -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>;
|
||||
}
|
||||
@ -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"
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
18
engine/modules/engine/asset/include/asset/res/type.h
Normal file
18
engine/modules/engine/asset/include/asset/res/type.h
Normal 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>;
|
||||
}
|
||||
130
engine/modules/engine/asset/include/asset/resource_system.h
Normal file
130
engine/modules/engine/asset/include/asset/resource_system.h
Normal 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"
|
||||
145
engine/modules/engine/asset/include/asset/resource_system.inl
Normal file
145
engine/modules/engine/asset/include/asset/resource_system.inl
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
25
engine/modules/engine/asset/src/asset_loader.cpp
Normal file
25
engine/modules/engine/asset/src/asset_loader.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
14
engine/modules/engine/asset/src/module.cpp
Normal file
14
engine/modules/engine/asset/src/module.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
23
engine/modules/engine/asset/src/res/meta_bundle.cpp
Normal file
23
engine/modules/engine/asset/src/res/meta_bundle.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
17
engine/modules/engine/asset/src/res/resource_handle.cpp
Normal file
17
engine/modules/engine/asset/src/res/resource_handle.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
137
engine/modules/engine/asset/src/resource_system.cpp
Normal file
137
engine/modules/engine/asset/src/resource_system.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -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})
|
||||
@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
template <typename T>
|
||||
class Singleton{
|
||||
protected:
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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(); \
|
||||
}
|
||||
@ -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:
|
||||
|
||||
61
engine/modules/engine/core/include/os/file_handle.h
Normal file
61
engine/modules/engine/core/include/os/file_handle.h
Normal 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"
|
||||
39
engine/modules/engine/core/include/os/file_handle.inl
Normal file
39
engine/modules/engine/core/include/os/file_handle.inl
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
75
engine/modules/engine/core/src/os/file_handle.cpp
Normal file
75
engine/modules/engine/core/src/os/file_handle.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
|
||||
18
engine/modules/engine/zlib/include/meta/comparable.h
Normal file
18
engine/modules/engine/zlib/include/meta/comparable.h
Normal 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"
|
||||
43
engine/modules/engine/zlib/include/meta/comparable.inl
Normal file
43
engine/modules/engine/zlib/include/meta/comparable.inl
Normal 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);
|
||||
}
|
||||
}
|
||||
43
engine/modules/engine/zlib/include/meta/tuple.h
Normal file
43
engine/modules/engine/zlib/include/meta/tuple.h
Normal 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"
|
||||
30
engine/modules/engine/zlib/include/meta/tuple.inl
Normal file
30
engine/modules/engine/zlib/include/meta/tuple.inl
Normal 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>...>;
|
||||
};
|
||||
}
|
||||
27
engine/modules/engine/zlib/include/meta/variant.h
Normal file
27
engine/modules/engine/zlib/include/meta/variant.h
Normal 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"
|
||||
64
engine/modules/engine/zlib/include/meta/variant.inl
Normal file
64
engine/modules/engine/zlib/include/meta/variant.inl
Normal 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;
|
||||
};
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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:
|
||||
|
||||
@ -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{};
|
||||
};
|
||||
}
|
||||
@ -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})
|
||||
@ -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)
|
||||
|
||||
2
engine/src/editor/api.cpp
Normal file
2
engine/src/editor/api.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "api.h"
|
||||
int editor_v;
|
||||
14
engine/src/engine/api.cpp
Normal file
14
engine/src/engine/api.cpp
Normal 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)
|
||||
@ -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"});
|
||||
}
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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)
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user