diff --git a/doc/en/scripting/builtins/libblock.md b/doc/en/scripting/builtins/libblock.md index cc86b9a6..5bd0536e 100644 --- a/doc/en/scripting/builtins/libblock.md +++ b/doc/en/scripting/builtins/libblock.md @@ -10,6 +10,9 @@ block.index(name: str) -> int -- Returns the id of the block material. block.material(blockid: int) -> str +-- Table of materials by their full names (example: base:carpet) +block.materials: table + -- Returns the block display name. block.caption(blockid: int) -> str diff --git a/doc/ru/scripting/builtins/libblock.md b/doc/ru/scripting/builtins/libblock.md index e7746a37..19a28198 100644 --- a/doc/ru/scripting/builtins/libblock.md +++ b/doc/ru/scripting/builtins/libblock.md @@ -10,6 +10,9 @@ block.index(name: str) -> int -- Возвращает id материала блока. block.material(blockid: int) -> str +-- Таблица материалов по их полным именам (пример: base:carpet) +block.materials: table + -- Возвращает название блока, отображаемое в интерфейсе. block.caption(blockid: int) -> str diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index cb50e4a5..0f8bf6a2 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -483,16 +483,6 @@ void ContentLoader::loadBlock( auto configFile = folder / fs::path("blocks/" + name + ".json"); if (fs::exists(configFile)) loadBlock(def, full, configFile); - auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua"); - if (fs::is_regular_file(scriptfile)) { - scripting::load_block_script( - env, - full, - scriptfile, - pack->id + ":scripts/" + def.scriptName + ".lua", - def.rt.funcsset - ); - } if (!def.hidden) { auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX); item.generated = true; @@ -514,17 +504,6 @@ void ContentLoader::loadItem( auto folder = pack->folder; auto configFile = folder / fs::path("items/" + name + ".json"); if (fs::exists(configFile)) loadItem(def, full, configFile); - - auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua"); - if (fs::is_regular_file(scriptfile)) { - scripting::load_item_script( - env, - full, - scriptfile, - pack->id + ":scripts/" + def.scriptName + ".lua", - def.rt.funcsset - ); - } } static std::tuple create_unit_id( @@ -728,18 +707,6 @@ void ContentLoader::load() { auto folder = pack->folder; - // Load main world script - fs::path scriptFile = folder / fs::path("scripts/world.lua"); - if (fs::is_regular_file(scriptFile)) { - scripting::load_world_script( - env, - pack->id, - scriptFile, - pack->id + ":scripts/world.lua", - runtime->worldfuncsset - ); - } - // Load world generators fs::path generatorsDir = folder / fs::u8path("generators"); foreach_file(generatorsDir, [this](const fs::path& file) { @@ -807,17 +774,6 @@ void ContentLoader::load() { ); }); - // Load entity components - fs::path componentsDir = folder / fs::u8path("scripts/components"); - foreach_file(componentsDir, [this](const fs::path& file) { - auto name = pack->id + ":" + file.stem().u8string(); - scripting::load_entity_component( - name, - file, - pack->id + ":scripts/components/" + file.filename().u8string() - ); - }); - // Process content.json and load defined content units auto contentFile = pack->getContentFile(); if (fs::exists(contentFile)) { @@ -825,6 +781,61 @@ void ContentLoader::load() { } } +template +static void load_scripts(Content& content, ContentUnitDefs& units) { + for (const auto& [name, def] : units.getDefs()) { + size_t pos = name.find(':'); + if (pos == std::string::npos) { + throw std::runtime_error("invalid content unit name"); + } + const auto runtime = content.getPackRuntime(name.substr(0, pos)); + const auto& pack = runtime->getInfo(); + const auto& folder = pack.folder; + auto scriptfile = folder / fs::path("scripts/" + def->scriptName + ".lua"); + if (fs::is_regular_file(scriptfile)) { + scripting::load_content_script( + runtime->getEnvironment(), + name, + scriptfile, + pack.id + ":scripts/" + def->scriptName + ".lua", + def->rt.funcsset + ); + } + } +} + +void ContentLoader::loadScripts(Content& content) { + load_scripts(content, content.blocks); + load_scripts(content, content.items); + + for (const auto& [packid, runtime] : content.getPacks()) { + const auto& pack = runtime->getInfo(); + const auto& folder = pack.folder; + + // Load main world script + fs::path scriptFile = folder / fs::path("scripts/world.lua"); + if (fs::is_regular_file(scriptFile)) { + scripting::load_world_script( + runtime->getEnvironment(), + pack.id, + scriptFile, + pack.id + ":scripts/world.lua", + runtime->worldfuncsset + ); + } + // Load entity components + fs::path componentsDir = folder / fs::u8path("scripts/components"); + foreach_file(componentsDir, [&pack](const fs::path& file) { + auto name = pack.id + ":" + file.stem().u8string(); + scripting::load_entity_component( + name, + file, + pack.id + ":scripts/components/" + file.filename().u8string() + ); + }); + } +} + void ContentLoader::loadResources(ResourceType type, const dv::value& list) { for (size_t i = 0; i < list.size(); i++) { builder.resourceIndices[static_cast(type)].add( diff --git a/src/content/ContentLoader.hpp b/src/content/ContentLoader.hpp index 22cb33ef..d99aa622 100644 --- a/src/content/ContentLoader.hpp +++ b/src/content/ContentLoader.hpp @@ -17,6 +17,7 @@ struct ContentPack; struct GeneratorDef; class ResPaths; +class Content; class ContentBuilder; class ContentPackRuntime; struct ContentPackStats; @@ -76,4 +77,6 @@ public: void fixPackIndices(); void load(); + + static void loadScripts(Content& content); }; diff --git a/src/engine.cpp b/src/engine.cpp index 85a9e42b..f08175a1 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -361,8 +361,10 @@ void Engine::loadContent() { ContentLoader(&pack, contentBuilder, *resPaths).load(); load_configs(pack.folder); } - content = contentBuilder.build(); + scripting::on_content_load(content.get()); + + ContentLoader::loadScripts(*content); langs::setup(resdir, langs::current->getId(), contentPacks); loadAssets(); diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index f0082a3c..0778fd45 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -157,10 +157,25 @@ void scripting::process_post_runnables() { } } +void scripting::on_content_load(Content* content) { + scripting::content = content; + scripting::indices = content->getIndices(); + + auto L = lua::get_main_state(); + if (lua::getglobal(L, "block")) { + const auto& materials = content->getBlockMaterials(); + lua::createtable(L, 0, materials.size()); + for (const auto& [name, material] : materials) { + lua::pushvalue(L, material->serialize()); + lua::setfield(L, name); + } + lua::setfield(L, "materials"); + lua::pop(L); + } +} + void scripting::on_world_load(LevelController* controller) { scripting::level = controller->getLevel(); - scripting::content = level->content; - scripting::indices = level->content->getIndices(); scripting::blocks = controller->getBlocksController(); scripting::controller = controller; @@ -671,7 +686,7 @@ int scripting::get_values_on_stack() { return lua::gettop(lua::get_main_state()); } -void scripting::load_block_script( +void scripting::load_content_script( const scriptenv& senv, const std::string& prefix, const fs::path& file, @@ -692,7 +707,7 @@ void scripting::load_block_script( register_event(env, "on_blocks_tick", prefix + ".blockstick"); } -void scripting::load_item_script( +void scripting::load_content_script( const scriptenv& senv, const std::string& prefix, const fs::path& file, diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index ca0ea433..3cd8a022 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -45,6 +45,8 @@ namespace scripting { void initialize(Engine* engine); + void on_content_load(Content* content); + bool register_event( int env, const std::string& name, const std::string& id ); @@ -128,7 +130,7 @@ namespace scripting { /// @param file item script file /// @param fileName script file path using the engine format /// @param funcsset block callbacks set - void load_block_script( + void load_content_script( const scriptenv& env, const std::string& prefix, const fs::path& file, @@ -142,7 +144,7 @@ namespace scripting { /// @param file item script file /// @param fileName script file path using the engine format /// @param funcsset item callbacks set - void load_item_script( + void load_content_script( const scriptenv& env, const std::string& prefix, const fs::path& file, diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp index 6d4ff761..520f9f99 100644 --- a/src/voxels/Block.cpp +++ b/src/voxels/Block.cpp @@ -8,6 +8,15 @@ #include "presets/ParticlesPreset.hpp" #include "util/stringutil.hpp" +dv::value BlockMaterial::serialize() const { + return dv::object({ + {"name", name}, + {"stepsSound", stepsSound}, + {"placeSound", placeSound}, + {"breakSound", breakSound} + }); +} + std::string to_string(BlockModel model) { switch (model) { case BlockModel::none: diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 84835534..4fe51b0d 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -104,6 +104,8 @@ struct BlockMaterial { std::string stepsSound {""}; std::string placeSound {""}; std::string breakSound {""}; + + dv::value serialize() const; }; /// @brief Block properties definition