From fcb420c4c707f14e702d0ee4f9d466e9190931c3 Mon Sep 17 00:00:00 2001 From: InfiniteCoder Date: Thu, 7 Mar 2024 22:30:21 +0300 Subject: [PATCH 1/2] Event queue --- res/scripts/stdlib.lua | 20 +++ src/logic/scripting/lua/LuaState.cpp | 30 ++++- src/logic/scripting/lua/LuaState.h | 6 +- src/logic/scripting/lua/libblock.cpp | 2 + src/logic/scripting/scripting.cpp | 137 ++++++++++----------- src/logic/scripting/scripting.h | 4 + src/logic/scripting/scripting_frontend.cpp | 12 +- 7 files changed, 131 insertions(+), 80 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 4968b675..50218698 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -120,6 +120,26 @@ function color_mt.__tostring(self) return "rgba("..self[1]..", "..self[2]..", "..self[3]..", "..self[4]..")" end +-- events +events = { + handlers = {} +} + +function events.on(event, func) + events.handlers[event] = events.handlers[event] or {} + table.insert(events.handlers[event], func) +end + +function events.emit(event, ...) + result = nil + if events.handlers[event] then + for _, func in ipairs(events.handlers[event]) do + result = result or func(...) + end + end + return result +end + -- class designed for simple UI-nodes access via properties syntax local Element = {} function Element.new(docname, name) diff --git a/src/logic/scripting/lua/LuaState.cpp b/src/logic/scripting/lua/LuaState.cpp index e7988dd5..e472831d 100644 --- a/src/logic/scripting/lua/LuaState.cpp +++ b/src/logic/scripting/lua/LuaState.cpp @@ -1,5 +1,6 @@ #include "LuaState.h" +#include #include #include "lua_util.h" #include "api_lua.h" @@ -217,8 +218,8 @@ int lua::LuaState::pushnil() { return 1; } -bool lua::LuaState::getfield(const std::string& name) { - lua_getfield(L, -1, name.c_str()); +bool lua::LuaState::getfield(const std::string& name, int idx) { + lua_getfield(L, idx, name.c_str()); if (lua_isnil(L, -1)) { lua_pop(L, -1); return false; @@ -287,3 +288,28 @@ void lua::LuaState::removeEnvironment(int id) { lua_pushnil(L); setglobal(envName(id)); } + +void lua::LuaState::dumpStack() { + int top = gettop(); + for (int i = 1; i <= top; i++) { + std::cout << std::setw(3) << i << std::setw(20) << luaL_typename(L, i) << std::setw(30); + switch (lua_type(L, i)) { + case LUA_TNUMBER: + std::cout << tonumber(i); + break; + case LUA_TSTRING: + std::cout << tostring(i); + break; + case LUA_TBOOLEAN: + std::cout << (toboolean(i) ? "true" : "false"); + break; + case LUA_TNIL: + std::cout << "nil"; + break; + default: + std::cout << lua_topointer(L, i); + break; + } + std::cout << std::endl; + } +} diff --git a/src/logic/scripting/lua/LuaState.h b/src/logic/scripting/lua/LuaState.h index 319ee280..d9a7e49d 100644 --- a/src/logic/scripting/lua/LuaState.h +++ b/src/logic/scripting/lua/LuaState.h @@ -41,8 +41,8 @@ namespace lua { 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 getfield(const std::string& name, int idx = -1); + void setfield(const std::string& name, int idx = -2); bool toboolean(int idx); luaint tointeger(int idx); luanumber tonumber(int idx); @@ -61,6 +61,8 @@ namespace lua { int createEnvironment(int parent); void removeEnvironment(int id); const std::string storeAnonymous(); + + void dumpStack(); }; } diff --git a/src/logic/scripting/lua/libblock.cpp b/src/logic/scripting/lua/libblock.cpp index 56b3d963..2f0c18a8 100644 --- a/src/logic/scripting/lua/libblock.cpp +++ b/src/logic/scripting/lua/libblock.cpp @@ -228,6 +228,8 @@ const luaL_Reg blocklib [] = { {"get_Z", lua_wrap_errors}, {"get_states", lua_wrap_errors}, {"set_states", lua_wrap_errors}, + {"get_rotation", lua_wrap_errors}, + {"set_rotation", lua_wrap_errors}, {"get_user_bits", lua_wrap_errors}, {"set_user_bits", lua_wrap_errors}, {NULL, NULL} diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index d5bc3e6c..350e2949 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -105,25 +105,19 @@ void scripting::on_world_load(Level* level, BlocksController* blocks) { load_script("world.lua"); for (auto& pack : scripting::engine->getContentPacks()) { - if (state->getglobal(pack.id+".worldopen")) { - state->callNoThrow(0); - } + emit_event(pack.id + ".worldopen"); } } void scripting::on_world_save() { for (auto& pack : scripting::engine->getContentPacks()) { - if (state->getglobal(pack.id+".worldsave")) { - state->callNoThrow(0); - } + emit_event(pack.id + ".worldsave"); } } void scripting::on_world_quit() { for (auto& pack : scripting::engine->getContentPacks()) { - if (state->getglobal(pack.id+".worldquit")) { - state->callNoThrow(0); - } + emit_event(pack.id + ".worldquit"); } if (state->getglobal("__scripts_cleanup")) { state->callNoThrow(0); @@ -134,109 +128,97 @@ void scripting::on_world_quit() { } void scripting::on_blocks_tick(const Block* block, int tps) { - std::string name = block->name+".blockstick"; - if (state->getglobal(name)) { + std::string name = block->name + ".blockstick"; + emit_event(name, [tps] (lua::LuaState* state) { state->pushinteger(tps); - state->callNoThrow(1); - } + return 1; + }); } void scripting::update_block(const Block* block, int x, int y, int z) { - std::string name = block->name+".update"; - if (state->getglobal(name)) { + std::string name = block->name + ".update"; + emit_event(name, [x, y, z] (lua::LuaState* state) { state->pushivec3(x, y, z); - state->callNoThrow(3); - } + return 3; + }); } void scripting::random_update_block(const Block* block, int x, int y, int z) { - std::string name = block->name+".randupdate"; - if (state->getglobal(name)) { + std::string name = block->name + ".randupdate"; + emit_event(name, [x, y, z] (lua::LuaState* state) { state->pushivec3(x, y, z); - state->callNoThrow(3); - } + return 3; + }); } void scripting::on_block_placed(Player* player, const Block* block, int x, int y, int z) { - std::string name = block->name+".placed"; - if (state->getglobal(name)) { + std::string name = block->name + ".placed"; + emit_event(name, [x, y, z, player] (lua::LuaState* state) { state->pushivec3(x, y, z); state->pushinteger(player->getId()); - state->callNoThrow(4); - } + return 4; + }); } void scripting::on_block_broken(Player* player, const Block* block, int x, int y, int z) { - std::string name = block->name+".broken"; - if (state->getglobal(name)) { + std::string name = block->name + ".broken"; + emit_event(name, [x, y, z, player] (lua::LuaState* state) { state->pushivec3(x, y, z); state->pushinteger(player->getId()); - state->callNoThrow(4); - } + return 4; + }); } bool scripting::on_block_interact(Player* player, const Block* block, int x, int y, int z) { - std::string name = block->name+".interact"; - if (state->getglobal(name)) { + std::string name = block->name + ".interact"; + return emit_event(name, [x, y, z, player] (lua::LuaState* state) { state->pushivec3(x, y, z); state->pushinteger(player->getId()); - if (state->callNoThrow(4)) { - return state->toboolean(-1); - } - } - return false; + return 4; + }); } bool scripting::on_item_use(Player* player, const ItemDef* item) { - std::string name = item->name+".use"; - if (state->getglobal(name)) { + std::string name = item->name + ".use"; + return emit_event(name, [player] (lua::LuaState* state) { state->pushinteger(player->getId()); - if (state->callNoThrow(1)) { - return state->toboolean(-1); - } - } - return false; + return 1; + }); } bool scripting::on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z) { - std::string name = item->name+".useon"; - if (state->getglobal(name)) { + std::string name = item->name + ".useon"; + return emit_event(name, [x, y, z, player] (lua::LuaState* state) { state->pushivec3(x, y, z); state->pushinteger(player->getId()); - if (state->callNoThrow(4)) { - return state->toboolean(-1); - } - } - return false; + return 4; + }); } bool scripting::on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z) { - std::string name = item->name+".blockbreakby"; - if (state->getglobal(name)) { + std::string name = item->name + ".blockbreakby"; + return emit_event(name, [x, y, z, player] (lua::LuaState* state) { state->pushivec3(x, y, z); state->pushinteger(player->getId()); - if (state->callNoThrow(4)) { - return state->toboolean(-1); - } - } - return false; + return 4; + }); } void scripting::on_ui_open(UiDocument* layout, Inventory* inventory, glm::ivec3 blockcoord) { - std::string name = layout->getId()+".open"; - if (state->getglobal(name)) { + std::string name = layout->getId() + ".open"; + emit_event(name, [inventory, blockcoord] (lua::LuaState* state) { state->pushinteger(inventory == nullptr ? 0 : inventory->getId()); state->pushivec3(blockcoord.x, blockcoord.y, blockcoord.z); - state->callNoThrow(4); - } + return 4; + }); } void scripting::on_ui_close(UiDocument* layout, Inventory* inventory) { - std::string name = layout->getId()+".close"; - if (state->getglobal(name)) { - state->pushinteger(inventory->getId()); - state->callNoThrow(1); - } + std::string name = layout->getId() + ".close"; + emit_event(name, [inventory] (lua::LuaState* state) { + state->pushinteger(inventory == nullptr ? 0 : inventory->getId()); + return 1; + }); } bool scripting::register_event(int env, const std::string& name, const std::string& id) { @@ -244,17 +226,32 @@ bool scripting::register_event(int env, const std::string& name, const std::stri state->pushglobals(); } if (state->getfield(name)) { + state->pop(); + state->getglobal("events"); + state->getfield("on"); + state->pushstring(id); + state->getfield(name, -4); + state->callNoThrow(2); + state->pop(); + // remove previous name state->pushnil(); - state->setfield(name, -3); - // add new global name - state->setglobal(id); - state->pop(); + state->setfield(name); return true; } return false; } +bool scripting::emit_event(const std::string &name, std::function args) { + state->getglobal("events"); + state->getfield("emit"); + state->pushstring(name); + state->callNoThrow(args(state) + 1); + bool result = state->toboolean(-1); + state->pop(2); + return result; +} + 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; diff --git a/src/logic/scripting/scripting.h b/src/logic/scripting/scripting.h index b4d8c312..5dbc8878 100644 --- a/src/logic/scripting/scripting.h +++ b/src/logic/scripting/scripting.h @@ -4,6 +4,7 @@ #include "../../delegates.h" +#include "lua/LuaState.h" #include "scripting_functional.h" namespace fs = std::filesystem; @@ -44,6 +45,9 @@ namespace scripting { extern bool register_event(int env, const std::string& name, const std::string& id); + static int noargs(lua::LuaState *) { return 0; } + extern bool emit_event(const std::string& name, std::function args = noargs); + std::unique_ptr create_environment(int parent=0); std::unique_ptr create_pack_environment(const ContentPack& pack); std::unique_ptr create_doc_environment(int parent, const std::string& name); diff --git a/src/logic/scripting/scripting_frontend.cpp b/src/logic/scripting/scripting_frontend.cpp index 25828b70..65ee9ff9 100644 --- a/src/logic/scripting/scripting_frontend.cpp +++ b/src/logic/scripting/scripting_frontend.cpp @@ -22,20 +22,20 @@ void scripting::on_frontend_init(Hud* hud) { scripting::state->openlib("hud", hudlib, 0); for (auto& pack : scripting::engine->getContentPacks()) { - if (state->getglobal(pack.id+".hudopen")) { + emit_event(pack.id + ".hudopen", [&] (lua::LuaState* state) { state->pushinteger(hud->getPlayer()->getId()); - state->callNoThrow(1); - } + return 1; + }); } } void scripting::on_frontend_close() { scripting::hud = nullptr; for (auto& pack : scripting::engine->getContentPacks()) { - if (state->getglobal(pack.id+".hudclose")) { + emit_event(pack.id + ".hudclose", [&] (lua::LuaState* state) { state->pushinteger(hud->getPlayer()->getId()); - state->callNoThrow(1); - } + return 1; + }); } } From 8b949c4c9a4eeae87a66ccfe2f04868260fbd96f Mon Sep 17 00:00:00 2001 From: InfiniteCoder Date: Fri, 8 Mar 2024 00:08:01 +0300 Subject: [PATCH 2/2] Overrides! --- src/content/Content.cpp | 12 ++++----- src/content/ContentLoader.cpp | 30 ++++++++++++++++++---- src/logic/scripting/scripting_frontend.cpp | 2 +- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/content/Content.cpp b/src/content/Content.cpp index 99db7f5c..4a847433 100644 --- a/src/content/Content.cpp +++ b/src/content/Content.cpp @@ -32,8 +32,8 @@ void ContentBuilder::add(ContentPackRuntime* pack) { Block& ContentBuilder::createBlock(std::string id) { auto found = blockDefs.find(id); if (found != blockDefs.end()) { - //return found->second; - throw namereuse_error("name "+id+" is already used", contenttype::item); + return *found->second; + // throw namereuse_error("name "+id+" is already used", contenttype::item); } Block* block = new Block(id); add(block); @@ -43,10 +43,10 @@ Block& ContentBuilder::createBlock(std::string id) { ItemDef& ContentBuilder::createItem(std::string id) { auto found = itemDefs.find(id); if (found != itemDefs.end()) { - if (found->second->generated) { - return *found->second; - } - throw namereuse_error("name "+id+" is already used", contenttype::item); + // if (found->second->generated) { + return *found->second; + // } + // throw namereuse_error("name "+id+" is already used", contenttype::item); } ItemDef* item = new ItemDef(id); add(item); diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 7efced5e..951e522c 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -36,6 +36,19 @@ bool ContentLoader::fixPackIndices(fs::path folder, if (name[0] == '_') continue; detected.push_back(name); + } else if (fs::is_directory(file)) { + std::string space = file.stem().string(); + if (space[0] == '_') + continue; + for (auto entry : fs::directory_iterator(file)) { + fs::path file = entry.path(); + if (fs::is_regular_file(file) && file.extension() == ".json") { + std::string name = file.stem().string(); + if (name[0] == '_') + continue; + detected.push_back(space + ':' + name); + } + } } } } @@ -268,7 +281,7 @@ void ContentLoader::loadBlock(Block& def, std::string full, std::string name) { auto folder = pack->folder; fs::path configFile = folder/fs::path("blocks/"+name+".json"); - loadBlock(def, full, configFile); + if (fs::exists(configFile)) loadBlock(def, full, configFile); fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua"); if (fs::is_regular_file(scriptfile)) { @@ -280,7 +293,7 @@ void ContentLoader::loadItem(ItemDef& def, std::string full, std::string name) { auto folder = pack->folder; fs::path configFile = folder/fs::path("items/"+name+".json"); - loadItem(def, full, configFile); + if (fs::exists(configFile)) loadItem(def, full, configFile); fs::path scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua"); if (fs::is_regular_file(scriptfile)) { @@ -313,8 +326,11 @@ void ContentLoader::load(ContentBuilder& builder) { if (blocksarr) { for (uint i = 0; i < blocksarr->size(); i++) { std::string name = blocksarr->str(i); - std::string full = pack->id+":"+name; + auto colon = name.find(':'); + std::string full = colon == std::string::npos ? pack->id + ":" + name : name; + if (colon != std::string::npos) name[colon] = '/'; auto& def = builder.createBlock(full); + if (colon != std::string::npos) def.scriptName = name.substr(0, colon) + '/' + def.scriptName; loadBlock(def, full, name); stats.totalBlocks++; if (!def.hidden) { @@ -336,8 +352,12 @@ void ContentLoader::load(ContentBuilder& builder) { if (itemsarr) { for (uint i = 0; i < itemsarr->size(); i++) { std::string name = itemsarr->str(i); - std::string full = pack->id+":"+name; - loadItem(builder.createItem(full), full, name); + auto colon = name.find(':'); + std::string full = colon == std::string::npos ? pack->id + ":" + name : name; + if (colon != std::string::npos) name[colon] = '/'; + auto& def = builder.createItem(full); + if (colon != std::string::npos) def.scriptName = name.substr(0, colon) + '/' + def.scriptName; + loadItem(def, full, name); stats.totalItems++; } } diff --git a/src/logic/scripting/scripting_frontend.cpp b/src/logic/scripting/scripting_frontend.cpp index 65ee9ff9..c36ea409 100644 --- a/src/logic/scripting/scripting_frontend.cpp +++ b/src/logic/scripting/scripting_frontend.cpp @@ -30,13 +30,13 @@ void scripting::on_frontend_init(Hud* hud) { } void scripting::on_frontend_close() { - scripting::hud = nullptr; for (auto& pack : scripting::engine->getContentPacks()) { emit_event(pack.id + ".hudclose", [&] (lua::LuaState* state) { state->pushinteger(hud->getPlayer()->getId()); return 1; }); } + scripting::hud = nullptr; } void scripting::load_hud_script(int env, std::string packid, fs::path file) {