From 28385f236c3e3d2ccf020b116f08a8f6d33ec1a3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 26 Jul 2026 15:27:38 +0300 Subject: [PATCH 1/2] fix user component initialization exception handling & fix fatal error on uninitialized component access --- src/logic/scripting/scripting_entities.cpp | 10 +++++++++- src/objects/Entity.cpp | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/logic/scripting/scripting_entities.cpp b/src/logic/scripting/scripting_entities.cpp index ca9ed6db1..2de177562 100644 --- a/src/logic/scripting/scripting_entities.cpp +++ b/src/logic/scripting/scripting_entities.cpp @@ -148,7 +148,12 @@ void scripting::on_entity_spawn( lua::call(L, 1); } for (auto& component : components) { - create_component(L, -1, *component, args, saved); + try { + create_component(L, -1, *component, args, saved); + } catch (const std::runtime_error& err) { + logger.error() << "could not to initialize user component " + << component->name << ": " << err.what(); + } } for (auto& [packid, pack] : content->getPacks()) { @@ -166,6 +171,9 @@ static void process_entity_callback( const std::string& name, std::function args ) { + if (env == nullptr) { + return; + } auto L = lua::get_main_state(); lua::pushenv(L, *env); if (lua::hasfield(L, "__disabled")) { diff --git a/src/objects/Entity.cpp b/src/objects/Entity.cpp index 6629d2981..46664e24e 100644 --- a/src/objects/Entity.cpp +++ b/src/objects/Entity.cpp @@ -71,6 +71,9 @@ dv::value Entity::serialize() const { if (!scripts.components.empty()) { auto& compsMap = root.object("comps"); for (auto& comp : scripts.components) { + if (comp->env == nullptr) { + continue; + } auto data = scripting::get_component_value(comp->env, SAVED_DATA_VARNAME); compsMap[comp->name] = data; From ea0d23831f06d8050b3efed951d12adbb98918e0 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 26 Jul 2026 15:57:41 +0300 Subject: [PATCH 2/2] add required components check --- src/content/Content.hpp | 1 + src/content/ContentLoader.cpp | 15 ++++++++++++++- src/logic/scripting/scripting.cpp | 3 ++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/content/Content.hpp b/src/content/Content.hpp index dd0e30bf8..27596c4ac 100644 --- a/src/content/Content.hpp +++ b/src/content/Content.hpp @@ -188,6 +188,7 @@ public: ContentUnitDefs generators; std::unique_ptr const drawGroups; ResourceIndicesSet resourceIndices {}; + std::set components {}; Content( std::unique_ptr indices, diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 14da690a2..3c45c4438 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -506,6 +506,7 @@ void ContentLoader::loadScripts(Content& content) { scripting::on_scripts_loading(); load_scripts(content, content.blocks); load_scripts(content, content.items); + auto& tmpContent = content; for (const auto& [packid, runtime] : content.getPacks()) { auto env = runtime->getEnvironment(); @@ -516,7 +517,7 @@ void ContentLoader::loadScripts(Content& content) { // Load entity components io::path componentsDir = folder / "scripts/components"; - foreach_file(componentsDir, [&pack, env](const io::path& file) { + foreach_file(componentsDir, [&pack, env, &tmpContent](const io::path& file) { auto name = pack.id + ":" + file.stem(); scripting::load_entity_component( env, @@ -524,9 +525,21 @@ void ContentLoader::loadScripts(Content& content) { file, pack.id + ":scripts/components/" + file.name() ); + tmpContent.components.insert(name); }); } + for (const auto& [eid, def] : content.entities.getDefs()) { + for (const auto& instance : def->components) { + if (content.components.find(instance.component) == content.components.end()) { + throw std::runtime_error( + "component " + instance.component + + " is not available (required by entity " + eid + ")" + ); + } + } + } + scripting::on_content_loaded(); } diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 6954ee6b8..8c039fa32 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -744,9 +744,10 @@ void scripting::load_entity_component( const io::path& file, const std::string& fileName ) { + logger.info() << "script (component) " << file.string(); + auto L = lua::get_main_state(); std::string src = io::read_string(file); - logger.info() << "script (component) " << file.string(); lua::loadbuffer(L, *env, src, fileName); lua::store_in_registry(L, lua::CHUNKS_TABLE, name); }