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); } 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;