From 80082ff2f67ce47ca9ca0631297eb3b911739274 Mon Sep 17 00:00:00 2001 From: Chris Cranford Date: Sat, 26 Oct 2024 17:36:23 -0400 Subject: [PATCH] GH-825 Refactor OScriptLanguage & add OScriptNodeFactory --- .../actions/default_action_registrar.cpp | 5 +- src/editor/register_editor_types.cpp | 148 +++++++-------- src/script/graph.cpp | 5 +- src/script/language.cpp | 33 ---- src/script/language.h | 150 +-------------- src/script/node.h | 1 + src/script/node_factory.cpp | 56 ++++++ src/script/node_factory.h | 175 ++++++++++++++++++ src/script/register_script_types.cpp | 30 +-- 9 files changed, 328 insertions(+), 275 deletions(-) create mode 100644 src/script/node_factory.cpp create mode 100644 src/script/node_factory.h diff --git a/src/editor/graph/actions/default_action_registrar.cpp b/src/editor/graph/actions/default_action_registrar.cpp index 060191f3..4d7f2c46 100644 --- a/src/editor/graph/actions/default_action_registrar.cpp +++ b/src/editor/graph/actions/default_action_registrar.cpp @@ -33,11 +33,10 @@ void OrchestratorDefaultGraphActionRegistrar::_register_node(const StringName& p_class_name, const StringName& p_category, const Dictionary& p_data) { - OScriptLanguage* language = OScriptLanguage::get_singleton(); Orchestration* orchestration = _context->graph->get_orchestration(); - const Ref node = language->create_node_from_name(p_class_name, orchestration, false); - if (!node->get_flags().has_flag(OScriptNode::ScriptNodeFlags::CATALOGABLE)) + const Ref node = OScriptNodeFactory::create_node_from_name(p_class_name, orchestration); + if (!node.is_valid() || !node->get_flags().has_flag(OScriptNode::ScriptNodeFlags::CATALOGABLE)) return; PackedStringArray name_parts = p_category.split("/"); diff --git a/src/editor/register_editor_types.cpp b/src/editor/register_editor_types.cpp index 100762ee..5ac4e3be 100644 --- a/src/editor/register_editor_types.cpp +++ b/src/editor/register_editor_types.cpp @@ -58,96 +58,96 @@ void register_editor_types() { // Plugin bits - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorPlugin) + GDREGISTER_INTERNAL_CLASS(OrchestratorPlugin) #if GODOT_VERSION >= 0x040300 - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorDebuggerPlugin) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorDebuggerPlugin) #endif - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorExportPlugin) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorInspectorPluginFunction) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorInspectorPluginSignal) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorInspectorPluginVariable) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorThemeCache) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorCache) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorBuildOutputPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorExportPlugin) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorInspectorPluginFunction) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorInspectorPluginSignal) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorInspectorPluginVariable) + GDREGISTER_INTERNAL_CLASS(OrchestratorThemeCache) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorCache) + GDREGISTER_INTERNAL_CLASS(OrchestratorBuildOutputPanel) // Editor bits - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorPropertyInfoContainerEditorProperty) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorPropertyVariableClassification) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorFileDialog) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorSearchDialogItem) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorSearchDialog) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorSelectTypeSearchDialog) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorSearchHelpBit) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptAutowireSelections) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorPropertySelector) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorSceneNodeSelector) + GDREGISTER_INTERNAL_CLASS(OrchestratorPropertyInfoContainerEditorProperty) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorPropertyVariableClassification) + GDREGISTER_INTERNAL_CLASS(OrchestratorFileDialog) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorSearchDialogItem) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorSearchDialog) + GDREGISTER_INTERNAL_CLASS(OrchestratorSelectTypeSearchDialog) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorSearchHelpBit) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptAutowireSelections) + GDREGISTER_INTERNAL_CLASS(OrchestratorPropertySelector) + GDREGISTER_INTERNAL_CLASS(OrchestratorSceneNodeSelector) // Action components - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphActionMenu) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphActionMenuItem) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphActionHandler) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawner) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphActionRegistrar) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorDefaultGraphActionRegistrar) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphActionMenu) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphActionMenuItem) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphActionHandler) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawner) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphActionRegistrar) + GDREGISTER_INTERNAL_CLASS(OrchestratorDefaultGraphActionRegistrar) // Node spawners - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerProperty) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerPropertyGet) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerPropertySet) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerCallMemberFunction) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerCallScriptFunction) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerEvent) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerEmitMemberSignal) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerEmitSignal) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerVariable) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerVariableGet) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerVariableSet) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerScriptNode) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerProperty) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerPropertyGet) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerPropertySet) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerCallMemberFunction) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerCallScriptFunction) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerEvent) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerEmitMemberSignal) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerEmitSignal) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerVariable) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerVariableGet) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerVariableSet) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeSpawnerScriptNode) // View components - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorPanel) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorEditorViewport) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptEditorViewport) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGotoNodeDialog) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorUpdaterButton) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorUpdaterVersionPicker) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorUpdaterReleaseNotesDialog) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorAboutDialog) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScreenSelect) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorWindowWrapper) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGettingStarted) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptConnectionsDialog) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptComponentPanel) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptFunctionsComponentPanel) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptGraphsComponentPanel) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptMacrosComponentPanel) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptSignalsComponentPanel) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorScriptVariablesComponentPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorEditorViewport) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptEditorViewport) + GDREGISTER_INTERNAL_CLASS(OrchestratorGotoNodeDialog) + GDREGISTER_INTERNAL_CLASS(OrchestratorUpdaterButton) + GDREGISTER_INTERNAL_CLASS(OrchestratorUpdaterVersionPicker) + GDREGISTER_INTERNAL_CLASS(OrchestratorUpdaterReleaseNotesDialog) + GDREGISTER_INTERNAL_CLASS(OrchestratorAboutDialog) + GDREGISTER_INTERNAL_CLASS(OrchestratorScreenSelect) + GDREGISTER_INTERNAL_CLASS(OrchestratorWindowWrapper) + GDREGISTER_INTERNAL_CLASS(OrchestratorGettingStarted) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptConnectionsDialog) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptComponentPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptFunctionsComponentPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptGraphsComponentPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptMacrosComponentPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptSignalsComponentPanel) + GDREGISTER_INTERNAL_CLASS(OrchestratorScriptVariablesComponentPanel) // Graph Classes - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphEdit) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNode) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePin) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorKnotPoint) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphEdit) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNode) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePin) + GDREGISTER_INTERNAL_CLASS(OrchestratorKnotPoint) // Graph Node Type - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeDefault) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodeComment) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphKnot) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeDefault) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodeComment) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphKnot) // Graph Pin Types - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinBitField) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinBool) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinColor) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinEnum) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinExec) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinFile) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinInputAction) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinNodePath) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinNumeric) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinObject) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinString) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinStruct) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinBitField) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinBool) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinColor) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinEnum) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinExec) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinFile) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinInputAction) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinNodePath) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinNumeric) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinObject) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinString) + GDREGISTER_INTERNAL_CLASS(OrchestratorGraphNodePinStruct) // Add plugin to the editor EditorPlugins::add_by_type(); diff --git a/src/script/graph.cpp b/src/script/graph.cpp index d5e5077d..ff04eec1 100644 --- a/src/script/graph.cpp +++ b/src/script/graph.cpp @@ -452,9 +452,12 @@ void OScriptGraph::remove_connection_knot(uint64_t p_connection_id) Ref OScriptGraph::create_node(const StringName& p_type, const OScriptNodeInitContext& p_context, const Vector2& p_position) { - const Ref spawned = OScriptLanguage::get_singleton()->create_node_from_name(p_type, _orchestration); + const Ref spawned = OScriptNodeFactory::create_node_from_name(p_type, _orchestration); if (spawned.is_valid()) + { + spawned->set_id(_orchestration->get_available_id()); _initialize_node(spawned, p_context, p_position); + } return spawned; } diff --git a/src/script/language.cpp b/src/script/language.cpp index 9586f468..c75a4ce9 100644 --- a/src/script/language.cpp +++ b/src/script/language.cpp @@ -33,7 +33,6 @@ #endif OScriptLanguage* OScriptLanguage::_singleton = nullptr; -HashMap OScriptLanguage::_nodes; OScriptLanguage::OScriptLanguage() { @@ -59,27 +58,6 @@ OScriptLanguage* OScriptLanguage::get_singleton() return _singleton; } -void OScriptLanguage::_add_node_class_internal(const StringName& p_class, const StringName& p_inherits) -{ - const StringName& name = p_class; - ERR_FAIL_COND_MSG(_nodes.has(name), "Class '" + String(p_class) + "' already exists."); - - _nodes[name] = ScriptNodeInfo(); - ScriptNodeInfo& sni = _nodes[name]; - sni.name = name; - sni.inherits = p_inherits; - - if (!sni.inherits.is_empty()) - { - ERR_FAIL_COND_MSG(!_nodes.has(sni.inherits), "Node " + p_inherits + " is not defined as a node"); - sni.inherits_ptr = &_nodes[sni.inherits]; - } - else - { - sni.inherits_ptr = nullptr; - } -} - void OScriptLanguage::_init() { Logger::info("Initializing OrchestratorScript"); @@ -729,14 +707,3 @@ String OScriptLanguage::get_script_extension_filter() const return StringUtils::join(",", results); } - -Ref OScriptLanguage::create_node_from_name(const String& p_class_name, Orchestration* p_owner, bool p_allocate_id) -{ - ERR_FAIL_COND_V_MSG(!_nodes.has(p_class_name), Ref(), "No node found with name: " + p_class_name); - - Ref node(_nodes[p_class_name].creation_func()); - node->set_id(p_allocate_id ? p_owner->get_available_id() : -1); - node->_orchestration = p_owner; - - return node; -} diff --git a/src/script/language.h b/src/script/language.h index e4103f12..f642c470 100644 --- a/src/script/language.h +++ b/src/script/language.h @@ -19,7 +19,7 @@ #include "common/logger.h" #include "common/version.h" -#include "serialization/format_defs.h" +#include "script/serialization/format_defs.h" #include #include @@ -38,9 +38,6 @@ class OScriptInstance; class OScriptNode; class OScriptVirtualMachine; -/// Defines the script node creation function callback -typedef Ref (*OScriptNodeRegisterFunc)(const String& p_type); - /// Defines an extension for Godot where we define the language for Orchestrations. class OScriptLanguage : public ScriptLanguageExtension { @@ -51,21 +48,6 @@ class OScriptLanguage : public ScriptLanguageExtension private: - // Structure that describes a registered node that provides some unique - // functionality to the visual script subsystem. - struct ScriptNodeInfo - { - ScriptNodeInfo* inherits_ptr { nullptr }; - void* class_ptr { nullptr }; - StringName inherits; - StringName name; - - Object* (*creation_func)() { nullptr }; - - ScriptNodeInfo() = default; - ~ScriptNodeInfo() = default; - }; - #if GODOT_VERSION >= 0x040300 struct CallStack { @@ -78,7 +60,6 @@ class OScriptLanguage : public ScriptLanguageExtension #endif static OScriptLanguage* _singleton; //! The one and only instance - static HashMap _nodes; //! Script node registration data SelfList::List _scripts; //! all loaded scripts HashMap _global_constants; //! Stores global constants HashMap _named_global_constants; //! Stores named global constants @@ -93,20 +74,6 @@ class OScriptLanguage : public ScriptLanguageExtension CallStack* _call_stack{ nullptr }; //! The call stack #endif -protected: - - /// Standard creator method for nodes - /// @tparam T the node type - /// @return the created node - template - static Object* creator() - { - return memnew(T); - } - - // Internal Registration - static void _add_node_class_internal(const StringName& p_class, const StringName& p_inherits); - public: /// Public lock used for specific synchronizing use cases. Ref lock; @@ -205,126 +172,11 @@ class OScriptLanguage : public ScriptLanguageExtension String get_script_extension_filter() const; - /// Adds the node clas to the language (DO NOT USE DIRECTLY!!!!) - /// @tparam T the class type - template static void _add_node_class() - { - if (T::get_class_static().match("OScriptNode")) - _add_node_class_internal(T::get_class_static(), StringName()); - else - _add_node_class_internal(T::get_class_static(), T::get_parent_class_static()); - } - - /// Registers a node class with the language - /// @tparam T the node class type - template - static void register_node_class() - { - static_assert(TypesAreSame::value, - "Node not declared properly, please use ORCHESTRATOR_CLASS."); - T::initialize_orchestrator_class(); - - ScriptNodeInfo* node = _nodes.getptr(T::get_class_static()); - ERR_FAIL_NULL(node); - node->creation_func = &creator; - node->class_ptr = T::get_orchestrator_node_ptr_static(); - - T::register_custom_orchestrator_data_to_otdb(); - Logger::debug("Registered node '", T::get_class_static(), "'."); - } - #ifdef TOOLS_ENABLED /// Get a list of all orchestration scripts /// @return list of references List> get_scripts() const; #endif - - /// Create a script node based on the name of the node. - /// @param p_class_name the node class name - /// @param p_owner the orchestration - /// @param p_allocate_id allocate node id from script, defaults to true. - /// @return the script node reference - Ref create_node_from_name(const String& p_class_name, Orchestration* p_owner, bool p_allocate_id = true); - - /// Templated function to create a node from a node type - /// @tparam T the node type - /// @param p_owner the orchestration - /// @return the created node reference, may be an invalid reference on failure - template - Ref create_node_from_type(Orchestration* p_owner) - { - for (const KeyValue& E : _nodes) - if (E.key == T::get_class_static()) - return create_node_from_name(E.key, p_owner); - ERR_FAIL_V_MSG(Ref(), "No node found with class type: " + T::get_class_static()); - } }; -#define ORCHESTRATOR_NODE_CLASS_COMMON(m_class, m_inherits) /*************************************/ \ - GDCLASS(m_class, m_inherits); \ -private: \ - friend class ::OScriptLanguage; \ -public: \ - typedef m_class self_node_type; \ - typedef m_inherits super; \ - static _FORCE_INLINE_ void* get_orchestrator_node_ptr_static() \ - { \ - static int ptr; \ - return &ptr; \ - } - -#define ORCHESTRATOR_NODE_CLASS_BASE(m_class, m_inherits) /***************************************/ \ - ORCHESTRATOR_NODE_CLASS_COMMON(m_class, m_inherits); \ -public: \ - static void initialize_orchestrator_class() \ - { \ - static bool orchestrator_initialized = false; \ - if (orchestrator_initialized) \ - { \ - return; \ - } \ - OScriptLanguage::_add_node_class(); \ - orchestrator_initialized = true; \ - } \ -protected: \ - virtual void _initialize_orchestator_classv() \ - { \ - initialize_orchestrator_class(); \ - } - -#define ORCHESTRATOR_NODE_CLASS(m_class, m_inherits) /********************************************/ \ - ORCHESTRATOR_NODE_CLASS_COMMON(m_class, m_inherits); \ -public: \ - static void initialize_orchestrator_class() \ - { \ - static bool orchestrator_initialized = false; \ - if (orchestrator_initialized) \ - { \ - return; \ - } \ - m_inherits::initialize_orchestrator_class(); \ - OScriptLanguage::_add_node_class(); \ - orchestrator_initialized = true; \ - } \ -protected: \ - virtual void _initialize_orchestator_classv() override \ - { \ - initialize_orchestrator_class(); \ - } \ -private: - -#define ORCHESTRATOR_REGISTER_NODE_CLASS(m_class) /***********************************************/ \ - GDREGISTER_CLASS(m_class); \ - ::OScriptLanguage::register_node_class(); - -#define ORCHESTRATOR_REGISTER_ABSTRACT_NODE_CLASS(m_class) /**************************************/ \ - GDREGISTER_ABSTRACT_CLASS(m_class); \ - ::OScriptLanguage::register_node_class(); - -#define ORCHESTRATOR_REGISTER_CLASS(m_class) /****************************************************/ \ - GDREGISTER_CLASS(m_class) - -#define ORCHESTRATOR_REGISTER_INTERNAL_CLASS(m_class) /*******************************************/ \ - GDREGISTER_INTERNAL_CLASS(m_class) - #endif // ORCHESTRATOR_SCRIPT_LANGUAGE_H \ No newline at end of file diff --git a/src/script/node.h b/src/script/node.h index e66c75bf..db77a838 100644 --- a/src/script/node.h +++ b/src/script/node.h @@ -21,6 +21,7 @@ #include "orchestration/build_log.h" #include "script/action.h" #include "script/language.h" +#include "script/node_factory.h" #include "script/graph.h" #include "script/node_pin.h" #include "script/target_object.h" diff --git a/src/script/node_factory.cpp b/src/script/node_factory.cpp new file mode 100644 index 00000000..4d1b15d7 --- /dev/null +++ b/src/script/node_factory.cpp @@ -0,0 +1,56 @@ +// This file is part of the Godot Orchestrator project. +// +// Copyright (c) 2023-present Crater Crash Studios LLC and its contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "script/node_factory.h" + +#include "orchestration/orchestration.h" +#include "script/node.h" + +HashMap OScriptNodeFactory::_nodes; + +void OScriptNodeFactory::_add_node_class(const StringName& p_class, const StringName& p_inherits) +{ + ERR_FAIL_COND_MSG(_nodes.has(p_class), vformat("Class '%s' already exists.", p_class)); + + _nodes[p_class] = ScriptNodeInfo(); + + ScriptNodeInfo& info = _nodes[p_class]; + info.name = p_class; + info.inherits = p_inherits; + + if (!info.inherits.is_empty()) + { + ERR_FAIL_COND_MSG(!_nodes.has(info.inherits), vformat("Class '%s' is not defined as a node", p_inherits)); + info.inherits_ptr = &_nodes[info.inherits]; + } +} + +bool OScriptNodeFactory::_is_base_node_type(const StringName& p_class) +{ + return OScriptNode::get_class_static().match(p_class); +} + +Ref OScriptNodeFactory::create_node_from_name(const String& p_class_name, Orchestration* p_owner) +{ + ERR_FAIL_COND_V_MSG(!_nodes.has(p_class_name), nullptr, "No node found with name: " + p_class_name); + + // No unique ID is assigned by default + Ref node(_nodes[p_class_name].creation_func()); + node->_orchestration = p_owner; + + return node; +} + diff --git a/src/script/node_factory.h b/src/script/node_factory.h new file mode 100644 index 00000000..0dd9b357 --- /dev/null +++ b/src/script/node_factory.h @@ -0,0 +1,175 @@ +// This file is part of the Godot Orchestrator project. +// +// Copyright (c) 2023-present Crater Crash Studios LLC and its contributors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef ORCHESTRATOR_SCRIPT_NODE_FACTORY_H +#define ORCHESTRATOR_SCRIPT_NODE_FACTORY_H + +#include +#include + +using namespace godot; + +/// Forward declarations +class Orchestration; +class OScriptNode; + +/// Factory that stores and provides a way to create OScriptNode instances +class OScriptNodeFactory +{ + // Describes a registered script node that provides functionality + struct ScriptNodeInfo + { + StringName name; //! Name of this node + StringName inherits; //! Name of parent script node + ScriptNodeInfo* inherits_ptr{ nullptr }; //! Parent script node type + void* class_ptr{ nullptr }; //! + + Object* (*creation_func)() { nullptr }; //! Function used to create instance of node + }; + + static HashMap _nodes; //! Registry of nodes + + /// Standard creator method for nodes + /// @tparam T the node class type + /// @return the node instance + template + static Object* creator() { return memnew(T); } + + /// Registers the class. + /// Classes should be registered in hierarchical order, parents before children. + /// @param p_class the node class name to register + /// @param p_inherits the parent node class name of the registered subject + static void _add_node_class(const StringName& p_class, const StringName& p_inherits); + + /// Checks whether the class is the base script node type + /// @param p_class the class name to check + /// @return true if it's the base node type, false otherwise + static bool _is_base_node_type(const StringName& p_class); + +public: + + /// Adds a node class to the factory by type + /// @tparam T the node class type + template + static void add_node_class() + { + const bool is_base_node = _is_base_node_type(T::get_class_static()); + _add_node_class(T::get_class_static(), is_base_node ? StringName() : T::get_parent_class_static()); + } + + /// Registers the node class with the factory + /// @tparam T the node class type + template + static void register_node_class() + { + static_assert(TypesAreSame::value, + "Node not declared properly, please use ORCHESTRATOR_CLASS."); + + T::initialize_orchestrator_class(); + + // Node should already be registered in factory using `add_node_class` + // This is done via the ORCHESTRATOR_REGISTER_NODE_CLASS and friend macros + ScriptNodeInfo* node_info = _nodes.getptr(T::get_class_static()); + ERR_FAIL_NULL(node_info); + + node_info->creation_func = &creator; + node_info->class_ptr = T::get_orchestrator_node_ptr_static(); + + T::register_custom_orchestrator_data_to_otdb(); + } + + /// Creates an Orchestration node instance by name + /// @param p_class_name the node class type to create + /// @param p_owner the orchestration that should own the node instance + /// @return the script node reference + static Ref create_node_from_name(const String& p_class_name, Orchestration* p_owner); + + /// Creates an Orchestration node instance by type + /// @tparam T the node type to create + /// @param p_owner the orchestration that should own the node instance + /// @return the node reference + template + static Ref create_node_from_type(Orchestration* p_owner) + { + if (_nodes.has(T::get_class_static())) + return create_node_from_name(T::get_class_static(), p_owner); + + ERR_FAIL_V_MSG(Ref(), "No node definition found with class type: " + T::get_class_static()); + } +}; + +#define ORCHESTRATOR_NODE_CLASS_COMMON(m_class, m_inherits) /*************************************/ \ + GDCLASS(m_class, m_inherits); \ +private: \ + friend class ::OScriptNodeFactory; \ +public: \ + typedef m_class self_node_type; \ + typedef m_inherits super; \ + static _FORCE_INLINE_ void* get_orchestrator_node_ptr_static() \ + { \ + static int ptr; \ + return &ptr; \ + } + +#define ORCHESTRATOR_NODE_CLASS_BASE(m_class, m_inherits) /***************************************/ \ + ORCHESTRATOR_NODE_CLASS_COMMON(m_class, m_inherits); \ +public: \ + static void initialize_orchestrator_class() \ + { \ + static bool orchestrator_initialized = false; \ + if (orchestrator_initialized) \ + { \ + return; \ + } \ + OScriptNodeFactory::add_node_class(); \ + orchestrator_initialized = true; \ + } \ +protected: \ + virtual void _initialize_orchestator_classv() \ + { \ + initialize_orchestrator_class(); \ + } + +#define ORCHESTRATOR_NODE_CLASS(m_class, m_inherits) /********************************************/ \ + ORCHESTRATOR_NODE_CLASS_COMMON(m_class, m_inherits); \ +public: \ + static void initialize_orchestrator_class() \ + { \ + static bool orchestrator_initialized = false; \ + if (orchestrator_initialized) \ + { \ + return; \ + } \ + m_inherits::initialize_orchestrator_class(); \ + OScriptNodeFactory::add_node_class(); \ + orchestrator_initialized = true; \ + } \ +protected: \ + virtual void _initialize_orchestator_classv() override \ + { \ + initialize_orchestrator_class(); \ + } \ +private: + +#define ORCHESTRATOR_REGISTER_NODE_CLASS(m_class) /***********************************************/ \ + GDREGISTER_CLASS(m_class); \ + ::OScriptNodeFactory::register_node_class(); + +#define ORCHESTRATOR_REGISTER_ABSTRACT_NODE_CLASS(m_class) /**************************************/ \ + GDREGISTER_ABSTRACT_CLASS(m_class); \ + ::OScriptNodeFactory::register_node_class(); + +#endif // ORCHESTRATOR_SCRIPT_NODE_FACTORY_H diff --git a/src/script/register_script_types.cpp b/src/script/register_script_types.cpp index 3d9eeb73..4e84d937 100644 --- a/src/script/register_script_types.cpp +++ b/src/script/register_script_types.cpp @@ -48,28 +48,28 @@ void register_script_types() using namespace orchestrator::internal; // Register loader/savers - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptBinaryResourceLoader) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptBinaryResourceSaver) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptTextResourceLoader) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptTextResourceSaver) + GDREGISTER_INTERNAL_CLASS(OScriptBinaryResourceLoader) + GDREGISTER_INTERNAL_CLASS(OScriptBinaryResourceSaver) + GDREGISTER_INTERNAL_CLASS(OScriptTextResourceLoader) + GDREGISTER_INTERNAL_CLASS(OScriptTextResourceSaver) // Settings - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OrchestratorSettings) + GDREGISTER_INTERNAL_CLASS(OrchestratorSettings) // Nodes - Abstract first ORCHESTRATOR_REGISTER_ABSTRACT_NODE_CLASS(OScriptNode) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptTargetObject) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptNodePin) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptLanguage) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptGraph) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptFunction) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptVariable) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptSignal) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptState) - ORCHESTRATOR_REGISTER_INTERNAL_CLASS(OScriptAction) + GDREGISTER_INTERNAL_CLASS(OScriptTargetObject) + GDREGISTER_INTERNAL_CLASS(OScriptNodePin) + GDREGISTER_INTERNAL_CLASS(OScriptLanguage) + GDREGISTER_INTERNAL_CLASS(OScriptGraph) + GDREGISTER_INTERNAL_CLASS(OScriptFunction) + GDREGISTER_INTERNAL_CLASS(OScriptVariable) + GDREGISTER_INTERNAL_CLASS(OScriptSignal) + GDREGISTER_INTERNAL_CLASS(OScriptState) + GDREGISTER_INTERNAL_CLASS(OScriptAction) // Purposely public - ORCHESTRATOR_REGISTER_CLASS(OScript) + GDREGISTER_CLASS(OScript) // Create the ScriptExtension language = memnew(OScriptLanguage);