support module system

This commit is contained in:
ouczbs 2024-07-31 10:48:28 +08:00
parent b17f3ef1d3
commit 7e2712848c
43 changed files with 685 additions and 168 deletions

21
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "emmylua_new",
"request": "launch",
"name": "EmmyLua New Debug",
"host": "localhost",
"port": 9966,
"ext": [
".lua",
".lua.txt",
".lua.bytes"
],
"ideConnectDebugger": true
}
]
}

View File

@ -1 +1 @@
add_requires("spdlog") add_requires("spdlog", "lemon")

View File

@ -27,6 +27,17 @@ namespace gen {
return obj; return obj;
} }
}; };
template<typename T>
struct JsonSerde<T, std::enable_if_t<refl::is_container_v<T>>> {
inline static bool Read(yyjson_val* val, const void* ptr) {
return true;
}
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, const void* ptr) {
T& v = *(T*)ptr;
yyjson_mut_val* obj = yyjson_mut_obj(doc);
return obj;
}
};
} }
namespace api { namespace api {
namespace detail { namespace detail {

View File

@ -2,7 +2,7 @@
#include "serde.h" #include "serde.h"
namespace api { namespace api {
// 定义 yyjson_alc 适配器类 // 定义 yyjson_alc 适配器类
inline yyjson_alc JsonAllocatorAdapter(std::pmr::memory_resource* mr = &FramePool) { inline yyjson_alc JsonAllocatorAdapter(std::pmr::memory_resource* mr = FramePool) {
// 初始化 yyjson_alc 结构体 // 初始化 yyjson_alc 结构体
yyjson_alc alc; yyjson_alc alc;
alc.malloc = [](void* ctx, size_t size) -> void* { alc.malloc = [](void* ctx, size_t size) -> void* {
@ -29,7 +29,7 @@ namespace api {
} }
inline JsonFuncTable JsonArchive::BuildFuncTable() inline JsonFuncTable JsonArchive::BuildFuncTable()
{ {
JsonFuncTable funcTable{ &MemPool }; JsonFuncTable funcTable{ MemPool };
using std::string_view; using std::string_view;
#define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>()) #define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>())
#include "../register.inl" #include "../register.inl"

View File

@ -9,6 +9,14 @@ namespace api {
Reload = 1, Reload = 1,
}; };
ENABLE_BITMASK_OPERATORS(EModuleFlag); ENABLE_BITMASK_OPERATORS(EModuleFlag);
struct ModuleDependency {
UPROPERTY()
Name name;
UPROPERTY()
Name version;
UPROPERTY()
Name kind;
};
struct ModuleInfo { struct ModuleInfo {
UPROPERTY() UPROPERTY()
EModuleFlag flag{0}; EModuleFlag flag{0};
@ -28,6 +36,9 @@ namespace api {
Name url; //!< url of the plugin Name url; //!< url of the plugin
UPROPERTY() UPROPERTY()
Name copyright; //!< copyright of the plugin Name copyright; //!< copyright of the plugin
UPROPERTY()
pmr::vector<ModuleDependency> dependencies;
ModuleInfo(pmr::memory_resource* mr = MemPool) : dependencies(mr){};
public: public:
bool IsReload() { bool IsReload() {
return !!(flag & EModuleFlag::Reload); return !!(flag & EModuleFlag::Reload);
@ -43,8 +54,8 @@ namespace api {
virtual void EndLoad() {} virtual void EndLoad() {}
}; };
struct IModule { struct IModule {
friend class ModuleManagerImpl;
public: public:
friend class ModuleManager;
using CreatePFN = IModule * (*)(); using CreatePFN = IModule * (*)();
IModule() = default; IModule() = default;
IModule(const IModule& rhs) = delete; IModule(const IModule& rhs) = delete;
@ -53,7 +64,7 @@ namespace api {
virtual void OnLoad(int argc, char** argv) = 0; virtual void OnLoad(int argc, char** argv) = 0;
virtual void OnUnload() = 0; virtual void OnUnload() = 0;
virtual const char* MetaData(void) = 0; virtual void InitMetaData(void) = 0;
virtual int Main(int argc, char** argv) { return 0; } virtual int Main(int argc, char** argv) { return 0; }
virtual const ModuleInfo* GetModuleInfo() virtual const ModuleInfo* GetModuleInfo()
@ -62,7 +73,7 @@ namespace api {
} }
protected: protected:
ModuleInfo mInfo; ModuleInfo mInfo;
std::vector<IModuleSubsystem*> mSubSystems; pmr::vector<IModuleSubsystem*> mSubSystems;
}; };
} }
#include "module.inl" #include "module.inl"

View File

@ -5,8 +5,13 @@ namespace api {
} }
SharedLibrary mSharedLib; SharedLibrary mSharedLib;
}; };
struct IStaticModule : public IModule { struct DefaultDynamicModule : public IDynamicModule {
DefaultDynamicModule(Name name) : IDynamicModule() {};
void OnLoad(int argc, char** argv) override {};
void OnUnload() override {};
void InitMetaData(void) override {};
}; };
using IStaticModule = IModule;
struct IHotfixModule : public IDynamicModule { struct IHotfixModule : public IDynamicModule {
void* state = nullptr; void* state = nullptr;
//IHotfixModule(){ mInfo.flag |= EModuleFlag::Reload; } //IHotfixModule(){ mInfo.flag |= EModuleFlag::Reload; }
@ -15,11 +20,11 @@ namespace api {
}; };
} }
#define IMPLEMENT_STATIC_MODULE(ModuleImplClass, ModuleName) \ #define IMPLEMENT_STATIC_MODULE(ModuleImplClass, ModuleName) \
inline static const api::ModuleRegistrantImpl<ModuleImplClass> __RegisterModule##ModuleName((const char*)#ModuleName); inline const api::ModuleRegistrantImpl<ModuleImplClass> __RegisterModule__##ModuleName(#ModuleName);
#define IMPLEMENT_DYNAMIC_MODULE(ModuleImplClass, ModuleName) \ #define IMPLEMENT_DYNAMIC_MODULE(DLL_APL, ModuleImplClass, ModuleName) \
extern "C" api::IModule* __newDynamicModule##ModuleName() \ using __##ModuleName##__module = ModuleImplClass; \
{ \ extern "C" DLL_APL api::IModule* __newDynamicModule__##ModuleName() \
return new ModuleImplClass(); \ { \
} return new(MemPool) ModuleImplClass(); \
#define MODULE_DEPENDENCY(...) }

View File

@ -1,31 +1,54 @@
#pragma once #pragma once
#include "module.h" #include "module.h"
namespace api { namespace api {
template<typename T1, typename T2, typename Hasher = std::hash<T1>>
using table = std::pmr::unordered_map<T1, T2, Hasher>;
class ModuleManager class ModuleManager
{ {
friend struct IModule; friend struct IModule;
private: private:
struct ModuleBlock {
bool isActive;
};
struct ExecuteInfo {
Name name;
int argc;
char** argv;
bool isActive;
};
ExecuteInfo mInfo;
SharedLibrary mProcessLib; SharedLibrary mProcessLib;
table<Name, IModule*> mModuleTable; pmr::table<Name, ModuleBlock> mModuleBlocks{ GetMemPool() };
pmr::table<Name, IModule*> mModuleTable{GetMemPool()};
pmr::table<Name, IModule::CreatePFN> mInitializeTable{ GetMemPool() };
public: public:
ModuleManager() = default;
IModule* GetModule(Name name);
bool RegisterModule(Name name, IModule::CreatePFN fn);
static ModuleManager* Ptr(); static ModuleManager* Ptr();
public:
ModuleManager();
~ModuleManager();
IModule* GetModule(Name name);
void RegisterModule(Name name, IModule::CreatePFN fn) { mInitializeTable[name] = fn; }
void CreateModule(Name name, bool shared);
void DestroyModule(Name name);
void MakeGraph(Name name, bool shared, int argc, char** argv);
void DestroyGraph();
protected:
IModule* spawnDynamicModule(Name name, bool hotfix);
IModule* spawnStaticModule(Name name);
}; };
struct empty {
};
static empty e;
template <typename ModuleClass> template <typename ModuleClass>
struct ModuleRegistrantImpl { struct ModuleRegistrantImpl {
ModuleRegistrantImpl(const char* InModuleName) ModuleRegistrantImpl(const char* InModuleName)
{ {
ModuleManager::Ptr()->RegisterModule(InModuleName, []() { ModuleManager::Ptr()->RegisterModule(InModuleName, []()->IModule* {
return new ModuleClass(); return new ModuleClass();
}); });
} }
}; };
class CoreModule : public IStaticModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
void InitMetaData(void) override;
};
IMPLEMENT_STATIC_MODULE(CoreModule, core)
} }

View File

@ -0,0 +1,69 @@
#pragma once
#include "singleton.h"
#include "package_path.h"
namespace api
{
class FileManager : public Singleton<FileManager>
{
public:
FileManager();
~FileManager();
public:
void Mount(Name name, const string& path) {
MountMap.emplace(name, std::make_pair(name, path));
}
std::pair<string, string> FindMount(Name id) {
auto it = MountMap.find(id);
if (it != MountMap.end()) {
return it->second;
}
return {};
}
string_view FindMountName(Name id) {
auto pair = FindMount(id);
return pair.first;
}
string_view FindMountPath(Name id) {
auto pair = FindMount(id);
return pair.second;
}
string_view FindPathView(Name name) {
auto it = FileMap.find(name);
if (it != FileMap.end()) {
return it->second.path;
}
return "";
}
string_view FindOrPathView(Name name) {
auto it = FileMap.find(name);
if (it != FileMap.end()) {
return it->second.path;
}
auto res = FileMap.emplace(name, FileBlock{ FileFlag::File_Default, name.ToString()});
return res.first->second.path;
}
uint32_t FindPathFlag(const 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) {
auto it = FileMap.find(pack_path());
if (it == FileMap.end()) {
return nullptr;
}
return &it->second;
}
void SaveMountMap();
void LoadFileMap();
void SaveFileMap();
private:
pmr::table<Name, std::pair<string, string>> MountMap{GetMemPool()};
pmr::table<Name, FileBlock> FileMap{GetMemPool()};
public:
//外界不应该使用绝对路径
pmr::string RealPath(const PackagePath& pack_path);
};
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <string>
#include "pmr/name.h"
namespace api
{
using std::string;
using std::string_view;
using pmr::Name;
enum FileFlag : uint32_t {
File_Default = 0,
File_Success = 1 << 0,
File_Binary = 1 << 1,
File_Compress = 1 << 2,
File_Http = 1 << 3,
File_Not_Exist = 1 << 4,
File_Error = 1 << 5,
};
//占位符浪费了四个字节
struct FileBlock {
uint32_t flag{ 0 };
string path;
string addr;
operator bool() {
return !(flag & FileFlag::File_Not_Exist);
}
};
struct PackagePath {
string_view path;
PackagePath() {};
PackagePath(const char* path) : path(path) {}
PackagePath(string_view path) : path(path) {}
PackagePath(const string& path) : path(path) {}
PackagePath(const pmr::string& path) : path(path) {}
operator bool() {
return path != "";
}
string_view operator()() const {
return path;
}
size_t size() const {
return path.size();
}
pmr::string operator+(const char* suffix) const {
return pmr::string(path, FramePool) + suffix;
}
string_view ParsePackage()const {
string_view name;
if (path[0] == '/') {
size_t pos = path.find('/', 1);
if (pos != string::npos) {
return path.substr(1, pos - 1);
}
}
return name;
}
string_view GetFileName()const {
size_t pos = path.rfind('/');
if (pos != std::string::npos)
return path.substr(pos + 1);
return "";
}
Name GetExtension() const {
size_t pos = path.rfind('.');
if (pos != std::string::npos)
return path.substr(pos);
return "";
}
PackagePath ToSuffixPath(string_view suffix)const;
PackagePath SafePath()const;
pmr::string RealPath()const;
};
}

View File

@ -1,9 +1,13 @@
#pragma once #pragma once
#include "os/package_path.h"
namespace api { namespace api {
using NativeLibHandle = void*; using NativeLibHandle = void*;
class SharedLibrary { class SharedLibrary {
NativeLibHandle mHandle; NativeLibHandle mHandle;
public: public:
bool Load(const char* path = nullptr); bool Load(PackagePath path = "");
void* GetSymbol(const char* name);
static string_view GetExtensionName();
}; };
} }

View File

@ -0,0 +1,16 @@
#include "module/module_manager.h"
#include "os/file_manager.h"
namespace api {
void CoreModule::OnLoad(int argc, char** argv)
{
}
void CoreModule::OnUnload()
{
}
void CoreModule::InitMetaData(void)
{
}
}

View File

@ -1,14 +1,103 @@
#include "module/module_manager.h" #include "module/module_manager.h"
#include "os/file_manager.h"
namespace api { namespace api {
ModuleManager* ModuleManager::Ptr() ModuleManager* ModuleManager::Ptr()
{ {
static ModuleManager* ptr; static ModuleManager ptr;
if (ptr) { return &ptr;
return ptr; }
ModuleManager::ModuleManager()
{
GetMemPool();
GetFramePool();
mProcessLib.Load();
new FileManager();
}
ModuleManager::~ModuleManager()
{
DestroyGraph();
delete FileManager::Ptr();
delete GetFramePool();
delete GetMemPool();
}
void ModuleManager::CreateModule(Name name, bool shared)
{
bool hotfix = true;
IModule* module = shared ?
spawnDynamicModule(name, hotfix) :
spawnStaticModule(name);
if (!module) { return; }
mModuleBlocks[name] = ModuleBlock{false};
ModuleBlock& block = mModuleBlocks[name];
auto& moduleInfo = module->mInfo;
for (auto& dep : moduleInfo.dependencies) {
if(auto it = mModuleBlocks.find(name); it != mModuleBlocks.end())
CreateModule(dep.name, dep.kind == pmr::FName("shared"));
} }
ptr = new ModuleManager(); module->OnLoad(mInfo.argc, mInfo.argv);
ptr->mProcessLib.Load(); block.isActive = true;
return ptr; }
void ModuleManager::DestroyModule(Name name)
{
auto it = mModuleBlocks.find(name);
if (it == mModuleBlocks.end() || !it->second.isActive) {
return;
}
IModule* module = mModuleTable[name];
auto& moduleInfo = module->mInfo;
for (auto& dep : moduleInfo.dependencies) {
DestroyModule(dep.name);
}
it->second.isActive = false;
}
void ModuleManager::MakeGraph(Name name, bool shared, int argc, char** argv)
{
mInfo = { name, argc, argv , true};
CreateModule(name, shared);
}
void ModuleManager::DestroyGraph()
{
if(mInfo.isActive)
DestroyModule(mInfo.name);
}
IModule* ModuleManager::spawnDynamicModule(Name name, bool hotfix)
{
if (auto it = mModuleTable.find(name); it != mModuleTable.end()) {
return it->second;
}
SharedLibrary sharedLib;
string_view name_view = name.ToStringView();
pmr::string newFuncName("__newDynamicModule__", FramePool);
newFuncName.append(name_view);
void* newFuncAddr = mProcessLib.GetSymbol(newFuncName.data());
if (!newFuncAddr) {
pmr::string libPath("/exe/", FramePool);
libPath.reserve(10 + name_view.size());
libPath.append(name_view);
libPath.append(SharedLibrary::GetExtensionName());
if (sharedLib.Load(libPath)) {
newFuncAddr = sharedLib.GetSymbol(newFuncName.data());
}
}
IDynamicModule* module = newFuncAddr ? (IDynamicModule*)((IModule::CreatePFN)newFuncAddr)() : new(MemPool) DefaultDynamicModule(name);
mModuleTable[name] = module;
module->mSharedLib = sharedLib;
module->InitMetaData();
return module;
}
IModule* ModuleManager::spawnStaticModule(Name name)
{
if (auto it = mModuleTable.find(name); it != mModuleTable.end()) {
return it->second;
}
auto it = mInitializeTable.find(name);
if (it == mInitializeTable.end()) {
return nullptr;
}
IModule* module = it->second();
module->InitMetaData();
mModuleTable[name] = module;
return module;
} }
IModule* ModuleManager::GetModule(Name name) IModule* ModuleManager::GetModule(Name name)
{ {
@ -18,8 +107,4 @@ namespace api {
} }
return it->second; return it->second;
} }
bool ModuleManager::RegisterModule(Name name, IModule::CreatePFN fn)
{
return false;
}
} }

View File

@ -0,0 +1,43 @@
#include "os/file_manager.h"
#include "os/file_system.h"
#include <fstream>
#include "zlog.h"
namespace api {
FileManager::FileManager()
{
Mount("exe", fs::GetExecutablePath());
Mount("engine", fs::GetWorkPath());
LoadFileMap();
}
FileManager::~FileManager()
{
SaveMountMap();
SaveFileMap();
}
void FileManager::SaveMountMap()
{
}
void FileManager::LoadFileMap()
{
}
void FileManager::SaveFileMap()
{
}
pmr::string FileManager::RealPath(const 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);
}
pmr::string path{FramePool};
path.reserve(pre_path.size() + pack_path.size() - name.size() - 1);
path.append(pre_path);
path.append(pack_path().substr(name.size() + 1));
return path;
}
}

View File

@ -0,0 +1,25 @@
#include "os/package_path.h"
#include "os/file_manager.h"
namespace api {
PackagePath PackagePath::ToSuffixPath(string_view suffix)const
{
string_view name = ParsePackage();
if (name.empty() || suffix.empty())
return *this;
string suffixPath;
suffixPath.reserve(path.size() + suffix.size());
suffixPath.append(name);
suffixPath.append(suffix);
suffixPath.append(path.substr(name.size()));
return PackagePath{ FileManager::Ptr()->FindPathView(suffixPath) };
}
PackagePath PackagePath::SafePath()const
{
return PackagePath{ FileManager::Ptr()->FindPathView(path) };
}
pmr::string PackagePath::RealPath() const
{
return FileManager::Ptr()->RealPath(*this);
}
}

View File

@ -1,21 +1,35 @@
#include "os/shared_library.h" #include "os/shared_library.h"
#include <Windows.h> #include <Windows.h>
namespace api { namespace api {
bool SharedLibrary::Load(const char* path) bool SharedLibrary::Load(PackagePath path)
{ {
if (path == nullptr) if (path)
{ {
mHandle = GetModuleHandle(nullptr); auto rpath = path.RealPath();
mHandle = GetModuleHandle(rpath.c_str());
if (mHandle == NULL)
{
mHandle = LoadLibrary(rpath.c_str());
}
} }
else else
{ {
mHandle = GetModuleHandle(path); mHandle = GetModuleHandle(nullptr);
if (mHandle == NULL)
{
mHandle = LoadLibrary(path);
}
} }
return mHandle; return mHandle;
} }
void* SharedLibrary::GetSymbol(const char* name)
{
void* addr = (void*)GetProcAddress((HMODULE)mHandle, name);
return addr;
}
string_view SharedLibrary::GetExtensionName()
{
#ifdef _WIN32
return string_view(".dll");
#elif __linux__
return string_view(".so");
#endif
}
} }

View File

@ -6,5 +6,4 @@ static_component("core","engine")
add_headerfiles("include/**.h","include/**.inl") add_headerfiles("include/**.h","include/**.inl")
add_files("src/**.cpp") add_files("src/**.cpp")
add_deps("zlib", {public = true}) add_deps("zlib", {public = true})
add_packages("spdlog", {public = true}) add_packages("spdlog", {public = true})
--add_syslinks("Kernel32")

View File

@ -2,7 +2,9 @@
#include <vector> #include <vector>
#include <memory_resource> #include <memory_resource>
namespace pmr { namespace pmr {
class FrameAllocator : public std::pmr::memory_resource { using std::pmr::memory_resource;
using std::pmr::vector;
class FrameAllocator : public memory_resource {
private: private:
char* buffer; char* buffer;
size_t capacity; size_t capacity;
@ -23,9 +25,9 @@ namespace pmr {
void move_clear() { buffer = nullptr; capacity = 0; offset = 0; }; void move_clear() { buffer = nullptr; capacity = 0; offset = 0; };
void* do_allocate(size_t bytes, size_t alignment) override; void* do_allocate(size_t bytes, size_t alignment) override;
void do_deallocate(void* p, size_t bytes, size_t alignment) override {}; void do_deallocate(void* p, size_t bytes, size_t alignment) override {};
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; }; bool do_is_equal(const memory_resource& other) const noexcept override { return this == &other; };
}; };
class FrameAllocatorPool : public std::pmr::memory_resource { class FrameAllocatorPool : public memory_resource {
public: public:
FrameAllocatorPool(size_t allocatorSize = 1024 * 1024) noexcept : allocatorSize(allocatorSize) {} FrameAllocatorPool(size_t allocatorSize = 1024 * 1024) noexcept : allocatorSize(allocatorSize) {}
@ -33,17 +35,30 @@ namespace pmr {
void reset(); void reset();
void* do_allocate(size_t bytes, size_t alignment) override { return allocate(bytes, alignment); } void* do_allocate(size_t bytes, size_t alignment) override { return allocate(bytes, alignment); }
void do_deallocate(void* p, size_t bytes, size_t alignment) override {}; void do_deallocate(void* p, size_t bytes, size_t alignment) override {};
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; }; bool do_is_equal(const memory_resource& other) const noexcept override { return this == &other; };
private: private:
size_t allocatorSize; size_t allocatorSize;
std::vector<FrameAllocator> allocators{}; vector<FrameAllocator> allocators{};
}; };
}; };
// 自定义的new操作符 // 自定义的new操作符
inline void* operator new(size_t size, pmr::FrameAllocatorPool& pool, size_t alignment = alignof(std::max_align_t)) { inline void* operator new(size_t size, pmr::FrameAllocatorPool* pool, size_t alignment = alignof(std::max_align_t)) {
size = (size + alignment - 1) & ~(alignment - 1); size = (size + alignment - 1) & ~(alignment - 1);
return pool.allocate(size, alignment); return pool->allocate(size, alignment);
} }
#include "frame_allocator.inl" #include "frame_allocator.inl"
inline static pmr::FrameAllocatorPool MemPool{};
inline static pmr::FrameAllocatorPool FramePool{}; inline pmr::FrameAllocatorPool* MemPool{};
inline pmr::FrameAllocatorPool* FramePool{};
inline pmr::FrameAllocatorPool* GetMemPool(){
if(!MemPool){
MemPool = new pmr::FrameAllocatorPool();
}
return MemPool;
}
inline pmr::FrameAllocatorPool* GetFramePool(){
if(!FramePool){
FramePool = new(GetMemPool()) pmr::FrameAllocatorPool();
}
return FramePool;
}

View File

@ -3,6 +3,9 @@
#include <unordered_map> #include <unordered_map>
namespace pmr namespace pmr
{ {
template<typename T1, typename T2, typename Hasher = std::hash<T1>>
using table = std::pmr::unordered_map<T1, T2, Hasher>;
using std::pmr::string;
static consteval inline size_t InvalidValue() noexcept { return static_cast<size_t>(-1); } static consteval inline size_t InvalidValue() noexcept { return static_cast<size_t>(-1); }
constexpr inline size_t string_hash(std::string_view str) noexcept; constexpr inline size_t string_hash(std::string_view str) noexcept;
struct Name { struct Name {
@ -17,6 +20,7 @@ namespace pmr
Name(const char(&str)[N]) noexcept; Name(const char(&str)[N]) noexcept;
Name(const char* str)noexcept; Name(const char* str)noexcept;
Name(const std::string& str)noexcept; Name(const std::string& str)noexcept;
Name(const string& str)noexcept;
Name(std::string_view str)noexcept; Name(std::string_view str)noexcept;
auto operator<=>(const Name& other) const noexcept { return hash <=> other.hash; }; auto operator<=>(const Name& other) const noexcept { return hash <=> other.hash; };
bool operator==(const Name& other) const {return hash == other.hash;} bool operator==(const Name& other) const {return hash == other.hash;}
@ -32,6 +36,7 @@ namespace pmr
std::string_view value; std::string_view value;
public: public:
constexpr CName() noexcept : hash{ InvalidValue() } {} constexpr CName() noexcept : hash{ InvalidValue() } {}
constexpr CName(string str) noexcept : hash{ string_hash(str) }, value(str) {}
constexpr CName(std::string_view str) noexcept : hash{ string_hash(str) } ,value(str) {} constexpr CName(std::string_view str) noexcept : hash{ string_hash(str) } ,value(str) {}
template<size_t N> template<size_t N>
constexpr CName(const char(&str)[N]) noexcept : hash{ string_hash(str) }, value(str) {} constexpr CName(const char(&str)[N]) noexcept : hash{ string_hash(str) }, value(str) {}
@ -47,7 +52,7 @@ namespace pmr
std::string ToString() const { return std::string(value); }; std::string ToString() const { return std::string(value); };
operator std::string() const { return ToString(); } operator std::string() const { return ToString(); }
}; };
bool operator==(const CName& cname, const Name& name) { inline bool operator==(const CName& cname, const Name& name) {
return cname.Hash() == name.Hash(); return cname.Hash() == name.Hash();
} }
constexpr inline size_t string_hash(std::string_view str) noexcept constexpr inline size_t string_hash(std::string_view str) noexcept

View File

@ -1,21 +1,22 @@
#include "name.h"
namespace pmr { namespace pmr {
using NameTable_t = std::pmr::unordered_map<size_t,const std::pmr::string>; using NameTable_t = table<size_t,const string>;
struct NameTable { struct NameTable {
static const std::pmr::string& Find(size_t id); static const string& Find(size_t id);
template<typename T> template<typename T>
static std::string_view MakePair(size_t id, T&& str); static std::string_view MakePair(size_t id, T&& str);
static NameTable_t BuildNameTable() { static NameTable_t& TableRef() {
static FrameAllocatorPool MemPool; static NameTable_t Table{GetMemPool()};
return NameTable_t(&MemPool); return Table;
} }
inline static NameTable_t Table = BuildNameTable();
}; };
template<typename T> template<typename T>
inline std::string_view NameTable::MakePair(size_t id, T&& str) inline std::string_view NameTable::MakePair(size_t id, T&& str)
{ {
auto& Table = TableRef();
auto it = Table.find(id); auto it = Table.find(id);
if (it == Table.end()) { if (it == Table.end()) {
auto it2 = Table.emplace(std::make_pair(id, std::pmr::string(str, Table.get_allocator()))); auto it2 = Table.emplace(std::make_pair(id, string(str, Table.get_allocator())));
if (it2.second) { if (it2.second) {
return it2.first->second; return it2.first->second;
} }
@ -23,11 +24,12 @@ namespace pmr {
} }
return it->second; return it->second;
} }
inline const std::pmr::string& NameTable::Find(size_t id) inline const string& NameTable::Find(size_t id)
{ {
auto& Table = TableRef();
auto it = Table.find(id); auto it = Table.find(id);
if (it == Table.end()) { if (it == Table.end()) {
static std::pmr::string empty("", Table.get_allocator()); static string empty("", Table.get_allocator());
return empty; return empty;
} }
return it->second; return it->second;
@ -64,6 +66,10 @@ namespace pmr {
{ {
MAKE_NAME_PAIR(hash, str); MAKE_NAME_PAIR(hash, str);
} }
inline Name::Name(const string& str)noexcept : hash(string_hash(str))
{
MAKE_NAME_PAIR(hash, str);
}
#undef MAKE_NAME_PAIR #undef MAKE_NAME_PAIR
#undef NAME_TO_STRING #undef NAME_TO_STRING
} }

View File

@ -1,11 +1,12 @@
#pragma once
#include "module/module.h" #include "module/module.h"
#include "asset/asset.h" #include "asset/asset.h"
class VulkanModule : public api::IDynamicModule class VULKAN_API VulkanModule : public api::IDynamicModule
{ {
public: public:
void OnLoad(int argc, char** argv) override; void OnLoad(int argc, char** argv) override;
void OnUnload() override; void OnUnload() override;
const char* MetaData(void) override; void InitMetaData(void) override;
}; };
MODULE_DEPENDENCY(core, asset, {public = true}) IMPLEMENT_DYNAMIC_MODULE(VULKAN_API, VulkanModule, vulkan)
IMPLEMENT_DYNAMIC_MODULE(VulkanModule, vulkan) #include "vulkan.plugin.inl"

View File

@ -8,8 +8,3 @@ void VulkanModule::OnLoad(int argc, char** argv)
void VulkanModule::OnUnload() void VulkanModule::OnUnload()
{ {
} }
const char* VulkanModule::MetaData(void)
{
return nullptr;
}

View File

@ -1 +0,0 @@
{"flag":0,"name":"vulkan"}

View File

@ -1,5 +1,5 @@
shared_component("vulkan","engine") shared_module("vulkan","engine")
add_includedirs("include/vulkan") add_includedirs("include/vulkan")
add_headerfiles("include/**.h") add_headerfiles("include/**.h")
add_files("src/**.cpp") add_files("src/**.cpp")
add_rules("engine.plugin", {file = "include/vulkan/module.h"}) add_dependency("core", "asset", {public = true})

View File

@ -16,13 +16,36 @@ function static_component(name, owner, opt)
set_group("Engine/"..owner.."__comp") set_group("Engine/"..owner.."__comp")
add_includedirs("include", {public = true}) add_includedirs("include", {public = true})
end end
function shared_component(name, owner, opt) function shared_module(name, owner, opt)
target(owner)
add_deps(name, { public = opt and opt.public or true })
target_end()
target(name) target(name)
set_kind("shared") set_kind("shared")
set_group("Engine/"..owner.."__comp") set_group("Engine/"..owner.."__dyn")
add_rules("engine.api")
add_includedirs("include", {public = true}) add_includedirs("include", {public = true})
add_rules("engine.plugin", {file = opt and opt.file or "include/" .. name .. "/module.h"})
end
function add_dependency(...)
add_deps(...)
local args = {...}
local opt = args[#args]
if type(opt) ~= "table" or not opt.public then
return
end
for _,v in ipairs(args) do
if v ~= opt then
add_values("module.public_dependencies", v)
end
end
end
function game_instance(name, opt)
target(name)
set_kind("shared")
set_group("Games")
add_rules("engine.api")
add_rules("engine.plugin", {file = opt and opt.file or "src/" .. name .. ".h"})
target(name .. "-editor")
set_kind("binary")
set_group("Games")
add_deps(name)
end end
includes("**/xmake.lua") includes("**/xmake.lua")

View File

@ -4,7 +4,7 @@
#include <optional> #include <optional>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
std::string_view module_macro[] = { MODULE_DEPENDENCY , IMPLEMENT_DYNAMIC_MODULE , IMPLEMENT_STATIC_MODULE }; std::string_view module_macro[] = { PUBLIC_MODULE_DEPENDENCY, PRIVATE_MODULE_DEPENDENCY , IMPLEMENT_DYNAMIC_MODULE, EXPORT_MODULE };
pmr::vector<pmr::string> parseArgs(std::string_view& str) { pmr::vector<pmr::string> parseArgs(std::string_view& str) {
pmr::vector<pmr::string> args(&pool); pmr::vector<pmr::string> args(&pool);
std::stack<char> stack; std::stack<char> stack;
@ -75,20 +75,25 @@ std::optional<MacroData> parseLine(std::string_view line) {
return std::optional<MacroData>{}; return std::optional<MacroData>{};
} }
// 读取文件并返回每一行内容 // 读取文件并返回每一行内容
pmr::vector<MacroData> readMacroFile(const char* file_path) { void readMacroFile(const char* file_path, ParseData& pd) {
pmr::vector<MacroData> lines(&pool);
std::ifstream file(file_path); std::ifstream file(file_path);
if (!file.is_open()) { if (!file.is_open()) {
//std::cerr << "Failed to open file: " << file_path << std::endl; //std::cerr << "Failed to open file: " << file_path << std::endl;
return lines; return;
} }
std::string line; std::string line;
while (std::getline(file, line)) { while (std::getline(file, line)) {
std::string_view line_view(line); std::string_view line_view(line);
if (auto md = parseLine(line_view)) { if (auto md = parseLine(line_view)) {
lines.push_back(md.value()); const char* macro = md.value().macro;
if (macro == EXPORT_MODULE) {
std::string_view text = md.value().args[0];
text = text.substr(3, text.size() - 5);//R(" + )" = 3 + 2 = 5;
pd.exportText = text;
}
else
pd.mdList.push_back(md.value());
} }
} }
file.close(); file.close();
return lines;
} }

View File

@ -5,13 +5,20 @@ namespace pmr {
using std::pmr::string; using std::pmr::string;
} }
inline pmr::monotonic_buffer_resource pool; inline pmr::monotonic_buffer_resource pool;
inline const char* MODULE_DEPENDENCY = "MODULE_DEPENDENCY"; inline const char* PUBLIC_MODULE_DEPENDENCY = "PUBLIC_MODULE_DEPENDENCY";
inline const char* PRIVATE_MODULE_DEPENDENCY = "PRIVATE_MODULE_DEPENDENCY";
inline const char* IMPLEMENT_DYNAMIC_MODULE = "IMPLEMENT_DYNAMIC_MODULE"; inline const char* IMPLEMENT_DYNAMIC_MODULE = "IMPLEMENT_DYNAMIC_MODULE";
inline const char* IMPLEMENT_STATIC_MODULE = "IMPLEMENT_STATIC_MODULE"; inline const char* EXPORT_MODULE = "EXPORT_MODULE";
struct MacroData { struct MacroData {
const char* macro{ nullptr }; const char* macro{ nullptr };
pmr::vector<pmr::string> args; pmr::vector<pmr::string> args;
MacroData() :args(&pool) {} MacroData() :args(&pool) {}
MacroData(const pmr::vector<pmr::string>& args) :args(args) {} MacroData(const pmr::vector<pmr::string>& args) :args(args) {}
operator bool() const { return macro; }
}; };
pmr::vector<MacroData> readMacroFile(const char* file_path); struct ParseData {
pmr::string moduleFile;
pmr::string exportText;
pmr::vector<MacroData> mdList;
};
void readMacroFile(const char* file_path, ParseData& pd);

View File

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <algorithm>
std::string_view readFile(const char* file_path) { std::string_view readFile(const char* file_path) {
std::ifstream file(file_path, std::ios::ate); std::ifstream file(file_path, std::ios::ate);
if (!file.is_open()) { if (!file.is_open()) {
@ -24,47 +25,46 @@ void genLua(const char* file_path, const pmr::vector<MacroData>& mdList) {
std::ostringstream oss; std::ostringstream oss;
oss << "{\n"; oss << "{\n";
for (auto& md : mdList) { for (auto& md : mdList) {
if (md.macro == MODULE_DEPENDENCY) { if (md.macro == PUBLIC_MODULE_DEPENDENCY || md.macro == PRIVATE_MODULE_DEPENDENCY) {
oss << "\t{"; oss << "\t{";
for (auto& args : md.args) { for (auto& args : md.args) {
if (args[0] != '{') { oss << '"' << args << "\", ";
oss << '"' << args << "\", ";
}
else {
oss << args;
}
} }
oss << "},\n"; oss << (md.macro == PUBLIC_MODULE_DEPENDENCY ? "{public = true}},\n" : "{public = false}},\n");
} }
} }
oss << '}'; oss << '}';
writeFile(file_path, oss.str()); writeFile(file_path, oss.str());
} }
void genPlugin(const char* file_path, const pmr::vector<MacroData>& mdList) { void genPlugin(const char* file_path, ParseData& pd) {
std::string_view text = readFile(file_path); readMacroFile(file_path, pd);
api::ModuleInfo info; api::ModuleInfo info;
std::string_view text = pd.exportText;
api::JsonDeserialize<api::ModuleInfo>(text, &info); api::JsonDeserialize<api::ModuleInfo>(text, &info);
bool bchange = false; info.dependencies.clear();
for (auto& md : mdList) { for (auto& md : pd.mdList) {
if (md.macro == IMPLEMENT_DYNAMIC_MODULE || md.macro == IMPLEMENT_STATIC_MODULE) { if (md.macro == IMPLEMENT_DYNAMIC_MODULE) {
api::Name name = md.args[1].c_str(); info.name = md.args[1];
bchange = info.name != name;
info.name = name;
} }
else if (md.macro == MODULE_DEPENDENCY) { else if (md.macro == PUBLIC_MODULE_DEPENDENCY) {
for (auto& args : md.args) { for (auto& args : md.args) {
if (args[0] != '{') { std::pmr::string upname{ args, FramePool};
std::transform(upname.begin(), upname.end(), upname.begin(), std::toupper);
} info.dependencies.push_back({args, upname + "_VERSION", upname + "_KIND"});
} }
} }
} }
if (bchange) { std::ostringstream oss;
writeFile(file_path, api::JsonSerialize(info)); std::string name = info.name.ToString();
} std::transform(name.begin(), name.end(), name.begin(), std::toupper);
oss << "#include \"" << pd.moduleFile << "\"\n";
oss << "#define EXPORT_MODULE(json)" << name << "_API const char* __module_meta_" << info.name.data() << "__ = json\n";
oss << "EXPORT_MODULE(R\"(" << api::JsonSerialize(info) << ")\");\n";
writeFile(file_path, oss.str());
} }
//已废弃
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if (argc < 6) { if (argc < 100) {
return -1; return -1;
} }
std::string project_dir = argv[1]; std::string project_dir = argv[1];
@ -72,8 +72,10 @@ int main(int argc, char* argv[]) {
std::string script_dir = argv[3]; std::string script_dir = argv[3];
std::string module_file = script_dir + "\\" + argv[4]; std::string module_file = script_dir + "\\" + argv[4];
std::string plugin_file = script_dir + "\\" + argv[5]; std::string plugin_file = script_dir + "\\" + argv[5];
auto mdList = readMacroFile(module_file.c_str()); ParseData pd;
genLua(lua_file.c_str(), mdList); pd.moduleFile = argv[4];
genPlugin(plugin_file.c_str(), mdList); readMacroFile(module_file.c_str(), pd);
genLua(lua_file.c_str(), pd.mdList);
genPlugin(plugin_file.c_str(), pd);
return 0; return 0;
} }

View File

@ -1,8 +1,7 @@
tool_target("make_plugin") -- tool_target("make_plugin", "shared")
add_includedirs("src") -- add_includedirs("src")
add_files("src/*.cpp") -- add_files("src/*.cpp")
add_headerfiles("src/*.h") -- add_headerfiles("src/*.h")
add_rules("engine.tool") -- add_deps("core")
add_deps("core") -- set_runargs(os.projectdir(), [[build\.gens\vulkan\windows\xmake.lua]],
set_runargs([[F:\engine\zengine]], [[build\.gens\vulkan\windows\xmake.lua]], -- os.projectdir() .. [[\engine\modules\render\vulkan]], [[include\vulkan\module.h]], "vulkan" .. ".plugin.cpp")
[[F:\engine\zengine\engine\modules\render\vulkan]], [[include/vulkan/module.h]], [[vulkan.plugin]])

View File

@ -1,6 +1,7 @@
function tool_target(name) function tool_target(name, kind)
target(name) target(name)
set_kind("binary") set_kind(kind or "binary")
set_group("Tools") set_group("Tools")
add_rules("engine.tool")
end end
includes("*/xmake.lua") includes("*/xmake.lua")

View File

@ -1,9 +1,5 @@
import("core.project.depend") import("core.project.depend")
local genList = {}
function cmd_compile(genfile, sourcefile, template, macro, define) function cmd_compile(genfile, sourcefile, template, macro, define)
if genList[genfile] then
return
end
import("find_sdk") import("find_sdk")
local meta = find_sdk.find_my_program("refl") local meta = find_sdk.find_my_program("refl")
template = template or path.join(meta.sdkdir, "template") template = template or path.join(meta.sdkdir, "template")
@ -18,7 +14,6 @@ function cmd_compile(genfile, sourcefile, template, macro, define)
table.insert(argv, "-d") table.insert(argv, "-d")
table.insert(argv, define) table.insert(argv, define)
end end
genList[genfile] = true
print("cmd_meta_compile", genfile) print("cmd_meta_compile", genfile)
os.execv(meta.program, argv) os.execv(meta.program, argv)
return argv return argv
@ -26,6 +21,7 @@ end
function _listen_gen_file(target, batch, template, macro, define) function _listen_gen_file(target, batch, template, macro, define)
genfile, sourcefile = batch[1], batch[2] genfile, sourcefile = batch[1], batch[2]
sourcefile = string.lower(sourcefile)
local dependfile = target:dependfile(genfile) local dependfile = target:dependfile(genfile)
depend.on_changed( depend.on_changed(
function() function()
@ -33,7 +29,7 @@ function _listen_gen_file(target, batch, template, macro, define)
end, end,
{dependfile = dependfile, files = sourcefile} {dependfile = dependfile, files = sourcefile}
) )
end end
function gen(target) function gen(target)
if is_mode("release") then return end if is_mode("release") then return end
local gen_batch = target:data("codegen.batch") local gen_batch = target:data("codegen.batch")

View File

@ -1,30 +1,43 @@
import("core.project.depend") import("core.project.depend")
local loadTable = {}
function cmd_compile(target, genfile, file) function cmd_compile(target, genfile, file)
if is_mode("release") then return end local name = target:name()
import("find_sdk") if loadTable[name] then
local plugin = find_sdk.find_my_program("make_plugin") return
if not plugin then return end end
print("cmd_compile plugin", genfile, file) loadTable[name] = true
argv = { os.projectdir() , genfile, target:scriptdir(), file, target:name() .. ".plugin"} import("core.project.project")
os.execv(plugin.program, argv) target:data_set("compile", true)
local pub_deps = target:values("module.public_dependencies")
local cpp_content = "inline void __" .. name .. "__module::InitMetaData(void){\n"
cpp_content = cpp_content.."\tmInfo.name = \"" .. name.."\";\n"
cpp_content = cpp_content.."\tmInfo.dependencies = {\n "
for k,dep in ipairs(pub_deps) do
local deptarget = project.target(dep)
if deptarget then
local kind = deptarget:kind()
local version = deptarget:version() or "0.0"
cpp_content = cpp_content.."\t\t{\"" .. dep .. "\", \""..version.."\", \""..kind.."\" },\n"
end
end
cpp_content = cpp_content.sub(cpp_content, 1, -3)
cpp_content = cpp_content.."\n\t};\n};"
print("cmd_compile plugin ", genfile)
io.writefile(genfile, cpp_content)
end end
function main(target, file) function main(target, file)
local sourcedir = path.join(target:autogendir({root = true}), target:plat()) local sourcedir = path.join(target:autogendir({root = true}), target:plat(), "inl")
if not os.isdir(sourcedir) then if not os.isdir(sourcedir) then
os.mkdir(sourcedir) os.mkdir(sourcedir)
end end
local genfile = path.join(sourcedir,"xmake.lua") target:add("includedirs", sourcedir, {public = true})
local genfile = path.join(sourcedir, target:name() .. ".plugin.inl")
local dependfile = target:dependfile(genfile) local dependfile = target:dependfile(genfile)
local sourcefile = string.lower(path.join(target:scriptdir(), file))
depend.on_changed( depend.on_changed(
function() function()
cmd_compile(target, genfile, file) cmd_compile(target, genfile, file)
end, end,
{dependfile = dependfile, files = {path.join(target:scriptdir(), file)}} {dependfile = dependfile, files = sourcefile}
) )
if os.exists(genfile) then
local dependency = io.load(genfile)
for k,v in ipairs(dependency) do
target:add("deps", v[1], v[2])
end
end
end end

View File

@ -4,4 +4,5 @@ rule("engine.plugin")
import("make_plugin") import("make_plugin")
local file = target:extraconf("rules", "engine.plugin", "file") local file = target:extraconf("rules", "engine.plugin", "file")
make_plugin(target, file or "module.h") make_plugin(target, file or "module.h")
end) end)

View File

@ -6,4 +6,10 @@ rule("engine.tool")
end end
local exefile = target:targetfile() local exefile = target:targetfile()
os.cp(exefile, path.join(tooldir, path.filename(exefile))) os.cp(exefile, path.join(tooldir, path.filename(exefile)))
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})
end) end)

View File

@ -8,8 +8,8 @@
void test(std::string_view str = "") { void test(std::string_view str = "") {
std::cout << "test " << str << std::endl; std::cout << "test " << str << std::endl;
} }
int main() { int main(int argc, char** argv) {
api::ModuleManager::Ptr(); api::ModuleManager::Ptr()->MakeGraph("zworld", true, argc, argv);
test("sss"); test("sss");
using namespace refl; using namespace refl;
constexpr TStr str1{ "Hello" }; constexpr TStr str1{ "Hello" };
@ -36,14 +36,14 @@ int main() {
std::string s1 = name.ToString(); std::string s1 = name.ToString();
std::string s2 = name2.ToString(); std::string s2 = name2.ToString();
if (s1.c_str() == s2.c_str()) { if (s1.c_str() == s2.c_str()) {
new(pool)int(1); new(&pool)int(1);
} }
if (s1 == s2) { if (s1 == s2) {
new(pool)int(1); new(&pool)int(1);
} }
} }
int* a = new(pool)int(1); int* a = new(&pool)int(1);
int* b = new(pool)int(2); int* b = new(&pool)int(2);
int* c = new(pool)int(3); int* c = new(&pool)int(3);
std::cout << "hello engine\n"; std::cout << "hello engine\n";
} }

View File

@ -1,5 +1,9 @@
#include "zworld.h" #include "zworld.h"
void ZWorldModule::OnLoad(int argc, char** argv)
{
void hello() { }
} void ZWorldModule::OnUnload()
{
}

View File

@ -1 +1,11 @@
void hello(); #pragma once
#include "module/module.h"
class ZWORLD_API ZWorldModule : public api::IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
void InitMetaData(void) override;
};
IMPLEMENT_DYNAMIC_MODULE(ZWORLD_API, ZWorldModule, zworld)
#include "zworld.plugin.inl"

View File

@ -1,11 +1,7 @@
game_instance("zworld", "src/zworld.h")
target("zworld") target("zworld")
set_kind("shared")
set_group("Games")
add_deps("engine", "editor", "vulkan", {public = true})
add_files("src/*.cpp") add_files("src/*.cpp")
add_headerfiles("src/*.h") add_headerfiles("src/*.h")
add_dependency("engine", "editor", "vulkan", {public = true})
target("zworld-editor") target("zworld-editor")
set_kind("binary")
set_group("Games")
add_deps("zworld")
add_files("editor/main.cpp") add_files("editor/main.cpp")

View File

@ -0,0 +1,9 @@
#include "src/zworld.h"
void __zworld__module::InitMetaData(void){
mInfo.name = "zworld";
mInfo.dependencies = {
{"engine", "1.0.1", "static" },
{"editor", "1.0.1", "static" },
{"vulkan", "1.0.1", "shared" }
};
};

7
module.plugin.inl Normal file
View File

@ -0,0 +1,7 @@
inline void __vulkan__module::InitMetaData(void){
mInfo.name = "vulkan";
mInfo.dependencies = {
{"core", "1.0.1", "static" },
{"asset", "1.0.1", "static" }
};
};

8
nil.plugin.inl Normal file
View File

@ -0,0 +1,8 @@
inline void __zworld__module::InitMetaData(void){
mInfo.name = "zworld";
mInfo.dependencies = {
{"engine", "1.0.1", "static" },
{"editor", "1.0.1", "static" },
{"vulkan", "1.0.1", "shared" }
};
};

View File

@ -1,4 +1,5 @@
add_rules("mode.debug", "mode.release") add_rules("mode.debug", "mode.release")
set_version("1.0.1", {soname = true})
set_arch("x64") set_arch("x64")
set_languages("cxx20") set_languages("cxx20")
set_project("zengine") set_project("zengine")
@ -7,4 +8,6 @@ set_runtimes("MD","c++_shared")
includes("engine") includes("engine")
includes("game/*/xmake.lua") includes("game/*/xmake.lua")
--xmake project -k vsxmake2022 -a x64 --xmake project -k vsxmake2022 -a x64
--xmake project -k vsxmake2022 -m "debug;release" --xmake project -k vsxmake2022 -m "debug;release"
--xmake build -vD -y -P . "zworld-editor"
--xrepo env -b emmylua_debugger -- xmake project -k vsxmake2022 -m "debug;release"

8
zworld.plugin.inl Normal file
View File

@ -0,0 +1,8 @@
inline void __zworld__module::InitMetaData(void){
mInfo.name = "zworld";
mInfo.dependencies = {
{"engine", "1.0.1", "static" },
{"editor", "1.0.1", "static" },
{"vulkan", "1.0.1", "shared" }
};
};