From 6fc312b65102b192d55c0c6d54b7f0a5db8e423e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 9 Feb 2024 19:47:22 +0300 Subject: [PATCH] lua content pack environments test --- src/content/Content.cpp | 1 + src/content/ContentLoader.cpp | 11 +++-- src/content/ContentLoader.h | 1 + src/content/ContentPack.cpp | 7 +++- src/content/ContentPack.h | 28 ++++++++++--- src/engine.cpp | 1 + src/frontend/UiDocument.cpp | 2 +- src/logic/scripting/LuaState.cpp | 41 ++++++++++++++++-- src/logic/scripting/LuaState.h | 6 +++ src/logic/scripting/scripting.cpp | 69 ++++++++++++++++++++----------- src/logic/scripting/scripting.h | 8 ++-- 11 files changed, 131 insertions(+), 44 deletions(-) diff --git a/src/content/Content.cpp b/src/content/Content.cpp index dcd14f00..d208af2b 100644 --- a/src/content/Content.cpp +++ b/src/content/Content.cpp @@ -8,6 +8,7 @@ #include "../items/ItemDef.h" #include "ContentPack.h" +#include "../logic/scripting/scripting.h" ContentBuilder::~ContentBuilder() { } diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 0a03b3dd..4f803ec0 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -255,7 +255,7 @@ void ContentLoader::loadBlock(Block& def, std::string full, std::string name) { fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua"); if (fs::is_regular_file(scriptfile)) { - scripting::load_block_script(full, scriptfile, def.rt.funcsset); + scripting::load_block_script(env, full, scriptfile, def.rt.funcsset); } } @@ -267,13 +267,16 @@ void ContentLoader::loadItem(ItemDef& def, std::string full, std::string name) { fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua"); if (fs::is_regular_file(scriptfile)) { - scripting::load_item_script(full, scriptfile, def.rt.funcsset); + scripting::load_item_script(env, full, scriptfile, def.rt.funcsset); } } void ContentLoader::load(ContentBuilder& builder) { std::cout << "-- loading pack [" << pack->id << "]" << std::endl; - builder.add(new ContentPackRuntime(*pack)); + + auto runtime = new ContentPackRuntime(*pack, scripting::create_environment()); + builder.add(runtime); + env = runtime->getEnvironment()->getId(); fixPackIndices(); @@ -281,7 +284,7 @@ void ContentLoader::load(ContentBuilder& builder) { fs::path scriptFile = folder/fs::path("scripts/world.lua"); if (fs::is_regular_file(scriptFile)) { - scripting::load_world_script(pack->id, scriptFile); + scripting::load_world_script(env, pack->id, scriptFile); } if (!fs::is_regular_file(pack->getContentFile())) diff --git a/src/content/ContentLoader.h b/src/content/ContentLoader.h index 2a39f76e..2606e71d 100644 --- a/src/content/ContentLoader.h +++ b/src/content/ContentLoader.h @@ -17,6 +17,7 @@ namespace dynamic { class ContentLoader { const ContentPack* pack; + int env = 0; void loadBlock(Block& def, std::string full, std::string name); void loadCustomBlockModel(Block& def, dynamic::Map* primitives); diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 9f511ae7..ad6587c1 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -7,6 +7,7 @@ #include "../files/files.h" #include "../files/engine_paths.h" #include "../data/dynamic.h" +#include "../logic/scripting/scripting.h" namespace fs = std::filesystem; @@ -150,5 +151,9 @@ void ContentPack::readPacks(const EnginePaths* paths, } } -ContentPackRuntime::ContentPackRuntime(ContentPack info) : info(info) { +ContentPackRuntime::ContentPackRuntime( + ContentPack info, + std::unique_ptr env +) : info(info), env(std::move(env)) +{ } diff --git a/src/content/ContentPack.h b/src/content/ContentPack.h index bf4bd7e8..ac4a5b79 100644 --- a/src/content/ContentPack.h +++ b/src/content/ContentPack.h @@ -10,6 +10,10 @@ class EnginePaths; namespace fs = std::filesystem; +namespace scripting { + class Environment; +} + class contentpack_error : public std::runtime_error { std::string packId; fs::path folder; @@ -52,17 +56,25 @@ struct ContentPack { static fs::path findPack( const EnginePaths* paths, fs::path worldDir, - std::string name); - static void readPacks(const EnginePaths* paths, - std::vector& packs, - const std::vector& names, - fs::path worldDir); + std::string name + ); + + static void readPacks( + const EnginePaths* paths, + std::vector& packs, + const std::vector& names, + fs::path worldDir + ); }; class ContentPackRuntime { ContentPack info; + std::unique_ptr env; public: - ContentPackRuntime(ContentPack info); + ContentPackRuntime( + ContentPack info, + std::unique_ptr env + ); inline const std::string& getId() { return info.id; @@ -71,6 +83,10 @@ public: inline const ContentPack& getInfo() const { return info; } + + inline scripting::Environment* getEnvironment() const { + return env.get(); + } }; #endif // CONTENT_CONTENT_PACK_H_ diff --git a/src/engine.cpp b/src/engine.cpp index 41e5227c..3b1797e5 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -130,6 +130,7 @@ void Engine::mainloop() { Engine::~Engine() { screen = nullptr; + content.reset(); scripting::close(); Audio::finalize(); diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index 3d2f774a..cfb769a8 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -54,7 +54,7 @@ std::unique_ptr UiDocument::read(std::string namesp, fs::path file) uidocscript script {}; auto scriptFile = fs::path(file.u8string()+".lua"); if (fs::is_regular_file(scriptFile)) { - scripting::load_layout_script(env->getId(), scriptFile, script); + scripting::load_layout_script(env->getId(), namesp, scriptFile, script); } return std::make_unique(namesp, script, view, env.release()->getId()); } diff --git a/src/logic/scripting/LuaState.cpp b/src/logic/scripting/LuaState.cpp index 8d3836c0..c098ce70 100644 --- a/src/logic/scripting/LuaState.cpp +++ b/src/logic/scripting/LuaState.cpp @@ -172,6 +172,40 @@ int lua::LuaState::pushstring(const std::string& str) { return 1; } +int lua::LuaState::pushenv(int env) { + if (getglobal(envName(env))) { + return 1; + } + return 0; +} + +int lua::LuaState::pushglobals() { + lua_pushvalue(L, LUA_GLOBALSINDEX); + return 1; +} + +void lua::LuaState::pop(int n) { + lua_pop(L, n); +} + +int lua::LuaState::pushnil() { + lua_pushnil(L); + return 1; +} + +bool lua::LuaState::getfield(const std::string& name) { + lua_getfield(L, -1, name.c_str()); + if (lua_isnil(L, -1)) { + lua_pop(L, -1); + return false; + } + return true; +} + +void lua::LuaState::setfield(const std::string& name, int idx) { + lua_setfield(L, idx, name.c_str()); +} + bool lua::LuaState::toboolean(int index) { return lua_toboolean(L, index); } @@ -195,16 +229,17 @@ const std::string lua::LuaState::storeAnonymous() { int lua::LuaState::createEnvironment() { int id = nextEnvironment++; - // globals table + + // local env = {} lua_createtable(L, 0, 1); - // metatable + // setmetatable(env, {__index=_G}) lua_createtable(L, 0, 1); - lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); + // envname = env setglobal(envName(id)); return id; } diff --git a/src/logic/scripting/LuaState.h b/src/logic/scripting/LuaState.h index 71a231cd..df4e6267 100644 --- a/src/logic/scripting/LuaState.h +++ b/src/logic/scripting/LuaState.h @@ -31,6 +31,12 @@ namespace lua { int pushinteger(luaint x); int pushnumber(luanumber x); int pushstring(const std::string& str); + int pushenv(int env); + int pushnil(); + int pushglobals(); + void pop(int n=1); + bool getfield(const std::string& name); + void setfield(const std::string& name, int idx=-2); bool toboolean(int index); luaint tointeger(int index); int call(int argc); diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index de2056e5..b9e27721 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -205,51 +205,70 @@ bool scripting::on_item_break_block(Player* player, const ItemDef* item, int x, return false; } -void scripting::load_block_script(std::string prefix, fs::path file, block_funcs_set& funcsset) { - std::string src = files::read_string(file); - std::cout << "loading script " << file.u8string() << std::endl; - state->execute(0, src, file.u8string()); +bool register_event(int env, const std::string& name, const std::string& id) { + std::cout << "register " << name << " -> " << id << std::endl; + if (state->pushenv(env) == 0) { + state->pushglobals(); + } + if (state->getfield(name)) { + // remove previous name + state->pushnil(); + state->setfield(name, -3); - funcsset.init=state->rename("init", prefix+".init"); - funcsset.update=state->rename("on_update", prefix+".update"); - funcsset.randupdate=state->rename("on_random_update", prefix+".randupdate"); - funcsset.onbroken=state->rename("on_broken", prefix+".broken"); - funcsset.onplaced=state->rename("on_placed", prefix+".placed"); - funcsset.oninteract=state->rename("on_interact", prefix+".oninteract"); - funcsset.onblockstick=state->rename("on_blocks_tick", prefix+".blockstick"); + std::cout << id << std::endl; + // add new global name + state->setglobal(id); + state->pop(); + return true; + } + return false; } -void scripting::load_item_script(std::string prefix, fs::path file, item_funcs_set& funcsset) { +void scripting::load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset) { std::string src = files::read_string(file); std::cout << "loading script " << file.u8string() << std::endl; - state->execute(0, src, file.u8string()); - funcsset.init=state->rename("init", prefix+".init"); - funcsset.on_use_on_block=state->rename("on_use_on_block", prefix+".useon"); - funcsset.on_block_break_by=state->rename("on_block_break_by", prefix+".blockbreakby"); + state->execute(env, src, file.u8string()); + funcsset.init = register_event(env, "init", prefix+".init"); + funcsset.update = register_event(env, "on_update", prefix+".update"); + funcsset.randupdate = register_event(env, "on_random_update", prefix+".randupdate"); + funcsset.onbroken = register_event(env, "on_broken", prefix+".broken"); + funcsset.onplaced = register_event(env, "on_placed", prefix+".placed"); + funcsset.oninteract = register_event(env, "on_interact", prefix+".interact"); + funcsset.onblockstick = register_event(env, "on_blocks_tick", prefix+".blockstick"); } -void scripting::load_world_script(std::string prefix, fs::path file) { +void scripting::load_item_script(int env, std::string prefix, fs::path file, item_funcs_set& funcsset) { + std::string src = files::read_string(file); + std::cout << "loading script " << file.u8string() << std::endl; + state->execute(env, src, file.u8string()); + + funcsset.init = register_event(env, "init", prefix+".init"); + funcsset.on_use_on_block = register_event(env, "on_use_on_block", prefix+".useon"); + funcsset.on_block_break_by = register_event(env, "on_block_break_by", prefix+".blockbreakby"); +} + +void scripting::load_world_script(int env, std::string prefix, fs::path file) { std::string src = files::read_string(file); std::cout << "loading script " << file.u8string() << std::endl; - state->loadbuffer(0, src, file.u8string()); + state->loadbuffer(env, src, file.u8string()); state->callNoThrow(0); - state->rename("init", prefix+".init"); - state->rename("on_world_open", prefix+".worldopen"); - state->rename("on_world_save", prefix+".worldsave"); - state->rename("on_world_quit", prefix+".worldquit"); + register_event(env, "init", prefix+".init"); + register_event(env, "on_world_open", prefix+".worldopen"); + register_event(env, "on_world_save", prefix+".worldsave"); + register_event(env, "on_world_quit", prefix+".worldquit"); } -void scripting::load_layout_script(int env, fs::path file, uidocscript& script) { +void scripting::load_layout_script(int env, std::string prefix, fs::path file, uidocscript& script) { std::string src = files::read_string(file); std::cout << "loading script " << file.u8string() << std::endl; script.environment = env; state->loadbuffer(env, src, file.u8string()); state->callNoThrow(0); - script.onopen = state->hasglobal("on_open"); - script.onclose = state->hasglobal("on_close"); + script.onopen = register_event(env, "on_open", prefix+".open"); + script.onclose = register_event(env, "on_close", prefix+".close"); } void scripting::close() { diff --git a/src/logic/scripting/scripting.h b/src/logic/scripting/scripting.h index 64bbc452..1606bc30 100644 --- a/src/logic/scripting/scripting.h +++ b/src/logic/scripting/scripting.h @@ -62,9 +62,9 @@ namespace scripting { bool on_block_interact(Player* player, const Block* block, int x, int y, int z); bool on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z); bool on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z); - void load_block_script(std::string prefix, fs::path file, block_funcs_set& funcsset); - void load_item_script(std::string prefix, fs::path file, item_funcs_set& funcsset); - void load_world_script(std::string prefix, fs::path file); - void load_layout_script(int env, fs::path file, uidocscript& script); + void load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset); + void load_item_script(int env, std::string prefix, fs::path file, item_funcs_set& funcsset); + void load_world_script(int env, std::string prefix, fs::path file); + void load_layout_script(int env, std::string prefix, fs::path file, uidocscript& script); void close(); }