From 75db2f5e90ab83e3c51c778f7d72e7be852922d4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 24 Apr 2026 10:11:04 +0900 Subject: [PATCH 1/7] Make editor script library manager optional --- editor/Editor.cpp | 51 +------- editor/Editor.hpp | 23 +--- editor/UI/EntityInspectorPanel.cpp | 19 +-- editor/UI/EntityInspectorPanel.hpp | 11 +- include/Game-Engine/Game.hpp | 11 +- include/Game-Engine/ScriptLibraryManager.hpp | 53 ++++++++ src/Game.cpp | 22 ++-- src/ScriptLibraryManager.cpp | 131 +++++++++++++++++++ tests/Script_testCases.cpp | 23 ++++ 9 files changed, 243 insertions(+), 101 deletions(-) create mode 100644 include/Game-Engine/ScriptLibraryManager.hpp create mode 100644 src/ScriptLibraryManager.cpp diff --git a/editor/Editor.cpp b/editor/Editor.cpp index 2a58a78..67514c0 100644 --- a/editor/Editor.cpp +++ b/editor/Editor.cpp @@ -160,60 +160,21 @@ void Editor::reloadScriptLib() [](const auto& e) -> bool { return e.template get<0>().instance == nullptr; } )); - m_listScriptNames = {}; - m_listScriptParameters = {}; - m_makeScriptInstance = {}; - if (m_project.scriptLib().empty()) - m_scriptLibHandle.reset(); - else - m_scriptLibHandle.reset(dlLoad(m_project.scriptLib().string().c_str())); - - if (m_scriptLibHandle == nullptr) - throw std::runtime_error(std::format("unable to load shared lib : {}", m_project.scriptLib().string())); - - void* listScriptNamesSym = getSym(m_scriptLibHandle.get(), "listScriptNames"); - void* listScriptParametersSym = getSym(m_scriptLibHandle.get(), "listScriptParameters"); - void* makeScriptInstanceSym = getSym(m_scriptLibHandle.get(), "makeScriptInstance"); - - if (listScriptNamesSym == nullptr || listScriptParametersSym == nullptr || makeScriptInstanceSym == nullptr) { - m_scriptLibHandle.reset(); - throw std::runtime_error(std::format("unable to get symbols in lib : {}", m_project.scriptLib().string())); + m_scriptLibrary.reset(); + return; } - m_listScriptNames = [listScriptNamesSym]() -> std::vector { - const char** names = nullptr; - unsigned long count = 0; - reinterpret_cast(listScriptNamesSym)(&names, &count); - std::vector output; - for (unsigned long i = 0; i < count; i++) - if (names[i] != nullptr) - output.emplace_back(names[i]); - return output; - }; - - m_listScriptParameters = [listScriptParametersSym](const std::string& name) -> std::vector { - const GE::ScriptParameterDescriptor* parameters = nullptr; - unsigned long count = 0; - reinterpret_cast(listScriptParametersSym)(name.c_str(), ¶meters, &count); - std::vector output; - output.reserve(count); - for (unsigned long i = 0; i < count; i++) - output.emplace_back(parameters[i]); - return output; - }; - - m_makeScriptInstance = [makeScriptInstanceSym](const std::string& name) -> std::shared_ptr { - return std::shared_ptr(reinterpret_cast(makeScriptInstanceSym)(name.c_str())); - }; + m_scriptLibrary.emplace(); + m_scriptLibrary->load(m_project.scriptLib()); } void Editor::startGame() { assert(m_game.has_value() == false); saveEditedScene(); - m_game.emplace(&assetManager(), m_makeScriptInstance, m_listScriptParameters, m_project.makeGameDescriptor()); + m_game.emplace(&assetManager(), m_scriptLibrary.has_value() ? &*m_scriptLibrary : nullptr, m_project.makeGameDescriptor()); setPrimaryInputContext(m_game->inputContext()); } @@ -300,7 +261,7 @@ void Editor::renderImgui() SceneGraphPanel(&m_editedScene.second, &m_selectedEntity) .render(); - EntityInspectorPanel(m_selectedEntity, m_listScriptNames, m_listScriptParameters) + EntityInspectorPanel(m_selectedEntity, m_scriptLibrary.has_value() ? &*m_scriptLibrary : nullptr) .render(); ContentBrowserPanel("Scenes", "scene_dnd", sizeof(GE::Scene::Descriptor)) diff --git a/editor/Editor.hpp b/editor/Editor.hpp index 1f2893f..0ef9e89 100644 --- a/editor/Editor.hpp +++ b/editor/Editor.hpp @@ -18,22 +18,16 @@ #include #include #include -#include +#include #include -#include - #include #include #include -#include #include #include -#include #include -#include -#include namespace GE_Editor { @@ -53,16 +47,6 @@ class Editor : public GE::Application ~Editor() override = default; private: - struct DlHandleDeleter - { - void operator()(DlHandle handle) const - { - if (handle != nullptr) - dlFree(handle); - } - }; - using UniqueDlHandle = std::unique_ptr, DlHandleDeleter>; - void loadProject(const std::filesystem::path&); void saveEditedScene(); void saveProject(); @@ -76,10 +60,7 @@ class Editor : public GE::Application void rebuildFrameGraph(); void renderImgui(); - UniqueDlHandle m_scriptLibHandle; // need to be before m_edited scene so it is destroyed after - std::function()> m_listScriptNames; - std::function(const std::string&)> m_listScriptParameters; - std::function(const std::string&)> m_makeScriptInstance; + std::optional m_scriptLibrary; std::filesystem::path m_projectFilePath; Project m_project; diff --git a/editor/UI/EntityInspectorPanel.cpp b/editor/UI/EntityInspectorPanel.cpp index 31bd5ad..0f33314 100644 --- a/editor/UI/EntityInspectorPanel.cpp +++ b/editor/UI/EntityInspectorPanel.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include @@ -92,20 +92,23 @@ template<> void EntityInspectorPanel::componentEditWidget() { GE::ScriptComponent& scriptComponent = m_entity.get(); + if (m_scriptLibrary == nullptr) + { + ImGui::TextDisabled("No script library loaded"); + return; + } const char* previewValue = scriptComponent.name.empty() ? "none" : scriptComponent.name.c_str(); if (ImGui::BeginCombo("Script##ScriptComponent_name", previewValue)) { - assert(m_listScriptNames); - for (const std::string& scriptName : m_listScriptNames()) + for (const std::string& scriptName : m_scriptLibrary->listScriptNames()) { const bool isSelected = scriptComponent.name == scriptName; if (ImGui::Selectable(scriptName.c_str(), isSelected)) { scriptComponent.name = scriptName; scriptComponent.parameters.clear(); - assert(m_listScriptParameters); - for (const GE::ScriptParameterDescriptor& parameter : m_listScriptParameters(scriptName)) + for (const GE::ScriptParameterDescriptor& parameter : m_scriptLibrary->listScriptParameters(scriptName)) { auto [parameterIt, inserted] = scriptComponent.parameters.try_emplace(parameter.name, parameter.defaultValue); assert(inserted); @@ -150,12 +153,10 @@ void EntityInspectorPanel::componentEditWidget() EntityInspectorPanel::EntityInspectorPanel( const GE::Entity& entity, - std::function()> listScriptNames, - std::function(const std::string&)> listScriptParameters + const GE::ScriptLibraryManager* scriptLibrary ) : m_entity(entity) - , m_listScriptNames(std::move(listScriptNames)) - , m_listScriptParameters(std::move(listScriptParameters)) + , m_scriptLibrary(scriptLibrary) { } diff --git a/editor/UI/EntityInspectorPanel.hpp b/editor/UI/EntityInspectorPanel.hpp index 36cf109..41152fb 100644 --- a/editor/UI/EntityInspectorPanel.hpp +++ b/editor/UI/EntityInspectorPanel.hpp @@ -11,10 +11,9 @@ #define ENTITYINSPECTORPANEL_HPP #include -#include +#include + #include -#include -#include namespace GE_Editor { @@ -28,8 +27,7 @@ class EntityInspectorPanel EntityInspectorPanel( const GE::Entity& entity, - std::function()> listScriptNames, - std::function(const std::string&)> listScriptParameters + const GE::ScriptLibraryManager* scriptLibrary ); EntityInspectorPanel& onEntityDelete(std::function&& f) { return m_onEntityDelete = std::move(f), *this; } @@ -44,8 +42,7 @@ class EntityInspectorPanel void addComponentPopUp(); GE::Entity m_entity; - std::function()> m_listScriptNames; - std::function(const std::string&)> m_listScriptParameters; + const GE::ScriptLibraryManager* m_scriptLibrary = nullptr; std::function m_onEntityDelete; diff --git a/include/Game-Engine/Game.hpp b/include/Game-Engine/Game.hpp index d58917e..e4a85b4 100644 --- a/include/Game-Engine/Game.hpp +++ b/include/Game-Engine/Game.hpp @@ -13,13 +13,10 @@ #include "Game-Engine/InputContext.hpp" #include "Game-Engine/Scene.hpp" #include "Game-Engine/AssetManager.hpp" -#include "Game-Engine/Script.hpp" +#include "Game-Engine/ScriptLibraryManager.hpp" #include -#include #include -#include -#include namespace GE { @@ -41,8 +38,7 @@ class GE_API Game Game( AssetManager* assetManager, - std::function(const std::string&)> makeScriptInstance, - std::function(const std::string&)> listScriptParameters, + ScriptLibraryManager* scriptLibrary, const Descriptor& descriptor ); @@ -54,8 +50,7 @@ class GE_API Game ~Game(); private: - std::function(const std::string&)> m_makeScriptInstance; - std::function(const std::string&)> m_listScriptParameters; + ScriptLibraryManager* m_scriptLibrary = nullptr; std::map m_scenes; Scene* m_activeScene = nullptr; InputContext m_inputContext; diff --git a/include/Game-Engine/ScriptLibraryManager.hpp b/include/Game-Engine/ScriptLibraryManager.hpp new file mode 100644 index 0000000..d855aad --- /dev/null +++ b/include/Game-Engine/ScriptLibraryManager.hpp @@ -0,0 +1,53 @@ +/* + * --------------------------------------------------- + * ScriptLibraryManager.hpp + * + * Author: Thomas Choquet + * --------------------------------------------------- + */ + +#ifndef SCRIPT_LIBRARY_MANAGER_HPP +#define SCRIPT_LIBRARY_MANAGER_HPP + +#include "Game-Engine/Export.hpp" +#include "Game-Engine/Script.hpp" + +#include +#include +#include +#include + +namespace GE +{ + +class GE_API ScriptLibraryManager +{ +public: + ScriptLibraryManager() = default; + ScriptLibraryManager(const ScriptLibraryManager&) = delete; + ScriptLibraryManager(ScriptLibraryManager&&) = default; + + void load(const std::filesystem::path& path); + void unload(); + [[nodiscard]] bool isLoaded() const; + + [[nodiscard]] std::vector listScriptNames() const; + [[nodiscard]] std::vector listScriptParameters(const std::string& scriptName) const; + [[nodiscard]] std::shared_ptr