summaryrefslogtreecommitdiff
path: root/modules/visual_script
diff options
context:
space:
mode:
Diffstat (limited to 'modules/visual_script')
-rw-r--r--modules/visual_script/SCsub5
-rw-r--r--modules/visual_script/config.py11
-rw-r--r--modules/visual_script/register_types.cpp120
-rw-r--r--modules/visual_script/register_types.h30
-rw-r--r--modules/visual_script/visual_script.cpp2703
-rw-r--r--modules/visual_script/visual_script.h607
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp1186
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h110
-rw-r--r--modules/visual_script/visual_script_editor.cpp3091
-rw-r--r--modules/visual_script/visual_script_editor.h211
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp1875
-rw-r--r--modules/visual_script/visual_script_flow_control.h330
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp2470
-rw-r--r--modules/visual_script/visual_script_func_nodes.h338
-rw-r--r--modules/visual_script/visual_script_nodes.cpp3509
-rw-r--r--modules/visual_script/visual_script_nodes.h926
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp625
-rw-r--r--modules/visual_script/visual_script_yield_nodes.h128
18 files changed, 18275 insertions, 0 deletions
diff --git a/modules/visual_script/SCsub b/modules/visual_script/SCsub
new file mode 100644
index 0000000000..403fe68f66
--- /dev/null
+++ b/modules/visual_script/SCsub
@@ -0,0 +1,5 @@
+Import('env')
+
+env.add_source_files(env.modules_sources,"*.cpp")
+
+Export('env')
diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py
new file mode 100644
index 0000000000..ea7e83378a
--- /dev/null
+++ b/modules/visual_script/config.py
@@ -0,0 +1,11 @@
+
+
+def can_build(platform):
+ return True
+
+
+def configure(env):
+ pass
+
+
+
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
new file mode 100644
index 0000000000..50c3a4075f
--- /dev/null
+++ b/modules/visual_script/register_types.cpp
@@ -0,0 +1,120 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "register_types.h"
+
+#include "visual_script.h"
+#include "visual_script_editor.h"
+#include "io/resource_loader.h"
+#include "visual_script_nodes.h"
+#include "visual_script_func_nodes.h"
+#include "visual_script_builtin_funcs.h"
+#include "visual_script_flow_control.h"
+#include "visual_script_yield_nodes.h"
+
+
+VisualScriptLanguage *visual_script_language=NULL;
+
+
+void register_visual_script_types() {
+
+ visual_script_language=memnew( VisualScriptLanguage );
+ //script_language_gd->init();
+ ScriptServer::register_language(visual_script_language);
+
+ ObjectTypeDB::register_type<VisualScript>();
+ ObjectTypeDB::register_virtual_type<VisualScriptNode>();
+ ObjectTypeDB::register_virtual_type<VisualScriptFunctionState>();
+ ObjectTypeDB::register_type<VisualScriptFunction>();
+ ObjectTypeDB::register_type<VisualScriptOperator>();
+ ObjectTypeDB::register_type<VisualScriptVariableSet>();
+ ObjectTypeDB::register_type<VisualScriptVariableGet>();
+ ObjectTypeDB::register_type<VisualScriptConstant>();
+ ObjectTypeDB::register_type<VisualScriptIndexGet>();
+ ObjectTypeDB::register_type<VisualScriptIndexSet>();
+ ObjectTypeDB::register_type<VisualScriptGlobalConstant>();
+ ObjectTypeDB::register_type<VisualScriptMathConstant>();
+ ObjectTypeDB::register_type<VisualScriptEngineSingleton>();
+ ObjectTypeDB::register_type<VisualScriptSceneNode>();
+ ObjectTypeDB::register_type<VisualScriptSceneTree>();
+ ObjectTypeDB::register_type<VisualScriptResourcePath>();
+ ObjectTypeDB::register_type<VisualScriptSelf>();
+ ObjectTypeDB::register_type<VisualScriptCustomNode>();
+ ObjectTypeDB::register_type<VisualScriptSubCall>();
+ ObjectTypeDB::register_type<VisualScriptComment>();
+ ObjectTypeDB::register_type<VisualScriptConstructor>();
+ ObjectTypeDB::register_type<VisualScriptLocalVar>();
+ ObjectTypeDB::register_type<VisualScriptInputAction>();
+ ObjectTypeDB::register_type<VisualScriptDeconstruct>();
+ ObjectTypeDB::register_type<VisualScriptPreload>();
+
+
+ ObjectTypeDB::register_type<VisualScriptFunctionCall>();
+ ObjectTypeDB::register_type<VisualScriptPropertySet>();
+ ObjectTypeDB::register_type<VisualScriptPropertyGet>();
+// ObjectTypeDB::register_type<VisualScriptScriptCall>();
+ ObjectTypeDB::register_type<VisualScriptEmitSignal>();
+
+ ObjectTypeDB::register_type<VisualScriptReturn>();
+ ObjectTypeDB::register_type<VisualScriptCondition>();
+ ObjectTypeDB::register_type<VisualScriptWhile>();
+ ObjectTypeDB::register_type<VisualScriptIterator>();
+ ObjectTypeDB::register_type<VisualScriptSequence>();
+ ObjectTypeDB::register_type<VisualScriptInputFilter>();
+ ObjectTypeDB::register_type<VisualScriptInputSelector>();
+
+ ObjectTypeDB::register_type<VisualScriptYield>();
+ ObjectTypeDB::register_type<VisualScriptYieldSignal>();
+
+ ObjectTypeDB::register_type<VisualScriptBuiltinFunc>();
+
+
+ register_visual_script_nodes();
+ register_visual_script_func_nodes();
+ register_visual_script_builtin_func_node();
+ register_visual_script_flow_control_nodes();
+ register_visual_script_yield_nodes();
+
+#ifdef TOOLS_ENABLED
+ VisualScriptEditor::register_editor();
+#endif
+
+
+}
+
+void unregister_visual_script_types() {
+
+
+ unregister_visual_script_nodes();
+
+ ScriptServer::unregister_language(visual_script_language);
+
+ if (visual_script_language)
+ memdelete( visual_script_language );
+
+}
diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h
new file mode 100644
index 0000000000..0a5805eb0b
--- /dev/null
+++ b/modules/visual_script/register_types.h
@@ -0,0 +1,30 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+void register_visual_script_types();
+void unregister_visual_script_types();
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
new file mode 100644
index 0000000000..f2fb371d6b
--- /dev/null
+++ b/modules/visual_script/visual_script.cpp
@@ -0,0 +1,2703 @@
+#include "visual_script.h"
+#include "visual_script_nodes.h"
+#include "scene/main/node.h"
+#include "os/os.h"
+#include "globals.h"
+#define SCRIPT_VARIABLES_PREFIX "script_variables/"
+
+
+//used by editor, this is not really saved
+void VisualScriptNode::set_breakpoint(bool p_breakpoint) {
+ breakpoint=p_breakpoint;
+}
+
+bool VisualScriptNode::is_breakpoint() const {
+
+ return breakpoint;
+}
+
+void VisualScriptNode::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_POSTINITIALIZE) {
+
+ int dvc = get_input_value_port_count();
+ for(int i=0;i<dvc;i++) {
+ Variant::Type expected = get_input_value_port_info(i).type;
+ Variant::CallError ce;
+ default_input_values.push_back(Variant::construct(expected,NULL,0,ce,false));
+ }
+ }
+}
+
+void VisualScriptNode::ports_changed_notify(){
+
+
+ default_input_values.resize( MAX(default_input_values.size(),get_input_value_port_count()) ); //let it grow as big as possible, we don't want to lose values on resize
+
+ emit_signal("ports_changed");
+}
+
+void VisualScriptNode::set_default_input_value(int p_port,const Variant& p_value) {
+
+ ERR_FAIL_INDEX(p_port,default_input_values.size());
+
+ default_input_values[p_port]=p_value;
+}
+
+Variant VisualScriptNode::get_default_input_value(int p_port) const {
+
+ ERR_FAIL_INDEX_V(p_port,default_input_values.size(),Variant());
+ return default_input_values[p_port];
+}
+
+void VisualScriptNode::_set_default_input_values(Array p_values) {
+
+
+ default_input_values=p_values;
+}
+
+
+void VisualScriptNode::validate_input_default_values() {
+
+
+
+ default_input_values.resize(get_input_value_port_count());
+
+ //actually validate on save
+ for(int i=0;i<get_input_value_port_count();i++) {
+
+ Variant::Type expected = get_input_value_port_info(i).type;
+
+
+ if (expected==Variant::NIL || expected==default_input_values[i].get_type()) {
+ continue;
+ } else {
+ //not the same, reconvert
+ Variant::CallError ce;
+ Variant existing = default_input_values[i];
+ const Variant *existingp=&existing;
+ default_input_values[i] = Variant::construct(expected,&existingp,1,ce,false);
+ if (ce.error!=Variant::CallError::CALL_OK) {
+ //could not convert? force..
+ default_input_values[i] = Variant::construct(expected,NULL,0,ce,false);
+ }
+ }
+ }
+}
+
+Array VisualScriptNode::_get_default_input_values() const {
+
+ //validate on save, since on load there is little info about this
+
+ return default_input_values;
+}
+
+
+
+void VisualScriptNode::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("get_visual_script:VisualScript"),&VisualScriptNode::get_visual_script);
+ ObjectTypeDB::bind_method(_MD("set_default_input_value","port_idx","value:Variant"),&VisualScriptNode::set_default_input_value);
+ ObjectTypeDB::bind_method(_MD("get_default_input_value:Variant","port_idx"),&VisualScriptNode::get_default_input_value);
+ ObjectTypeDB::bind_method(_MD("_set_default_input_values","values"),&VisualScriptNode::_set_default_input_values);
+ ObjectTypeDB::bind_method(_MD("_get_default_input_values"),&VisualScriptNode::_get_default_input_values);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"_default_input_values",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_default_input_values"),_SCS("_get_default_input_values"));
+ ADD_SIGNAL(MethodInfo("ports_changed"));
+}
+
+
+Ref<VisualScript> VisualScriptNode::get_visual_script() const {
+
+ if (scripts_used.size())
+ return Ref<VisualScript>(scripts_used.front()->get());
+
+ return Ref<VisualScript>();
+
+}
+
+VisualScriptNode::VisualScriptNode() {
+ breakpoint=false;
+}
+
+////////////////
+
+/////////////////////
+
+VisualScriptNodeInstance::VisualScriptNodeInstance() {
+
+ sequence_outputs=NULL;
+ input_ports=NULL;
+}
+
+VisualScriptNodeInstance::~VisualScriptNodeInstance() {
+
+ if (sequence_outputs) {
+ memdelete(sequence_outputs);
+ }
+
+ if (input_ports) {
+ memdelete(input_ports);
+ }
+
+ if (output_ports) {
+ memdelete(output_ports);
+ }
+
+}
+
+void VisualScript::add_function(const StringName& p_name) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!String(p_name).is_valid_identifier());
+ ERR_FAIL_COND(functions.has(p_name));
+
+ functions[p_name]=Function();
+ functions[p_name].scroll=Vector2(-50,-100);
+}
+
+bool VisualScript::has_function(const StringName& p_name) const {
+
+ return functions.has(p_name);
+
+}
+void VisualScript::remove_function(const StringName& p_name) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!functions.has(p_name));
+
+ for (Map<int,Function::NodeData>::Element *E=functions[p_name].nodes.front();E;E=E->next()) {
+
+ E->get().node->disconnect("ports_changed",this,"_node_ports_changed");
+ E->get().node->scripts_used.erase(this);
+ }
+
+ functions.erase(p_name);
+
+}
+
+void VisualScript::rename_function(const StringName& p_name,const StringName& p_new_name) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!functions.has(p_name));
+ if (p_new_name==p_name)
+ return;
+
+ ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
+
+ ERR_FAIL_COND(functions.has(p_new_name));
+ ERR_FAIL_COND(variables.has(p_new_name));
+ ERR_FAIL_COND(custom_signals.has(p_new_name));
+
+ functions[p_new_name]=functions[p_name];
+ functions.erase(p_name);
+
+}
+
+void VisualScript::set_function_scroll(const StringName& p_name, const Vector2& p_scroll) {
+
+ ERR_FAIL_COND(!functions.has(p_name));
+ functions[p_name].scroll=p_scroll;
+
+}
+
+Vector2 VisualScript::get_function_scroll(const StringName& p_name) const {
+
+ ERR_FAIL_COND_V(!functions.has(p_name),Vector2());
+ return functions[p_name].scroll;
+
+}
+
+
+void VisualScript::get_function_list(List<StringName> *r_functions) const {
+
+ for (const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+ r_functions->push_back(E->key());
+ }
+
+ r_functions->sort_custom<StringName::AlphCompare>();
+
+}
+
+int VisualScript::get_function_node_id(const StringName& p_name) const {
+
+ ERR_FAIL_COND_V(!functions.has(p_name),-1);
+
+ return functions[p_name].function_id;
+
+}
+
+
+void VisualScript::_node_ports_changed(int p_id) {
+
+
+
+ StringName function;
+
+ for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+ if (E->get().nodes.has(p_id)) {
+ function=E->key();
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(function==StringName());
+
+ Function &func = functions[function];
+ Ref<VisualScriptNode> vsn = func.nodes[p_id].node;
+
+ if (OS::get_singleton()->get_main_loop() && OS::get_singleton()->get_main_loop()->cast_to<SceneTree>() && OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()->is_editor_hint()) {
+ vsn->validate_input_default_values(); //force validate default values when editing on editor
+ }
+
+ //must revalidate all the functions
+
+ {
+ List<SequenceConnection> to_remove;
+
+ for (Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) {
+ if (E->get().from_node==p_id && E->get().from_output>=vsn->get_output_sequence_port_count()) {
+
+ to_remove.push_back(E->get());
+ }
+ if (E->get().to_node==p_id && !vsn->has_input_sequence_port()) {
+
+ to_remove.push_back(E->get());
+ }
+ }
+
+ while(to_remove.size()) {
+ func.sequence_connections.erase(to_remove.front()->get());
+ to_remove.pop_front();
+ }
+ }
+
+ {
+
+ List<DataConnection> to_remove;
+
+
+ for (Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) {
+ if (E->get().from_node==p_id && E->get().from_port>=vsn->get_output_value_port_count()) {
+ to_remove.push_back(E->get());
+ }
+ if (E->get().to_node==p_id && E->get().to_port>=vsn->get_input_value_port_count()) {
+ to_remove.push_back(E->get());
+ }
+ }
+
+ while(to_remove.size()) {
+ func.data_connections.erase(to_remove.front()->get());
+ to_remove.pop_front();
+ }
+ }
+
+#ifdef TOOLS_ENABLED
+ set_edited(true); //something changed, let's set as edited
+ emit_signal("node_ports_changed",function,p_id);
+#endif
+}
+
+void VisualScript::add_node(const StringName& p_func,int p_id, const Ref<VisualScriptNode>& p_node, const Point2 &p_pos) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!functions.has(p_func));
+
+
+ for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+ ERR_FAIL_COND(E->get().nodes.has(p_id)); //id can exist only one in script, even for different functions
+ }
+
+ Function &func = functions[p_func];
+
+
+ if (p_node->cast_to<VisualScriptFunction>()) {
+ //the function indeed
+ ERR_EXPLAIN("A function node already has been set here.");
+ ERR_FAIL_COND(func.function_id>=0);
+
+ func.function_id=p_id;
+ }
+
+ Function::NodeData nd;
+ nd.node=p_node;
+ nd.pos=p_pos;
+
+ Ref<VisualScriptNode> vsn = p_node;
+ vsn->connect("ports_changed",this,"_node_ports_changed",varray(p_id));
+ vsn->scripts_used.insert(this);
+
+
+
+ func.nodes[p_id]=nd;
+}
+
+void VisualScript::remove_node(const StringName& p_func,int p_id){
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!functions.has(p_func));
+ Function &func = functions[p_func];
+
+ ERR_FAIL_COND(!func.nodes.has(p_id));
+ {
+ List<SequenceConnection> to_remove;
+
+ for (Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) {
+ if (E->get().from_node==p_id || E->get().to_node==p_id) {
+ to_remove.push_back(E->get());
+ }
+ }
+
+ while(to_remove.size()) {
+ func.sequence_connections.erase(to_remove.front()->get());
+ to_remove.pop_front();
+ }
+ }
+
+ {
+
+ List<DataConnection> to_remove;
+
+
+ for (Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) {
+ if (E->get().from_node==p_id || E->get().to_node==p_id) {
+ to_remove.push_back(E->get());
+ }
+ }
+
+ while(to_remove.size()) {
+ func.data_connections.erase(to_remove.front()->get());
+ to_remove.pop_front();
+ }
+ }
+
+ if (func.nodes[p_id].node->cast_to<VisualScriptFunction>()) {
+ func.function_id=-1; //revert to invalid
+ }
+
+ func.nodes[p_id].node->disconnect("ports_changed",this,"_node_ports_changed");
+ func.nodes[p_id].node->scripts_used.erase(this);
+
+ func.nodes.erase(p_id);
+
+
+}
+
+
+bool VisualScript::has_node(const StringName& p_func,int p_id) const {
+
+ ERR_FAIL_COND_V(!functions.has(p_func),false);
+ const Function &func = functions[p_func];
+
+ return func.nodes.has(p_id);
+}
+
+Ref<VisualScriptNode> VisualScript::get_node(const StringName& p_func,int p_id) const{
+
+ ERR_FAIL_COND_V(!functions.has(p_func),Ref<VisualScriptNode>());
+ const Function &func = functions[p_func];
+
+ ERR_FAIL_COND_V(!func.nodes.has(p_id),Ref<VisualScriptNode>());
+
+ return func.nodes[p_id].node;
+}
+
+void VisualScript::set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!functions.has(p_func));
+ Function &func = functions[p_func];
+
+ ERR_FAIL_COND(!func.nodes.has(p_id));
+ func.nodes[p_id].pos=p_pos;
+}
+
+Point2 VisualScript::get_node_pos(const StringName& p_func,int p_id) const{
+
+ ERR_FAIL_COND_V(!functions.has(p_func),Point2());
+ const Function &func = functions[p_func];
+
+ ERR_FAIL_COND_V(!func.nodes.has(p_id),Point2());
+ return func.nodes[p_id].pos;
+}
+
+
+void VisualScript::get_node_list(const StringName& p_func,List<int> *r_nodes) const{
+
+ ERR_FAIL_COND(!functions.has(p_func));
+ const Function &func = functions[p_func];
+
+ for (const Map<int,Function::NodeData>::Element *E=func.nodes.front();E;E=E->next()) {
+ r_nodes->push_back(E->key());
+ }
+
+}
+
+
+void VisualScript::sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!functions.has(p_func));
+ Function &func = functions[p_func];
+
+
+ SequenceConnection sc;
+ sc.from_node=p_from_node;
+ sc.from_output=p_from_output;
+ sc.to_node=p_to_node;
+ ERR_FAIL_COND(func.sequence_connections.has(sc));
+
+ func.sequence_connections.insert(sc);
+
+}
+
+void VisualScript::sequence_disconnect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){
+
+ ERR_FAIL_COND(!functions.has(p_func));
+ Function &func = functions[p_func];
+
+ SequenceConnection sc;
+ sc.from_node=p_from_node;
+ sc.from_output=p_from_output;
+ sc.to_node=p_to_node;
+ ERR_FAIL_COND(!func.sequence_connections.has(sc));
+
+ func.sequence_connections.erase(sc);
+
+}
+
+bool VisualScript::has_sequence_connection(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node) const{
+
+ ERR_FAIL_COND_V(!functions.has(p_func),false);
+ const Function &func = functions[p_func];
+
+ SequenceConnection sc;
+ sc.from_node=p_from_node;
+ sc.from_output=p_from_output;
+ sc.to_node=p_to_node;
+
+ return func.sequence_connections.has(sc);
+}
+
+void VisualScript::get_sequence_connection_list(const StringName& p_func,List<SequenceConnection> *r_connection) const {
+
+ ERR_FAIL_COND(!functions.has(p_func));
+ const Function &func = functions[p_func];
+
+ for (const Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) {
+ r_connection->push_back(E->get());
+ }
+}
+
+
+void VisualScript::data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!functions.has(p_func));
+ Function &func = functions[p_func];
+
+ DataConnection dc;
+ dc.from_node=p_from_node;
+ dc.from_port=p_from_port;
+ dc.to_node=p_to_node;
+ dc.to_port=p_to_port;
+
+ ERR_FAIL_COND( func.data_connections.has(dc));
+
+ func.data_connections.insert(dc);
+}
+
+void VisualScript::data_disconnect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) {
+
+ ERR_FAIL_COND(!functions.has(p_func));
+ Function &func = functions[p_func];
+
+ DataConnection dc;
+ dc.from_node=p_from_node;
+ dc.from_port=p_from_port;
+ dc.to_node=p_to_node;
+ dc.to_port=p_to_port;
+
+ ERR_FAIL_COND( !func.data_connections.has(dc));
+
+ func.data_connections.erase(dc);
+
+}
+
+bool VisualScript::has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const {
+
+ ERR_FAIL_COND_V(!functions.has(p_func),false);
+ const Function &func = functions[p_func];
+
+ DataConnection dc;
+ dc.from_node=p_from_node;
+ dc.from_port=p_from_port;
+ dc.to_node=p_to_node;
+ dc.to_port=p_to_port;
+
+ return func.data_connections.has(dc);
+
+}
+
+bool VisualScript::is_input_value_port_connected(const StringName& p_func,int p_node,int p_port) const {
+
+ ERR_FAIL_COND_V(!functions.has(p_func),false);
+ const Function &func = functions[p_func];
+
+ for (const Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) {
+ if (E->get().to_node==p_node && E->get().to_port==p_port)
+ return true;
+ }
+
+ return false;
+}
+
+void VisualScript::get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const {
+
+ ERR_FAIL_COND(!functions.has(p_func));
+ const Function &func = functions[p_func];
+
+ for (const Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) {
+ r_connection->push_back(E->get());
+ }
+}
+
+void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!String(p_name).is_valid_identifier());
+ ERR_FAIL_COND(variables.has(p_name));
+
+ Variable v;
+ v.default_value=p_default_value;
+ v.info.type=p_default_value.get_type();
+ v.info.name=p_name;
+ v.info.hint=PROPERTY_HINT_NONE;
+
+ variables[p_name]=v;
+ script_variable_remap[SCRIPT_VARIABLES_PREFIX+String(p_name)]=p_name;
+
+
+#ifdef TOOLS_ENABLED
+ _update_placeholders();
+#endif
+
+}
+
+bool VisualScript::has_variable(const StringName& p_name) const {
+
+ return variables.has(p_name);
+}
+
+void VisualScript::remove_variable(const StringName& p_name) {
+
+ ERR_FAIL_COND(!variables.has(p_name));
+ variables.erase(p_name);
+ script_variable_remap.erase(SCRIPT_VARIABLES_PREFIX+String(p_name));
+
+#ifdef TOOLS_ENABLED
+ _update_placeholders();
+#endif
+}
+
+void VisualScript::set_variable_default_value(const StringName& p_name,const Variant& p_value){
+
+ ERR_FAIL_COND(!variables.has(p_name));
+
+ variables[p_name].default_value=p_value;
+
+#ifdef TOOLS_ENABLED
+ _update_placeholders();
+#endif
+
+}
+Variant VisualScript::get_variable_default_value(const StringName& p_name) const{
+
+ ERR_FAIL_COND_V(!variables.has(p_name),Variant());
+ return variables[p_name].default_value;
+
+}
+void VisualScript::set_variable_info(const StringName& p_name,const PropertyInfo& p_info){
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!variables.has(p_name));
+ variables[p_name].info=p_info;
+ variables[p_name].info.name=p_name;
+
+#ifdef TOOLS_ENABLED
+ _update_placeholders();
+#endif
+
+
+}
+PropertyInfo VisualScript::get_variable_info(const StringName& p_name) const{
+
+ ERR_FAIL_COND_V(!variables.has(p_name),PropertyInfo());
+ return variables[p_name].info;
+}
+
+void VisualScript::_set_variable_info(const StringName& p_name,const Dictionary& p_info) {
+
+ PropertyInfo pinfo;
+ if (p_info.has("type"))
+ pinfo.type=Variant::Type(int(p_info["type"]));
+ if (p_info.has("name"))
+ pinfo.name=p_info["name"];
+ if (p_info.has("hint"))
+ pinfo.hint=PropertyHint(int(p_info["hint"]));
+ if (p_info.has("hint_string"))
+ pinfo.hint_string=p_info["hint_string"];
+ if (p_info.has("usage"))
+ pinfo.usage=p_info["usage"];
+
+ set_variable_info(p_name,pinfo);
+}
+
+Dictionary VisualScript::_get_variable_info(const StringName& p_name) const{
+
+ PropertyInfo pinfo=get_variable_info(p_name);
+ Dictionary d;
+ d["type"]=pinfo.type;
+ d["name"]=pinfo.name;
+ d["hint"]=pinfo.hint;
+ d["hint_string"]=pinfo.hint_string;
+ d["usage"]=pinfo.usage;
+
+ return d;
+}
+
+void VisualScript::get_variable_list(List<StringName> *r_variables) const{
+
+
+ for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+ r_variables->push_back(E->key());
+ }
+
+ r_variables->sort_custom<StringName::AlphCompare>();
+}
+
+
+void VisualScript::set_instance_base_type(const StringName& p_type) {
+
+ ERR_FAIL_COND( instances.size() );
+ base_type=p_type;
+}
+
+
+void VisualScript::rename_variable(const StringName& p_name,const StringName& p_new_name) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!variables.has(p_name));
+ if (p_new_name==p_name)
+ return;
+
+ ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
+
+ ERR_FAIL_COND(functions.has(p_new_name));
+ ERR_FAIL_COND(variables.has(p_new_name));
+ ERR_FAIL_COND(custom_signals.has(p_new_name));
+
+ variables[p_new_name]=variables[p_name];
+ variables.erase(p_name);
+
+}
+
+void VisualScript::add_custom_signal(const StringName& p_name) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!String(p_name).is_valid_identifier());
+ ERR_FAIL_COND(custom_signals.has(p_name));
+
+ custom_signals[p_name]=Vector<Argument>();
+}
+
+bool VisualScript::has_custom_signal(const StringName& p_name) const {
+
+ return custom_signals.has(p_name);
+
+}
+void VisualScript::custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!custom_signals.has(p_func));
+ Argument arg;
+ arg.type=p_type;
+ arg.name=p_name;
+ if (p_index<0)
+ custom_signals[p_func].push_back(arg);
+ else
+ custom_signals[p_func].insert(0,arg);
+
+}
+void VisualScript::custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!custom_signals.has(p_func));
+ ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+ custom_signals[p_func][p_argidx].type=p_type;
+}
+Variant::Type VisualScript::custom_signal_get_argument_type(const StringName& p_func,int p_argidx) const {
+
+ ERR_FAIL_COND_V(!custom_signals.has(p_func),Variant::NIL);
+ ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),Variant::NIL);
+ return custom_signals[p_func][p_argidx].type;
+}
+void VisualScript::custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name) {
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!custom_signals.has(p_func));
+ ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+ custom_signals[p_func][p_argidx].name=p_name;
+
+}
+String VisualScript::custom_signal_get_argument_name(const StringName& p_func,int p_argidx) const {
+
+ ERR_FAIL_COND_V(!custom_signals.has(p_func),String());
+ ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),String());
+ return custom_signals[p_func][p_argidx].name;
+
+}
+void VisualScript::custom_signal_remove_argument(const StringName& p_func,int p_argidx) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!custom_signals.has(p_func));
+ ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+ custom_signals[p_func].remove(p_argidx);
+
+}
+
+int VisualScript::custom_signal_get_argument_count(const StringName& p_func) const {
+
+ ERR_FAIL_COND_V(!custom_signals.has(p_func),0);
+ return custom_signals[p_func].size();
+
+}
+void VisualScript::custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!custom_signals.has(p_func));
+ ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+ ERR_FAIL_INDEX(p_with_argidx,custom_signals[p_func].size());
+
+ SWAP( custom_signals[p_func][p_argidx], custom_signals[p_func][p_with_argidx] );
+
+}
+void VisualScript::remove_custom_signal(const StringName& p_name) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!custom_signals.has(p_name));
+ custom_signals.erase(p_name);
+
+}
+
+void VisualScript::rename_custom_signal(const StringName& p_name,const StringName& p_new_name) {
+
+ ERR_FAIL_COND( instances.size() );
+ ERR_FAIL_COND(!custom_signals.has(p_name));
+ if (p_new_name==p_name)
+ return;
+
+ ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
+
+ ERR_FAIL_COND(functions.has(p_new_name));
+ ERR_FAIL_COND(variables.has(p_new_name));
+ ERR_FAIL_COND(custom_signals.has(p_new_name));
+
+ custom_signals[p_new_name]=custom_signals[p_name];
+ custom_signals.erase(p_name);
+
+}
+
+void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) const {
+
+ for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) {
+ r_custom_signals->push_back(E->key());
+ }
+
+ r_custom_signals->sort_custom<StringName::AlphCompare>();
+
+}
+
+int VisualScript::get_available_id() const {
+
+ int max_id=0;
+ for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+ if (E->get().nodes.empty())
+ continue;
+
+ int last_id = E->get().nodes.back()->key();
+ max_id=MAX(max_id,last_id+1);
+ }
+
+ return max_id;
+}
+
+/////////////////////////////////
+
+
+bool VisualScript::can_instance() const {
+
+ return true;//ScriptServer::is_scripting_enabled();
+
+}
+
+
+StringName VisualScript::get_instance_base_type() const {
+
+ return base_type;
+}
+
+Ref<Script> VisualScript::get_base_script() const {
+ return Ref<Script>(); // no inheritance in visual script
+}
+
+
+#ifdef TOOLS_ENABLED
+void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
+
+
+ placeholders.erase(p_placeholder);
+}
+
+
+void VisualScript::_update_placeholders() {
+
+ if (placeholders.size()==0)
+ return; //no bother if no placeholders
+ List<PropertyInfo> pinfo;
+ Map<StringName,Variant> values;
+
+ for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+
+ PropertyInfo p = E->get().info;
+ p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
+ pinfo.push_back(p);
+ values[p.name]=E->get().default_value;
+ }
+
+ for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
+
+ E->get()->update(pinfo,values);
+ }
+
+}
+
+#endif
+
+
+ScriptInstance* VisualScript::instance_create(Object *p_this) {
+
+
+
+#ifdef TOOLS_ENABLED
+
+ if (!ScriptServer::is_scripting_enabled()) {
+
+
+ PlaceHolderScriptInstance *sins = memnew( PlaceHolderScriptInstance(VisualScriptLanguage::singleton,Ref<Script>((Script*)this),p_this));
+ placeholders.insert(sins);
+
+ List<PropertyInfo> pinfo;
+ Map<StringName,Variant> values;
+
+ for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+
+ PropertyInfo p = E->get().info;
+ p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
+ pinfo.push_back(p);
+ values[p.name]=E->get().default_value;
+ }
+
+ sins->update(pinfo,values);
+
+ return sins;
+ }
+#endif
+
+
+ VisualScriptInstance *instance=memnew( VisualScriptInstance );
+ instance->create(Ref<VisualScript>(this),p_this);
+
+
+ if (VisualScriptLanguage::singleton->lock)
+ VisualScriptLanguage::singleton->lock->lock();
+
+ instances[p_this]=instance;
+
+ if (VisualScriptLanguage::singleton->lock)
+ VisualScriptLanguage::singleton->lock->unlock();
+
+ return instance;
+}
+
+bool VisualScript::instance_has(const Object *p_this) const {
+
+ return instances.has((Object*)p_this);
+}
+
+bool VisualScript::has_source_code() const {
+
+ return false;
+}
+
+String VisualScript::get_source_code() const {
+
+ return String();
+}
+
+void VisualScript::set_source_code(const String& p_code) {
+
+}
+
+Error VisualScript::reload(bool p_keep_state) {
+
+ return OK;
+}
+
+
+bool VisualScript::is_tool() const {
+
+ return false;
+}
+
+
+String VisualScript::get_node_type() const {
+
+ return String();
+}
+
+
+ScriptLanguage *VisualScript::get_language() const {
+
+ return VisualScriptLanguage::singleton;
+}
+
+
+bool VisualScript::has_script_signal(const StringName& p_signal) const {
+
+ return custom_signals.has(p_signal);
+}
+
+void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+
+ for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) {
+
+ MethodInfo mi;
+ mi.name=E->key();
+ for(int i=0;i<E->get().size();i++) {
+ PropertyInfo arg;
+ arg.type=E->get()[i].type;
+ arg.name=E->get()[i].name;
+ mi.arguments.push_back(arg);
+ }
+
+
+ r_signals->push_back(mi);
+ }
+
+
+}
+
+
+bool VisualScript::get_property_default_value(const StringName& p_property,Variant& r_value) const {
+
+ if (!script_variable_remap.has(p_property))
+ return false;
+
+ r_value=variables[ script_variable_remap[p_property] ].default_value;
+ return true;
+}
+void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const {
+
+ for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+ MethodInfo mi;
+ mi.name=E->key();
+ if (E->get().function_id>=0) {
+
+ Ref<VisualScriptFunction> func=E->get().nodes[E->get().function_id].node;
+ if (func.is_valid()) {
+
+ for(int i=0;i<func->get_argument_count();i++) {
+ PropertyInfo arg;
+ arg.name=func->get_argument_name(i);
+ arg.type=func->get_argument_type(i);
+ mi.arguments.push_back(arg);
+ }
+ }
+ }
+
+ p_list->push_back(mi);
+ }
+}
+
+bool VisualScript::has_method(const StringName& p_method) const {
+
+ return functions.has(p_method);
+}
+MethodInfo VisualScript::get_method_info(const StringName& p_method) const{
+
+ const Map<StringName,Function>::Element *E=functions.find(p_method);
+ if (!E)
+ return MethodInfo();
+
+ MethodInfo mi;
+ mi.name=E->key();
+ if (E->get().function_id>=0) {
+
+ Ref<VisualScriptFunction> func=E->get().nodes[E->get().function_id].node;
+ if (func.is_valid()) {
+
+ for(int i=0;i<func->get_argument_count();i++) {
+ PropertyInfo arg;
+ arg.name=func->get_argument_name(i);
+ arg.type=func->get_argument_type(i);
+ mi.arguments.push_back(arg);
+ }
+ }
+ }
+
+ return mi;
+}
+
+void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const {
+
+ List<StringName> vars;
+ get_variable_list(&vars);
+
+ for (List<StringName>::Element *E=vars.front();E;E=E->next()) {
+
+ p_list->push_back(variables[E->get()].info);
+ }
+}
+
+
+void VisualScript::_set_data(const Dictionary& p_data) {
+
+ Dictionary d = p_data;
+ if (d.has("base_type"))
+ base_type=d["base_type"];
+
+ variables.clear();
+ Array vars=d["variables"];
+ for (int i=0;i<vars.size();i++) {
+
+ Dictionary v=vars[i];
+ StringName name = v["name"];
+ add_variable(name);
+ _set_variable_info(name,v);
+ set_variable_default_value(name,v["default_value"]);
+
+ }
+
+
+ custom_signals.clear();
+ Array sigs=d["signals"];
+ for (int i=0;i<sigs.size();i++) {
+
+ Dictionary cs=sigs[i];
+ add_custom_signal(cs["name"]);
+
+ Array args=cs["arguments"];
+ for(int j=0;j<args.size();j+=2) {
+ custom_signal_add_argument(cs["name"],Variant::Type(int(args[j+1])),args[j]);
+ }
+ }
+
+ Array funcs=d["functions"];
+ functions.clear();
+
+ for (int i=0;i<funcs.size();i++) {
+
+ Dictionary func=funcs[i];
+
+
+ StringName name=func["name"];
+ //int id=func["function_id"];
+ add_function(name);
+
+ set_function_scroll(name,func["scroll"]);
+
+ Array nodes = func["nodes"];
+
+ for(int i=0;i<nodes.size();i+=3) {
+
+ add_node(name,nodes[i],nodes[i+2],nodes[i+1]);
+ }
+
+
+ Array sequence_connections=func["sequence_connections"];
+
+ for (int j=0;j<sequence_connections.size();j+=3) {
+
+ sequence_connect(name,sequence_connections[j+0],sequence_connections[j+1],sequence_connections[j+2]);
+ }
+
+
+ Array data_connections=func["data_connections"];
+
+ for (int j=0;j<data_connections.size();j+=4) {
+
+ data_connect(name,data_connections[j+0],data_connections[j+1],data_connections[j+2],data_connections[j+3]);
+
+ }
+
+
+ }
+
+}
+
+Dictionary VisualScript::_get_data() const{
+
+ Dictionary d;
+ d["base_type"]=base_type;
+ Array vars;
+ for (const Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+
+ Dictionary var = _get_variable_info(E->key());
+ var["name"]=E->key(); //make sure it's the right one
+ var["default_value"]=E->get().default_value;
+ vars.push_back(var);
+ }
+ d["variables"]=vars;
+
+ Array sigs;
+ for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) {
+
+ Dictionary cs;
+ cs["name"]=E->key();
+ Array args;
+ for(int i=0;i<E->get().size();i++) {
+ args.push_back(E->get()[i].name);
+ args.push_back(E->get()[i].type);
+ }
+ cs["arguments"]=args;
+
+ sigs.push_back(cs);
+ }
+
+ d["signals"]=sigs;
+
+ Array funcs;
+
+ for (const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+ Dictionary func;
+ func["name"]=E->key();
+ func["function_id"]=E->get().function_id;
+ func["scroll"]=E->get().scroll;
+
+ Array nodes;
+
+ for (const Map<int,Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) {
+
+ nodes.push_back(F->key());
+ nodes.push_back(F->get().pos);
+ nodes.push_back(F->get().node);
+
+ }
+
+ func["nodes"]=nodes;
+
+ Array sequence_connections;
+
+ for (const Set<SequenceConnection>::Element *F=E->get().sequence_connections.front();F;F=F->next()) {
+
+ sequence_connections.push_back(F->get().from_node);
+ sequence_connections.push_back(F->get().from_output);
+ sequence_connections.push_back(F->get().to_node);
+
+ }
+
+
+ func["sequence_connections"]=sequence_connections;
+
+ Array data_connections;
+
+ for (const Set<DataConnection>::Element *F=E->get().data_connections.front();F;F=F->next()) {
+
+ data_connections.push_back(F->get().from_node);
+ data_connections.push_back(F->get().from_port);
+ data_connections.push_back(F->get().to_node);
+ data_connections.push_back(F->get().to_port);
+
+ }
+
+
+ func["data_connections"]=data_connections;
+
+ funcs.push_back(func);
+
+ }
+
+ d["functions"]=funcs;
+
+
+ return d;
+
+}
+
+void VisualScript::_bind_methods() {
+
+
+
+ ObjectTypeDB::bind_method(_MD("_node_ports_changed"),&VisualScript::_node_ports_changed);
+
+ ObjectTypeDB::bind_method(_MD("add_function","name"),&VisualScript::add_function);
+ ObjectTypeDB::bind_method(_MD("has_function","name"),&VisualScript::has_function);
+ ObjectTypeDB::bind_method(_MD("remove_function","name"),&VisualScript::remove_function);
+ ObjectTypeDB::bind_method(_MD("rename_function","name","new_name"),&VisualScript::rename_function);
+ ObjectTypeDB::bind_method(_MD("set_function_scroll","ofs"),&VisualScript::set_function_scroll);
+ ObjectTypeDB::bind_method(_MD("get_function_scroll"),&VisualScript::get_function_scroll);
+
+ ObjectTypeDB::bind_method(_MD("add_node","func","id","node","pos"),&VisualScript::add_node,DEFVAL(Point2()));
+ ObjectTypeDB::bind_method(_MD("remove_node","func","id"),&VisualScript::remove_node);
+ ObjectTypeDB::bind_method(_MD("get_function_node_id","name"),&VisualScript::get_function_node_id);
+
+ ObjectTypeDB::bind_method(_MD("get_node","func","id"),&VisualScript::get_node);
+ ObjectTypeDB::bind_method(_MD("has_node","func","id"),&VisualScript::has_node);
+ ObjectTypeDB::bind_method(_MD("set_node_pos","func","id","pos"),&VisualScript::set_node_pos);
+ ObjectTypeDB::bind_method(_MD("get_node_pos","func","id"),&VisualScript::get_node_pos);
+
+ ObjectTypeDB::bind_method(_MD("sequence_connect","func","from_node","from_output","to_node"),&VisualScript::sequence_connect);
+ ObjectTypeDB::bind_method(_MD("sequence_disconnect","func","from_node","from_output","to_node"),&VisualScript::sequence_disconnect);
+ ObjectTypeDB::bind_method(_MD("has_sequence_connection","func","from_node","from_output","to_node"),&VisualScript::has_sequence_connection);
+
+ ObjectTypeDB::bind_method(_MD("data_connect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_connect);
+ ObjectTypeDB::bind_method(_MD("data_disconnect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_disconnect);
+ ObjectTypeDB::bind_method(_MD("has_data_connection","func","from_node","from_port","to_node","to_port"),&VisualScript::has_data_connection);
+
+ ObjectTypeDB::bind_method(_MD("add_variable","name","default_value"),&VisualScript::add_variable,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("has_variable","name"),&VisualScript::has_variable);
+ ObjectTypeDB::bind_method(_MD("remove_variable","name"),&VisualScript::remove_variable);
+ ObjectTypeDB::bind_method(_MD("set_variable_default_value","name","value"),&VisualScript::set_variable_default_value);
+ ObjectTypeDB::bind_method(_MD("get_variable_default_value","name"),&VisualScript::get_variable_default_value);
+ ObjectTypeDB::bind_method(_MD("set_variable_info","name","value"),&VisualScript::_set_variable_info);
+ ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VisualScript::_get_variable_info);
+ ObjectTypeDB::bind_method(_MD("rename_variable","name","new_name"),&VisualScript::rename_variable);
+
+ ObjectTypeDB::bind_method(_MD("add_custom_signal","name"),&VisualScript::add_custom_signal);
+ ObjectTypeDB::bind_method(_MD("has_custom_signal","name"),&VisualScript::has_custom_signal);
+ ObjectTypeDB::bind_method(_MD("custom_signal_add_argument","name","type","argname","index"),&VisualScript::custom_signal_add_argument,DEFVAL(-1));
+ ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_type","name","argidx","type"),&VisualScript::custom_signal_set_argument_type);
+ ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_type","name","argidx"),&VisualScript::custom_signal_get_argument_type);
+ ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_name","name","argidx","argname"),&VisualScript::custom_signal_set_argument_name);
+ ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_name","name","argidx"),&VisualScript::custom_signal_get_argument_name);
+ ObjectTypeDB::bind_method(_MD("custom_signal_remove_argument","argidx"),&VisualScript::custom_signal_remove_argument);
+ ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_count","name"),&VisualScript::custom_signal_get_argument_count);
+ ObjectTypeDB::bind_method(_MD("custom_signal_swap_argument","name","argidx","withidx"),&VisualScript::custom_signal_swap_argument);
+ ObjectTypeDB::bind_method(_MD("remove_custom_signal","name"),&VisualScript::remove_custom_signal);
+ ObjectTypeDB::bind_method(_MD("rename_custom_signal","name","new_name"),&VisualScript::rename_custom_signal);
+
+ //ObjectTypeDB::bind_method(_MD("set_variable_info","name","info"),&VScript::set_variable_info);
+ //ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VScript::set_variable_info);
+
+ ObjectTypeDB::bind_method(_MD("set_instance_base_type","type"),&VisualScript::set_instance_base_type);
+
+ ObjectTypeDB::bind_method(_MD("_set_data","data"),&VisualScript::_set_data);
+ ObjectTypeDB::bind_method(_MD("_get_data"),&VisualScript::_get_data);
+
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_data"),_SCS("_get_data"));
+
+ ADD_SIGNAL(MethodInfo("node_ports_changed",PropertyInfo(Variant::STRING,"function"),PropertyInfo(Variant::INT,"id")));
+}
+
+VisualScript::VisualScript() {
+
+ base_type="Object";
+
+}
+
+VisualScript::~VisualScript() {
+
+ while(!functions.empty()) {
+ remove_function(functions.front()->key());
+ }
+
+}
+
+////////////////////////////////////////////
+
+
+
+bool VisualScriptInstance::set(const StringName& p_name, const Variant& p_value) {
+
+ const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name);
+ if (!remap)
+ return false;
+
+ Map<StringName,Variant>::Element *E=variables.find(remap->get());
+ ERR_FAIL_COND_V(!E,false);
+
+ E->get()=p_value;
+
+ return true;
+}
+
+
+bool VisualScriptInstance::get(const StringName& p_name, Variant &r_ret) const {
+
+ const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name);
+ if (!remap)
+ return false;
+
+ const Map<StringName,Variant>::Element *E=variables.find(remap->get());
+ ERR_FAIL_COND_V(!E,false);
+
+ return E->get();
+}
+void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const{
+
+ for (const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) {
+
+ PropertyInfo p = E->get().info;
+ p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
+ p_properties->push_back(p);
+
+ }
+}
+Variant::Type VisualScriptInstance::get_property_type(const StringName& p_name,bool *r_is_valid) const{
+
+ const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name);
+ if (!remap) {
+ if (r_is_valid)
+ *r_is_valid=false;
+ return Variant::NIL;
+ }
+
+ const Map<StringName,VisualScript::Variable>::Element *E=script->variables.find(remap->get());
+ if (!E) {
+ if (r_is_valid)
+ *r_is_valid=false;
+ ERR_FAIL_V(Variant::NIL);
+ }
+
+ if (r_is_valid)
+ *r_is_valid=true;
+
+ return E->get().info.type;
+
+}
+
+void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const{
+
+ for (const Map<StringName,VisualScript::Function>::Element *E=script->functions.front();E;E=E->next()) {
+
+ MethodInfo mi;
+ mi.name=E->key();
+ if (E->get().function_id>=0 && E->get().nodes.has(E->get().function_id)) {
+
+ Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
+ if (vsf.is_valid()) {
+
+ for(int i=0;i<vsf->get_argument_count();i++) {
+ PropertyInfo arg;
+ arg.name=vsf->get_argument_name(i);
+ arg.type=vsf->get_argument_type(i);
+
+ mi.arguments.push_back(arg);
+ }
+
+ //vsf->Get_ for now at least it does not return..
+ }
+ }
+
+ p_list->push_back(mi);
+ }
+
+}
+bool VisualScriptInstance::has_method(const StringName& p_method) const{
+
+ return script->functions.has(p_method);
+}
+
+
+//#define VSDEBUG(m_text) print_line(m_text)
+#define VSDEBUG(m_text)
+
+Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p_stack, int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, bool p_resuming_yield, Variant::CallError &r_error) {
+
+ Map<StringName,Function>::Element *F = functions.find(p_method);
+ ERR_FAIL_COND_V(!F,Variant());
+ Function *f=&F->get();
+
+ //this call goes separate, so it can e yielded and suspended
+ Variant *variant_stack=(Variant*)p_stack;
+ bool *sequence_bits = (bool*)(variant_stack + f->max_stack);
+ const Variant **input_args=(const Variant**)(sequence_bits+f->node_count);
+ Variant **output_args=(Variant**)(input_args + max_input_args);
+ int flow_max = f->flow_stack_size;
+ int* flow_stack = flow_max? (int*)(output_args + max_output_args) : (int*)NULL;
+
+ String error_str;
+
+ VisualScriptNodeInstance* node=p_node;
+ bool error=false;
+ int current_node_id=f->node;
+ Variant return_value;
+ Variant *working_mem=NULL;
+
+ int flow_stack_pos=p_flow_stack_pos;
+
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton()) {
+ VisualScriptLanguage::singleton->enter_function(this,&p_method,variant_stack,&working_mem,&current_node_id);
+ }
+#endif
+
+ while(true) {
+
+ current_node_id=node->get_id();
+
+ VSDEBUG("==========AT NODE: "+itos(current_node_id)+" base: "+node->get_base_node()->get_type());
+ VSDEBUG("AT STACK POS: "+itos(flow_stack_pos));
+
+
+ //setup working mem
+ working_mem=node->working_mem_idx>=0 ? &variant_stack[node->working_mem_idx] : (Variant*)NULL;
+
+ VSDEBUG("WORKING MEM: "+itos(node->working_mem_idx));
+
+ if (current_node_id==f->node) {
+ //if function node, set up function arguments from begining of stack
+
+ for(int i=0;i<f->argument_count;i++) {
+ input_args[i]=&variant_stack[i];
+ }
+ } else {
+ //setup input pointers normally
+ VSDEBUG("INPUT PORTS: "+itos(node->input_port_count));
+
+ for(int i=0 ; i<node->input_port_count ; i++) {
+
+
+ int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK;
+
+ if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
+ //is a default value (unassigned input port)
+ input_args[i]=&default_values[index];
+ VSDEBUG("\tPORT "+itos(i)+" DEFAULT VAL");
+ } else if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT) {
+ //from a node that requires read
+ Function::UnsequencedGet *ug = &f->unsequenced_gets[index];
+
+ Variant* ug_working_mem=ug->from->working_mem_idx>=0 ? &variant_stack[ug->from->working_mem_idx] : (Variant*)NULL;
+
+
+ bool ok = ug->from->get_output_port_unsequenced(i,&variant_stack[ug->to_stack],ug_working_mem,error_str);
+ if (!ok) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ current_node_id=ug->from->get_id();
+ error=true;
+ working_mem=NULL;
+ break;
+ }
+
+ VSDEBUG("\tPORT "+itos(i)+" UNSEQ READ TO STACK: " + itos(ug->to_stack));
+ input_args[i]=&variant_stack[ug->to_stack];
+ } else {
+ //regular temporary in stack
+ input_args[i]=&variant_stack[index];
+ VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(index));
+
+ }
+ }
+ }
+
+ if (error)
+ break;
+
+ //setup output pointers
+
+ VSDEBUG("OUTPUT PORTS: "+itos(node->output_port_count));
+ for(int i=0 ; i<node->output_port_count ; i++) {
+ output_args[i] = &variant_stack[ node->output_ports[i] ];
+ VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(node->output_ports[i]));
+ }
+
+ //do step
+
+ VisualScriptNodeInstance::StartMode start_mode;
+ {
+ if (p_resuming_yield)
+ start_mode=VisualScriptNodeInstance::START_MODE_RESUME_YIELD;
+ else if (!flow_stack || !(flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT)) //if there is a push bit, it means we are continuing a sequence
+ start_mode=VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE;
+ else
+ start_mode=VisualScriptNodeInstance::START_MODE_CONTINUE_SEQUENCE;
+ }
+
+ VSDEBUG("STEP - STARTSEQ: "+itos(start_mode));
+
+ int ret = node->step(input_args,output_args,start_mode,working_mem,r_error,error_str);
+
+ if (r_error.error!=Variant::CallError::CALL_OK) {
+ //use error from step
+ error=true;
+ break;
+ }
+
+ if (ret&VisualScriptNodeInstance::STEP_YIELD_BIT) {
+ //yielded!
+ if (node->get_working_memory_size()==0) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ error_str=RTR("A node yielded without working memory, please read the docs on how to yield properly!");
+ error=true;
+ break;
+
+ } else {
+ Ref<VisualScriptFunctionState> state = *working_mem;
+ if (!state.is_valid()) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ error_str=RTR("Node yielded, but did not return a function state in the first working memory.");
+ error=true;
+ break;
+
+ }
+
+ //step 1, capture all state
+ state->instance_id=get_owner_ptr()->get_instance_ID();
+ state->script_id=get_script()->get_instance_ID();
+ state->instance=this;
+ state->function=p_method;
+ state->working_mem_index=node->working_mem_idx;
+ state->variant_stack_size=f->max_stack;
+ state->node=node;
+ state->flow_stack_pos=flow_stack_pos;
+ state->stack.resize(p_stack_size);
+ copymem(state->stack.ptr(),p_stack,p_stack_size);
+ //step 2, run away, return directly
+ r_error.error=Variant::CallError::CALL_OK;
+
+
+#ifdef DEBUG_ENABLED
+ //will re-enter later, so exiting
+ if (ScriptDebugger::get_singleton()) {
+ VisualScriptLanguage::singleton->exit_function();
+ }
+#endif
+
+ return state;
+
+ }
+ }
+
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton()) {
+ // line
+ bool do_break=false;
+
+ if (ScriptDebugger::get_singleton()->get_lines_left()>0) {
+
+ if (ScriptDebugger::get_singleton()->get_depth()<=0)
+ ScriptDebugger::get_singleton()->set_lines_left( ScriptDebugger::get_singleton()->get_lines_left() -1 );
+ if (ScriptDebugger::get_singleton()->get_lines_left()<=0)
+ do_break=true;
+ }
+
+ if (ScriptDebugger::get_singleton()->is_breakpoint(current_node_id,source))
+ do_break=true;
+
+ if (do_break) {
+ VisualScriptLanguage::singleton->debug_break("Breakpoint",true);
+ }
+
+ ScriptDebugger::get_singleton()->line_poll();
+
+ }
+#endif
+ int output = ret & VisualScriptNodeInstance::STEP_MASK;
+
+ VSDEBUG("STEP RETURN: "+itos(ret));
+
+ if (ret & VisualScriptNodeInstance::STEP_EXIT_FUNCTION_BIT) {
+ if (node->get_working_memory_size()==0) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ error_str=RTR("Return value must be assigned to first element of node working memory! Fix your node please.");
+ error=true;
+ } else {
+ //assign from working memory, first element
+ return_value=*working_mem;
+ }
+
+ VSDEBUG("EXITING FUNCTION - VALUE "+String(return_value));
+ break; //exit function requested, bye
+ }
+
+ VisualScriptNodeInstance *next=NULL; //next node
+
+ if ( (ret==output || ret&VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) {
+ //if no exit bit was set, and has sequence outputs, guess next node
+ if (output<0 || output>=node->sequence_output_count) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ error_str=RTR("Node returned an invalid sequence output: ")+itos(output);
+ error=true;
+ break;
+ }
+
+ next = node->sequence_outputs[output];
+ if (next) {
+ VSDEBUG("GOT NEXT NODE - "+itos(next->get_id()));
+ } else {
+ VSDEBUG("GOT NEXT NODE - NULL");
+ }
+ }
+
+ if (flow_stack) {
+
+ //update flow stack pos (may have changed)
+ flow_stack[flow_stack_pos] = current_node_id;
+
+ //add stack push bit if requested
+ if (ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) {
+
+ flow_stack[flow_stack_pos] |= VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT;
+ sequence_bits[ node ->sequence_index ]=true; //remember sequence bit
+ VSDEBUG("NEXT SEQ - FLAG BIT");
+ } else {
+ sequence_bits[ node ->sequence_index ]=false; //forget sequence bit
+ VSDEBUG("NEXT SEQ - NORMAL");
+ }
+
+
+ if (ret & VisualScriptNodeInstance::STEP_FLAG_GO_BACK_BIT) {
+ //go back request
+
+ if (flow_stack_pos>0) {
+ flow_stack_pos--;
+ node = instances[ flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_MASK ];
+ VSDEBUG("NEXT IS GO BACK");
+ } else {
+ VSDEBUG("NEXT IS GO BACK, BUT NO NEXT SO EXIT");
+ break; //simply exit without value or error
+ }
+ } else if (next) {
+
+
+ if (sequence_bits[next->sequence_index]) {
+ // what happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front
+ // because each node has a working memory, we can't really do a sub-sequence
+ // as a result, the sequence will be restarted and the stack will roll back to find where this node
+ // started the sequence
+
+ bool found = false;
+
+ for(int i=flow_stack_pos;i>=0;i--) {
+
+
+ if ( (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK ) == next->get_id() ) {
+ flow_stack_pos=i; //roll back and remove bit
+ flow_stack[i]=next->get_id();
+ sequence_bits[next->sequence_index]=false;
+ found=true;
+ }
+ }
+
+ if (!found) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ error_str=RTR("Found sequence bit but not the node in the stack, report bug!");
+ error=true;
+ break;
+ }
+
+ node=next;
+ VSDEBUG("RE-ENTERED A LOOP, RETURNED STACK POS TO - "+itos(flow_stack_pos));
+
+ } else {
+ // check for stack overflow
+ if (flow_stack_pos+1 >= flow_max) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ error_str=RTR("Stack overflow with stack depth: ")+itos(output);
+ error=true;
+ break;
+ }
+
+ node = next;
+
+ flow_stack_pos++;
+ flow_stack[flow_stack_pos]=node->get_id();
+
+ VSDEBUG("INCREASE FLOW STACK");
+
+ }
+
+ } else {
+ //no next node, try to go back in stack to pushed bit
+
+ bool found = false;
+
+ for(int i=flow_stack_pos;i>=0;i--) {
+
+ VSDEBUG("FS "+itos(i)+" - "+itos(flow_stack[i]));
+ if (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT) {
+
+ node = instances[ flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK ];
+ flow_stack_pos=i;
+ found=true;
+ break;
+ }
+ }
+
+ if (!found) {
+ VSDEBUG("NO NEXT NODE, NO GO BACK, EXITING");
+ break; //done, couldn't find a push stack bit
+ }
+
+ VSDEBUG("NO NEXT NODE, GO BACK TO: "+itos(flow_stack_pos));
+
+ }
+ } else {
+
+ node=next; //stackless mode, simply assign next node
+ }
+
+ }
+
+
+
+ if (error) {
+
+ //error
+ // function, file, line, error, explanation
+ String err_file = script->get_path();
+ String err_func = p_method;
+ int err_line=current_node_id; //not a line but it works as one
+
+ if (node && (r_error.error!=Variant::CallError::CALL_ERROR_INVALID_METHOD || error_str==String())) {
+
+ if (r_error.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ int errorarg=r_error.argument;
+ error_str="Cannot convert argument "+itos(errorarg+1)+" to "+Variant::get_type_name(r_error.expected)+".";
+ } else if (r_error.error==Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+ error_str="Expected "+itos(r_error.argument)+" arguments.";
+ } else if (r_error.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+ error_str="Expected "+itos(r_error.argument)+" arguments.";
+ } else if (r_error.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) {
+ error_str="Invalid Call.";
+ } else if (r_error.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+ error_str="Instance is null";
+ }
+ }
+
+
+ //if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) {
+ // debugger break did not happen
+
+ if (!VisualScriptLanguage::singleton->debug_break(error_str,false)) {
+
+ _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,error_str.utf8().get_data(),ERR_HANDLER_SCRIPT);
+ }
+
+ //}
+ } else {
+
+
+ //return_value=
+ }
+
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton()) {
+ VisualScriptLanguage::singleton->exit_function();
+ }
+#endif
+
+ //clean up variant stack
+ for(int i=0;i<f->max_stack;i++) {
+ variant_stack[i].~Variant();
+ }
+
+
+ return return_value;
+}
+
+
+Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p_args, int p_argcount, Variant::CallError &r_error){
+
+ r_error.error=Variant::CallError::CALL_OK; //ok by default
+
+ Map<StringName,Function>::Element *F = functions.find(p_method);
+ if (!F) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+
+ VSDEBUG("CALLING: "+String(p_method));
+
+ Function *f=&F->get();
+
+ int total_stack_size=0;
+
+ total_stack_size+=f->max_stack*sizeof(Variant); //variants
+ total_stack_size+=f->node_count*sizeof(bool);
+ total_stack_size+=(max_input_args+max_output_args)*sizeof(Variant*); //arguments
+ total_stack_size+=f->flow_stack_size*sizeof(int); //flow
+
+ VSDEBUG("STACK SIZE: "+itos(total_stack_size));
+ VSDEBUG("STACK VARIANTS: : "+itos(f->max_stack));
+ VSDEBUG("SEQBITS: : "+itos(f->node_count));
+ VSDEBUG("MAX INPUT: "+itos(max_input_args));
+ VSDEBUG("MAX OUTPUT: "+itos(max_output_args));
+ VSDEBUG("FLOW STACK SIZE: "+itos(f->flow_stack_size));
+
+ void *stack = alloca(total_stack_size);
+
+ Variant *variant_stack=(Variant*)stack;
+ bool *sequence_bits = (bool*)(variant_stack + f->max_stack);
+ const Variant **input_args=(const Variant**)(sequence_bits+f->node_count);
+ Variant **output_args=(Variant**)(input_args + max_input_args);
+ int flow_max = f->flow_stack_size;
+ int* flow_stack = flow_max? (int*)(output_args + max_output_args) : (int*)NULL;
+
+ for(int i=0;i<f->node_count;i++) {
+ sequence_bits[i]=false; //all starts as false
+ }
+
+
+ Map<int,VisualScriptNodeInstance*>::Element *E = instances.find(f->node);
+ if (!E) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+
+ ERR_EXPLAIN("No VisualScriptFunction node in function!");
+ ERR_FAIL_V(Variant());
+ }
+
+ VisualScriptNodeInstance *node = E->get();
+
+
+ if (flow_stack) {
+ flow_stack[0]=node->get_id();
+ }
+
+ VSDEBUG("ARGUMENTS: "+itos(f->argument_count)=" RECEIVED: "+itos(p_argcount));
+
+ if (p_argcount<f->argument_count) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=node->get_input_port_count();
+
+ return Variant();
+ }
+
+ if (p_argcount>f->argument_count) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=node->get_input_port_count();
+
+ return Variant();
+ }
+
+ //allocate variant stack
+ for(int i=0;i<f->max_stack;i++) {
+ memnew_placement(&variant_stack[i],Variant);
+ }
+
+ //allocate function arguments (must be copied for yield to work properly)
+ for(int i=0;i<p_argcount;i++) {
+ variant_stack[i]=*p_args[i];
+ }
+
+ return _call_internal(p_method,stack,total_stack_size,node,0,false,r_error);
+
+
+}
+
+void VisualScriptInstance::notification(int p_notification){
+
+ //do nothing as this is called using virtual
+
+ Variant what=p_notification;
+ const Variant*whatp=&what;
+ Variant::CallError ce;
+ call(VisualScriptLanguage::singleton->notification,&whatp,1,ce); //do as call
+
+}
+
+Ref<Script> VisualScriptInstance::get_script() const{
+
+ return script;
+}
+
+ScriptInstance::RPCMode VisualScriptInstance::get_rpc_mode(const StringName& p_method) const {
+
+ const Map<StringName,VisualScript::Function>::Element *E = script->functions.find(p_method);
+ if (!E) {
+ return RPC_MODE_DISABLED;
+ }
+
+ if (E->get().function_id>=0 && E->get().nodes.has(E->get().function_id)) {
+
+ Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
+ if (vsf.is_valid()) {
+
+ return vsf->get_rpc_mode();
+ }
+ }
+
+ return RPC_MODE_DISABLED;
+}
+
+ScriptInstance::RPCMode VisualScriptInstance::get_rset_mode(const StringName& p_variable) const {
+
+ return RPC_MODE_DISABLED;
+}
+
+
+void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_owner) {
+
+ script=p_script;
+ owner=p_owner;
+ source=p_script->get_path();
+
+ max_input_args = 0;
+ max_output_args = 0;
+
+ if (p_owner->cast_to<Node>()) {
+ //turn on these if they exist and base is a node
+ Node* node = p_owner->cast_to<Node>();
+ if (p_script->functions.has("_process"))
+ node->set_process(true);
+ if (p_script->functions.has("_fixed_process"))
+ node->set_fixed_process(true);
+ if (p_script->functions.has("_input"))
+ node->set_process_input(true);
+ if (p_script->functions.has("_unhandled_input"))
+ node->set_process_unhandled_input(true);
+ if (p_script->functions.has("_unhandled_key_input"))
+ node->set_process_unhandled_key_input(true);
+ }
+
+ for(const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) {
+ variables[E->key()]=E->get().default_value;
+ }
+
+
+ for(const Map<StringName,VisualScript::Function>::Element *E=script->functions.front();E;E=E->next()) {
+
+ Function function;
+ function.node=E->get().function_id;
+ function.max_stack=0;
+ function.flow_stack_size=0;
+ function.node_count=0;
+ Map<StringName,int> local_var_indices;
+
+ if (function.node<0) {
+ VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No start node in function: "+String(E->key()));
+
+ ERR_CONTINUE( function.node < 0 );
+ }
+
+ {
+ Ref<VisualScriptFunction> func_node = script->get_node(E->key(),E->get().function_id);
+
+ if (func_node.is_null()) {
+ VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No VisualScriptFunction typed start node in function: "+String(E->key()));
+ }
+
+ ERR_CONTINUE( !func_node.is_valid() );
+
+ function.argument_count=func_node->get_argument_count();
+ function.max_stack+=function.argument_count;
+ function.flow_stack_size= func_node->is_stack_less() ? 0 : func_node->get_stack_size();
+
+ }
+
+ //multiple passes are required to set up this complex thing..
+
+
+
+
+ //first create the nodes
+ for (const Map<int,VisualScript::Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) {
+
+ Ref<VisualScriptNode> node = F->get().node;
+ VisualScriptNodeInstance *instance = node->instance(this); //create instance
+ ERR_FAIL_COND(!instance);
+
+ instance->base=node.ptr();
+
+ instance->id=F->key();
+ instance->input_port_count = node->get_input_value_port_count();
+ instance->output_port_count = node->get_output_value_port_count();
+ instance->sequence_output_count = node->get_output_sequence_port_count();
+ instance->sequence_index=function.node_count++;
+
+ if (instance->input_port_count) {
+ instance->input_ports = memnew_arr(int,instance->input_port_count);
+ for(int i=0;i<instance->input_port_count;i++) {
+ instance->input_ports[i]=-1; //if not assigned, will become default value
+ }
+ }
+
+ if (instance->output_port_count) {
+ instance->output_ports = memnew_arr(int,instance->output_port_count);
+ for(int i=0;i<instance->output_port_count;i++) {
+ instance->output_ports[i]=-1; //if not assigned, will output to trash
+ }
+ }
+
+ if (instance->sequence_output_count) {
+ instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance*,instance->sequence_output_count);
+ for(int i=0;i<instance->sequence_output_count;i++) {
+ instance->sequence_outputs[i]=NULL; //if it remains null, flow ends here
+ }
+ }
+
+ if (node->cast_to<VisualScriptLocalVar>()) {
+ //working memory is shared only for this node, for the same variables
+ Ref<VisualScriptLocalVar> vslv = node;
+
+ StringName var_name = String(vslv->get_var_name()).strip_edges();
+
+ if (!local_var_indices.has(var_name)) {
+ local_var_indices[var_name]=function.max_stack;
+ function.max_stack++;
+ }
+
+ instance->working_mem_idx=local_var_indices[var_name];
+
+ } else if (instance->get_working_memory_size()) {
+ instance->working_mem_idx = function.max_stack;
+ function.max_stack+=instance->get_working_memory_size();
+ } else {
+ instance->working_mem_idx=-1; //no working mem
+ }
+
+ max_input_args = MAX( max_input_args, instance->input_port_count );
+ max_output_args = MAX( max_output_args, instance->output_port_count );
+
+ instances[F->key()]=instance;
+
+
+ }
+
+ function.trash_pos = function.max_stack++; //create pos for trash
+
+ //second pass, do data connections
+
+ for(const Set<VisualScript::DataConnection>::Element *F=E->get().data_connections.front();F;F=F->next()) {
+
+ VisualScript::DataConnection dc = F->get();
+ ERR_CONTINUE(!instances.has(dc.from_node));
+ VisualScriptNodeInstance *from = instances[dc.from_node];
+ ERR_CONTINUE(!instances.has(dc.to_node));
+ VisualScriptNodeInstance *to = instances[dc.to_node];
+ ERR_CONTINUE(dc.from_port >= from->output_port_count);
+ ERR_CONTINUE(dc.to_port >= to->input_port_count);
+
+ if (from->output_ports[dc.from_port]==-1) {
+
+ int stack_pos = function.max_stack++;
+ from->output_ports[dc.from_port] = stack_pos;
+ }
+
+
+ if (from->is_output_port_unsequenced(dc.from_node)) {
+
+ //prepare an unsequenced read (must actually get the value from the output)
+ int stack_pos = function.max_stack++;
+
+ Function::UnsequencedGet uget;
+ uget.from=from;
+ uget.from_port=dc.from_port;
+ uget.to_stack=stack_pos;
+
+ to->input_ports[dc.to_port] = function.unsequenced_gets.size() | VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT;
+ function.unsequenced_gets.push_back(uget);
+
+ } else {
+
+ to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; //read from wherever the stack is
+ }
+
+ }
+
+ //third pass, do sequence connections
+
+ for(const Set<VisualScript::SequenceConnection>::Element *F=E->get().sequence_connections.front();F;F=F->next()) {
+
+ VisualScript::SequenceConnection sc = F->get();
+ ERR_CONTINUE(!instances.has(sc.from_node));
+ VisualScriptNodeInstance *from = instances[sc.from_node];
+ ERR_CONTINUE(!instances.has(sc.to_node));
+ VisualScriptNodeInstance *to = instances[sc.to_node];
+ ERR_CONTINUE(sc.from_output >= from->sequence_output_count);
+
+ from->sequence_outputs[sc.from_output]=to;
+
+ }
+
+ //fourth pass:
+ // 1) unassigned input ports to default values
+ // 2) connect unassigned output ports to trash
+
+
+ for (const Map<int,VisualScript::Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) {
+
+ ERR_CONTINUE(!instances.has(F->key()));
+
+ Ref<VisualScriptNode> node = F->get().node;
+ VisualScriptNodeInstance *instance = instances[F->key()];
+
+ // conect to default values
+ for(int i=0;i<instance->input_port_count;i++) {
+ if (instance->input_ports[i]==-1) {
+
+ //unassigned, connect to default val
+ instance->input_ports[i] = default_values.size() | VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT;
+ default_values.push_back( node->get_default_input_value(i) );
+ }
+ }
+
+ // conect to trash
+ for(int i=0;i<instance->output_port_count;i++) {
+ if (instance->output_ports[i]==-1) {
+ instance->output_ports[i] = function.trash_pos; //trash is same for all
+ }
+ }
+ }
+
+
+ functions[E->key()]=function;
+ }
+}
+
+ScriptLanguage *VisualScriptInstance::get_language(){
+
+ return VisualScriptLanguage::singleton;
+}
+
+
+VisualScriptInstance::VisualScriptInstance() {
+
+
+}
+
+VisualScriptInstance::~VisualScriptInstance() {
+
+ if (VisualScriptLanguage::singleton->lock)
+ VisualScriptLanguage::singleton->lock->lock();
+
+ script->instances.erase(owner);
+
+ if (VisualScriptLanguage::singleton->lock)
+ VisualScriptLanguage::singleton->lock->unlock();
+
+ for (Map<int,VisualScriptNodeInstance*>::Element *E=instances.front();E;E=E->next()) {
+ memdelete(E->get());
+ }
+}
+
+
+
+/////////////////////////////////////////////
+
+
+/////////////////////
+
+
+Variant VisualScriptFunctionState::_signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error) {
+
+ ERR_FAIL_COND_V(function==StringName(),Variant());
+
+#ifdef DEBUG_ENABLED
+ if (instance_id && !ObjectDB::get_instance(instance_id)) {
+ ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ ERR_FAIL_V(Variant());
+ }
+
+ if (script_id && !ObjectDB::get_instance(script_id)) {
+ ERR_EXPLAIN("Resumed after yield, but script is gone");
+ ERR_FAIL_V(Variant());
+ }
+#endif
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Array args;
+
+ if (p_argcount==0) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=1;
+ return Variant();
+ } else if (p_argcount==1) {
+ //noooneee, reserved for me, me and only me.
+ } else {
+
+ for(int i=0;i<p_argcount-1;i++) {
+ args.push_back(*p_args[i]);
+ }
+ }
+
+ Ref<VisualScriptFunctionState> self = *p_args[p_argcount-1]; //hi, I'm myself, needed this to remain alive.
+
+ if (self.is_null()) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=p_argcount-1;
+ r_error.expected=Variant::OBJECT;
+ return Variant();
+ }
+
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Variant *working_mem = ((Variant*)stack.ptr()) + working_mem_index;
+
+ *working_mem=args; //arguments go to working mem.
+
+ Variant ret = instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,true,r_error);
+ function=StringName(); //invalidate
+ return ret;
+}
+
+void VisualScriptFunctionState::connect_to_signal(Object* p_obj, const String& p_signal, Array p_binds) {
+
+ Vector<Variant> binds;
+ for(int i=0;i<p_binds.size();i++) {
+ binds.push_back(p_binds[i]);
+ }
+ binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing
+ p_obj->connect(p_signal,this,"_signal_callback",binds);
+}
+
+bool VisualScriptFunctionState::is_valid() const {
+
+ return function!=StringName();
+}
+
+Variant VisualScriptFunctionState::resume(Array p_args) {
+
+ ERR_FAIL_COND_V(function==StringName(),Variant());
+#ifdef DEBUG_ENABLED
+ if (instance_id && !ObjectDB::get_instance(instance_id)) {
+ ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ ERR_FAIL_V(Variant());
+ }
+
+ if (script_id && !ObjectDB::get_instance(script_id)) {
+ ERR_EXPLAIN("Resumed after yield, but script is gone");
+ ERR_FAIL_V(Variant());
+ }
+#endif
+
+ Variant::CallError r_error;
+ r_error.error=Variant::CallError::CALL_OK;
+
+ Variant *working_mem = ((Variant*)stack.ptr()) + working_mem_index;
+
+ *working_mem=p_args; //arguments go to working mem.
+
+ Variant ret= instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,true,r_error);
+ function=StringName(); //invalidate
+ return ret;
+}
+
+
+void VisualScriptFunctionState::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("connect_to_signal","obj","signals","args"),&VisualScriptFunctionState::connect_to_signal);
+ ObjectTypeDB::bind_method(_MD("resume:Array","args"),&VisualScriptFunctionState::resume,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("is_valid"),&VisualScriptFunctionState::is_valid);
+ ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback"));
+}
+
+VisualScriptFunctionState::VisualScriptFunctionState() {
+
+}
+
+VisualScriptFunctionState::~VisualScriptFunctionState() {
+
+ if (function!=StringName()) {
+ Variant *s = ((Variant*)stack.ptr());
+ for(int i=0;i<variant_stack_size;i++) {
+ s[i].~Variant();
+ }
+ }
+}
+
+
+
+
+
+///////////////////////////////////////////////
+
+String VisualScriptLanguage::get_name() const {
+
+ return "VisualScript";
+}
+
+/* LANGUAGE FUNCTIONS */
+void VisualScriptLanguage::init() {
+
+
+}
+String VisualScriptLanguage::get_type() const {
+
+ return "VisualScript";
+}
+String VisualScriptLanguage::get_extension() const {
+
+ return "vs";
+}
+Error VisualScriptLanguage::execute_file(const String& p_path) {
+
+ return OK;
+}
+void VisualScriptLanguage::finish() {
+
+
+}
+
+/* EDITOR FUNCTIONS */
+void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const {
+
+
+}
+void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
+
+
+}
+void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
+
+
+}
+Ref<Script> VisualScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const {
+
+ Ref<VisualScript> script;
+ script.instance();
+ script->set_instance_base_type(p_base_class_name);
+ return script;
+}
+bool VisualScriptLanguage::validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path,List<String> *r_functions) const {
+
+ return false;
+}
+Script *VisualScriptLanguage::create_script() const {
+
+ return memnew( VisualScript );
+}
+bool VisualScriptLanguage::has_named_classes() const {
+
+ return false;
+}
+int VisualScriptLanguage::find_function(const String& p_function,const String& p_code) const {
+
+ return -1;
+}
+String VisualScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const {
+
+ return String();
+}
+
+void VisualScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const {
+
+
+}
+void VisualScriptLanguage::add_global_constant(const StringName& p_variable,const Variant& p_value) {
+
+
+}
+
+
+/* DEBUGGER FUNCTIONS */
+
+
+
+bool VisualScriptLanguage::debug_break_parse(const String& p_file, int p_node,const String& p_error) {
+ //break because of parse error
+
+ if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) {
+
+ _debug_parse_err_node=p_node;
+ _debug_parse_err_file=p_file;
+ _debug_error=p_error;
+ ScriptDebugger::get_singleton()->debug(this,false);
+ return true;
+ } else {
+ return false;
+ }
+
+}
+
+bool VisualScriptLanguage::debug_break(const String& p_error,bool p_allow_continue) {
+
+ if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) {
+
+ _debug_parse_err_node=-1;
+ _debug_parse_err_file="";
+ _debug_error=p_error;
+ ScriptDebugger::get_singleton()->debug(this,p_allow_continue);
+ return true;
+ } else {
+ return false;
+ }
+
+}
+
+
+String VisualScriptLanguage::debug_get_error() const {
+
+ return _debug_error;
+}
+
+int VisualScriptLanguage::debug_get_stack_level_count() const {
+
+ if (_debug_parse_err_node>=0)
+ return 1;
+
+
+ return _debug_call_stack_pos;
+}
+int VisualScriptLanguage::debug_get_stack_level_line(int p_level) const {
+
+ if (_debug_parse_err_node>=0)
+ return _debug_parse_err_node;
+
+ ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,-1);
+
+ int l = _debug_call_stack_pos - p_level -1;
+
+ return *(_call_stack[l].current_id);
+
+}
+String VisualScriptLanguage::debug_get_stack_level_function(int p_level) const {
+
+ if (_debug_parse_err_node>=0)
+ return "";
+
+ ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,"");
+ int l = _debug_call_stack_pos - p_level -1;
+ return *_call_stack[l].function;
+}
+String VisualScriptLanguage::debug_get_stack_level_source(int p_level) const {
+
+ if (_debug_parse_err_node>=0)
+ return _debug_parse_err_file;
+
+ ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,"");
+ int l = _debug_call_stack_pos - p_level -1;
+ return _call_stack[l].instance->get_script_ptr()->get_path();
+
+}
+void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
+
+ if (_debug_parse_err_node>=0)
+ return;
+
+ ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+
+ int l = _debug_call_stack_pos - p_level -1;
+ const StringName *f = _call_stack[l].function;
+
+ ERR_FAIL_COND(!_call_stack[l].instance->functions.has(*f));
+ VisualScriptInstance::Function *func = &_call_stack[l].instance->functions[*f];
+
+ VisualScriptNodeInstance *node =_call_stack[l].instance->instances[*_call_stack[l].current_id];
+ ERR_FAIL_COND(!node);
+
+ p_locals->push_back("node_name");
+ p_values->push_back(node->get_base_node()->get_text());
+
+ for(int i=0;i<node->input_port_count;i++) {
+ String name = node->get_base_node()->get_input_value_port_info(i).name;
+ if (name==String()) {
+ name="in_"+itos(i);
+ }
+
+ p_locals->push_back("input/"+name);
+
+ //value is trickier
+
+ int in_from = node->input_ports[i];
+ int in_value = in_from&VisualScriptNodeInstance::INPUT_MASK;
+
+ if (in_from&VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
+ p_values->push_back(_call_stack[l].instance->default_values[in_value]);
+ } else if (in_from&VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT) {
+ p_values->push_back( _call_stack[l].stack[ func->unsequenced_gets[ in_value ].to_stack ] );
+ } else {
+ p_values->push_back( _call_stack[l].stack[ in_value] );
+ }
+ }
+
+ for(int i=0;i<node->output_port_count;i++) {
+
+ String name = node->get_base_node()->get_output_value_port_info(i).name;
+ if (name==String()) {
+ name="out_"+itos(i);
+ }
+
+ p_locals->push_back("output/"+name);
+
+ //value is trickier
+
+ int in_from = node->output_ports[i];
+ p_values->push_back( _call_stack[l].stack[ in_from] );
+
+ }
+
+ for(int i=0;i<node->get_working_memory_size();i++) {
+ p_locals->push_back("working_mem/mem_"+itos(i));
+ p_values->push_back( (*_call_stack[l].work_mem)[i]);
+ }
+
+/*
+ ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+
+
+ VisualFunction *f = _call_stack[l].function;
+
+ List<Pair<StringName,int> > locals;
+
+ f->debug_get_stack_member_state(*_call_stack[l].line,&locals);
+ for( List<Pair<StringName,int> >::Element *E = locals.front();E;E=E->next() ) {
+
+ p_locals->push_back(E->get().first);
+ p_values->push_back(_call_stack[l].stack[E->get().second]);
+ }
+*/
+}
+void VisualScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
+
+ if (_debug_parse_err_node>=0)
+ return;
+
+ ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+ int l = _debug_call_stack_pos - p_level -1;
+
+
+ Ref<VisualScript> vs = _call_stack[l].instance->get_script();
+ if (vs.is_null())
+ return;
+
+ List<StringName> vars;
+ vs->get_variable_list(&vars);
+ for (List<StringName>::Element *E=vars.front();E;E=E->next()) {
+ Variant v;
+ if (_call_stack[l].instance->get_variable(E->get(),&v)) {
+ p_members->push_back("variables/"+E->get());
+ p_values->push_back(v);
+ }
+ }
+}
+
+void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
+
+ //no globals are really reachable in gdscript
+}
+String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems,int p_max_depth) {
+
+ if (_debug_parse_err_node>=0)
+ return "";
+ return "";
+}
+
+
+
+void VisualScriptLanguage::reload_all_scripts() {
+
+
+}
+void VisualScriptLanguage::reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload) {
+
+
+}
+/* LOADER FUNCTIONS */
+
+void VisualScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("vs");
+
+}
+void VisualScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
+
+
+}
+void VisualScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_constants) const {
+
+
+}
+
+void VisualScriptLanguage::profiling_start() {
+
+
+}
+void VisualScriptLanguage::profiling_stop() {
+
+
+}
+
+int VisualScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,int p_info_max) {
+
+ return 0;
+}
+
+int VisualScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr,int p_info_max) {
+
+ return 0;
+}
+
+
+VisualScriptLanguage* VisualScriptLanguage::singleton=NULL;
+
+
+void VisualScriptLanguage::add_register_func(const String& p_name,VisualScriptNodeRegisterFunc p_func) {
+
+ ERR_FAIL_COND(register_funcs.has(p_name));
+ register_funcs[p_name]=p_func;
+}
+
+Ref<VisualScriptNode> VisualScriptLanguage::create_node_from_name(const String& p_name) {
+
+ ERR_FAIL_COND_V(!register_funcs.has(p_name),Ref<VisualScriptNode>());
+
+ return register_funcs[p_name](p_name);
+}
+
+void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) {
+
+ for (Map<String,VisualScriptNodeRegisterFunc>::Element *E=register_funcs.front();E;E=E->next()) {
+ r_names->push_back(E->key());
+ }
+}
+
+
+VisualScriptLanguage::VisualScriptLanguage() {
+
+ notification="_notification";
+ _get_output_port_unsequenced="_get_output_port_unsequenced";
+ _step="_step";
+ _subcall="_subcall";
+ singleton=this;
+#ifndef NO_THREADS
+ lock = Mutex::create();
+#endif
+
+
+ _debug_parse_err_node=-1;
+ _debug_parse_err_file="";
+ _debug_call_stack_pos=0;
+ int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024);
+ if (ScriptDebugger::get_singleton()) {
+ //debugging enabled!
+ _debug_max_call_stack = dmcs;
+ if (_debug_max_call_stack<1024)
+ _debug_max_call_stack=1024;
+ _call_stack = memnew_arr( CallLevel, _debug_max_call_stack+1 );
+
+ } else {
+ _debug_max_call_stack=0;
+ _call_stack=NULL;
+ }
+
+}
+
+VisualScriptLanguage::~VisualScriptLanguage() {
+
+ if (lock)
+ memdelete(lock);
+
+ if (_call_stack) {
+ memdelete_arr(_call_stack);
+ }
+ singleton=NULL;
+}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
new file mode 100644
index 0000000000..c9734d1b11
--- /dev/null
+++ b/modules/visual_script/visual_script.h
@@ -0,0 +1,607 @@
+#ifndef VSCRIPT_H
+#define VSCRIPT_H
+
+#include "script_language.h"
+#include "os/thread.h"
+
+class VisualScriptInstance;
+class VisualScriptNodeInstance;
+class VisualScript;
+
+class VisualScriptNode : public Resource {
+ OBJ_TYPE(VisualScriptNode,Resource)
+
+friend class VisualScript;
+
+ Set<VisualScript*> scripts_used;
+
+ Array default_input_values;
+ bool breakpoint;
+
+ void _set_default_input_values(Array p_values);
+ Array _get_default_input_values() const;
+
+ void validate_input_default_values();
+protected:
+
+ virtual bool _use_builtin_script() const { return false; }
+
+ void _notification(int p_what);
+ void ports_changed_notify();
+ static void _bind_methods();
+public:
+
+ Ref<VisualScript> get_visual_script() const;
+
+ virtual int get_output_sequence_port_count() const=0;
+ virtual bool has_input_sequence_port() const=0;
+
+ virtual String get_output_sequence_port_text(int p_port) const=0;
+
+ virtual int get_input_value_port_count() const=0;
+ virtual int get_output_value_port_count() const=0;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const=0;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const=0;
+
+ void set_default_input_value(int p_port,const Variant& p_value);
+ Variant get_default_input_value(int p_port) const;
+
+ virtual String get_caption() const=0;
+ virtual String get_text() const=0;
+ virtual String get_category() const=0;
+
+ //used by editor, this is not really saved
+ void set_breakpoint(bool p_breakpoint);
+ bool is_breakpoint() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance)=0;
+
+ VisualScriptNode();
+};
+
+
+class VisualScriptNodeInstance {
+friend class VisualScriptInstance;
+friend class VisualScriptLanguage; //for debugger
+
+
+ enum { //input argument addressing
+ INPUT_SHIFT=1<<24,
+ INPUT_MASK=INPUT_SHIFT-1,
+ INPUT_DEFAULT_VALUE_BIT=INPUT_SHIFT, // from unassigned input port, using default value (edited by user)
+ INPUT_UNSEQUENCED_READ_BIT=INPUT_SHIFT<<1, //from unsequenced read (requires calling a function, used for constants, variales, etc).
+ };
+
+
+ int id;
+ int sequence_index;
+ VisualScriptNodeInstance **sequence_outputs;
+ int sequence_output_count;
+ int *input_ports;
+ int input_port_count;
+ int *output_ports;
+ int output_port_count;
+ int working_mem_idx;
+
+ VisualScriptNode *base;
+
+public:
+
+ enum StartMode {
+ START_MODE_BEGIN_SEQUENCE,
+ START_MODE_CONTINUE_SEQUENCE,
+ START_MODE_RESUME_YIELD
+ };
+
+ enum {
+ STEP_SHIFT=1<<24,
+ STEP_MASK=STEP_SHIFT-1,
+ STEP_FLAG_PUSH_STACK_BIT=STEP_SHIFT, //push bit to stack
+ STEP_FLAG_GO_BACK_BIT=STEP_SHIFT<<1, //go back to previous node
+ STEP_NO_ADVANCE_BIT=STEP_SHIFT<<2, //do not advance past this node
+ STEP_EXIT_FUNCTION_BIT=STEP_SHIFT<<3, //return from function
+ STEP_YIELD_BIT=STEP_SHIFT<<4, //yield (will find VisualScriptFunctionState state in first working memory)
+
+ FLOW_STACK_PUSHED_BIT=1<<30, //in flow stack, means bit was pushed (must go back here if end of sequence)
+ FLOW_STACK_MASK=FLOW_STACK_PUSHED_BIT-1
+
+ };
+
+ _FORCE_INLINE_ int get_input_port_count() const { return input_port_count; }
+ _FORCE_INLINE_ int get_output_port_count() const { return output_port_count; }
+ _FORCE_INLINE_ int get_sequence_output_count() const { return sequence_output_count; }
+
+ _FORCE_INLINE_ int get_id() const { return id; }
+
+ virtual int get_working_memory_size() const { return 0; }
+
+ //unsequenced ports are those that can return a value even if no sequence happened through them, used for constants, variables, etc.
+ virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str)=0; //do a step, return which sequence port to go out
+
+ Ref<VisualScriptNode> get_base_node() { return Ref<VisualScriptNode>( base ); }
+
+ VisualScriptNodeInstance();
+ virtual ~VisualScriptNodeInstance();
+};
+
+
+class VisualScript : public Script {
+
+ OBJ_TYPE( VisualScript, Script )
+
+ RES_BASE_EXTENSION("vs");
+
+public:
+
+ struct SequenceConnection {
+
+ union {
+
+ struct {
+ uint64_t from_node : 24;
+ uint64_t from_output : 16;
+ uint64_t to_node : 24;
+ };
+ uint64_t id;
+ };
+
+ bool operator<(const SequenceConnection& p_connection) const {
+
+ return id<p_connection.id;
+ }
+ };
+
+ struct DataConnection {
+
+ union {
+
+ struct {
+ uint64_t from_node : 24;
+ uint64_t from_port : 8;
+ uint64_t to_node : 24;
+ uint64_t to_port : 8;
+ };
+ uint64_t id;
+ };
+
+ bool operator<(const DataConnection& p_connection) const {
+
+ return id<p_connection.id;
+ }
+ };
+
+
+private:
+friend class VisualScriptInstance;
+
+ StringName base_type;
+ struct Argument {
+ String name;
+ Variant::Type type;
+ };
+
+ struct Function {
+ struct NodeData {
+ Point2 pos;
+ Ref<VisualScriptNode> node;
+ };
+
+ Map<int,NodeData> nodes;
+
+ Set<SequenceConnection> sequence_connections;
+
+ Set<DataConnection> data_connections;
+
+ int function_id;
+
+ Vector2 scroll;
+
+
+ Function() { function_id=-1; }
+
+ };
+
+ struct Variable {
+ PropertyInfo info;
+ Variant default_value;
+ };
+
+
+
+ Map<StringName,Function> functions;
+ Map<StringName,Variable> variables;
+ Map<StringName,StringName> script_variable_remap;
+ Map<StringName,Vector<Argument> > custom_signals;
+
+ Map<Object*,VisualScriptInstance*> instances;
+
+#ifdef TOOLS_ENABLED
+ Set<PlaceHolderScriptInstance*> placeholders;
+ //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
+ virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
+ void _update_placeholders();
+#endif
+
+ void _set_variable_info(const StringName& p_name,const Dictionary& p_info);
+ Dictionary _get_variable_info(const StringName& p_name) const;
+
+
+ void _set_data(const Dictionary& p_data);
+ Dictionary _get_data() const;
+
+protected:
+
+ void _node_ports_changed(int p_id);
+ static void _bind_methods();
+public:
+
+
+ void add_function(const StringName& p_name);
+ bool has_function(const StringName& p_name) const;
+ void remove_function(const StringName& p_name);
+ void rename_function(const StringName& p_name,const StringName& p_new_name);
+ void set_function_scroll(const StringName& p_name, const Vector2& p_scroll);
+ Vector2 get_function_scroll(const StringName& p_name) const;
+ void get_function_list(List<StringName> *r_functions) const;
+ int get_function_node_id(const StringName& p_name) const;
+
+
+ void add_node(const StringName& p_func,int p_id,const Ref<VisualScriptNode>& p_node,const Point2& p_pos=Point2());
+ void remove_node(const StringName& p_func,int p_id);
+ bool has_node(const StringName& p_func,int p_id) const;
+ Ref<VisualScriptNode> get_node(const StringName& p_func,int p_id) const;
+ void set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos);
+ Point2 get_node_pos(const StringName& p_func,int p_id) const;
+ void get_node_list(const StringName& p_func,List<int> *r_nodes) const;
+
+ void sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node);
+ void sequence_disconnect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node);
+ bool has_sequence_connection(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node) const;
+ void get_sequence_connection_list(const StringName& p_func,List<SequenceConnection> *r_connection) const;
+
+ void data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port);
+ void data_disconnect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port);
+ bool has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const;
+ void get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const;
+ bool is_input_value_port_connected(const StringName& p_name,int p_node,int p_port) const;
+
+ void add_variable(const StringName& p_name,const Variant& p_default_value=Variant());
+ bool has_variable(const StringName& p_name) const;
+ void remove_variable(const StringName& p_name);
+ void set_variable_default_value(const StringName& p_name,const Variant& p_value);
+ Variant get_variable_default_value(const StringName& p_name) const;
+ void set_variable_info(const StringName& p_name,const PropertyInfo& p_info);
+ PropertyInfo get_variable_info(const StringName& p_name) const;
+ void get_variable_list(List<StringName> *r_variables) const;
+ void rename_variable(const StringName& p_name,const StringName& p_new_name);
+
+
+ void add_custom_signal(const StringName& p_name);
+ bool has_custom_signal(const StringName& p_name) const;
+ void custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index=-1);
+ void custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type);
+ Variant::Type custom_signal_get_argument_type(const StringName& p_func,int p_argidx) const;
+ void custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name);
+ String custom_signal_get_argument_name(const StringName& p_func,int p_argidx) const;
+ void custom_signal_remove_argument(const StringName& p_func,int p_argidx);
+ int custom_signal_get_argument_count(const StringName& p_func) const;
+ void custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx);
+ void remove_custom_signal(const StringName& p_name);
+ void rename_custom_signal(const StringName& p_name,const StringName& p_new_name);
+
+ void get_custom_signal_list(List<StringName> *r_custom_signals) const;
+
+ int get_available_id() const;
+
+ void set_instance_base_type(const StringName& p_type);
+
+ virtual bool can_instance() const;
+
+ virtual Ref<Script> get_base_script() const;
+ virtual StringName get_instance_base_type() const;
+ virtual ScriptInstance* instance_create(Object *p_this);
+ virtual bool instance_has(const Object *p_this) const;
+
+
+ virtual bool has_source_code() const;
+ virtual String get_source_code() const;
+ virtual void set_source_code(const String& p_code);
+ virtual Error reload(bool p_keep_state=false);
+
+ virtual bool is_tool() const;
+
+ virtual String get_node_type() const;
+
+ virtual ScriptLanguage *get_language() const;
+
+ virtual bool has_script_signal(const StringName& p_signal) const;
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
+
+ virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const;
+ virtual void get_script_method_list(List<MethodInfo> *p_list) const;
+
+ virtual bool has_method(const StringName& p_method) const;
+ virtual MethodInfo get_method_info(const StringName& p_method) const;
+
+ virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
+
+
+ VisualScript();
+ ~VisualScript();
+};
+
+
+class VisualScriptInstance : public ScriptInstance {
+ Object *owner;
+ Ref<VisualScript> script;
+
+ Map<StringName,Variant> variables; //using variable path, not script
+ Map<int,VisualScriptNodeInstance*> instances;
+
+ struct Function {
+ int node;
+ int max_stack;
+ int trash_pos;
+ int return_pos;
+ int flow_stack_size;
+ int node_count;
+ int argument_count;
+ bool valid;
+
+ struct UnsequencedGet {
+ VisualScriptNodeInstance* from;
+ int from_port;
+ int to_stack;
+ };
+
+ Vector<UnsequencedGet> unsequenced_gets;
+
+ };
+
+ Map<StringName,Function> functions;
+
+ Vector<Variant> default_values;
+ int max_input_args,max_output_args;
+
+ StringName source;
+
+ Variant _call_internal(const StringName& p_method, void* p_stack,int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, bool p_resuming_yield,Variant::CallError &r_error);
+
+
+ //Map<StringName,Function> functions;
+friend class VisualScriptFunctionState; //for yield
+friend class VisualScriptLanguage; //for debugger
+public:
+ virtual bool set(const StringName& p_name, const Variant& p_value);
+ virtual bool get(const StringName& p_name, Variant &r_ret) const;
+ virtual void get_property_list(List<PropertyInfo> *p_properties) const;
+ virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const;
+
+ virtual void get_method_list(List<MethodInfo> *p_list) const;
+ virtual bool has_method(const StringName& p_method) const;
+ virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error);
+ virtual void notification(int p_notification);
+
+ bool set_variable(const StringName& p_variable,const Variant& p_value) {
+
+ Map<StringName,Variant>::Element *E=variables.find(p_variable);
+ if (!E)
+ return false;
+
+ E->get()=p_value;
+ return true;
+ }
+
+ bool get_variable(const StringName& p_variable,Variant* r_variable) const {
+
+ const Map<StringName,Variant>::Element *E=variables.find(p_variable);
+ if (!E)
+ return false;
+
+ *r_variable=E->get();
+ return true;
+
+ }
+
+ virtual Ref<Script> get_script() const;
+
+ _FORCE_INLINE_ VisualScript *get_script_ptr() { return script.ptr(); }
+ _FORCE_INLINE_ Object *get_owner_ptr() { return owner; }
+
+ void create(const Ref<VisualScript>& p_script,Object *p_owner);
+
+ virtual ScriptLanguage *get_language();
+
+ virtual RPCMode get_rpc_mode(const StringName& p_method) const;
+ virtual RPCMode get_rset_mode(const StringName& p_variable) const;
+
+ VisualScriptInstance();
+ ~VisualScriptInstance();
+};
+
+
+class VisualScriptFunctionState : public Reference {
+
+ OBJ_TYPE(VisualScriptFunctionState,Reference);
+friend class VisualScriptInstance;
+
+ ObjectID instance_id;
+ ObjectID script_id;
+ VisualScriptInstance *instance;
+ StringName function;
+ Vector<uint8_t> stack;
+ int working_mem_index;
+ int variant_stack_size;
+ VisualScriptNodeInstance *node;
+ int flow_stack_pos;
+
+ Variant _signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
+protected:
+ static void _bind_methods();
+public:
+
+ void connect_to_signal(Object* p_obj,const String& p_signal,Array p_binds);
+ bool is_valid() const;
+ Variant resume(Array p_args);
+ VisualScriptFunctionState();
+ ~VisualScriptFunctionState();
+};
+
+
+typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String& p_type);
+
+class VisualScriptLanguage : public ScriptLanguage {
+
+ Map<String,VisualScriptNodeRegisterFunc> register_funcs;
+
+ struct CallLevel {
+
+ Variant *stack;
+ Variant **work_mem;
+ const StringName *function;
+ VisualScriptInstance *instance;
+ int *current_id;
+
+ };
+
+
+ int _debug_parse_err_node;
+ String _debug_parse_err_file;
+ String _debug_error;
+ int _debug_call_stack_pos;
+ int _debug_max_call_stack;
+ CallLevel *_call_stack;
+
+public:
+ StringName notification;
+ StringName _get_output_port_unsequenced;
+ StringName _step;
+ StringName _subcall;
+
+ static VisualScriptLanguage* singleton;
+
+ Mutex *lock;
+
+ bool debug_break(const String& p_error,bool p_allow_continue=true);
+ bool debug_break_parse(const String& p_file, int p_node,const String& p_error);
+
+ _FORCE_INLINE_ void enter_function(VisualScriptInstance *p_instance,const StringName* p_function, Variant *p_stack, Variant **p_work_mem,int *current_id) {
+
+ if (Thread::get_main_ID()!=Thread::get_caller_ID())
+ return; //no support for other threads than main for now
+
+ if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0)
+ ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() +1 );
+
+ if (_debug_call_stack_pos >= _debug_max_call_stack) {
+ //stack overflow
+ _debug_error="Stack Overflow (Stack Size: "+itos(_debug_max_call_stack)+")";
+ ScriptDebugger::get_singleton()->debug(this);
+ return;
+ }
+
+ _call_stack[_debug_call_stack_pos].stack=p_stack;
+ _call_stack[_debug_call_stack_pos].instance=p_instance;
+ _call_stack[_debug_call_stack_pos].function=p_function;
+ _call_stack[_debug_call_stack_pos].work_mem=p_work_mem;
+ _call_stack[_debug_call_stack_pos].current_id=current_id;
+ _debug_call_stack_pos++;
+ }
+
+ _FORCE_INLINE_ void exit_function() {
+
+ if (Thread::get_main_ID()!=Thread::get_caller_ID())
+ return; //no support for other threads than main for now
+
+ if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0)
+ ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() -1 );
+
+ if (_debug_call_stack_pos==0) {
+
+ _debug_error="Stack Underflow (Engine Bug)";
+ ScriptDebugger::get_singleton()->debug(this);
+ return;
+ }
+
+ _debug_call_stack_pos--;
+ }
+
+ //////////////////////////////////////
+
+ virtual String get_name() const;
+
+ /* LANGUAGE FUNCTIONS */
+ virtual void init();
+ virtual String get_type() const;
+ virtual String get_extension() const;
+ virtual Error execute_file(const String& p_path) ;
+ virtual void finish();
+
+ /* EDITOR FUNCTIONS */
+ virtual void get_reserved_words(List<String> *p_words) const;
+ virtual void get_comment_delimiters(List<String> *p_delimiters) const;
+ virtual void get_string_delimiters(List<String> *p_delimiters) const;
+ virtual Ref<Script> get_template(const String& p_class_name, const String& p_base_class_name) const;
+ virtual bool validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path="",List<String> *r_functions=NULL) const;
+ virtual Script *create_script() const;
+ virtual bool has_named_classes() const;
+ virtual int find_function(const String& p_function,const String& p_code) const;
+ virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
+ virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const;
+ virtual void add_global_constant(const StringName& p_variable,const Variant& p_value);
+
+
+ /* DEBUGGER FUNCTIONS */
+
+ virtual String debug_get_error() const;
+ virtual int debug_get_stack_level_count() const;
+ virtual int debug_get_stack_level_line(int p_level) const;
+ virtual String debug_get_stack_level_function(int p_level) const;
+ virtual String debug_get_stack_level_source(int p_level) const;
+ virtual void debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
+ virtual void debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
+ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
+ virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1);
+
+
+ virtual void reload_all_scripts();
+ virtual void reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload);
+ /* LOADER FUNCTIONS */
+
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual void get_public_functions(List<MethodInfo> *p_functions) const;
+ virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const;
+
+ virtual void profiling_start();
+ virtual void profiling_stop();
+
+ virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr,int p_info_max);
+ virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr,int p_info_max);
+
+ void add_register_func(const String& p_name,VisualScriptNodeRegisterFunc p_func);
+ Ref<VisualScriptNode> create_node_from_name(const String& p_name);
+ void get_registered_node_names(List<String> *r_names);
+
+
+ VisualScriptLanguage();
+ ~VisualScriptLanguage();
+
+};
+
+//aid for registering
+template<class T>
+static Ref<VisualScriptNode> create_node_generic(const String& p_name) {
+
+ Ref<T> node;
+ node.instance();
+ return node;
+}
+
+
+
+#endif // VSCRIPT_H
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
new file mode 100644
index 0000000000..e813d9ea84
--- /dev/null
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -0,0 +1,1186 @@
+#include "visual_script_builtin_funcs.h"
+#include "math_funcs.h"
+#include "object_type_db.h"
+#include "reference.h"
+#include "func_ref.h"
+#include "os/os.h"
+#include "variant_parser.h"
+#include "io/marshalls.h"
+
+const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX]={
+ "sin",
+ "cos",
+ "tan",
+ "sinh",
+ "cosh",
+ "tanh",
+ "asin",
+ "acos",
+ "atan",
+ "atan2",
+ "sqrt",
+ "fmod",
+ "fposmod",
+ "floor",
+ "ceil",
+ "round",
+ "abs",
+ "sign",
+ "pow",
+ "log",
+ "exp",
+ "is_nan",
+ "is_inf",
+ "ease",
+ "decimals",
+ "stepify",
+ "lerp",
+ "dectime",
+ "randomize",
+ "randi",
+ "randf",
+ "rand_range",
+ "seed",
+ "rand_seed",
+ "deg2rad",
+ "rad2deg",
+ "linear2db",
+ "db2linear",
+ "max",
+ "min",
+ "clamp",
+ "nearest_po2",
+ "weakref",
+ "funcref",
+ "convert",
+ "typeof",
+ "type_exists",
+ "str",
+ "print",
+ "printerr",
+ "printraw",
+ "var2str",
+ "str2var",
+ "var2bytes",
+ "bytes2var",
+};
+
+
+
+int VisualScriptBuiltinFunc::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptBuiltinFunc::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptBuiltinFunc::get_input_value_port_count() const{
+
+
+ switch(func) {
+
+ case MATH_RANDOMIZE:
+ case MATH_RAND:
+ case MATH_RANDF:
+ return 0;
+ case MATH_SIN:
+ case MATH_COS:
+ case MATH_TAN:
+ case MATH_SINH:
+ case MATH_COSH:
+ case MATH_TANH:
+ case MATH_ASIN:
+ case MATH_ACOS:
+ case MATH_ATAN:
+ case MATH_SQRT:
+ case MATH_FLOOR:
+ case MATH_CEIL:
+ case MATH_ROUND:
+ case MATH_ABS:
+ case MATH_SIGN:
+ case MATH_LOG:
+ case MATH_EXP:
+ case MATH_ISNAN:
+ case MATH_ISINF:
+ case MATH_DECIMALS:
+ case MATH_SEED:
+ case MATH_RANDSEED:
+ case MATH_DEG2RAD:
+ case MATH_RAD2DEG:
+ case MATH_LINEAR2DB:
+ case MATH_DB2LINEAR:
+ case LOGIC_NEAREST_PO2:
+ case OBJ_WEAKREF:
+ case TYPE_OF:
+ case TEXT_STR:
+ case TEXT_PRINT:
+ case TEXT_PRINTERR:
+ case TEXT_PRINTRAW:
+ case VAR_TO_STR:
+ case STR_TO_VAR:
+ case VAR_TO_BYTES:
+ case BYTES_TO_VAR:
+ case TYPE_EXISTS:
+ return 1;
+ case MATH_ATAN2:
+ case MATH_FMOD:
+ case MATH_FPOSMOD:
+ case MATH_POW:
+ case MATH_EASE:
+ case MATH_STEPIFY:
+ case MATH_RANDOM:
+ case LOGIC_MAX:
+ case LOGIC_MIN:
+ case FUNC_FUNCREF:
+ case TYPE_CONVERT:
+ return 2;
+ case MATH_LERP:
+ case MATH_DECTIME:
+ case LOGIC_CLAMP:
+ return 3;
+ case FUNC_MAX:{}
+
+ }
+ return 0;
+}
+int VisualScriptBuiltinFunc::get_output_value_port_count() const{
+
+ switch(func) {
+ case MATH_RANDOMIZE:
+ case TEXT_PRINT:
+ case TEXT_PRINTERR:
+ case TEXT_PRINTRAW:
+ case MATH_SEED:
+ return 0;
+ case MATH_RANDSEED:
+ return 2;
+ default:
+ return 1;
+ }
+
+ return 1;
+}
+
+String VisualScriptBuiltinFunc::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const{
+
+ switch(func) {
+
+ case MATH_SIN:
+ case MATH_COS:
+ case MATH_TAN:
+ case MATH_SINH:
+ case MATH_COSH:
+ case MATH_TANH:
+ case MATH_ASIN:
+ case MATH_ACOS:
+ case MATH_ATAN:
+ case MATH_ATAN2:
+ case MATH_SQRT: {
+ return PropertyInfo(Variant::REAL,"num");
+ } break;
+ case MATH_FMOD:
+ case MATH_FPOSMOD: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"x");
+ else
+ return PropertyInfo(Variant::REAL,"y");
+ } break;
+ case MATH_FLOOR:
+ case MATH_CEIL:
+ case MATH_ROUND:
+ case MATH_ABS:
+ case MATH_SIGN: {
+ return PropertyInfo(Variant::REAL,"num");
+
+ } break;
+
+ case MATH_POW: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"x");
+ else
+ return PropertyInfo(Variant::REAL,"y");
+ } break;
+ case MATH_LOG:
+ case MATH_EXP:
+ case MATH_ISNAN:
+ case MATH_ISINF: {
+ return PropertyInfo(Variant::REAL,"num");
+ } break;
+ case MATH_EASE: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"s");
+ else
+ return PropertyInfo(Variant::REAL,"curve");
+ } break;
+ case MATH_DECIMALS: {
+ return PropertyInfo(Variant::REAL,"step");
+ } break;
+ case MATH_STEPIFY: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"s");
+ else
+ return PropertyInfo(Variant::REAL,"steps");
+ } break;
+ case MATH_LERP: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"from");
+ else if (p_idx==1)
+ return PropertyInfo(Variant::REAL,"to");
+ else
+ return PropertyInfo(Variant::REAL,"weight");
+
+ } break;
+ case MATH_DECTIME: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"value");
+ else if (p_idx==1)
+ return PropertyInfo(Variant::REAL,"amount");
+ else
+ return PropertyInfo(Variant::REAL,"step");
+ } break;
+ case MATH_RANDOMIZE: {
+
+ } break;
+ case MATH_RAND: {
+
+ } break;
+ case MATH_RANDF: {
+
+ } break;
+ case MATH_RANDOM: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"from");
+ else
+ return PropertyInfo(Variant::REAL,"to");
+ } break;
+ case MATH_SEED: {
+ return PropertyInfo(Variant::INT,"seed");
+ } break;
+ case MATH_RANDSEED: {
+ return PropertyInfo(Variant::INT,"seed");
+ } break;
+ case MATH_DEG2RAD: {
+ return PropertyInfo(Variant::REAL,"deg");
+ } break;
+ case MATH_RAD2DEG: {
+ return PropertyInfo(Variant::REAL,"rad");
+ } break;
+ case MATH_LINEAR2DB: {
+ return PropertyInfo(Variant::REAL,"nrg");
+ } break;
+ case MATH_DB2LINEAR: {
+ return PropertyInfo(Variant::REAL,"db");
+ } break;
+ case LOGIC_MAX: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"a");
+ else
+ return PropertyInfo(Variant::REAL,"b");
+ } break;
+ case LOGIC_MIN: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"a");
+ else
+ return PropertyInfo(Variant::REAL,"b");
+ } break;
+ case LOGIC_CLAMP: {
+ if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"a");
+ else if (p_idx==0)
+ return PropertyInfo(Variant::REAL,"min");
+ else
+ return PropertyInfo(Variant::REAL,"max");
+ } break;
+ case LOGIC_NEAREST_PO2: {
+ return PropertyInfo(Variant::INT,"num");
+ } break;
+ case OBJ_WEAKREF: {
+
+ return PropertyInfo(Variant::OBJECT,"source");
+
+ } break;
+ case FUNC_FUNCREF: {
+
+ if (p_idx==0)
+ return PropertyInfo(Variant::OBJECT,"instance");
+ else
+ return PropertyInfo(Variant::STRING,"funcname");
+
+ } break;
+ case TYPE_CONVERT: {
+
+ if (p_idx==0)
+ return PropertyInfo(Variant::NIL,"what");
+ else
+ return PropertyInfo(Variant::STRING,"type");
+ } break;
+ case TYPE_OF: {
+ return PropertyInfo(Variant::NIL,"what");
+
+ } break;
+ case TYPE_EXISTS: {
+
+ return PropertyInfo(Variant::STRING,"type");
+
+ } break;
+ case TEXT_STR: {
+
+ return PropertyInfo(Variant::NIL,"value");
+
+
+ } break;
+ case TEXT_PRINT: {
+
+ return PropertyInfo(Variant::NIL,"value");
+
+ } break;
+ case TEXT_PRINTERR: {
+ return PropertyInfo(Variant::NIL,"value");
+
+ } break;
+ case TEXT_PRINTRAW: {
+
+ return PropertyInfo(Variant::NIL,"value");
+
+ } break;
+ case VAR_TO_STR: {
+ return PropertyInfo(Variant::NIL,"var");
+
+ } break;
+ case STR_TO_VAR: {
+
+ return PropertyInfo(Variant::STRING,"string");
+ } break;
+ case VAR_TO_BYTES: {
+ return PropertyInfo(Variant::NIL,"var");
+
+ } break;
+ case BYTES_TO_VAR: {
+
+ return PropertyInfo(Variant::RAW_ARRAY,"bytes");
+ } break;
+ case FUNC_MAX:{}
+ }
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) const{
+
+ Variant::Type t=Variant::NIL;
+ switch(func) {
+
+ case MATH_SIN:
+ case MATH_COS:
+ case MATH_TAN:
+ case MATH_SINH:
+ case MATH_COSH:
+ case MATH_TANH:
+ case MATH_ASIN:
+ case MATH_ACOS:
+ case MATH_ATAN:
+ case MATH_ATAN2:
+ case MATH_SQRT:
+ case MATH_FMOD:
+ case MATH_FPOSMOD:
+ case MATH_FLOOR:
+ case MATH_CEIL: {
+ t=Variant::REAL;
+ } break;
+ case MATH_ROUND: {
+ t=Variant::INT;
+ } break;
+ case MATH_ABS: {
+ t=Variant::NIL;
+ } break;
+ case MATH_SIGN: {
+ t=Variant::NIL;
+ } break;
+ case MATH_POW:
+ case MATH_LOG:
+ case MATH_EXP: {
+ t=Variant::REAL;
+ } break;
+ case MATH_ISNAN:
+ case MATH_ISINF: {
+ t=Variant::BOOL;
+ } break;
+ case MATH_EASE: {
+ t=Variant::REAL;
+ } break;
+ case MATH_DECIMALS: {
+ t=Variant::INT;
+ } break;
+ case MATH_STEPIFY:
+ case MATH_LERP:
+ case MATH_DECTIME: {
+ t=Variant::REAL;
+
+ } break;
+ case MATH_RANDOMIZE: {
+
+ } break;
+ case MATH_RAND: {
+
+ t=Variant::INT;
+ } break;
+ case MATH_RANDF:
+ case MATH_RANDOM: {
+ t=Variant::REAL;
+ } break;
+ case MATH_SEED: {
+
+ } break;
+ case MATH_RANDSEED: {
+
+ if (p_idx==0)
+ return PropertyInfo(Variant::INT,"rnd");
+ else
+ return PropertyInfo(Variant::INT,"seed");
+ } break;
+ case MATH_DEG2RAD:
+ case MATH_RAD2DEG:
+ case MATH_LINEAR2DB:
+ case MATH_DB2LINEAR: {
+ t=Variant::REAL;
+ } break;
+ case LOGIC_MAX:
+ case LOGIC_MIN:
+ case LOGIC_CLAMP: {
+
+
+ } break;
+
+ case LOGIC_NEAREST_PO2: {
+ t=Variant::NIL;
+ } break;
+ case OBJ_WEAKREF: {
+
+ t=Variant::OBJECT;
+
+ } break;
+ case FUNC_FUNCREF: {
+
+ t=Variant::OBJECT;
+
+ } break;
+ case TYPE_CONVERT: {
+
+
+
+ } break;
+ case TYPE_OF: {
+ t=Variant::INT;
+
+ } break;
+ case TYPE_EXISTS: {
+
+ t=Variant::BOOL;
+
+ } break;
+ case TEXT_STR: {
+
+ t=Variant::STRING;
+
+ } break;
+ case TEXT_PRINT: {
+
+
+ } break;
+ case TEXT_PRINTERR: {
+
+ } break;
+ case TEXT_PRINTRAW: {
+
+ } break;
+ case VAR_TO_STR: {
+ t=Variant::STRING;
+ } break;
+ case STR_TO_VAR: {
+
+ } break;
+ case VAR_TO_BYTES: {
+ t=Variant::RAW_ARRAY;
+
+ } break;
+ case BYTES_TO_VAR: {
+
+
+ } break;
+ case FUNC_MAX:{}
+ }
+
+ return PropertyInfo(t,"");
+}
+
+String VisualScriptBuiltinFunc::get_caption() const {
+
+ return "BuiltinFunc";
+}
+
+String VisualScriptBuiltinFunc::get_text() const {
+
+ return func_name[func];
+}
+
+void VisualScriptBuiltinFunc::set_func(BuiltinFunc p_which) {
+
+ ERR_FAIL_INDEX(p_which,FUNC_MAX);
+ func=p_which;
+ _change_notify();
+ ports_changed_notify();
+}
+
+VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() {
+ return func;
+}
+
+
+#define VALIDATE_ARG_NUM(m_arg) \
+ if (!p_inputs[m_arg]->is_num()) {\
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\
+ r_error.argument=m_arg;\
+ r_error.expected=Variant::REAL;\
+ return 0;\
+ }
+
+class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptBuiltinFunc *node;
+ VisualScriptInstance *instance;
+
+ VisualScriptBuiltinFunc::BuiltinFunc func;
+
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ switch(func) {
+ case VisualScriptBuiltinFunc::MATH_SIN: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::sin(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_COS: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::cos(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_TAN: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::tan(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_SINH: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::sinh(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_COSH: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::cosh(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_TANH: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::tanh(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ASIN: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::asin(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ACOS: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::acos(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ATAN: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::atan(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ATAN2: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *p_outputs[0]=Math::atan2(*p_inputs[0],*p_inputs[1]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_SQRT: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::sqrt(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_FMOD: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *p_outputs[0]=Math::fmod(*p_inputs[0],*p_inputs[1]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_FPOSMOD: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_FLOOR: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::floor(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_CEIL: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::ceil(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ROUND: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::round(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ABS: {
+
+ if (p_inputs[0]->get_type()==Variant::INT) {
+
+ int64_t i = *p_inputs[0];
+ *p_outputs[0]=ABS(i);
+ } else if (p_inputs[0]->get_type()==Variant::REAL) {
+
+ real_t r = *p_inputs[0];
+ *p_outputs[0]=Math::abs(r);
+ } else {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::REAL;
+
+ }
+ } break;
+ case VisualScriptBuiltinFunc::MATH_SIGN: {
+
+ if (p_inputs[0]->get_type()==Variant::INT) {
+
+ int64_t i = *p_inputs[0];
+ *p_outputs[0]= i < 0 ? -1 : ( i > 0 ? +1 : 0);
+ } else if (p_inputs[0]->get_type()==Variant::REAL) {
+
+ real_t r = *p_inputs[0];
+ *p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0);
+ } else {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::REAL;
+
+ }
+ } break;
+ case VisualScriptBuiltinFunc::MATH_POW: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *p_outputs[0]=Math::pow(*p_inputs[0],*p_inputs[1]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_LOG: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::log(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_EXP: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::exp(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ISNAN: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::is_nan(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_ISINF: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::is_inf(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_EASE: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_DECIMALS: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::step_decimals(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_STEPIFY: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *p_outputs[0]=Math::stepify(*p_inputs[0],*p_inputs[1]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_LERP: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *p_outputs[0]=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_DECTIME: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *p_outputs[0]=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_RANDOMIZE: {
+ Math::randomize();
+
+ } break;
+ case VisualScriptBuiltinFunc::MATH_RAND: {
+ *p_outputs[0]=Math::rand();
+ } break;
+ case VisualScriptBuiltinFunc::MATH_RANDF: {
+ *p_outputs[0]=Math::randf();
+ } break;
+ case VisualScriptBuiltinFunc::MATH_RANDOM: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_SEED: {
+
+ VALIDATE_ARG_NUM(0);
+ uint32_t seed=*p_inputs[0];
+ Math::seed(seed);
+
+ } break;
+ case VisualScriptBuiltinFunc::MATH_RANDSEED: {
+
+ VALIDATE_ARG_NUM(0);
+ uint32_t seed=*p_inputs[0];
+ int ret = Math::rand_from_seed(&seed);
+ Array reta;
+ reta.push_back(ret);
+ reta.push_back(seed);
+ *p_outputs[0]=reta;
+
+ } break;
+ case VisualScriptBuiltinFunc::MATH_DEG2RAD: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::deg2rad(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_RAD2DEG: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::rad2deg(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_LINEAR2DB: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::linear2db(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_DB2LINEAR: {
+
+ VALIDATE_ARG_NUM(0);
+ *p_outputs[0]=Math::db2linear(*p_inputs[0]);
+ } break;
+ case VisualScriptBuiltinFunc::LOGIC_MAX: {
+
+ if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) {
+
+ int64_t a = *p_inputs[0];
+ int64_t b = *p_inputs[1];
+ *p_outputs[0]=MAX(a,b);
+ } else {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+
+ real_t a = *p_inputs[0];
+ real_t b = *p_inputs[1];
+
+ *p_outputs[0]=MAX(a,b);
+ }
+
+ } break;
+ case VisualScriptBuiltinFunc::LOGIC_MIN: {
+
+ if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) {
+
+ int64_t a = *p_inputs[0];
+ int64_t b = *p_inputs[1];
+ *p_outputs[0]=MIN(a,b);
+ } else {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+
+ real_t a = *p_inputs[0];
+ real_t b = *p_inputs[1];
+
+ *p_outputs[0]=MIN(a,b);
+ }
+ } break;
+ case VisualScriptBuiltinFunc::LOGIC_CLAMP: {
+
+ if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) {
+
+ int64_t a = *p_inputs[0];
+ int64_t b = *p_inputs[1];
+ int64_t c = *p_inputs[2];
+ *p_outputs[0]=CLAMP(a,b,c);
+ } else {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+
+ real_t a = *p_inputs[0];
+ real_t b = *p_inputs[1];
+ real_t c = *p_inputs[2];
+
+ *p_outputs[0]=CLAMP(a,b,c);
+ }
+ } break;
+ case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: {
+
+ VALIDATE_ARG_NUM(0);
+ int64_t num = *p_inputs[0];
+ *p_outputs[0] = nearest_power_of_2(num);
+ } break;
+ case VisualScriptBuiltinFunc::OBJ_WEAKREF: {
+
+ if (p_inputs[0]->get_type()!=Variant::OBJECT) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::OBJECT;
+
+ return 0;
+
+ }
+
+ if (p_inputs[0]->is_ref()) {
+
+ REF r = *p_inputs[0];
+ if (!r.is_valid()) {
+
+ return 0;
+ }
+
+ Ref<WeakRef> wref = memnew( WeakRef );
+ wref->set_ref(r);
+ *p_outputs[0]=wref;
+ } else {
+ Object *obj = *p_inputs[0];
+ if (!obj) {
+
+ return 0;
+ }
+ Ref<WeakRef> wref = memnew( WeakRef );
+ wref->set_obj(obj);
+ *p_outputs[0]=wref;
+ }
+
+
+
+
+ } break;
+ case VisualScriptBuiltinFunc::FUNC_FUNCREF: {
+
+ if (p_inputs[0]->get_type()!=Variant::OBJECT) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::OBJECT;
+
+ return 0;
+
+ }
+ if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=1;
+ r_error.expected=Variant::STRING;
+
+ return 0;
+
+ }
+
+ Ref<FuncRef> fr = memnew( FuncRef);
+
+ fr->set_instance(*p_inputs[0]);
+ fr->set_function(*p_inputs[1]);
+
+ *p_outputs[0]=fr;
+
+ } break;
+ case VisualScriptBuiltinFunc::TYPE_CONVERT: {
+
+ VALIDATE_ARG_NUM(1);
+ int type=*p_inputs[1];
+ if (type<0 || type>=Variant::VARIANT_MAX) {
+
+ *p_outputs[0]=RTR("Invalid type argument to convert(), use TYPE_* constants.");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::INT;
+ return 0;
+
+ } else {
+
+
+ *p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error);
+ }
+ } break;
+ case VisualScriptBuiltinFunc::TYPE_OF: {
+
+
+ *p_outputs[0] = p_inputs[0]->get_type();
+
+ } break;
+ case VisualScriptBuiltinFunc::TYPE_EXISTS: {
+
+
+ *p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]);
+
+ } break;
+ case VisualScriptBuiltinFunc::TEXT_STR: {
+
+ String str = *p_inputs[0];
+
+ *p_outputs[0]=str;
+
+ } break;
+ case VisualScriptBuiltinFunc::TEXT_PRINT: {
+
+ String str = *p_inputs[0];
+ print_line(str);
+
+
+ } break;
+
+ case VisualScriptBuiltinFunc::TEXT_PRINTERR: {
+
+ String str = *p_inputs[0];
+
+ //str+="\n";
+ OS::get_singleton()->printerr("%s\n",str.utf8().get_data());
+
+
+ } break;
+ case VisualScriptBuiltinFunc::TEXT_PRINTRAW: {
+ String str = *p_inputs[0];
+
+ //str+="\n";
+ OS::get_singleton()->print("%s",str.utf8().get_data());
+
+
+ } break;
+ case VisualScriptBuiltinFunc::VAR_TO_STR: {
+
+ String vars;
+ VariantWriter::write_to_string(*p_inputs[0],vars);
+ *p_outputs[0]=vars;
+ } break;
+ case VisualScriptBuiltinFunc::STR_TO_VAR: {
+
+ if (p_inputs[0]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::STRING;
+
+ return 0;
+ }
+
+ VariantParser::StreamString ss;
+ ss.s=*p_inputs[0];
+
+ String errs;
+ int line;
+ Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line);
+
+ if (err!=OK) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::STRING;
+ *p_outputs[0]="Parse error at line "+itos(line)+": "+errs;
+ return 0;
+ }
+
+ } break;
+ case VisualScriptBuiltinFunc::VAR_TO_BYTES: {
+
+
+ ByteArray barr;
+ int len;
+ Error err = encode_variant(*p_inputs[0],NULL,len);
+ if (err) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::NIL;
+ *p_outputs[0]="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
+ return 0;
+ }
+
+ barr.resize(len);
+ {
+ ByteArray::Write w = barr.write();
+ encode_variant(*p_inputs[0],w.ptr(),len);
+
+ }
+ *p_outputs[0]=barr;
+ } break;
+ case VisualScriptBuiltinFunc::BYTES_TO_VAR: {
+
+ if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::RAW_ARRAY;
+
+ return 0;
+ }
+
+ ByteArray varr=*p_inputs[0];
+ Variant ret;
+ {
+ ByteArray::Read r=varr.read();
+ Error err = decode_variant(ret,r.ptr(),varr.size(),NULL);
+ if (err!=OK) {
+ *p_outputs[0]=RTR("Not enough bytes for decoding bytes, or invalid format.");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::RAW_ARRAY;
+ return 0;
+ }
+
+ }
+
+ *p_outputs[0]=ret;
+
+ } break;
+ default: {}
+ }
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptBuiltinFunc::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceBuiltinFunc * instance = memnew(VisualScriptNodeInstanceBuiltinFunc );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->func=func;
+ return instance;
+}
+
+
+void VisualScriptBuiltinFunc::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_func","which"),&VisualScriptBuiltinFunc::set_func);
+ ObjectTypeDB::bind_method(_MD("get_func"),&VisualScriptBuiltinFunc::get_func);
+
+ String cc;
+
+ for(int i=0;i<FUNC_MAX;i++) {
+
+ if (i>0)
+ cc+=",";
+ cc+=func_name[i];
+ }
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"function",PROPERTY_HINT_ENUM,cc),_SCS("set_func"),_SCS("get_func"));
+}
+
+VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() {
+
+ func=MATH_SIN;
+}
+
+template<VisualScriptBuiltinFunc::BuiltinFunc func>
+static Ref<VisualScriptNode> create_builtin_func_node(const String& p_name) {
+
+ Ref<VisualScriptBuiltinFunc> node;
+ node.instance();
+ node->set_func(func);
+ return node;
+}
+
+void register_visual_script_builtin_func_node() {
+
+
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/sin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/cos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COS>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/tan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TAN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/sinh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SINH>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/cosh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COSH>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/tanh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TANH>);
+
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/asin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ASIN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/acos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ACOS>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan2",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN2>);
+
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/sqrt",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/fmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/fposmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/floor",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/ceil",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/round",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/abs",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ABS>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/sign",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIGN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/pow",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POW>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/log",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LOG>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/exp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EXP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/isnan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISNAN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/isinf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISINF>);
+
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/ease",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/decimals",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECIMALS>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/stepify",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/rand",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/random",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOM>);
+
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/seed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/randseed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/deg2rad",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DEG2RAD>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>);
+
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/max",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/min",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/clamp",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_CLAMP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/nearest_po2",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>);
+
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/weakref",create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/funcref",create_builtin_func_node<VisualScriptBuiltinFunc::FUNC_FUNCREF>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/convert",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/typeof",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/type_exists",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/str",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/print",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/printerr",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/printraw",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2str",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var",create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var",create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>);
+
+}
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
new file mode 100644
index 0000000000..ebf227a192
--- /dev/null
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -0,0 +1,110 @@
+#ifndef VISUAL_SCRIPT_BUILTIN_FUNCS_H
+#define VISUAL_SCRIPT_BUILTIN_FUNCS_H
+
+#include "visual_script.h"
+
+
+class VisualScriptBuiltinFunc : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptBuiltinFunc,VisualScriptNode)
+public:
+
+ enum BuiltinFunc {
+ MATH_SIN,
+ MATH_COS,
+ MATH_TAN,
+ MATH_SINH,
+ MATH_COSH,
+ MATH_TANH,
+ MATH_ASIN,
+ MATH_ACOS,
+ MATH_ATAN,
+ MATH_ATAN2,
+ MATH_SQRT,
+ MATH_FMOD,
+ MATH_FPOSMOD,
+ MATH_FLOOR,
+ MATH_CEIL,
+ MATH_ROUND,
+ MATH_ABS,
+ MATH_SIGN,
+ MATH_POW,
+ MATH_LOG,
+ MATH_EXP,
+ MATH_ISNAN,
+ MATH_ISINF,
+ MATH_EASE,
+ MATH_DECIMALS,
+ MATH_STEPIFY,
+ MATH_LERP,
+ MATH_DECTIME,
+ MATH_RANDOMIZE,
+ MATH_RAND,
+ MATH_RANDF,
+ MATH_RANDOM,
+ MATH_SEED,
+ MATH_RANDSEED,
+ MATH_DEG2RAD,
+ MATH_RAD2DEG,
+ MATH_LINEAR2DB,
+ MATH_DB2LINEAR,
+ LOGIC_MAX,
+ LOGIC_MIN,
+ LOGIC_CLAMP,
+ LOGIC_NEAREST_PO2,
+ OBJ_WEAKREF,
+ FUNC_FUNCREF,
+ TYPE_CONVERT,
+ TYPE_OF,
+ TYPE_EXISTS,
+ TEXT_STR,
+ TEXT_PRINT,
+ TEXT_PRINTERR,
+ TEXT_PRINTRAW,
+ VAR_TO_STR,
+ STR_TO_VAR,
+ VAR_TO_BYTES,
+ BYTES_TO_VAR,
+ FUNC_MAX
+ };
+
+private:
+ static const char* func_name[FUNC_MAX];
+ BuiltinFunc func;
+protected:
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "functions"; }
+
+ void set_func(BuiltinFunc p_which);
+ BuiltinFunc get_func();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptBuiltinFunc();
+};
+
+VARIANT_ENUM_CAST(VisualScriptBuiltinFunc::BuiltinFunc)
+
+
+void register_visual_script_builtin_func_node();
+
+
+#endif // VISUAL_SCRIPT_BUILTIN_FUNCS_H
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
new file mode 100644
index 0000000000..f10e4db9c9
--- /dev/null
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -0,0 +1,3091 @@
+#include "visual_script_editor.h"
+#include "tools/editor/editor_node.h"
+#include "visual_script_nodes.h"
+#include "visual_script_flow_control.h"
+#include "visual_script_func_nodes.h"
+#include "os/input.h"
+#include "tools/editor/editor_resource_preview.h"
+#include "os/keyboard.h"
+
+#ifdef TOOLS_ENABLED
+class VisualScriptEditorSignalEdit : public Object {
+
+ OBJ_TYPE(VisualScriptEditorSignalEdit,Object)
+
+ StringName sig;
+public:
+ UndoRedo *undo_redo;
+ Ref<VisualScript> script;
+
+
+protected:
+
+ static void _bind_methods() {
+ ObjectTypeDB::bind_method("_sig_changed",&VisualScriptEditorSignalEdit::_sig_changed);
+ }
+
+ void _sig_changed() {
+
+ _change_notify();
+ }
+
+ bool _set(const StringName& p_name, const Variant& p_value) {
+
+ if (sig==StringName())
+ return false;
+
+ if (p_name=="argument_count") {
+
+ int new_argc=p_value;
+ int argc = script->custom_signal_get_argument_count(sig);
+ if (argc==new_argc)
+ return true;
+
+ undo_redo->create_action("Change Signal Arguments");
+
+
+
+ if (new_argc < argc) {
+ for(int i=new_argc;i<argc;i++) {
+ undo_redo->add_do_method(script.ptr(),"custom_signal_remove_argument",sig,new_argc);
+ undo_redo->add_undo_method(script.ptr(),"custom_signal_add_argument",sig,script->custom_signal_get_argument_name(sig,i),script->custom_signal_get_argument_type(sig,i),-1);
+ }
+ } else if (new_argc>argc) {
+
+ for(int i=argc;i<new_argc;i++) {
+
+ undo_redo->add_do_method(script.ptr(),"custom_signal_add_argument",sig,Variant::NIL,"arg"+itos(i+1),-1);
+ undo_redo->add_undo_method(script.ptr(),"custom_signal_remove_argument",sig,argc);
+ }
+ }
+
+ undo_redo->add_do_method(this,"_sig_changed");
+ undo_redo->add_undo_method(this,"_sig_changed");
+
+ undo_redo->commit_action();
+
+ return true;
+ }
+ if (String(p_name).begins_with("argument/")) {
+ int idx = String(p_name).get_slice("/",1).to_int()-1;
+ ERR_FAIL_INDEX_V(idx,script->custom_signal_get_argument_count(sig),false);
+ String what = String(p_name).get_slice("/",2);
+ if (what=="type") {
+
+ int old_type = script->custom_signal_get_argument_type(sig,idx);
+ int new_type=p_value;
+ undo_redo->create_action("Change Argument Type");
+ undo_redo->add_do_method(script.ptr(),"custom_signal_set_argument_type",sig,idx,new_type);
+ undo_redo->add_undo_method(script.ptr(),"custom_signal_set_argument_type",sig,idx,old_type);
+ undo_redo->commit_action();
+
+ return true;
+ }
+
+ if (what=="name") {
+
+ String old_name = script->custom_signal_get_argument_name(sig,idx);
+ String new_name=p_value;
+ undo_redo->create_action("Change Argument name");
+ undo_redo->add_do_method(script.ptr(),"custom_signal_set_argument_name",sig,idx,new_name);
+ undo_redo->add_undo_method(script.ptr(),"custom_signal_set_argument_name",sig,idx,old_name);
+ undo_redo->commit_action();
+ return true;
+ }
+
+
+ }
+
+
+ return false;
+ }
+
+ bool _get(const StringName& p_name,Variant &r_ret) const {
+
+ if (sig==StringName())
+ return false;
+
+ if (p_name=="argument_count") {
+ r_ret = script->custom_signal_get_argument_count(sig);
+ return true;
+ }
+ if (String(p_name).begins_with("argument/")) {
+ int idx = String(p_name).get_slice("/",1).to_int()-1;
+ ERR_FAIL_INDEX_V(idx,script->custom_signal_get_argument_count(sig),false);
+ String what = String(p_name).get_slice("/",2);
+ if (what=="type") {
+ r_ret = script->custom_signal_get_argument_type(sig,idx);
+ return true;
+ }
+ if (what=="name") {
+ r_ret = script->custom_signal_get_argument_name(sig,idx);
+ return true;
+ }
+
+
+
+ }
+
+ return false;
+ }
+ void _get_property_list( List<PropertyInfo> *p_list) const {
+
+ if (sig==StringName())
+ return;
+
+ p_list->push_back(PropertyInfo(Variant::INT,"argument_count",PROPERTY_HINT_RANGE,"0,256"));
+ String argt="Variant";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+ for(int i=0;i<script->custom_signal_get_argument_count(sig);i++) {
+ p_list->push_back(PropertyInfo(Variant::INT,"argument/"+itos(i+1)+"/type",PROPERTY_HINT_ENUM,argt));
+ p_list->push_back(PropertyInfo(Variant::STRING,"argument/"+itos(i+1)+"/name"));
+ }
+ }
+
+public:
+
+
+ void edit(const StringName& p_sig) {
+
+ sig=p_sig;
+ _change_notify();
+ }
+
+ VisualScriptEditorSignalEdit() { undo_redo=NULL; }
+};
+
+class VisualScriptEditorVariableEdit : public Object {
+
+ OBJ_TYPE(VisualScriptEditorVariableEdit,Object)
+
+ StringName var;
+public:
+ UndoRedo *undo_redo;
+ Ref<VisualScript> script;
+
+
+protected:
+
+ static void _bind_methods() {
+ ObjectTypeDB::bind_method("_var_changed",&VisualScriptEditorVariableEdit::_var_changed);
+ ObjectTypeDB::bind_method("_var_value_changed",&VisualScriptEditorVariableEdit::_var_value_changed);
+ }
+
+ void _var_changed() {
+
+ _change_notify();
+ }
+ void _var_value_changed() {
+
+ _change_notify("value"); //so the whole tree is not redrawn, makes editing smoother in general
+ }
+
+ bool _set(const StringName& p_name, const Variant& p_value) {
+
+ if (var==StringName())
+ return false;
+
+
+
+ if (String(p_name)=="value") {
+ undo_redo->create_action("Set Variable Default Value");
+ Variant current=script->get_variable_default_value(var);
+ undo_redo->add_do_method(script.ptr(),"set_variable_default_value",var,p_value);
+ undo_redo->add_undo_method(script.ptr(),"set_variable_default_value",var,current);
+ undo_redo->add_do_method(this,"_var_value_changed");
+ undo_redo->add_undo_method(this,"_var_value_changed");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ Dictionary d = script->call("get_variable_info",var);
+
+ if (String(p_name)=="type") {
+
+ Dictionary dc=d.copy();
+ dc["type"]=p_value;
+ undo_redo->create_action("Set Variable Type");
+ undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc);
+ undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d);
+ undo_redo->add_do_method(this,"_var_changed");
+ undo_redo->add_undo_method(this,"_var_changed");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ if (String(p_name)=="hint") {
+
+ Dictionary dc=d.copy();
+ dc["hint"]=p_value;
+ undo_redo->create_action("Set Variable Type");
+ undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc);
+ undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d);
+ undo_redo->add_do_method(this,"_var_changed");
+ undo_redo->add_undo_method(this,"_var_changed");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ if (String(p_name)=="hint_string") {
+
+ Dictionary dc=d.copy();
+ dc["hint_string"]=p_value;
+ undo_redo->create_action("Set Variable Type");
+ undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc);
+ undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d);
+ undo_redo->add_do_method(this,"_var_changed");
+ undo_redo->add_undo_method(this,"_var_changed");
+ undo_redo->commit_action();
+ return true;
+ }
+
+
+ return false;
+ }
+
+ bool _get(const StringName& p_name,Variant &r_ret) const {
+
+ if (var==StringName())
+ return false;
+
+ if (String(p_name)=="value") {
+ r_ret=script->get_variable_default_value(var);
+ return true;
+ }
+
+ PropertyInfo pinfo = script->get_variable_info(var);
+
+ if (String(p_name)=="type") {
+ r_ret=pinfo.type;
+ return true;
+ }
+ if (String(p_name)=="hint") {
+ r_ret=pinfo.hint;
+ return true;
+ }
+ if (String(p_name)=="hint_string") {
+ r_ret=pinfo.hint_string;
+ return true;
+ }
+
+ return false;
+ }
+ void _get_property_list( List<PropertyInfo> *p_list) const {
+
+ if (var==StringName())
+ return;
+
+ String argt="Variant";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+ p_list->push_back(PropertyInfo(Variant::INT,"type",PROPERTY_HINT_ENUM,argt));
+ p_list->push_back(PropertyInfo(script->get_variable_info(var).type,"value",script->get_variable_info(var).hint,script->get_variable_info(var).hint_string,PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::INT,"hint",PROPERTY_HINT_ENUM,"None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,BitFlags,AllFlags,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText"));
+ p_list->push_back(PropertyInfo(Variant::STRING,"hint_string"));
+
+ }
+
+public:
+
+
+ void edit(const StringName& p_var) {
+
+ var=p_var;
+ _change_notify();
+ }
+
+ VisualScriptEditorVariableEdit() { undo_redo=NULL; }
+};
+
+static Color _color_from_type(Variant::Type p_type) {
+ Color color;
+ switch(p_type) {
+ case Variant::NIL: color = Color::html("69ecbd"); break;
+
+ case Variant::BOOL: color = Color::html("8da6f0"); break;
+ case Variant::INT: color = Color::html("7dc6ef"); break;
+ case Variant::REAL: color = Color::html("61daf4"); break;
+ case Variant::STRING: color = Color::html("6ba7ec"); break;
+
+ case Variant::VECTOR2: color = Color::html("bd91f1"); break;
+ case Variant::RECT2: color = Color::html("f191a5"); break;
+ case Variant::VECTOR3: color = Color::html("d67dee"); break;
+ case Variant::MATRIX32: color = Color::html("c4ec69"); break;
+ case Variant::PLANE: color = Color::html("f77070"); break;
+ case Variant::QUAT: color = Color::html("ec69a3"); break;
+ case Variant::_AABB: color = Color::html("ee7991"); break;
+ case Variant::MATRIX3: color = Color::html("e3ec69"); break;
+ case Variant::TRANSFORM: color = Color::html("ecd669"); break;
+
+ case Variant::COLOR: color = Color::html("9dff70"); break;
+ case Variant::IMAGE: color = Color::html("93f1b9"); break;
+ case Variant::NODE_PATH: color = Color::html("6993ec"); break;
+ case Variant::_RID: color = Color::html("69ec9a"); break;
+ case Variant::OBJECT: color = Color::html("79f3e8"); break;
+ case Variant::INPUT_EVENT: color = Color::html("adf18f"); break;
+ case Variant::DICTIONARY: color = Color::html("77edb1"); break;
+
+ case Variant::ARRAY: color = Color::html("e0e0e0"); break;
+ case Variant::RAW_ARRAY: color = Color::html("aaf4c8"); break;
+ case Variant::INT_ARRAY: color = Color::html("afdcf5"); break;
+ case Variant::REAL_ARRAY: color = Color::html("97e7f8"); break;
+ case Variant::STRING_ARRAY: color = Color::html("9dc4f2"); break;
+ case Variant::VECTOR2_ARRAY: color = Color::html("d1b3f5"); break;
+ case Variant::VECTOR3_ARRAY: color = Color::html("df9bf2"); break;
+ case Variant::COLOR_ARRAY: color = Color::html("e9ff97"); break;
+
+ default:
+ color.set_hsv(p_type/float(Variant::VARIANT_MAX),0.7,0.7);
+ }
+ return color;
+}
+
+
+
+void VisualScriptEditor::_update_graph_connections() {
+
+ graph->clear_connections();
+
+ List<VisualScript::SequenceConnection> sequence_conns;
+ script->get_sequence_connection_list(edited_func,&sequence_conns);
+
+
+ for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) {
+
+ graph->connect_node(itos(E->get().from_node),E->get().from_output,itos(E->get().to_node),0);
+ }
+
+ List<VisualScript::DataConnection> data_conns;
+ script->get_data_connection_list(edited_func,&data_conns);
+
+ for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) {
+
+ VisualScript::DataConnection dc=E->get();
+
+
+ Ref<VisualScriptNode> from_node = script->get_node(edited_func,E->get().from_node);
+ Ref<VisualScriptNode> to_node = script->get_node(edited_func,E->get().to_node);
+
+ if (to_node->has_input_sequence_port()) {
+ dc.to_port++;
+ }
+
+ dc.from_port+=from_node->get_output_sequence_port_count();
+
+ graph->connect_node(itos(E->get().from_node),dc.from_port,itos(E->get().to_node),dc.to_port);
+ }
+
+}
+
+
+void VisualScriptEditor::_update_graph(int p_only_id) {
+
+ if (updating_graph)
+ return;
+
+ updating_graph=true;
+
+ //byebye all nodes
+ if (p_only_id>=0) {
+ if (graph->has_node(itos(p_only_id))) {
+ Node* gid = graph->get_node(itos(p_only_id));
+ if (gid)
+ memdelete(gid);
+ }
+ } else {
+
+ for(int i=0;i<graph->get_child_count();i++) {
+
+ if (graph->get_child(i)->cast_to<GraphNode>()) {
+ memdelete(graph->get_child(i));
+ i--;
+ }
+ }
+ }
+
+ if (!script->has_function(edited_func)) {
+ graph->hide();
+ select_func_text->show();
+ updating_graph=false;
+ return;
+ }
+
+ graph->show();
+ select_func_text->hide();
+
+ Ref<Texture> type_icons[Variant::VARIANT_MAX]={
+ Control::get_icon("MiniVariant","EditorIcons"),
+ Control::get_icon("MiniBoolean","EditorIcons"),
+ Control::get_icon("MiniInteger","EditorIcons"),
+ Control::get_icon("MiniFloat","EditorIcons"),
+ Control::get_icon("MiniString","EditorIcons"),
+ Control::get_icon("MiniVector2","EditorIcons"),
+ Control::get_icon("MiniRect2","EditorIcons"),
+ Control::get_icon("MiniVector3","EditorIcons"),
+ Control::get_icon("MiniMatrix32","EditorIcons"),
+ Control::get_icon("MiniPlane","EditorIcons"),
+ Control::get_icon("MiniQuat","EditorIcons"),
+ Control::get_icon("MiniAabb","EditorIcons"),
+ Control::get_icon("MiniMatrix3","EditorIcons"),
+ Control::get_icon("MiniTransform","EditorIcons"),
+ Control::get_icon("MiniColor","EditorIcons"),
+ Control::get_icon("MiniImage","EditorIcons"),
+ Control::get_icon("MiniPath","EditorIcons"),
+ Control::get_icon("MiniRid","EditorIcons"),
+ Control::get_icon("MiniObject","EditorIcons"),
+ Control::get_icon("MiniInput","EditorIcons"),
+ Control::get_icon("MiniDictionary","EditorIcons"),
+ Control::get_icon("MiniArray","EditorIcons"),
+ Control::get_icon("MiniRawArray","EditorIcons"),
+ Control::get_icon("MiniIntArray","EditorIcons"),
+ Control::get_icon("MiniFloatArray","EditorIcons"),
+ Control::get_icon("MiniStringArray","EditorIcons"),
+ Control::get_icon("MiniVector2Array","EditorIcons"),
+ Control::get_icon("MiniVector3Array","EditorIcons"),
+ Control::get_icon("MiniColorArray","EditorIcons")
+ };
+
+
+
+ Ref<Texture> seq_port = Control::get_icon("VisualShaderPort","EditorIcons");
+
+ List<int> ids;
+ script->get_node_list(edited_func,&ids);
+ StringName editor_icons="EditorIcons";
+
+ for(List<int>::Element *E=ids.front();E;E=E->next()) {
+
+ if (p_only_id>=0 && p_only_id!=E->get())
+ continue;
+
+ Ref<VisualScriptNode> node = script->get_node(edited_func,E->get());
+ Vector2 pos = script->get_node_pos(edited_func,E->get());
+
+ GraphNode *gnode = memnew( GraphNode );
+ gnode->set_title(node->get_caption());
+ if (error_line==E->get()) {
+ gnode->set_overlay(GraphNode::OVERLAY_POSITION);
+ } else if (node->is_breakpoint()) {
+ gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);
+ }
+
+ if (EditorSettings::get_singleton()->has("visual_script_editor/color_"+node->get_category())) {
+ gnode->set_modulate(EditorSettings::get_singleton()->get("visual_script_editor/color_"+node->get_category()));
+ }
+
+
+
+ gnode->set_meta("__vnode",node);
+ gnode->set_name(itos(E->get()));
+ gnode->connect("dragged",this,"_node_moved",varray(E->get()));
+ gnode->connect("close_request",this,"_remove_node",varray(E->get()),CONNECT_DEFERRED);
+
+
+ if (E->get()!=script->get_function_node_id(edited_func)) {
+ //function can't be erased
+ gnode->set_show_close_button(true);
+ }
+
+
+ Label *text = memnew( Label );
+ text->set_text(node->get_text());
+ gnode->add_child(text);
+
+ if (node->cast_to<VisualScriptComment>()) {
+ Ref<VisualScriptComment> vsc=node;
+ gnode->set_comment(true);
+ gnode->set_resizeable(true);
+ gnode->set_custom_minimum_size(vsc->get_size()*EDSCALE);
+ gnode->connect("resize_request",this,"_comment_node_resized",varray(E->get()));
+
+ }
+
+
+ int slot_idx=0;
+
+ bool single_seq_output = node->get_output_sequence_port_count()==1 && node->get_output_sequence_port_text(0)==String();
+ gnode->set_slot(0,node->has_input_sequence_port(),TYPE_SEQUENCE,Color(1,1,1,1),single_seq_output,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port);
+ gnode->set_offset(pos*EDSCALE);
+ slot_idx++;
+
+ if (!single_seq_output) {
+ for(int i=0;i<node->get_output_sequence_port_count();i++) {
+
+ Label *text2 = memnew( Label );
+ text2->set_text(node->get_output_sequence_port_text(i));
+ text2->set_align(Label::ALIGN_RIGHT);
+ gnode->add_child(text2);
+ gnode->set_slot(slot_idx,false,0,Color(),true,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port);
+ slot_idx++;
+ }
+ }
+
+ for(int i=0;i<MAX(node->get_output_value_port_count(),node->get_input_value_port_count());i++) {
+
+ bool left_ok=false;
+ Variant::Type left_type=Variant::NIL;
+ String left_name;
+
+
+
+ if (i<node->get_input_value_port_count()) {
+ PropertyInfo pi = node->get_input_value_port_info(i);
+ left_ok=true;
+ left_type=pi.type;
+ left_name=pi.name;
+ }
+
+ bool right_ok=false;
+ Variant::Type right_type=Variant::NIL;
+ String right_name;
+
+ if (i<node->get_output_value_port_count()) {
+ PropertyInfo pi = node->get_output_value_port_info(i);
+ right_ok=true;
+ right_type=pi.type;
+ right_name=pi.name;
+ }
+
+ HBoxContainer *hbc = memnew( HBoxContainer);
+
+ if (left_ok) {
+
+ Ref<Texture> t;
+ if (left_type>=0 && left_type<Variant::VARIANT_MAX) {
+ t=type_icons[left_type];
+ }
+ if (t.is_valid()) {
+ TextureFrame *tf = memnew(TextureFrame);
+ tf->set_texture(t);
+ tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED);
+ hbc->add_child(tf);
+ }
+
+ hbc->add_child(memnew(Label(left_name)));
+
+ if (left_type!=Variant::NIL && !script->is_input_value_port_connected(edited_func,E->get(),i)) {
+
+ PropertyInfo pi = node->get_input_value_port_info(i);
+ Button *button = memnew( Button );
+ Variant value = node->get_default_input_value(i);
+ if (value.get_type()!=left_type) {
+ //different type? for now convert
+ //not the same, reconvert
+ Variant::CallError ce;
+ const Variant *existingp=&value;
+ value = Variant::construct(left_type,&existingp,1,ce,false);
+ }
+
+ if (left_type==Variant::COLOR) {
+ button->set_custom_minimum_size(Size2(30,0)*EDSCALE);
+ button->connect("draw",this,"_draw_color_over_button",varray(button,value));
+ } else if (left_type==Variant::OBJECT && Ref<Resource>(value).is_valid()) {
+
+ Ref<Resource> res = value;
+ Array arr;
+ arr.push_back(button->get_instance_ID());
+ arr.push_back(String(value));
+ EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res,this,"_button_resource_previewed",arr);
+
+ } else if (pi.type==Variant::INT && pi.hint==PROPERTY_HINT_ENUM){
+
+ button->set_text(pi.hint_string.get_slice(",",value));
+ } else {
+
+ button->set_text(value);
+ }
+ button->connect("pressed",this,"_default_value_edited",varray(button,E->get(),i));
+ hbc->add_child(button);
+ }
+ } else {
+ Control *c = memnew(Control);
+ c->set_custom_minimum_size(Size2(10,0)*EDSCALE);
+ hbc->add_child(c);
+ }
+
+ hbc->add_spacer();
+
+ if (right_ok) {
+
+ hbc->add_child(memnew(Label(right_name)));
+
+ Ref<Texture> t;
+ if (right_type>=0 && right_type<Variant::VARIANT_MAX) {
+ t=type_icons[right_type];
+ }
+ if (t.is_valid()) {
+ TextureFrame *tf = memnew(TextureFrame);
+ tf->set_texture(t);
+ tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED);
+ hbc->add_child(tf);
+ }
+
+ }
+
+ gnode->add_child(hbc);
+
+ gnode->set_slot(slot_idx,left_ok,left_type,_color_from_type(left_type),right_ok,right_type,_color_from_type(right_type));
+
+ slot_idx++;
+ }
+
+ graph->add_child(gnode);
+
+ if (gnode->is_comment()) {
+ graph->move_child(gnode,0);
+ }
+ }
+
+ _update_graph_connections();
+ graph->call_deferred("set_scroll_ofs",script->get_function_scroll(edited_func)*EDSCALE); //may need to adapt a bit, let it do so
+ updating_graph=false;
+
+}
+
+void VisualScriptEditor::_update_members() {
+
+
+ updating_members=true;
+
+ members->clear();
+ TreeItem *root = members->create_item();
+
+ TreeItem *functions = members->create_item(root);
+ functions->set_selectable(0,false);
+ functions->set_text(0,TTR("Functions:"));
+ functions->add_button(0,Control::get_icon("Override","EditorIcons"),1);
+ functions->add_button(0,Control::get_icon("Add","EditorIcons"),0);
+ functions->set_custom_bg_color(0,Control::get_color("prop_section","Editor"));
+
+ List<StringName> func_names;
+ script->get_function_list(&func_names);
+ for (List<StringName>::Element *E=func_names.front();E;E=E->next()) {
+ TreeItem *ti = members->create_item(functions) ;
+ ti->set_text(0,E->get());
+ ti->set_selectable(0,true);
+ ti->set_editable(0,true);
+ //ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); function arguments are in the node now
+ ti->add_button(0,Control::get_icon("Del","EditorIcons"),1);
+ ti->set_metadata(0,E->get());
+ if (E->get()==edited_func) {
+ ti->set_custom_bg_color(0,get_color("prop_category","Editor"));
+ ti->set_custom_color(0,Color(1,1,1,1));
+ }
+ if (selected==E->get())
+ ti->select(0);
+ }
+
+ TreeItem *variables = members->create_item(root);
+ variables->set_selectable(0,false);
+ variables->set_text(0,TTR("Variables:"));
+ variables->add_button(0,Control::get_icon("Add","EditorIcons"));
+ variables->set_custom_bg_color(0,Control::get_color("prop_section","Editor"));
+
+
+ List<StringName> var_names;
+ script->get_variable_list(&var_names);
+ for (List<StringName>::Element *E=var_names.front();E;E=E->next()) {
+ TreeItem *ti = members->create_item(variables);
+ ti->set_text(0,E->get());
+ ti->set_selectable(0,true);
+ ti->set_editable(0,true);
+ ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0);
+ ti->add_button(0,Control::get_icon("Del","EditorIcons"),1);
+ ti->set_metadata(0,E->get());
+ if (selected==E->get())
+ ti->select(0);
+ }
+
+ TreeItem *_signals = members->create_item(root);
+ _signals->set_selectable(0,false);
+ _signals->set_text(0,TTR("Signals:"));
+ _signals->add_button(0,Control::get_icon("Add","EditorIcons"));
+ _signals->set_custom_bg_color(0,Control::get_color("prop_section","Editor"));
+
+ List<StringName> signal_names;
+ script->get_custom_signal_list(&signal_names);
+ for (List<StringName>::Element *E=signal_names.front();E;E=E->next()) {
+ TreeItem *ti = members->create_item(_signals);
+ ti->set_text(0,E->get());
+ ti->set_selectable(0,true);
+ ti->set_editable(0,true);
+ ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0);
+ ti->add_button(0,Control::get_icon("Del","EditorIcons"),1);
+ ti->set_metadata(0,E->get());
+ if (selected==E->get())
+ ti->select(0);
+ }
+
+ String base_type=script->get_instance_base_type();
+ String icon_type=base_type;
+ if (!Control::has_icon(base_type,"EditorIcons")) {
+ icon_type="Object";
+ }
+
+ base_type_select->set_text(base_type);
+ base_type_select->set_icon(Control::get_icon(icon_type,"EditorIcons"));
+
+ updating_members=false;
+
+}
+
+void VisualScriptEditor::_member_selected() {
+
+ if (updating_members)
+ return;
+
+ TreeItem *ti=members->get_selected();
+ ERR_FAIL_COND(!ti);
+
+
+ selected=ti->get_metadata(0);
+// print_line("selected: "+String(selected));
+
+
+ if (ti->get_parent()==members->get_root()->get_children()) {
+
+ if (edited_func!=selected) {
+
+ revert_on_drag=edited_func;
+ edited_func=selected;
+ _update_members();
+ _update_graph();
+ }
+
+ return; //or crash because it will become invalid
+
+ }
+
+
+
+}
+
+void VisualScriptEditor::_member_edited() {
+
+ if (updating_members)
+ return;
+
+ TreeItem *ti=members->get_edited();
+ ERR_FAIL_COND(!ti);
+
+ String name = ti->get_metadata(0);
+ String new_name = ti->get_text(0);
+
+ if (name==new_name)
+ return;
+
+ if (!new_name.is_valid_identifier()) {
+
+ EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:")+" "+new_name);
+ updating_members=true;
+ ti->set_text(0,name);
+ updating_members=false;
+ return;
+
+ }
+
+ if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {
+
+ EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:")+" "+new_name);
+ updating_members=true;
+ ti->set_text(0,name);
+ updating_members=false;
+ return;
+ }
+
+ TreeItem *root=members->get_root();
+
+ if (ti->get_parent()==root->get_children()) {
+
+ if (edited_func==selected) {
+ edited_func=new_name;
+ }
+ selected=new_name;
+
+
+ _update_graph();
+
+ undo_redo->create_action(TTR("Rename Function"));
+ undo_redo->add_do_method(script.ptr(),"rename_function",name,new_name);
+ undo_redo->add_undo_method(script.ptr(),"rename_function",new_name,name);
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+
+ return; //or crash because it will become invalid
+
+ }
+
+ if (ti->get_parent()==root->get_children()->get_next()) {
+
+ selected=new_name;
+ undo_redo->create_action(TTR("Rename Variable"));
+ undo_redo->add_do_method(script.ptr(),"rename_variable",name,new_name);
+ undo_redo->add_undo_method(script.ptr(),"rename_variable",new_name,name);
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+
+ return; //or crash because it will become invalid
+ }
+
+ if (ti->get_parent()==root->get_children()->get_next()->get_next()) {
+
+ selected=new_name;
+ undo_redo->create_action(TTR("Rename Signal"));
+ undo_redo->add_do_method(script.ptr(),"rename_custom_signal",name,new_name);
+ undo_redo->add_undo_method(script.ptr(),"rename_custom_signal",new_name,name);
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+
+ return; //or crash because it will become invalid
+ }
+}
+
+void VisualScriptEditor::_override_pressed(int p_id) {
+
+ //override a virtual function or method from base type
+
+ ERR_FAIL_COND(!virtuals_in_menu.has(p_id));
+
+ VirtualInMenu vim=virtuals_in_menu[p_id];
+
+ String name = _validate_name(vim.name);
+ selected=name;
+ edited_func=selected;
+ Ref<VisualScriptFunction> func_node;
+ func_node.instance();
+ func_node->set_name(vim.name);
+
+ undo_redo->create_action(TTR("Add Function"));
+ undo_redo->add_do_method(script.ptr(),"add_function",name);
+ for(int i=0;i<vim.args.size();i++) {
+ func_node->add_argument(vim.args[i].first,vim.args[i].second);
+ }
+
+
+ undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id(),func_node);
+ if (vim.ret!=Variant::NIL || vim.ret_variant) {
+ Ref<VisualScriptReturn> ret_node;
+ ret_node.instance();
+ ret_node->set_return_type(vim.ret);
+ ret_node->set_enable_return_value(true);
+ ret_node->set_name(vim.name);
+ undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id()+1,ret_node,Vector2(500,0));
+
+ }
+
+ undo_redo->add_undo_method(script.ptr(),"remove_function",name);
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+
+ undo_redo->commit_action();
+
+
+ _update_graph();
+}
+
+void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button) {
+
+ TreeItem *ti=p_item->cast_to<TreeItem>();
+
+ TreeItem *root=members->get_root();
+
+ if (ti->get_parent()==root) {
+ //main buttons
+ if (ti==root->get_children()) {
+ //add function, this one uses menu
+
+ if (p_button==1) {
+ new_function_menu->clear();
+ new_function_menu->set_size(Size2(0,0));
+ int idx=0;
+
+ virtuals_in_menu.clear();
+
+ List<MethodInfo> mi;
+ ObjectTypeDB::get_method_list(script->get_instance_base_type(),&mi);
+ for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+ MethodInfo mi=E->get();
+ if (mi.flags&METHOD_FLAG_VIRTUAL) {
+
+ VirtualInMenu vim;
+ vim.name=mi.name;
+ vim.ret=mi.return_val.type;
+ if (mi.return_val.name!=String())
+ vim.ret_variant=true;
+ else
+ vim.ret_variant=false;
+
+ String desc;
+
+ if (mi.return_val.type==Variant::NIL)
+ desc="var";
+ else
+ desc=Variant::get_type_name(mi.return_val.type);
+ desc+=" "+mi.name+" ( ";
+
+
+ for(int i=0;i<mi.arguments.size();i++) {
+
+ if (i>0)
+ desc+=", ";
+
+ if (mi.arguments[i].type==Variant::NIL)
+ desc+="var ";
+ else
+ desc+=Variant::get_type_name(mi.arguments[i].type)+" ";
+
+ desc+=mi.arguments[i].name;
+
+ Pair<Variant::Type,String> p;
+ p.first=mi.arguments[i].type;
+ p.second=mi.arguments[i].name;
+ vim.args.push_back( p );
+
+ }
+
+ desc+=" )";
+
+ virtuals_in_menu[idx]=vim;
+
+ new_function_menu->add_item(desc,idx);
+ idx++;
+ }
+ }
+
+ Rect2 pos = members->get_item_rect(ti);
+ new_function_menu->set_pos(members->get_global_pos()+pos.pos+Vector2(0,pos.size.y));
+ new_function_menu->popup();
+ return;
+ } else if (p_button==0) {
+
+
+ String name = _validate_name("new_function");
+ selected=name;
+ edited_func=selected;
+
+ Ref<VisualScriptFunction> func_node;
+ func_node.instance();
+ func_node->set_name(name);
+
+ undo_redo->create_action(TTR("Add Function"));
+ undo_redo->add_do_method(script.ptr(),"add_function",name);
+ undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id(),func_node);
+ undo_redo->add_undo_method(script.ptr(),"remove_function",name);
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+
+ undo_redo->commit_action();
+
+ _update_graph();
+ }
+
+ return; //or crash because it will become invalid
+
+ }
+
+ if (ti==root->get_children()->get_next()) {
+ //add variable
+ String name = _validate_name("new_variable");
+ selected=name;
+
+ undo_redo->create_action(TTR("Add Variable"));
+ undo_redo->add_do_method(script.ptr(),"add_variable",name);
+ undo_redo->add_undo_method(script.ptr(),"remove_variable",name);
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+ return; //or crash because it will become invalid
+
+ }
+
+ if (ti==root->get_children()->get_next()->get_next()) {
+ //add variable
+ String name = _validate_name("new_signal");
+ selected=name;
+
+ undo_redo->create_action(TTR("Add Signal"));
+ undo_redo->add_do_method(script.ptr(),"add_custom_signal",name);
+ undo_redo->add_undo_method(script.ptr(),"remove_custom_signal",name);
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+ return; //or crash because it will become invalid
+
+ }
+
+ } else {
+
+ if (ti->get_parent()==root->get_children()) {
+ //edit/remove function
+ String name = ti->get_metadata(0);
+
+ if (p_button==1) {
+ //delete the function
+ undo_redo->create_action(TTR("Remove Function"));
+ undo_redo->add_do_method(script.ptr(),"remove_function",name);
+ undo_redo->add_undo_method(script.ptr(),"add_function",name);
+ List<int> nodes;
+ script->get_node_list(name,&nodes);
+ for (List<int>::Element *E=nodes.front();E;E=E->next()) {
+ undo_redo->add_undo_method(script.ptr(),"add_node",name,E->get(),script->get_node(name,E->get()),script->get_node_pos(name,E->get()));
+ }
+
+ List<VisualScript::SequenceConnection> seq_connections;
+
+ script->get_sequence_connection_list(name,&seq_connections);
+
+ for (List<VisualScript::SequenceConnection>::Element *E=seq_connections.front();E;E=E->next()) {
+ undo_redo->add_undo_method(script.ptr(),"sequence_connect",name,E->get().from_node,E->get().from_output,E->get().to_node);
+ }
+
+ List<VisualScript::DataConnection> data_connections;
+
+ script->get_data_connection_list(name,&data_connections);
+
+ for (List<VisualScript::DataConnection>::Element *E=data_connections.front();E;E=E->next()) {
+ undo_redo->add_undo_method(script.ptr(),"data_connect",name,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port);
+ }
+
+ //for(int i=0;i<script->function_get_argument_count(name);i++) {
+ //// undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i));
+ //}
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ } else if (p_button==0) {
+
+ }
+ return; //or crash because it will become invalid
+
+ }
+
+ if (ti->get_parent()==root->get_children()->get_next()) {
+ //edit/remove variable
+
+ String name = ti->get_metadata(0);
+
+ if (p_button==1) {
+
+
+ undo_redo->create_action(TTR("Remove Variable"));
+ undo_redo->add_do_method(script.ptr(),"remove_variable",name);
+ undo_redo->add_undo_method(script.ptr(),"add_variable",name,script->get_variable_default_value(name));
+ undo_redo->add_undo_method(script.ptr(),"set_variable_info",name,script->call("get_variable_info",name)); //return as dict
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+ return; //or crash because it will become invalid
+ } else if (p_button==0) {
+
+ variable_editor->edit(name);
+ edit_variable_dialog->set_title(TTR("Editing Variable:")+" "+name);
+ edit_variable_dialog->popup_centered_minsize(Size2(400,200)*EDSCALE);
+ }
+
+ }
+
+ if (ti->get_parent()==root->get_children()->get_next()->get_next()) {
+ //edit/remove variable
+ String name = ti->get_metadata(0);
+
+ if (p_button==1) {
+
+ undo_redo->create_action(TTR("Remove Signal"));
+ undo_redo->add_do_method(script.ptr(),"remove_custom_signal",name);
+ undo_redo->add_undo_method(script.ptr(),"add_custom_signal",name);
+
+ for(int i=0;i<script->custom_signal_get_argument_count(name);i++) {
+ undo_redo->add_undo_method(script.ptr(),"custom_signal_add_argument",name,script->custom_signal_get_argument_name(name,i),script->custom_signal_get_argument_type(name,i));
+ }
+
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+ } else if (p_button==0) {
+
+ signal_editor->edit(name);
+ edit_signal_dialog->set_title(TTR("Editing Signal:")+" "+name);
+ edit_signal_dialog->popup_centered_minsize(Size2(400,300)*EDSCALE);
+ }
+
+ return; //or crash because it will become invalid
+
+ }
+
+
+ }
+}
+
+void VisualScriptEditor::_available_node_doubleclicked() {
+
+ TreeItem *item = nodes->get_selected();
+
+ if (!item)
+ return;
+
+ String which = item->get_metadata(0);
+ if (which==String())
+ return;
+
+ Vector2 ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5;
+
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+ ofs/=EDSCALE;
+
+ while(true) {
+ bool exists=false;
+ List<int> existing;
+ script->get_node_list(edited_func,&existing);
+ for (List<int>::Element *E=existing.front();E;E=E->next()) {
+ Point2 pos = script->get_node_pos(edited_func,E->get());
+ if (pos.distance_to(ofs)<15) {
+ ofs+=Vector2(graph->get_snap(),graph->get_snap());
+ exists=true;
+ break;
+ }
+ }
+
+ if (exists)
+ continue;
+ break;
+
+ }
+
+
+ Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(which);
+ int new_id = script->get_available_id();
+
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ Node* node = graph->get_node(itos(new_id));
+ if (node) {
+ graph->set_selected(node);
+ _node_selected(node);
+ }
+
+}
+
+void VisualScriptEditor::_update_available_nodes() {
+
+ nodes->clear();
+
+ TreeItem *root = nodes->create_item();
+
+ Map<String,TreeItem*> path_cache;
+
+ String filter = node_filter->get_text();
+
+ List<String> fnodes;
+ VisualScriptLanguage::singleton->get_registered_node_names(&fnodes);
+
+ for (List<String>::Element *E=fnodes.front();E;E=E->next()) {
+
+
+ Vector<String> path = E->get().split("/");
+
+ if (filter!=String() && path.size() && path[path.size()-1].findn(filter)==-1)
+ continue;
+
+ String sp;
+ TreeItem* parent=root;
+
+ for(int i=0;i<path.size()-1;i++) {
+
+ if (i>0)
+ sp+=",";
+ sp+=path[i];
+ if (!path_cache.has(sp)) {
+ TreeItem* pathn = nodes->create_item(parent);
+ pathn->set_selectable(0,false);
+ pathn->set_text(0,path[i].capitalize());
+ path_cache[sp]=pathn;
+ parent=pathn;
+ if (filter==String()) {
+ pathn->set_collapsed(true); //should remember state
+ }
+ } else {
+ parent=path_cache[sp];
+ }
+ }
+
+ TreeItem *item = nodes->create_item(parent);
+ item->set_text(0,path[path.size()-1].capitalize());
+ item->set_selectable(0,true);
+ item->set_metadata(0,E->get());
+ }
+
+}
+
+String VisualScriptEditor::_validate_name(const String& p_name) const {
+
+ String valid=p_name;
+
+ int counter=1;
+ while(true) {
+
+ bool exists = script->has_function(valid) || script->has_variable(valid) || script->has_custom_signal(valid);
+
+ if (exists) {
+ counter++;
+ valid=p_name+"_"+itos(counter);
+ continue;
+ }
+
+ break;
+ }
+
+ return valid;
+}
+
+void VisualScriptEditor::_on_nodes_delete() {
+
+
+ List<int> to_erase;
+
+ for(int i=0;i<graph->get_child_count();i++) {
+ GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+ if (gn) {
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ to_erase.push_back(gn->get_name().operator String().to_int());
+ }
+ }
+ }
+
+ if (to_erase.empty())
+ return;
+
+ undo_redo->create_action("Remove VisualScript Nodes");
+
+ for(List<int>::Element*F=to_erase.front();F;F=F->next()) {
+
+
+ undo_redo->add_do_method(script.ptr(),"remove_node",edited_func,F->get());
+ undo_redo->add_undo_method(script.ptr(),"add_node",edited_func,F->get(),script->get_node(edited_func,F->get()),script->get_node_pos(edited_func,F->get()));
+
+
+ List<VisualScript::SequenceConnection> sequence_conns;
+ script->get_sequence_connection_list(edited_func,&sequence_conns);
+
+
+ for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) {
+
+ if (E->get().from_node==F->get() || E->get().to_node==F->get()) {
+ undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,E->get().from_node,E->get().from_output,E->get().to_node);
+ }
+ }
+
+ List<VisualScript::DataConnection> data_conns;
+ script->get_data_connection_list(edited_func,&data_conns);
+
+ for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) {
+
+ if (E->get().from_node==F->get() || E->get().to_node==F->get()) {
+ undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port);
+ }
+ }
+
+ }
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+
+ undo_redo->commit_action();
+}
+
+
+void VisualScriptEditor::_on_nodes_duplicate() {
+
+
+ List<int> to_duplicate;
+
+ for(int i=0;i<graph->get_child_count();i++) {
+ GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+ if (gn) {
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ to_duplicate.push_back(gn->get_name().operator String().to_int());
+ }
+ }
+ }
+
+ if (to_duplicate.empty())
+ return;
+
+ undo_redo->create_action("Duplicate VisualScript Nodes");
+ int idc=script->get_available_id()+1;
+
+ Set<int> to_select;
+
+ for(List<int>::Element*F=to_duplicate.front();F;F=F->next()) {
+
+ Ref<VisualScriptNode> node = script->get_node(edited_func,F->get());
+
+ Ref<VisualScriptNode> dupe = node->duplicate();
+
+ int new_id = idc++;
+ to_select.insert(new_id);
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,dupe,script->get_node_pos(edited_func,F->get())+Vector2(20,20));
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+
+ }
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+
+ undo_redo->commit_action();
+
+ for(int i=0;i<graph->get_child_count();i++) {
+ GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+ if (gn) {
+ int id = gn->get_name().operator String().to_int();
+ gn->set_selected(to_select.has(id));
+
+ }
+ }
+
+ if (to_select.size()) {
+ EditorNode::get_singleton()->push_item(script->get_node(edited_func,to_select.front()->get()).ptr());
+ }
+
+}
+
+void VisualScriptEditor::_input(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) {
+ revert_on_drag=String(); //so we can still drag functions
+ }
+}
+
+Variant VisualScriptEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) {
+
+
+ if (p_from==nodes) {
+
+ TreeItem *it = nodes->get_item_at_pos(p_point);
+ if (!it)
+ return Variant();
+ String type=it->get_metadata(0);
+ if (type==String())
+ return Variant();
+
+ Dictionary dd;
+ dd["type"]="visual_script_node_drag";
+ dd["node_type"]=type;
+
+ Label *label = memnew(Label);
+ label->set_text(it->get_text(0));
+ set_drag_preview(label);
+ return dd;
+ }
+
+ if (p_from==members) {
+
+
+ TreeItem *it = members->get_item_at_pos(p_point);
+ if (!it)
+ return Variant();
+
+ String type=it->get_metadata(0);
+
+ if (type==String())
+ return Variant();
+
+
+ Dictionary dd;
+ TreeItem *root=members->get_root();
+
+ if (it->get_parent()==root->get_children()) {
+
+ dd["type"]="visual_script_function_drag";
+ dd["function"]=type;
+ if (revert_on_drag!=String()) {
+ edited_func=revert_on_drag; //revert so function does not change
+ revert_on_drag=String();
+ _update_graph();
+ }
+ } else if (it->get_parent()==root->get_children()->get_next()) {
+
+ dd["type"]="visual_script_variable_drag";
+ dd["variable"]=type;
+ } else if (it->get_parent()==root->get_children()->get_next()->get_next()) {
+
+ dd["type"]="visual_script_signal_drag";
+ dd["signal"]=type;
+
+ } else {
+ return Variant();
+ }
+
+
+
+
+
+
+ Label *label = memnew(Label);
+ label->set_text(it->get_text(0));
+ set_drag_preview(label);
+ return dd;
+ }
+ return Variant();
+}
+
+bool VisualScriptEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{
+
+ if (p_from==graph) {
+
+
+ Dictionary d = p_data;
+ if (d.has("type") &&
+ (
+ String(d["type"])=="visual_script_node_drag" ||
+ String(d["type"])=="visual_script_function_drag" ||
+ String(d["type"])=="visual_script_variable_drag" ||
+ String(d["type"])=="visual_script_signal_drag" ||
+ String(d["type"])=="obj_property" ||
+ String(d["type"])=="resource" ||
+ String(d["type"])=="files" ||
+ String(d["type"])=="nodes"
+ ) ) {
+
+
+ if (String(d["type"])=="obj_property") {
+
+#ifdef OSX_ENABLED
+ const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Meta to drop a Getter. Hold Shift to drop a generic signature."));
+#else
+ const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."));
+#endif
+ }
+
+ if (String(d["type"])=="nodes") {
+
+#ifdef OSX_ENABLED
+ const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Meta to drop a simple reference to the node."));
+#else
+ const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Ctrl to drop a simple reference to the node."));
+#endif
+ }
+
+ if (String(d["type"])=="visual_script_variable_drag") {
+
+#ifdef OSX_ENABLED
+ const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Meta to drop a Variable Setter."));
+#else
+ const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Ctrl to drop a Variable Setter."));
+#endif
+ }
+
+ return true;
+
+ }
+
+
+
+ }
+
+
+ return false;
+}
+
+#ifdef TOOLS_ENABLED
+
+static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) {
+
+ if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene)
+ return NULL;
+
+ Ref<Script> scr = p_current_node->get_script();
+
+ if (scr.is_valid() && scr==script)
+ return p_current_node;
+
+ for(int i=0;i<p_current_node->get_child_count();i++) {
+ Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script);
+ if (n)
+ return n;
+ }
+
+ return NULL;
+}
+
+#endif
+
+
+
+void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){
+
+ if (p_from==graph) {
+
+ Dictionary d = p_data;
+ if (d.has("type") && String(d["type"])=="visual_script_node_drag") {
+
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+
+ ofs/=EDSCALE;
+
+ Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(d["node_type"]);
+ int new_id = script->get_available_id();
+
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ Node* node = graph->get_node(itos(new_id));
+ if (node) {
+ graph->set_selected(node);
+ _node_selected(node);
+ }
+ }
+
+ if (d.has("type") && String(d["type"])=="visual_script_variable_drag") {
+
+#ifdef OSX_ENABLED
+ bool use_set = Input::get_singleton()->is_key_pressed(KEY_META);
+#else
+ bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+#endif
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+ ofs/=EDSCALE;
+
+ Ref<VisualScriptNode> vnode;
+ if (use_set) {
+ Ref<VisualScriptVariableSet> vnodes;
+ vnodes.instance();
+ vnodes->set_variable(d["variable"]);
+ vnode=vnodes;
+ } else {
+
+ Ref<VisualScriptVariableGet> vnodeg;
+ vnodeg.instance();
+ vnodeg->set_variable(d["variable"]);
+ vnode=vnodeg;
+ }
+
+ int new_id = script->get_available_id();
+
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ Node* node = graph->get_node(itos(new_id));
+ if (node) {
+ graph->set_selected(node);
+ _node_selected(node);
+ }
+ }
+
+ if (d.has("type") && String(d["type"])=="visual_script_function_drag") {
+
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+ ofs/=EDSCALE;
+
+ Ref<VisualScriptFunctionCall> vnode;
+ vnode.instance();
+ vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF);
+
+ int new_id = script->get_available_id();
+
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+ undo_redo->add_do_method(vnode.ptr(),"set_base_type",script->get_instance_base_type());
+ undo_redo->add_do_method(vnode.ptr(),"set_function",d["function"]);
+
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ Node* node = graph->get_node(itos(new_id));
+ if (node) {
+ graph->set_selected(node);
+ _node_selected(node);
+ }
+
+ }
+
+
+ if (d.has("type") && String(d["type"])=="visual_script_signal_drag") {
+
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+ ofs/=EDSCALE;
+
+ Ref<VisualScriptEmitSignal> vnode;
+ vnode.instance();
+ vnode->set_signal(d["signal"]);
+
+ int new_id = script->get_available_id();
+
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ Node* node = graph->get_node(itos(new_id));
+ if (node) {
+ graph->set_selected(node);
+ _node_selected(node);
+ }
+ }
+
+ if (d.has("type") && String(d["type"])=="resource") {
+
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+ ofs/=EDSCALE;
+
+ Ref<VisualScriptPreload> prnode;
+ prnode.instance();
+ prnode->set_preload(d["resource"]);
+
+ int new_id = script->get_available_id();
+
+ undo_redo->create_action(TTR("Add Preload Node"));
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,prnode,ofs);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ Node* node = graph->get_node(itos(new_id));
+ if (node) {
+ graph->set_selected(node);
+ _node_selected(node);
+ }
+ }
+
+ if (d.has("type") && String(d["type"])=="files") {
+
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+ ofs/=EDSCALE;
+
+ Array files = d["files"];
+
+ List<int> new_ids;
+ int new_id = script->get_available_id();
+
+ if (files.size()) {
+ undo_redo->create_action(TTR("Add Preload Node"));
+
+ for(int i=0;i<files.size();i++) {
+
+ Ref<Resource> res = ResourceLoader::load(files[i]);
+ if (!res.is_valid())
+ continue;
+
+ Ref<VisualScriptPreload> prnode;
+ prnode.instance();
+ prnode->set_preload(res);
+
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,prnode,ofs);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ new_ids.push_back(new_id);
+ new_id++;
+ ofs+=Vector2(20,20)*EDSCALE;
+ }
+
+
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+ }
+
+ for(List<int>::Element *E=new_ids.front();E;E=E->next()) {
+
+ Node* node = graph->get_node(itos(E->get()));
+ if (node) {
+ graph->set_selected(node);
+ _node_selected(node);
+ }
+ }
+ }
+
+ if (d.has("type") && String(d["type"])=="nodes") {
+
+ Node* sn = _find_script_node(get_tree()->get_edited_scene_root(),get_tree()->get_edited_scene_root(),script);
+
+
+ if (!sn) {
+ EditorNode::get_singleton()->show_warning("Can't drop nodes because script '"+get_name()+"' is not used in this scene.");
+ return;
+ }
+
+
+#ifdef OSX_ENABLED
+ bool use_node = Input::get_singleton()->is_key_pressed(KEY_META);
+#else
+ bool use_node = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+#endif
+
+
+ Array nodes = d["nodes"];
+
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+ ofs/=EDSCALE;
+
+ undo_redo->create_action(TTR("Add Node(s) From Tree"));
+ int base_id = script->get_available_id();
+
+ if (nodes.size()>1) {
+ use_node=true;
+ }
+
+ for(int i=0;i<nodes.size();i++) {
+
+ NodePath np = nodes[i];
+ Node *node = get_node(np);
+ if (!node) {
+ continue;
+ }
+
+ Ref<VisualScriptNode> n;
+
+ if (use_node) {
+ Ref<VisualScriptSceneNode> scene_node;
+ scene_node.instance();
+ scene_node->set_node_path(sn->get_path_to(node));
+ n=scene_node;
+
+
+ } else {
+ Ref<VisualScriptFunctionCall> call;
+ call.instance();
+ call->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH);
+ call->set_base_path(sn->get_path_to(node));;
+ call->set_base_type(node->get_type());
+ n=call;
+
+ method_select->select_method_from_instance(node);
+ selecting_method_id=base_id;
+
+ }
+
+
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,n,ofs);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id);
+
+ base_id++;
+ ofs+=Vector2(25,25);
+ }
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+
+ }
+
+ if (d.has("type") && String(d["type"])=="obj_property") {
+
+ Node* sn = _find_script_node(get_tree()->get_edited_scene_root(),get_tree()->get_edited_scene_root(),script);
+
+
+ if (!sn && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ EditorNode::get_singleton()->show_warning("Can't drop properties because script '"+get_name()+"' is not used in this scene.\nDrop holding 'Shift' to just copy the signature.");
+ return;
+ }
+
+ Object *obj=d["object"];
+
+ if (!obj)
+ return;
+
+ Node *node = obj->cast_to<Node>();
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+
+ ofs/=EDSCALE;
+#ifdef OSX_ENABLED
+ bool use_get = Input::get_singleton()->is_key_pressed(KEY_META);
+#else
+ bool use_get = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+#endif
+
+ if (!node || Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+
+
+ if (use_get)
+ undo_redo->create_action(TTR("Add Getter Property"));
+ else
+ undo_redo->create_action(TTR("Add Setter Property"));
+
+ int base_id = script->get_available_id();
+
+ Ref<VisualScriptNode> vnode;
+
+ if (!use_get) {
+
+ Ref<VisualScriptPropertySet> pset;
+ pset.instance();
+ pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
+ pset->set_base_type(obj->get_type());
+ /*if (use_value) {
+ pset->set_use_builtin_value(true);
+ pset->set_builtin_value(d["value"]);
+ }*/
+ vnode=pset;
+ } else {
+
+ Ref<VisualScriptPropertyGet> pget;
+ pget.instance();
+ pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
+ pget->set_base_type(obj->get_type());
+
+ vnode=pget;
+
+ }
+
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,vnode,ofs);
+ undo_redo->add_do_method(vnode.ptr(),"set_property",d["property"]);
+ if (!use_get) {
+ undo_redo->add_do_method(vnode.ptr(),"set_default_input_value",0,d["value"]);
+ }
+
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id);
+
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+
+ } else {
+
+
+
+ if (use_get)
+ undo_redo->create_action(TTR("Add Getter Property"));
+ else
+ undo_redo->create_action(TTR("Add Setter Property"));
+
+ int base_id = script->get_available_id();
+
+ Ref<VisualScriptNode> vnode;
+
+ if (!use_get) {
+
+ Ref<VisualScriptPropertySet> pset;
+ pset.instance();
+ if (sn==node) {
+ pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);
+ } else {
+ pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);
+ pset->set_base_path(sn->get_path_to(node));
+ }
+
+ vnode=pset;
+ } else {
+
+ Ref<VisualScriptPropertyGet> pget;
+ pget.instance();
+ if (sn==node) {
+ pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);
+ } else {
+ pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);
+ pget->set_base_path(sn->get_path_to(node));
+ }
+ vnode=pget;
+
+ }
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,vnode,ofs);
+ undo_redo->add_do_method(vnode.ptr(),"set_property",d["property"]);
+ if (!use_get) {
+ undo_redo->add_do_method(vnode.ptr(),"set_default_input_value",0,d["value"]);
+ }
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id);
+
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+ undo_redo->commit_action();
+ }
+
+
+ }
+
+
+ }
+
+
+}
+
+
+void VisualScriptEditor::_selected_method(const String& p_method) {
+
+ Ref<VisualScriptFunctionCall> vsfc = script->get_node(edited_func,selecting_method_id);
+ if (!vsfc.is_valid())
+ return;
+ vsfc->set_function(p_method);
+
+}
+
+void VisualScriptEditor::_draw_color_over_button(Object* obj,Color p_color) {
+
+ Button *button = obj->cast_to<Button>();
+ if (!button)
+ return;
+
+ Ref<StyleBox> normal = get_stylebox("normal","Button" );
+ button->draw_rect(Rect2(normal->get_offset(),button->get_size()-normal->get_minimum_size()),p_color);
+
+}
+
+void VisualScriptEditor::_button_resource_previewed(const String& p_path,const Ref<Texture>& p_preview,Variant p_ud) {
+
+
+ Array ud=p_ud;
+ ERR_FAIL_COND(ud.size()!=2);
+
+ ObjectID id = ud[0];
+ Object *obj = ObjectDB::get_instance(id);
+
+ if (!obj)
+ return;
+
+ Button *b = obj->cast_to<Button>();
+ ERR_FAIL_COND(!b);
+
+ if (p_preview.is_null()) {
+ b->set_text(ud[1]);
+ } else {
+
+ b->set_icon(p_preview);
+ }
+
+}
+
+/////////////////////////
+
+
+
+void VisualScriptEditor::apply_code() {
+
+
+}
+
+Ref<Script> VisualScriptEditor::get_edited_script() const{
+
+ return script;
+}
+
+Vector<String> VisualScriptEditor::get_functions(){
+
+ return Vector<String>();
+}
+
+void VisualScriptEditor::set_edited_script(const Ref<Script>& p_script){
+
+ script=p_script;
+ signal_editor->script=p_script;
+ signal_editor->undo_redo=undo_redo;
+ variable_editor->script=p_script;
+ variable_editor->undo_redo=undo_redo;
+
+
+ script->connect("node_ports_changed",this,"_node_ports_changed");
+
+ _update_members();
+ _update_available_nodes();
+}
+
+void VisualScriptEditor::reload_text(){
+
+
+}
+
+String VisualScriptEditor::get_name(){
+
+ String name;
+
+ if (script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) {
+ name=script->get_path().get_file();
+ if (is_unsaved()) {
+ name+="(*)";
+ }
+ } else if (script->get_name()!="")
+ name=script->get_name();
+ else
+ name=script->get_type()+"("+itos(script->get_instance_ID())+")";
+
+ return name;
+
+}
+
+Ref<Texture> VisualScriptEditor::get_icon(){
+
+ return Control::get_icon("VisualScript","EditorIcons");
+}
+
+bool VisualScriptEditor::is_unsaved(){
+#ifdef TOOLS_ENABLED
+ return script->is_edited();
+#else
+ return false;
+#endif
+}
+
+Variant VisualScriptEditor::get_edit_state(){
+
+ Dictionary d;
+ d["function"]=edited_func;
+ d["scroll"]=graph->get_scroll_ofs();
+ d["zoom"]=graph->get_zoom();
+ d["using_snap"]=graph->is_using_snap();
+ d["snap"]=graph->get_snap();
+ return d;
+}
+
+void VisualScriptEditor::set_edit_state(const Variant& p_state){
+
+ Dictionary d = p_state;
+ if (d.has("function")) {
+ edited_func=p_state;
+ selected=edited_func;
+
+ }
+
+ _update_graph();
+ _update_members();
+
+ if (d.has("scroll")) {
+ graph->set_scroll_ofs(d["scroll"]);
+ }
+ if (d.has("zoom")) {
+ graph->set_zoom(d["zoom"]);
+ }
+ if (d.has("snap")) {
+ graph->set_snap(d["snap"]);
+ }
+ if (d.has("snap_enabled")) {
+ graph->set_use_snap(d["snap_enabled"]);
+ }
+
+}
+
+
+void VisualScriptEditor::_center_on_node(int p_id) {
+
+ Node *n = graph->get_node(itos(p_id));
+ if (!n)
+ return;
+ GraphNode *gn = n->cast_to<GraphNode>();
+ if (gn) {
+ gn->set_selected(true);
+ Vector2 new_scroll = gn->get_offset() - graph->get_size()*0.5 + gn->get_size()*0.5;
+ graph->set_scroll_ofs( new_scroll );
+ script->set_function_scroll(edited_func,new_scroll/EDSCALE);
+ script->set_edited(true); //so it's saved
+
+ }
+}
+
+void VisualScriptEditor::goto_line(int p_line, bool p_with_error){
+
+ p_line+=1; //add one because script lines begin from 0.
+
+ if (p_with_error)
+ error_line=p_line;
+
+ List<StringName> functions;
+ script->get_function_list(&functions);
+ for (List<StringName>::Element *E=functions.front();E;E=E->next()) {
+
+ if (script->has_node(E->get(),p_line)) {
+
+ edited_func=E->get();
+ selected=edited_func;
+ _update_graph();
+ _update_members();
+
+ call_deferred("_center_on_node",p_line); //editor might be just created and size might not exist yet
+
+ return;
+ }
+ }
+}
+
+void VisualScriptEditor::trim_trailing_whitespace(){
+
+
+}
+
+void VisualScriptEditor::ensure_focus(){
+
+ graph->grab_focus();
+}
+
+void VisualScriptEditor::tag_saved_version(){
+
+
+}
+
+void VisualScriptEditor::reload(bool p_soft){
+
+
+}
+
+void VisualScriptEditor::get_breakpoints(List<int> *p_breakpoints){
+
+ List<StringName> functions;
+ script->get_function_list(&functions);
+ for (List<StringName>::Element *E=functions.front();E;E=E->next()) {
+
+ List<int> nodes;
+ script->get_node_list(E->get(),&nodes);
+ for (List<int>::Element *F=nodes.front();F;F=F->next()) {
+
+ Ref<VisualScriptNode> vsn = script->get_node(E->get(),F->get());
+ if (vsn->is_breakpoint()) {
+ p_breakpoints->push_back(F->get()-1); //subtract 1 because breakpoints in text start from zero
+ }
+ }
+ }
+}
+
+bool VisualScriptEditor::goto_method(const String& p_method){
+
+ if (!script->has_function(p_method))
+ return false;
+
+ edited_func=p_method;
+ selected=edited_func;
+ _update_members();
+ _update_graph();
+ return true;
+}
+
+void VisualScriptEditor::add_callback(const String& p_function,StringArray p_args){
+
+ if (script->has_function(p_function)) {
+ edited_func=p_function;
+ selected=edited_func;
+ _update_members();
+ _update_graph();
+ return;
+ }
+
+ Ref<VisualScriptFunction> func;
+ func.instance();
+ for(int i=0;i<p_args.size();i++) {
+
+ String name = p_args[i];
+ Variant::Type type=Variant::NIL;
+
+ if (name.find(":")!=-1) {
+ String tt = name.get_slice(":",1);
+ name=name.get_slice(":",0);
+ for(int j=0;j<Variant::VARIANT_MAX;j++) {
+
+ String tname = Variant::get_type_name(Variant::Type(j));
+ if (tname==tt) {
+ type=Variant::Type(j);
+ break;
+ }
+ }
+ }
+
+ func->add_argument(type,name);
+ }
+
+ func->set_name(p_function);
+ script->add_function(p_function);
+ script->add_node(p_function,script->get_available_id(),func);
+
+ edited_func=p_function;
+ selected=edited_func;
+ _update_members();
+ _update_graph();
+ graph->call_deferred("set_scroll_ofs",script->get_function_scroll(edited_func)); //for first time it might need to be later
+
+ //undo_redo->clear_history();
+
+}
+
+void VisualScriptEditor::update_settings(){
+
+ _update_graph();
+}
+
+void VisualScriptEditor::set_debugger_active(bool p_active) {
+ if (!p_active) {
+ error_line=-1;
+ _update_graph(); //clear line break
+ }
+}
+
+void VisualScriptEditor::set_tooltip_request_func(String p_method,Object* p_obj){
+
+
+}
+
+Control *VisualScriptEditor::get_edit_menu(){
+
+ return edit_menu;
+}
+
+void VisualScriptEditor::_change_base_type() {
+
+ select_base_type->popup(true);
+}
+
+void VisualScriptEditor::_change_base_type_callback() {
+
+ String bt = select_base_type->get_selected_type();
+
+ ERR_FAIL_COND(bt==String());
+ undo_redo->create_action("Change Base Type");
+ undo_redo->add_do_method(script.ptr(),"set_instance_base_type",bt);
+ undo_redo->add_undo_method(script.ptr(),"set_instance_base_type",script->get_instance_base_type());
+ undo_redo->add_do_method(this,"_update_members");
+ undo_redo->add_undo_method(this,"_update_members");
+ undo_redo->commit_action();
+
+}
+
+void VisualScriptEditor::_node_selected(Node* p_node) {
+
+ Ref<VisualScriptNode> vnode = p_node->get_meta("__vnode");
+ if (vnode.is_null())
+ return;
+
+ EditorNode::get_singleton()->push_item(vnode.ptr()); //edit node in inspector
+}
+
+static bool _get_out_slot(const Ref<VisualScriptNode>& p_node,int p_slot,int& r_real_slot,bool& r_sequence) {
+
+ if (p_slot<p_node->get_output_sequence_port_count()) {
+ r_sequence=true;
+ r_real_slot=p_slot;
+
+ return true;
+ }
+
+ r_real_slot=p_slot-p_node->get_output_sequence_port_count();
+ r_sequence=false;
+
+ return (r_real_slot<p_node->get_output_value_port_count());
+
+}
+
+static bool _get_in_slot(const Ref<VisualScriptNode>& p_node,int p_slot,int& r_real_slot,bool& r_sequence) {
+
+ if (p_slot==0 && p_node->has_input_sequence_port()) {
+ r_sequence=true;
+ r_real_slot=0;
+ return true;
+ }
+
+
+ r_real_slot=p_slot-(p_node->has_input_sequence_port()?1:0);
+ r_sequence=false;
+
+ return r_real_slot<p_node->get_input_value_port_count();
+
+}
+
+
+void VisualScriptEditor::_begin_node_move() {
+
+ undo_redo->create_action("Move Node(s)");
+}
+
+void VisualScriptEditor::_end_node_move() {
+
+ undo_redo->commit_action();
+}
+
+void VisualScriptEditor::_move_node(String func,int p_id,const Vector2& p_to) {
+
+
+
+ if (func==String(edited_func)) {
+ Node* node = graph->get_node(itos(p_id));
+ if (node && node->cast_to<GraphNode>())
+ node->cast_to<GraphNode>()->set_offset(p_to);
+ }
+ script->set_node_pos(edited_func,p_id,p_to/EDSCALE);
+}
+
+void VisualScriptEditor::_node_moved(Vector2 p_from,Vector2 p_to, int p_id) {
+
+ undo_redo->add_do_method(this,"_move_node",String(edited_func),p_id,p_to);
+ undo_redo->add_undo_method(this,"_move_node",String(edited_func),p_id,p_from);
+}
+
+void VisualScriptEditor::_remove_node(int p_id) {
+
+
+ undo_redo->create_action("Remove VisualScript Node");
+
+ undo_redo->add_do_method(script.ptr(),"remove_node",edited_func,p_id);
+ undo_redo->add_undo_method(script.ptr(),"add_node",edited_func,p_id,script->get_node(edited_func,p_id),script->get_node_pos(edited_func,p_id));
+
+
+ List<VisualScript::SequenceConnection> sequence_conns;
+ script->get_sequence_connection_list(edited_func,&sequence_conns);
+
+
+ for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) {
+
+ if (E->get().from_node==p_id || E->get().to_node==p_id) {
+ undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,E->get().from_node,E->get().from_output,E->get().to_node);
+ }
+ }
+
+ List<VisualScript::DataConnection> data_conns;
+ script->get_data_connection_list(edited_func,&data_conns);
+
+ for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) {
+
+ if (E->get().from_node==p_id || E->get().to_node==p_id) {
+ undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port);
+ }
+ }
+
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+
+ undo_redo->commit_action();
+}
+
+
+void VisualScriptEditor::_node_ports_changed(const String& p_func,int p_id) {
+
+ if (p_func!=String(edited_func))
+ return;
+
+ _update_graph(p_id);
+}
+
+void VisualScriptEditor::_graph_connected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot) {
+
+ Ref<VisualScriptNode> from_node = script->get_node(edited_func,p_from.to_int());
+ ERR_FAIL_COND(!from_node.is_valid());
+
+ bool from_seq;
+ int from_port;
+
+ if (!_get_out_slot(from_node,p_from_slot,from_port,from_seq))
+ return; //can't connect this, it' s invalid
+
+ Ref<VisualScriptNode> to_node = script->get_node(edited_func,p_to.to_int());
+ ERR_FAIL_COND(!to_node.is_valid());
+
+ bool to_seq;
+ int to_port;
+
+ if (!_get_in_slot(to_node,p_to_slot,to_port,to_seq))
+ return; //can't connect this, it' s invalid
+
+
+ ERR_FAIL_COND(from_seq!=to_seq);
+
+
+ undo_redo->create_action("Connect Nodes");
+
+ if (from_seq) {
+ undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+ undo_redo->add_undo_method(script.ptr(),"sequence_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+ } else {
+ undo_redo->add_do_method(script.ptr(),"data_connect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+ undo_redo->add_undo_method(script.ptr(),"data_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+ //update nodes in sgraph
+ undo_redo->add_do_method(this,"_update_graph",p_from.to_int());
+ undo_redo->add_do_method(this,"_update_graph",p_to.to_int());
+ undo_redo->add_undo_method(this,"_update_graph",p_from.to_int());
+ undo_redo->add_undo_method(this,"_update_graph",p_to.to_int());
+ }
+
+ undo_redo->add_do_method(this,"_update_graph_connections");
+ undo_redo->add_undo_method(this,"_update_graph_connections");
+
+ undo_redo->commit_action();
+
+}
+
+void VisualScriptEditor::_graph_disconnected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot){
+
+ Ref<VisualScriptNode> from_node = script->get_node(edited_func,p_from.to_int());
+ ERR_FAIL_COND(!from_node.is_valid());
+
+ bool from_seq;
+ int from_port;
+
+ if (!_get_out_slot(from_node,p_from_slot,from_port,from_seq))
+ return; //can't connect this, it' s invalid
+
+ Ref<VisualScriptNode> to_node = script->get_node(edited_func,p_to.to_int());
+ ERR_FAIL_COND(!to_node.is_valid());
+
+ bool to_seq;
+ int to_port;
+
+ if (!_get_in_slot(to_node,p_to_slot,to_port,to_seq))
+ return; //can't connect this, it' s invalid
+
+
+ ERR_FAIL_COND(from_seq!=to_seq);
+
+
+ undo_redo->create_action("Connect Nodes");
+
+ if (from_seq) {
+ undo_redo->add_do_method(script.ptr(),"sequence_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+ undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+ } else {
+ undo_redo->add_do_method(script.ptr(),"data_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+ undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+ //update nodes in sgraph
+ undo_redo->add_do_method(this,"_update_graph",p_from.to_int());
+ undo_redo->add_do_method(this,"_update_graph",p_to.to_int());
+ undo_redo->add_undo_method(this,"_update_graph",p_from.to_int());
+ undo_redo->add_undo_method(this,"_update_graph",p_to.to_int());
+ }
+ undo_redo->add_do_method(this,"_update_graph_connections");
+ undo_redo->add_undo_method(this,"_update_graph_connections");
+
+ undo_redo->commit_action();
+}
+
+
+void VisualScriptEditor::_graph_connect_to_empty(const String& p_from,int p_from_slot,const Vector2& p_release_pos) {
+
+
+}
+
+void VisualScriptEditor::_default_value_changed() {
+
+
+ Ref<VisualScriptNode> vsn = script->get_node(edited_func,editing_id);
+ if (vsn.is_null())
+ return;
+
+ undo_redo->create_action("Change Input Value");
+ undo_redo->add_do_method(vsn.ptr(),"set_default_input_value",editing_input,default_value_edit->get_variant());
+ undo_redo->add_undo_method(vsn.ptr(),"set_default_input_value",editing_input,vsn->get_default_input_value(editing_input));
+
+ undo_redo->add_do_method(this,"_update_graph",editing_id);
+ undo_redo->add_undo_method(this,"_update_graph",editing_id);
+ undo_redo->commit_action();
+
+}
+
+void VisualScriptEditor::_default_value_edited(Node * p_button,int p_id,int p_input_port) {
+
+ Ref<VisualScriptNode> vsn = script->get_node(edited_func,p_id);
+ if (vsn.is_null())
+ return;
+
+ PropertyInfo pinfo = vsn->get_input_value_port_info(p_input_port);
+ Variant existing = vsn->get_default_input_value(p_input_port);
+ if (pinfo.type!=Variant::NIL && existing.get_type()!=pinfo.type) {
+
+ Variant::CallError ce;
+ const Variant *existingp=&existing;
+ existing = Variant::construct(pinfo.type,&existingp,1,ce,false);
+
+ }
+
+ default_value_edit->set_pos(p_button->cast_to<Control>()->get_global_pos()+Vector2(0,p_button->cast_to<Control>()->get_size().y));
+ default_value_edit->set_size(Size2(1,1));
+ if (default_value_edit->edit(NULL,pinfo.name,pinfo.type,existing,pinfo.hint,pinfo.hint_string)) {
+ if (pinfo.hint==PROPERTY_HINT_MULTILINE_TEXT)
+ default_value_edit->popup_centered_ratio();
+ else
+ default_value_edit->popup();
+ }
+
+ editing_id = p_id;
+ editing_input=p_input_port;
+
+}
+
+void VisualScriptEditor::_show_hint(const String& p_hint) {
+
+ hint_text->set_text(p_hint);
+ hint_text->show();
+ hint_text_timer->start();
+}
+
+void VisualScriptEditor::_hide_timer() {
+
+ hint_text->hide();
+}
+
+void VisualScriptEditor::_node_filter_changed(const String& p_text) {
+
+ _update_available_nodes();
+}
+
+void VisualScriptEditor::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_READY) {
+ node_filter_icon->set_texture(Control::get_icon("Zoom","EditorIcons"));
+ }
+}
+
+void VisualScriptEditor::_graph_ofs_changed(const Vector2& p_ofs) {
+
+ if (updating_graph)
+ return;
+
+ updating_graph=true;
+
+ if (script->has_function(edited_func)) {
+ script->set_function_scroll(edited_func,graph->get_scroll_ofs()/EDSCALE);
+ script->set_edited(true);
+ }
+ updating_graph=false;
+}
+
+void VisualScriptEditor::_comment_node_resized(const Vector2& p_new_size,int p_node) {
+
+ if (updating_graph)
+ return;
+
+ Ref<VisualScriptComment> vsc = script->get_node(edited_func,p_node);
+ if (vsc.is_null())
+ return;
+
+ Node *node = graph->get_node(itos(p_node));
+ if (!node)
+ return;
+ GraphNode *gn = node->cast_to<GraphNode>();
+ if (!gn)
+ return;
+
+ updating_graph=true;
+
+ graph->set_block_minimum_size_adjust(true); //faster resize
+
+ undo_redo->create_action("Resize Comment",UndoRedo::MERGE_ENDS);
+ undo_redo->add_do_method(vsc.ptr(),"set_size",p_new_size/EDSCALE);
+ undo_redo->add_undo_method(vsc.ptr(),"set_size",vsc->get_size());
+ undo_redo->commit_action();
+
+ gn->set_custom_minimum_size(p_new_size); //for this time since graph update is blocked
+ gn->set_size(Size2(1,1));
+ graph->set_block_minimum_size_adjust(false);
+ updating_graph=false;
+
+
+}
+
+void VisualScriptEditor::_menu_option(int p_what) {
+
+ switch(p_what) {
+ case EDIT_DELETE_NODES: {
+ _on_nodes_delete();
+ } break;
+ case EDIT_TOGGLE_BREAKPOINT: {
+
+ List<String> reselect;
+ for(int i=0;i<graph->get_child_count();i++) {
+ GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+ if (gn) {
+ if (gn->is_selected()) {
+ int id = String(gn->get_name()).to_int();
+ Ref<VisualScriptNode> vsn = script->get_node(edited_func,id);
+ if (vsn.is_valid()) {
+ vsn->set_breakpoint(!vsn->is_breakpoint());
+ reselect.push_back(gn->get_name());
+ }
+ }
+ }
+ }
+
+ _update_graph();
+
+ for(List<String>::Element *E=reselect.front();E;E=E->next()) {
+ GraphNode *gn = graph->get_node(E->get())->cast_to<GraphNode>();
+ gn->set_selected(true);
+ }
+
+ } break;
+ case EDIT_FIND_NODE_TYPE: {
+ //popup disappearing grabs focus to owner, so use call deferred
+ node_filter->call_deferred("grab_focus");
+ node_filter->call_deferred("select_all");
+ } break;
+ case EDIT_COPY_NODES:
+ case EDIT_CUT_NODES: {
+
+ if (!script->has_function(edited_func))
+ break;
+
+ clipboard.nodes.clear();
+ clipboard.data_connections.clear();
+ clipboard.sequence_connections.clear();
+
+ for(int i=0;i<graph->get_child_count();i++) {
+ GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+ if (gn) {
+ if (gn->is_selected()) {
+
+ int id = String(gn->get_name()).to_int();
+ Ref<VisualScriptNode> node = script->get_node(edited_func,id);
+ if (node->cast_to<VisualScriptFunction>()) {
+ EditorNode::get_singleton()->show_warning("Can't copy the function node.");
+ return;
+ }
+ if (node.is_valid()) {
+ clipboard.nodes[id]=node->duplicate();
+ clipboard.nodes_positions[id]=script->get_node_pos(edited_func,id);
+ }
+
+ }
+ }
+ }
+
+ if (clipboard.nodes.empty())
+ break;
+
+ List<VisualScript::SequenceConnection> sequence_connections;
+
+ script->get_sequence_connection_list(edited_func,&sequence_connections);
+
+ for (List<VisualScript::SequenceConnection>::Element *E=sequence_connections.front();E;E=E->next()) {
+
+ if (clipboard.nodes.has(E->get().from_node) && clipboard.nodes.has(E->get().to_node)) {
+
+ clipboard.sequence_connections.insert(E->get());
+ }
+ }
+
+ List<VisualScript::DataConnection> data_connections;
+
+ script->get_data_connection_list(edited_func,&data_connections);
+
+ for (List<VisualScript::DataConnection>::Element *E=data_connections.front();E;E=E->next()) {
+
+ if (clipboard.nodes.has(E->get().from_node) && clipboard.nodes.has(E->get().to_node)) {
+
+ clipboard.data_connections.insert(E->get());
+ }
+ }
+
+ if (p_what==EDIT_CUT_NODES) {
+ _on_nodes_delete(); // oh yeah, also delete on cut
+ }
+
+
+ } break;
+ case EDIT_PASTE_NODES: {
+ if (!script->has_function(edited_func))
+ break;
+
+ if (clipboard.nodes.empty()) {
+ EditorNode::get_singleton()->show_warning("Clipboard is empty!");
+ break;
+ }
+
+ Map<int,int> remap;
+
+ undo_redo->create_action("Paste VisualScript Nodes");
+ int idc=script->get_available_id()+1;
+
+ Set<int> to_select;
+
+ Set<Vector2> existing_positions;
+
+ {
+ List<int> nodes;
+ script->get_node_list(edited_func,&nodes);
+ for (List<int>::Element *E=nodes.front();E;E=E->next()) {
+ Vector2 pos = script->get_node_pos(edited_func,E->get()).snapped(Vector2(2,2));
+ existing_positions.insert(pos);
+ }
+ }
+
+ for (Map<int,Ref<VisualScriptNode> >::Element *E=clipboard.nodes.front();E;E=E->next()) {
+
+
+ Ref<VisualScriptNode> node = E->get()->duplicate();
+
+ int new_id = idc++;
+ to_select.insert(new_id);
+
+ remap[E->key()]=new_id;
+
+ Vector2 paste_pos = clipboard.nodes_positions[E->key()];
+
+ while(existing_positions.has(paste_pos.snapped(Vector2(2,2)))) {
+ paste_pos+=Vector2(20,20)*EDSCALE;
+ }
+
+
+ undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,node,paste_pos);
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+
+ }
+
+ for (Set<VisualScript::SequenceConnection>::Element *E=clipboard.sequence_connections.front();E;E=E->next()) {
+
+
+ undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,remap[E->get().from_node],E->get().from_output,remap[E->get().to_node]);
+ undo_redo->add_undo_method(script.ptr(),"sequence_disconnect",edited_func,remap[E->get().from_node],E->get().from_output,remap[E->get().to_node]);
+
+ }
+
+ for (Set<VisualScript::DataConnection>::Element *E=clipboard.data_connections.front();E;E=E->next()) {
+
+
+ undo_redo->add_do_method(script.ptr(),"data_connect",edited_func,remap[E->get().from_node],E->get().from_port,remap[E->get().to_node],E->get().to_port);
+ undo_redo->add_undo_method(script.ptr(),"data_disconnect",edited_func,remap[E->get().from_node],E->get().from_port,remap[E->get().to_node],E->get().to_port);
+
+ }
+
+ undo_redo->add_do_method(this,"_update_graph");
+ undo_redo->add_undo_method(this,"_update_graph");
+
+ undo_redo->commit_action();
+
+ for(int i=0;i<graph->get_child_count();i++) {
+ GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+ if (gn) {
+ int id = gn->get_name().operator String().to_int();
+ gn->set_selected(to_select.has(id));
+
+ }
+ }
+ } break;
+
+
+ }
+}
+
+void VisualScriptEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_member_button",&VisualScriptEditor::_member_button);
+ ObjectTypeDB::bind_method("_member_edited",&VisualScriptEditor::_member_edited);
+ ObjectTypeDB::bind_method("_member_selected",&VisualScriptEditor::_member_selected);
+ ObjectTypeDB::bind_method("_update_members",&VisualScriptEditor::_update_members);
+ ObjectTypeDB::bind_method("_change_base_type",&VisualScriptEditor::_change_base_type);
+ ObjectTypeDB::bind_method("_change_base_type_callback",&VisualScriptEditor::_change_base_type_callback);
+ ObjectTypeDB::bind_method("_override_pressed",&VisualScriptEditor::_override_pressed);
+ ObjectTypeDB::bind_method("_node_selected",&VisualScriptEditor::_node_selected);
+ ObjectTypeDB::bind_method("_node_moved",&VisualScriptEditor::_node_moved);
+ ObjectTypeDB::bind_method("_move_node",&VisualScriptEditor::_move_node);
+ ObjectTypeDB::bind_method("_begin_node_move",&VisualScriptEditor::_begin_node_move);
+ ObjectTypeDB::bind_method("_end_node_move",&VisualScriptEditor::_end_node_move);
+ ObjectTypeDB::bind_method("_remove_node",&VisualScriptEditor::_remove_node);
+ ObjectTypeDB::bind_method("_update_graph",&VisualScriptEditor::_update_graph,DEFVAL(-1));
+ ObjectTypeDB::bind_method("_node_ports_changed",&VisualScriptEditor::_node_ports_changed);
+ ObjectTypeDB::bind_method("_available_node_doubleclicked",&VisualScriptEditor::_available_node_doubleclicked);
+ ObjectTypeDB::bind_method("_default_value_edited",&VisualScriptEditor::_default_value_edited);
+ ObjectTypeDB::bind_method("_default_value_changed",&VisualScriptEditor::_default_value_changed);
+ ObjectTypeDB::bind_method("_menu_option",&VisualScriptEditor::_menu_option);
+ ObjectTypeDB::bind_method("_graph_ofs_changed",&VisualScriptEditor::_graph_ofs_changed);
+ ObjectTypeDB::bind_method("_center_on_node",&VisualScriptEditor::_center_on_node);
+ ObjectTypeDB::bind_method("_comment_node_resized",&VisualScriptEditor::_comment_node_resized);
+ ObjectTypeDB::bind_method("_button_resource_previewed",&VisualScriptEditor::_button_resource_previewed);
+
+
+
+
+ ObjectTypeDB::bind_method("get_drag_data_fw",&VisualScriptEditor::get_drag_data_fw);
+ ObjectTypeDB::bind_method("can_drop_data_fw",&VisualScriptEditor::can_drop_data_fw);
+ ObjectTypeDB::bind_method("drop_data_fw",&VisualScriptEditor::drop_data_fw);
+
+ ObjectTypeDB::bind_method("_input",&VisualScriptEditor::_input);
+ ObjectTypeDB::bind_method("_on_nodes_delete",&VisualScriptEditor::_on_nodes_delete);
+ ObjectTypeDB::bind_method("_on_nodes_duplicate",&VisualScriptEditor::_on_nodes_duplicate);
+
+ ObjectTypeDB::bind_method("_hide_timer",&VisualScriptEditor::_hide_timer);
+
+ ObjectTypeDB::bind_method("_graph_connected",&VisualScriptEditor::_graph_connected);
+ ObjectTypeDB::bind_method("_graph_disconnected",&VisualScriptEditor::_graph_disconnected);
+ ObjectTypeDB::bind_method("_graph_connect_to_empty",&VisualScriptEditor::_graph_connect_to_empty);
+
+ ObjectTypeDB::bind_method("_update_graph_connections",&VisualScriptEditor::_update_graph_connections);
+ ObjectTypeDB::bind_method("_node_filter_changed",&VisualScriptEditor::_node_filter_changed);
+
+ ObjectTypeDB::bind_method("_selected_method",&VisualScriptEditor::_selected_method);
+ ObjectTypeDB::bind_method("_draw_color_over_button",&VisualScriptEditor::_draw_color_over_button);
+
+
+
+
+}
+
+
+
+VisualScriptEditor::VisualScriptEditor() {
+
+ updating_graph=false;
+
+ edit_menu = memnew( MenuButton );
+ edit_menu->set_text(TTR("Edit"));
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/delete_selected"), EDIT_DELETE_NODES);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE);
+ edit_menu->get_popup()->add_separator();
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/copy_nodes"), EDIT_COPY_NODES);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/cut_nodes"), EDIT_CUT_NODES);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/paste_nodes"), EDIT_PASTE_NODES);
+
+ edit_menu->get_popup()->connect("item_pressed",this,"_menu_option");
+
+ main_hsplit = memnew( HSplitContainer );
+ add_child(main_hsplit);
+ main_hsplit->set_area_as_parent_rect();
+
+ left_vsplit = memnew( VSplitContainer );
+ main_hsplit->add_child(left_vsplit);
+
+ VBoxContainer *left_vb = memnew( VBoxContainer );
+ left_vsplit->add_child(left_vb);
+ left_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ left_vb->set_custom_minimum_size(Size2(180,1)*EDSCALE);
+
+ base_type_select = memnew( Button );
+ left_vb->add_margin_child(TTR("Base Type:"),base_type_select);
+ base_type_select->connect("pressed",this,"_change_base_type");
+
+ members = memnew( Tree );
+ left_vb->add_margin_child(TTR("Members:"),members,true);
+ members->set_hide_root(true);
+ members->connect("button_pressed",this,"_member_button");
+ members->connect("item_edited",this,"_member_edited");
+ members->connect("cell_selected",this,"_member_selected",varray(),CONNECT_DEFERRED);
+ members->set_single_select_cell_editing_only_when_already_selected(true);
+ members->set_hide_folding(true);
+ members->set_drag_forwarding(this);
+
+
+ VBoxContainer *left_vb2 = memnew( VBoxContainer );
+ left_vsplit->add_child(left_vb2);
+ left_vb2->set_v_size_flags(SIZE_EXPAND_FILL);
+
+
+ VBoxContainer *vbc_nodes = memnew( VBoxContainer );
+ HBoxContainer *hbc_nodes = memnew( HBoxContainer );
+ node_filter = memnew (LineEdit);
+ node_filter->connect("text_changed",this,"_node_filter_changed");
+ hbc_nodes->add_child(node_filter);
+ node_filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ node_filter_icon = memnew( TextureFrame );
+ node_filter_icon->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED);
+ hbc_nodes->add_child(node_filter_icon);
+ vbc_nodes->add_child(hbc_nodes);
+
+ nodes = memnew( Tree );
+ vbc_nodes->add_child(nodes);
+ nodes->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ left_vb2->add_margin_child(TTR("Available Nodes:"),vbc_nodes,true);
+
+ nodes->set_hide_root(true);
+ nodes->connect("item_activated",this,"_available_node_doubleclicked");
+ nodes->set_drag_forwarding(this);
+
+ graph = memnew( GraphEdit );
+ main_hsplit->add_child(graph);
+ graph->set_h_size_flags(SIZE_EXPAND_FILL);
+ graph->connect("node_selected",this,"_node_selected");
+ graph->connect("_begin_node_move",this,"_begin_node_move");
+ graph->connect("_end_node_move",this,"_end_node_move");
+ graph->connect("delete_nodes_request",this,"_on_nodes_delete");
+ graph->connect("duplicate_nodes_request",this,"_on_nodes_duplicate");
+ graph->set_drag_forwarding(this);
+ graph->hide();
+ graph->connect("scroll_offset_changed",this,"_graph_ofs_changed");
+
+ select_func_text = memnew( Label );
+ select_func_text->set_text(TTR("Select or create a function to edit graph"));
+ select_func_text->set_align(Label::ALIGN_CENTER);
+ select_func_text->set_valign(Label::VALIGN_CENTER);
+ select_func_text->set_h_size_flags(SIZE_EXPAND_FILL);
+ main_hsplit->add_child(select_func_text);
+
+
+ hint_text = memnew( Label );
+ hint_text->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,100);
+ hint_text->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0);
+ hint_text->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0);
+ hint_text->set_align(Label::ALIGN_CENTER);
+ hint_text->set_valign(Label::VALIGN_CENTER);
+ graph->add_child(hint_text);
+
+ hint_text_timer = memnew( Timer );
+ hint_text_timer->set_wait_time(4);
+ hint_text_timer->connect("timeout",this,"_hide_timer");
+ add_child(hint_text_timer);
+
+ //allowed casts (connections)
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ graph->add_valid_connection_type(Variant::NIL,i);
+ graph->add_valid_connection_type(i,Variant::NIL);
+ for(int j=0;j<Variant::VARIANT_MAX;j++) {
+ if (Variant::can_convert(Variant::Type(i),Variant::Type(j))) {
+ graph->add_valid_connection_type(i,j);
+ }
+ }
+
+ graph->add_valid_right_disconnect_type(i);
+ }
+
+ graph->add_valid_left_disconnect_type(TYPE_SEQUENCE);
+
+ graph->connect("connection_request",this,"_graph_connected");
+ graph->connect("disconnection_request",this,"_graph_disconnected");
+ graph->connect("connection_to_empty",this,"_graph_connect_to_empty");
+
+ edit_signal_dialog = memnew( AcceptDialog );
+ edit_signal_dialog->get_ok()->set_text(TTR("Close"));
+ add_child(edit_signal_dialog);
+ edit_signal_dialog->set_title(TTR("Edit Signal Arguments:"));
+
+ signal_editor = memnew( VisualScriptEditorSignalEdit );
+ edit_signal_edit = memnew( PropertyEditor );
+ edit_signal_edit->hide_top_label();
+ edit_signal_dialog->add_child(edit_signal_edit);
+ edit_signal_dialog->set_child_rect(edit_signal_edit);
+ edit_signal_edit->edit(signal_editor);
+
+ edit_variable_dialog = memnew( AcceptDialog );
+ edit_variable_dialog->get_ok()->set_text(TTR("Close"));
+ add_child(edit_variable_dialog);
+ edit_variable_dialog->set_title(TTR("Edit Variable:"));
+
+ variable_editor = memnew( VisualScriptEditorVariableEdit );
+ edit_variable_edit = memnew( PropertyEditor );
+ edit_variable_edit->hide_top_label();
+ edit_variable_dialog->add_child(edit_variable_edit);
+ edit_variable_dialog->set_child_rect(edit_variable_edit);
+ edit_variable_edit->edit(variable_editor);
+
+ select_base_type=memnew(CreateDialog);
+ select_base_type->set_base_type("Object"); //anything goes
+ select_base_type->connect("create",this,"_change_base_type_callback");
+ select_base_type->get_ok()->set_text(TTR("Change"));
+ add_child(select_base_type);
+
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ new_function_menu = memnew( PopupMenu );
+ new_function_menu->connect("item_pressed",this,"_override_pressed");
+ add_child(new_function_menu);
+ updating_members=false;
+
+ set_process_input(true); //for revert on drag
+ set_process_unhandled_input(true); //for revert on drag
+
+ default_value_edit= memnew( CustomPropertyEditor);
+ add_child(default_value_edit);
+ default_value_edit->connect("variant_changed",this,"_default_value_changed");
+
+ method_select = memnew( PropertySelector );
+ add_child(method_select);
+ method_select->connect("selected",this,"_selected_method");
+ error_line=-1;
+
+}
+
+VisualScriptEditor::~VisualScriptEditor() {
+
+ undo_redo->clear_history(); //avoid crashes
+ memdelete(signal_editor);
+ memdelete(variable_editor);
+}
+
+static ScriptEditorBase * create_editor(const Ref<Script>& p_script) {
+
+ if (p_script->cast_to<VisualScript>()) {
+ return memnew( VisualScriptEditor );
+ }
+
+ return NULL;
+}
+
+static void register_editor_callback() {
+
+ ScriptEditor::register_create_script_editor_function(create_editor);
+ EditorSettings::get_singleton()->set("visual_script_editor/color_functions",Color(1,0.9,0.9));
+ EditorSettings::get_singleton()->set("visual_script_editor/color_data",Color(0.9,1.0,0.9));
+ EditorSettings::get_singleton()->set("visual_script_editor/color_operators",Color(0.9,0.9,1.0));
+ EditorSettings::get_singleton()->set("visual_script_editor/color_flow_control",Color(1.0,1.0,0.8));
+ EditorSettings::get_singleton()->set("visual_script_editor/color_custom",Color(0.8,1.0,1.0));
+
+
+ ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"));
+ ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
+ ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KEY_MASK_CMD+KEY_F);
+ ED_SHORTCUT("visual_script_editor/copy_nodes", TTR("Copy Nodes"), KEY_MASK_CMD+KEY_C);
+ ED_SHORTCUT("visual_script_editor/cut_nodes", TTR("Cut Nodes"), KEY_MASK_CMD+KEY_X);
+ ED_SHORTCUT("visual_script_editor/paste_nodes", TTR("Paste Nodes"), KEY_MASK_CMD+KEY_V);
+
+}
+
+void VisualScriptEditor::register_editor() {
+
+ //too early to register stuff here, request a callback
+ EditorNode::add_plugin_init_callback(register_editor_callback);
+
+
+
+}
+
+#endif
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
new file mode 100644
index 0000000000..735eaae446
--- /dev/null
+++ b/modules/visual_script/visual_script_editor.h
@@ -0,0 +1,211 @@
+#ifndef VisualSCRIPT_EDITOR_H
+#define VisualSCRIPT_EDITOR_H
+
+#include "tools/editor/plugins/script_editor_plugin.h"
+#include "visual_script.h"
+#include "tools/editor/property_editor.h"
+#include "scene/gui/graph_edit.h"
+#include "tools/editor/create_dialog.h"
+#include "tools/editor/property_selector.h"
+class VisualScriptEditorSignalEdit;
+class VisualScriptEditorVariableEdit;
+
+
+#ifdef TOOLS_ENABLED
+
+class VisualScriptEditor : public ScriptEditorBase {
+ OBJ_TYPE(VisualScriptEditor,ScriptEditorBase)
+
+ enum {
+ TYPE_SEQUENCE=1000,
+ INDEX_BASE_SEQUENCE=1024
+
+
+ };
+
+ enum {
+ EDIT_DELETE_NODES,
+ EDIT_TOGGLE_BREAKPOINT,
+ EDIT_FIND_NODE_TYPE,
+ EDIT_COPY_NODES,
+ EDIT_CUT_NODES,
+ EDIT_PASTE_NODES,
+ };
+
+ MenuButton *edit_menu;
+
+ Ref<VisualScript> script;
+
+ Button *base_type_select;
+
+ HSplitContainer *main_hsplit;
+ VSplitContainer *left_vsplit;
+
+ GraphEdit *graph;
+
+ LineEdit *node_filter;
+ TextureFrame *node_filter_icon;
+
+ VisualScriptEditorSignalEdit *signal_editor;
+
+ AcceptDialog *edit_signal_dialog;
+ PropertyEditor *edit_signal_edit;
+
+ PropertySelector *method_select;
+
+ VisualScriptEditorVariableEdit *variable_editor;
+
+ AcceptDialog *edit_variable_dialog;
+ PropertyEditor *edit_variable_edit;
+
+ CustomPropertyEditor *default_value_edit;
+
+ UndoRedo *undo_redo;
+
+ Tree *members;
+ Tree *nodes;
+
+ Label *hint_text;
+ Timer *hint_text_timer;
+
+ Label *select_func_text;
+
+ bool updating_graph;
+
+ void _show_hint(const String& p_hint);
+ void _hide_timer();
+
+ CreateDialog *select_base_type;
+
+ struct VirtualInMenu {
+ String name;
+ Variant::Type ret;
+ bool ret_variant;
+ Vector< Pair<Variant::Type,String> > args;
+ };
+
+ Map<int,VirtualInMenu> virtuals_in_menu;
+
+ PopupMenu *new_function_menu;
+
+
+ StringName edited_func;
+
+ void _update_graph_connections();
+ void _update_graph(int p_only_id=-1);
+
+ bool updating_members;
+
+ void _update_members();
+
+ StringName selected;
+
+ String _validate_name(const String& p_name) const;
+
+ struct Clipboard {
+
+ Map<int,Ref<VisualScriptNode> > nodes;
+ Map<int,Vector2 > nodes_positions;
+
+ Set<VisualScript::SequenceConnection> sequence_connections;
+ Set<VisualScript::DataConnection> data_connections;
+ } clipboard;
+
+
+ int error_line;
+
+ void _node_selected(Node* p_node);
+ void _center_on_node(int p_id);
+
+ void _node_filter_changed(const String& p_text);
+ void _change_base_type_callback();
+ void _change_base_type();
+ void _member_selected();
+ void _member_edited();
+ void _override_pressed(int p_id);
+
+ void _begin_node_move();
+ void _end_node_move();
+ void _move_node(String func,int p_id,const Vector2& p_to);
+
+ void _node_moved(Vector2 p_from,Vector2 p_to, int p_id);
+ void _remove_node(int p_id);
+ void _graph_connected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot);
+ void _graph_disconnected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot);
+ void _graph_connect_to_empty(const String& p_from,int p_from_slot,const Vector2& p_release_pos);
+
+ void _node_ports_changed(const String& p_func,int p_id);
+ void _available_node_doubleclicked();
+
+ void _update_available_nodes();
+
+ void _member_button(Object *p_item, int p_column, int p_button);
+
+
+ String revert_on_drag;
+
+ void _input(const InputEvent& p_event);
+ void _on_nodes_delete();
+ void _on_nodes_duplicate();
+
+ Variant get_drag_data_fw(const Point2& p_point,Control* p_from);
+ bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const;
+ void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from);
+
+
+ int editing_id;
+ int editing_input;
+
+ void _default_value_changed();
+ void _default_value_edited(Node * p_button,int p_id,int p_input_port);
+
+ void _menu_option(int p_what);
+
+ void _graph_ofs_changed(const Vector2& p_ofs);
+ void _comment_node_resized(const Vector2& p_new_size,int p_node);
+
+ int selecting_method_id;
+ void _selected_method(const String& p_method);
+
+ void _draw_color_over_button(Object* obj,Color p_color);
+ void _button_resource_previewed(const String& p_path,const Ref<Texture>& p_preview,Variant p_ud);
+
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ virtual void apply_code();
+ virtual Ref<Script> get_edited_script() const;
+ virtual Vector<String> get_functions();
+ virtual void set_edited_script(const Ref<Script>& p_script);
+ virtual void reload_text();
+ virtual String get_name();
+ virtual Ref<Texture> get_icon();
+ virtual bool is_unsaved();
+ virtual Variant get_edit_state();
+ virtual void set_edit_state(const Variant& p_state);
+ virtual void goto_line(int p_line,bool p_with_error=false);
+ virtual void trim_trailing_whitespace();
+ virtual void ensure_focus();
+ virtual void tag_saved_version();
+ virtual void reload(bool p_soft);
+ virtual void get_breakpoints(List<int> *p_breakpoints);
+ virtual bool goto_method(const String& p_method);
+ virtual void add_callback(const String& p_function,StringArray p_args);
+ virtual void update_settings();
+ virtual void set_debugger_active(bool p_active);
+ virtual void set_tooltip_request_func(String p_method,Object* p_obj);
+ virtual Control *get_edit_menu();
+ virtual bool can_lose_focus_on_node_selection() { return false; }
+
+ static void register_editor();
+
+ VisualScriptEditor();
+ ~VisualScriptEditor();
+};
+#endif
+
+#endif // VisualSCRIPT_EDITOR_H
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
new file mode 100644
index 0000000000..700d5d57ff
--- /dev/null
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -0,0 +1,1875 @@
+#include "visual_script_flow_control.h"
+#include "os/keyboard.h"
+#include "globals.h"
+
+
+//////////////////////////////////////////
+////////////////RETURN////////////////////
+//////////////////////////////////////////
+
+int VisualScriptReturn::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptReturn::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptReturn::get_input_value_port_count() const{
+
+ return with_value?1:0;
+}
+int VisualScriptReturn::get_output_value_port_count() const{
+
+ return 0;
+}
+
+String VisualScriptReturn::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptReturn::get_input_value_port_info(int p_idx) const{
+
+ PropertyInfo pinfo;
+ pinfo.name="result";
+ pinfo.type=type;
+ return pinfo;
+}
+PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const{
+ return PropertyInfo();
+}
+
+String VisualScriptReturn::get_caption() const {
+
+ return "Return";
+}
+
+String VisualScriptReturn::get_text() const {
+
+ return get_name();
+}
+
+void VisualScriptReturn::set_return_type(Variant::Type p_type) {
+
+ if (type==p_type)
+ return;
+ type=p_type;
+ ports_changed_notify();
+
+}
+
+Variant::Type VisualScriptReturn::get_return_type() const{
+
+ return type;
+}
+
+void VisualScriptReturn::set_enable_return_value(bool p_enable) {
+ if (with_value==p_enable)
+ return;
+
+ with_value=p_enable;
+ ports_changed_notify();
+}
+
+bool VisualScriptReturn::is_return_value_enabled() const {
+
+ return with_value;
+}
+
+void VisualScriptReturn::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_return_type","type"),&VisualScriptReturn::set_return_type);
+ ObjectTypeDB::bind_method(_MD("get_return_type"),&VisualScriptReturn::get_return_type);
+ ObjectTypeDB::bind_method(_MD("set_enable_return_value","enable"),&VisualScriptReturn::set_enable_return_value);
+ ObjectTypeDB::bind_method(_MD("is_return_value_enabled"),&VisualScriptReturn::is_return_value_enabled);
+
+ String argt="Any";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"return_value/enabled"),_SCS("set_enable_return_value"),_SCS("is_return_value_enabled"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"return_value/type",PROPERTY_HINT_ENUM,argt),_SCS("set_return_type"),_SCS("get_return_type"));
+
+}
+
+class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptReturn *node;
+ VisualScriptInstance *instance;
+ bool with_value;
+
+ virtual int get_working_memory_size() const { return 1; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (with_value) {
+ *p_working_mem = *p_inputs[0];
+ } else {
+ *p_working_mem = Variant();
+ }
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptReturn::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceReturn * instance = memnew(VisualScriptNodeInstanceReturn );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->with_value=with_value;
+ return instance;
+}
+
+VisualScriptReturn::VisualScriptReturn() {
+
+ with_value=false;
+ type=Variant::NIL;
+}
+
+template<bool with_value>
+static Ref<VisualScriptNode> create_return_node(const String& p_name) {
+
+ Ref<VisualScriptReturn> node;
+ node.instance();
+ node->set_enable_return_value(with_value);
+ return node;
+}
+
+
+
+//////////////////////////////////////////
+////////////////CONDITION/////////////////
+//////////////////////////////////////////
+
+int VisualScriptCondition::get_output_sequence_port_count() const {
+
+ return 3;
+}
+
+bool VisualScriptCondition::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptCondition::get_input_value_port_count() const{
+
+ return 1;
+}
+int VisualScriptCondition::get_output_value_port_count() const{
+
+ return 0;
+}
+
+String VisualScriptCondition::get_output_sequence_port_text(int p_port) const {
+
+ if (p_port==0)
+ return "true";
+ else if (p_port==1)
+ return "false";
+ else
+ return "done";
+}
+
+PropertyInfo VisualScriptCondition::get_input_value_port_info(int p_idx) const{
+
+ PropertyInfo pinfo;
+ pinfo.name="cond";
+ pinfo.type=Variant::BOOL;
+ return pinfo;
+}
+PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const{
+ return PropertyInfo();
+}
+
+String VisualScriptCondition::get_caption() const {
+
+ return "Condition";
+}
+
+String VisualScriptCondition::get_text() const {
+
+ return "if (cond) is: ";
+}
+
+
+void VisualScriptCondition::_bind_methods() {
+
+
+
+}
+
+class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptCondition *node;
+ VisualScriptInstance *instance;
+
+ //virtual int get_working_memory_size() const { return 1; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (p_start_mode==START_MODE_CONTINUE_SEQUENCE)
+ return 2;
+ else if (p_inputs[0]->operator bool())
+ return 0 | STEP_FLAG_PUSH_STACK_BIT;
+ else
+ return 1 | STEP_FLAG_PUSH_STACK_BIT;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptCondition::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceCondition * instance = memnew(VisualScriptNodeInstanceCondition );
+ instance->node=this;
+ instance->instance=p_instance;
+ return instance;
+}
+
+VisualScriptCondition::VisualScriptCondition() {
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////WHILE/////////////////
+//////////////////////////////////////////
+
+int VisualScriptWhile::get_output_sequence_port_count() const {
+
+ return 2;
+}
+
+bool VisualScriptWhile::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptWhile::get_input_value_port_count() const{
+
+ return 1;
+}
+int VisualScriptWhile::get_output_value_port_count() const{
+
+ return 0;
+}
+
+String VisualScriptWhile::get_output_sequence_port_text(int p_port) const {
+
+ if (p_port==0)
+ return "repeat";
+ else
+ return "exit";
+}
+
+PropertyInfo VisualScriptWhile::get_input_value_port_info(int p_idx) const{
+
+ PropertyInfo pinfo;
+ pinfo.name="cond";
+ pinfo.type=Variant::BOOL;
+ return pinfo;
+}
+PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const{
+ return PropertyInfo();
+}
+
+String VisualScriptWhile::get_caption() const {
+
+ return "While";
+}
+
+String VisualScriptWhile::get_text() const {
+
+ return "while (cond): ";
+}
+
+
+void VisualScriptWhile::_bind_methods() {
+
+
+
+}
+
+class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptWhile *node;
+ VisualScriptInstance *instance;
+
+ //virtual int get_working_memory_size() const { return 1; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ bool keep_going = p_inputs[0]->operator bool();
+
+ if (keep_going)
+ return 0|STEP_FLAG_PUSH_STACK_BIT;
+ else
+ return 1;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptWhile::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceWhile * instance = memnew(VisualScriptNodeInstanceWhile );
+ instance->node=this;
+ instance->instance=p_instance;
+ return instance;
+}
+VisualScriptWhile::VisualScriptWhile() {
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////ITERATOR/////////////////
+//////////////////////////////////////////
+
+int VisualScriptIterator::get_output_sequence_port_count() const {
+
+ return 2;
+}
+
+bool VisualScriptIterator::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptIterator::get_input_value_port_count() const{
+
+ return 1;
+}
+int VisualScriptIterator::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptIterator::get_output_sequence_port_text(int p_port) const {
+
+ if (p_port==0)
+ return "each";
+ else
+ return "exit";
+}
+
+PropertyInfo VisualScriptIterator::get_input_value_port_info(int p_idx) const{
+
+ PropertyInfo pinfo;
+ pinfo.name="input";
+ pinfo.type=Variant::NIL;
+ return pinfo;
+}
+PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const{
+ PropertyInfo pinfo;
+ pinfo.name="elem";
+ pinfo.type=Variant::NIL;
+ return pinfo;
+}
+String VisualScriptIterator::get_caption() const {
+
+ return "Iterator";
+}
+
+String VisualScriptIterator::get_text() const {
+
+ return "for (elem) in (input): ";
+}
+
+
+void VisualScriptIterator::_bind_methods() {
+
+
+
+}
+
+class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptIterator *node;
+ VisualScriptInstance *instance;
+
+ virtual int get_working_memory_size() const { return 2; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (p_start_mode==START_MODE_BEGIN_SEQUENCE) {
+ p_working_mem[0]=*p_inputs[0];
+ bool valid;
+ bool can_iter = p_inputs[0]->iter_init(p_working_mem[1],valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Input type not iterable: ")+Variant::get_type_name(p_inputs[0]->get_type());
+ return 0;
+ }
+
+ if (!can_iter)
+ return 1; //nothing to iterate
+
+
+ *p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Iterator became invalid");
+ return 0;
+ }
+
+
+ } else { //continue sequence
+
+ bool valid;
+ bool can_iter = p_working_mem[0].iter_next(p_working_mem[1],valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Iterator became invalid: ")+Variant::get_type_name(p_inputs[0]->get_type());
+ return 0;
+ }
+
+ if (!can_iter)
+ return 1; //nothing to iterate
+
+
+ *p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Iterator became invalid");
+ return 0;
+ }
+
+ }
+
+ return 0|STEP_FLAG_PUSH_STACK_BIT; //go around
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptIterator::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceIterator * instance = memnew(VisualScriptNodeInstanceIterator );
+ instance->node=this;
+ instance->instance=p_instance;
+ return instance;
+}
+
+VisualScriptIterator::VisualScriptIterator() {
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////SEQUENCE/////////////////
+//////////////////////////////////////////
+
+int VisualScriptSequence::get_output_sequence_port_count() const {
+
+ return steps;
+}
+
+bool VisualScriptSequence::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptSequence::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptSequence::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptSequence::get_output_sequence_port_text(int p_port) const {
+
+ return itos(p_port+1);
+}
+
+PropertyInfo VisualScriptSequence::get_input_value_port_info(int p_idx) const{
+ return PropertyInfo();
+}
+PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const{
+ return PropertyInfo(Variant::INT,"current");
+}
+String VisualScriptSequence::get_caption() const {
+
+ return "Sequence";
+}
+
+String VisualScriptSequence::get_text() const {
+
+ return "in order: ";
+}
+
+void VisualScriptSequence::set_steps(int p_steps) {
+
+ ERR_FAIL_COND(p_steps<1);
+ if (steps==p_steps)
+ return;
+
+ steps=p_steps;
+ ports_changed_notify();
+
+}
+
+int VisualScriptSequence::get_steps() const {
+
+ return steps;
+}
+
+void VisualScriptSequence::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_steps","steps"),&VisualScriptSequence::set_steps);
+ ObjectTypeDB::bind_method(_MD("get_steps"),&VisualScriptSequence::get_steps);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"steps",PROPERTY_HINT_RANGE,"1,64,1"),_SCS("set_steps"),_SCS("get_steps"));
+
+}
+
+class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptSequence *node;
+ VisualScriptInstance *instance;
+ int steps;
+
+ virtual int get_working_memory_size() const { return 1; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (p_start_mode==START_MODE_BEGIN_SEQUENCE) {
+
+ p_working_mem[0]=0;
+ }
+
+ int step = p_working_mem[0];
+
+ *p_outputs[0]=step;
+
+ if (step+1==steps)
+ return step;
+ else {
+ p_working_mem[0]=step+1;
+ return step|STEP_FLAG_PUSH_STACK_BIT;
+ }
+
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptSequence::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceSequence * instance = memnew(VisualScriptNodeInstanceSequence );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->steps=steps;
+ return instance;
+}
+VisualScriptSequence::VisualScriptSequence() {
+
+ steps=1;
+}
+
+
+//////////////////////////////////////////
+////////////////EVENT TYPE FILTER///////////
+//////////////////////////////////////////
+
+static const char* event_type_names[InputEvent::TYPE_MAX]={
+ "None",
+ "Key",
+ "MouseMotion",
+ "MouseButton",
+ "JoystickMotion",
+ "JoystickButton",
+ "ScreenTouch",
+ "ScreenDrag",
+ "Action"
+};
+
+int VisualScriptInputSelector::get_output_sequence_port_count() const {
+
+ return InputEvent::TYPE_MAX;
+}
+
+bool VisualScriptInputSelector::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptInputSelector::get_input_value_port_count() const{
+
+
+ return 1;
+}
+int VisualScriptInputSelector::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptInputSelector::get_output_sequence_port_text(int p_port) const {
+
+ return event_type_names[p_port];
+}
+
+PropertyInfo VisualScriptInputSelector::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::INPUT_EVENT,"event");
+}
+
+PropertyInfo VisualScriptInputSelector::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::INPUT_EVENT,"");
+}
+
+
+String VisualScriptInputSelector::get_caption() const {
+
+ return "InputSelector";
+}
+
+String VisualScriptInputSelector::get_text() const {
+
+ return "";
+}
+
+
+class VisualScriptNodeInstanceInputSelector : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ InputEvent::Type type;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (p_inputs[0]->get_type()!=Variant::INPUT_EVENT) {
+ r_error_str="Input value not of type event";
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+
+ InputEvent event = *p_inputs[0];
+
+ *p_outputs[0] = event;
+
+ return event.type;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptInputSelector::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceInputSelector * instance = memnew(VisualScriptNodeInstanceInputSelector );
+ instance->instance=p_instance;
+ return instance;
+}
+
+
+
+void VisualScriptInputSelector::_bind_methods() {
+
+
+}
+
+VisualScriptInputSelector::VisualScriptInputSelector() {
+
+
+}
+
+//////////////////////////////////////////
+////////////////EVENT ACTION FILTER///////////
+//////////////////////////////////////////
+
+
+int VisualScriptInputFilter::get_output_sequence_port_count() const {
+
+ return filters.size();
+}
+
+bool VisualScriptInputFilter::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptInputFilter::get_input_value_port_count() const{
+
+
+ return 1;
+}
+int VisualScriptInputFilter::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const {
+
+ String text;
+
+ switch(filters[p_port].type) {
+ case InputEvent::NONE: {
+ text="None";
+ } break;
+ case InputEvent::KEY: {
+
+ InputEventKey k = filters[p_port].key;
+
+ if (k.scancode==0 && k.unicode==0) {
+ text="No Key";
+ } else {
+ if (k.scancode!=0) {
+ text="KeyCode: "+keycode_get_string(k.scancode);
+ } else if (k.unicode!=0) {
+ text="Uniode: "+String::chr(k.unicode);
+ }
+
+ if (k.pressed)
+ text+=", Pressed";
+ else
+ text+=", Released";
+
+ if (k.echo)
+ text+=", Echo";
+ if (k.mod.alt)
+ text="Alt+"+text;
+ if (k.mod.shift)
+ text="Shift+"+text;
+ if (k.mod.control)
+ text="Ctrl+"+text;
+ if (k.mod.meta)
+ text="Meta+"+text;
+ }
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+ InputEventMouseMotion mm = filters[p_port].mouse_motion;
+ text="Mouse Motion";
+
+ String b = "Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight";
+
+ for(int i=0;i<7;i++) {
+ if (mm.button_mask&(1<<i)) {
+ text=b.get_slice(",",i)+"+"+text;
+ }
+ }
+ if (mm.mod.alt)
+ text="Alt+"+text;
+ if (mm.mod.shift)
+ text="Shift+"+text;
+ if (mm.mod.control)
+ text="Ctrl+"+text;
+ if (mm.mod.meta)
+ text="Meta+"+text;
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ InputEventMouseButton mb = filters[p_port].mouse_button;
+
+ String b = "Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight";
+
+ text=b.get_slice(",",mb.button_index)+" Mouse Button";
+
+ if (mb.pressed)
+ text+=", Pressed";
+ else
+ text+=", Released";
+
+ if (mb.doubleclick)
+ text+=", DblClick";
+ if (mb.mod.alt)
+ text="Alt+"+text;
+ if (mb.mod.shift)
+ text="Shift+"+text;
+ if (mb.mod.control)
+ text="Ctrl+"+text;
+ if (mb.mod.meta)
+ text="Meta+"+text;
+
+
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ InputEventJoystickMotion jm = filters[p_port].joy_motion;
+
+ text="JoyMotion Axis "+itos(jm.axis>>1);
+ if (jm.axis&1)
+ text+=" > "+rtos(jm.axis_value);
+ else
+ text+=" < "+rtos(-jm.axis_value);
+
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+ InputEventJoystickButton jb = filters[p_port].joy_button;
+
+ text="JoyButton "+itos(jb.button_index);
+ if (jb.pressed)
+ text+=", Pressed";
+ else
+ text+=", Released";
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+ InputEventScreenTouch sd = filters[p_port].screen_touch;
+
+ text="Touch Finger "+itos(sd.index);
+ if (sd.pressed)
+ text+=", Pressed";
+ else
+ text+=", Released";
+ } break;
+ case InputEvent::SCREEN_DRAG: {
+ InputEventScreenDrag sd = filters[p_port].screen_drag;
+ text="Drag Finger "+itos(sd.index);
+ } break;
+ case InputEvent::ACTION: {
+
+
+ List<PropertyInfo> pinfo;
+ Globals::get_singleton()->get_property_list(&pinfo);
+ int index=1;
+
+ text="No Action";
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ const PropertyInfo &pi=E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+
+ if (filters[p_port].action.action==index) {
+ text="Action "+pi.name.substr(pi.name.find("/")+1,pi.name.length());
+ break;
+ }
+ index++;
+ }
+
+ if (filters[p_port].action.pressed)
+ text+=", Pressed";
+ else
+ text+=", Released";
+
+
+ } break;
+ }
+
+
+
+ return text+" - "+itos(p_port);
+}
+
+PropertyInfo VisualScriptInputFilter::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::INPUT_EVENT,"event");
+}
+
+PropertyInfo VisualScriptInputFilter::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::INPUT_EVENT,"");
+}
+
+
+String VisualScriptInputFilter::get_caption() const {
+
+ return "InputFilter";
+}
+
+String VisualScriptInputFilter::get_text() const {
+
+ return "";
+}
+
+
+
+bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_value) {
+
+ if (p_name=="filter_count") {
+ filters.resize(p_value);
+ _change_notify();
+ ports_changed_notify();
+ return true;
+ }
+
+
+ if (String(p_name).begins_with("filter_")) {
+
+ int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int();
+
+ ERR_FAIL_INDEX_V(idx,filters.size(),false);
+
+ String what = String(p_name).get_slice("/",1);
+
+
+ if (what=="type") {
+ filters[idx]=InputEvent();
+ filters[idx].type=InputEvent::Type(int(p_value));
+ if (filters[idx].type==InputEvent::JOYSTICK_MOTION) {
+ filters[idx].joy_motion.axis_value=0.5; //for treshold
+ } else if (filters[idx].type==InputEvent::KEY) {
+ filters[idx].key.pressed=true; //put these as true to make it more user friendly
+ } else if (filters[idx].type==InputEvent::MOUSE_BUTTON) {
+ filters[idx].mouse_button.pressed=true;
+ } else if (filters[idx].type==InputEvent::JOYSTICK_BUTTON) {
+ filters[idx].joy_button.pressed=true;
+ } else if (filters[idx].type==InputEvent::SCREEN_TOUCH) {
+ filters[idx].screen_touch.pressed=true;
+ } else if (filters[idx].type==InputEvent::ACTION) {
+ filters[idx].action.pressed=true;
+ }
+ _change_notify();
+ ports_changed_notify();
+
+ return true;
+ }
+ if (what=="device") {
+ filters[idx].device=p_value;
+ ports_changed_notify();
+ return true;
+ }
+
+ switch(filters[idx].type) {
+
+ case InputEvent::KEY: {
+
+ if (what=="scancode") {
+ String sc = p_value;
+ if (sc==String()) {
+ filters[idx].key.scancode=0;
+ } else {
+ filters[idx].key.scancode=find_keycode(p_value);
+ }
+
+ } else if (what=="unicode") {
+
+ String uc = p_value;
+
+ if (uc==String()) {
+ filters[idx].key.unicode=0;
+ } else {
+ filters[idx].key.unicode=uc[0];
+ }
+
+ } else if (what=="pressed") {
+
+ filters[idx].key.pressed=p_value;
+ } else if (what=="echo") {
+
+ filters[idx].key.echo=p_value;
+
+ } else if (what=="mod_alt") {
+ filters[idx].key.mod.alt=p_value;
+
+ } else if (what=="mod_shift") {
+ filters[idx].key.mod.shift=p_value;
+
+ } else if (what=="mod_ctrl") {
+ filters[idx].key.mod.control=p_value;
+
+ } else if (what=="mod_meta") {
+ filters[idx].key.mod.meta=p_value;
+ } else {
+ return false;
+ }
+ ports_changed_notify();
+
+ return true;
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+
+ if (what=="button_mask") {
+ filters[idx].mouse_motion.button_mask=p_value;
+
+ } else if (what=="mod_alt") {
+ filters[idx].mouse_motion.mod.alt=p_value;
+
+ } else if (what=="mod_shift") {
+ filters[idx].mouse_motion.mod.shift=p_value;
+
+ } else if (what=="mod_ctrl") {
+ filters[idx].mouse_motion.mod.control=p_value;
+
+ } else if (what=="mod_meta") {
+ filters[idx].mouse_motion.mod.meta=p_value;
+ } else {
+ return false;
+ }
+
+ ports_changed_notify();
+ return true;
+
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ if (what=="button_index") {
+ filters[idx].mouse_button.button_index=p_value;
+ } else if (what=="pressed") {
+ filters[idx].mouse_button.pressed=p_value;
+ } else if (what=="doubleclicked") {
+ filters[idx].mouse_button.doubleclick=p_value;
+
+ } else if (what=="mod_alt") {
+ filters[idx].mouse_button.mod.alt=p_value;
+
+ } else if (what=="mod_shift") {
+ filters[idx].mouse_button.mod.shift=p_value;
+
+ } else if (what=="mod_ctrl") {
+ filters[idx].mouse_button.mod.control=p_value;
+
+ } else if (what=="mod_meta") {
+ filters[idx].mouse_button.mod.meta=p_value;
+ } else {
+ return false;
+ }
+ ports_changed_notify();
+ return true;
+
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ if (what=="axis") {
+ filters[idx].joy_motion.axis=int(p_value)<<1|filters[idx].joy_motion.axis;
+ } else if (what=="mode") {
+ filters[idx].joy_motion.axis|=int(p_value);
+ } else if (what=="treshold") {
+ filters[idx].joy_motion.axis_value=p_value;
+ } else {
+ return false;
+ }
+ ports_changed_notify();
+ return true;
+
+
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ if (what=="button_index") {
+ filters[idx].joy_button.button_index=p_value;
+ } else if (what=="pressed") {
+ filters[idx].joy_button.pressed=p_value;
+ } else {
+ return false;
+ }
+ ports_changed_notify();
+ return true;
+
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+
+ if (what=="finger_index") {
+ filters[idx].screen_touch.index=p_value;
+ } else if (what=="pressed") {
+ filters[idx].screen_touch.pressed=p_value;
+ } else {
+ return false;
+ }
+ ports_changed_notify();
+ return true;
+ } break;
+ case InputEvent::SCREEN_DRAG: {
+ if (what=="finger_index") {
+ filters[idx].screen_drag.index=p_value;
+ } else {
+ return false;
+ }
+ ports_changed_notify();
+ return true;
+ } break;
+ case InputEvent::ACTION: {
+
+
+ if (what=="action_name") {
+
+ List<PropertyInfo> pinfo;
+ Globals::get_singleton()->get_property_list(&pinfo);
+ int index=1;
+
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ const PropertyInfo &pi=E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+ String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
+ if (name==String(p_value)) {
+
+ filters[idx].action.action=index;
+ ports_changed_notify();
+ return true;
+ }
+
+ index++;
+ }
+
+ filters[idx].action.action=0;
+ ports_changed_notify();
+
+ return false;
+
+ } else if (what=="pressed") {
+
+ filters[idx].action.pressed=p_value;
+ ports_changed_notify();
+ return true;
+ }
+
+
+ } break;
+
+ }
+ }
+ return false;
+}
+
+bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) const{
+
+ if (p_name=="filter_count") {
+ r_ret=filters.size();
+ return true;
+ }
+
+
+ if (String(p_name).begins_with("filter_")) {
+
+ int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int();
+
+ ERR_FAIL_INDEX_V(idx,filters.size(),false);
+
+ String what = String(p_name).get_slice("/",1);
+
+
+ if (what=="type") {
+ r_ret=filters[idx].type;
+ return true;
+ }
+ if (what=="device") {
+ r_ret=filters[idx].device;
+ return true;
+ }
+
+ switch(filters[idx].type) {
+
+ case InputEvent::KEY: {
+
+ if (what=="scancode") {
+ if (filters[idx].key.scancode==0)
+ r_ret=String();
+ else {
+
+ r_ret=keycode_get_string(filters[idx].key.scancode);
+ }
+
+ } else if (what=="unicode") {
+
+
+ if (filters[idx].key.unicode==0) {
+ r_ret=String();
+ } else {
+ CharType str[2]={ (CharType)filters[idx].key.unicode, 0};
+ r_ret=String(str);
+ }
+
+ } else if (what=="pressed") {
+
+ r_ret=filters[idx].key.pressed;
+ } else if (what=="echo") {
+
+ r_ret=filters[idx].key.echo;
+
+ } else if (what=="mod_alt") {
+ r_ret=filters[idx].key.mod.alt;
+
+ } else if (what=="mod_shift") {
+ r_ret=filters[idx].key.mod.shift;
+
+ } else if (what=="mod_ctrl") {
+ r_ret=filters[idx].key.mod.control;
+
+ } else if (what=="mod_meta") {
+ r_ret=filters[idx].key.mod.meta;
+ } else {
+ return false;
+ }
+
+ return true;
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+
+ if (what=="button_mask") {
+ r_ret=filters[idx].mouse_motion.button_mask;
+
+ } else if (what=="mod_alt") {
+ r_ret=filters[idx].mouse_motion.mod.alt;
+
+ } else if (what=="mod_shift") {
+ r_ret=filters[idx].mouse_motion.mod.shift;
+
+ } else if (what=="mod_ctrl") {
+ r_ret=filters[idx].mouse_motion.mod.control;
+
+ } else if (what=="mod_meta") {
+ r_ret=filters[idx].mouse_motion.mod.meta;
+ } else {
+ return false;
+ }
+
+ return true;
+
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ if (what=="button_index") {
+ r_ret=filters[idx].mouse_button.button_index;
+ } else if (what=="pressed") {
+ r_ret=filters[idx].mouse_button.pressed;
+ } else if (what=="doubleclicked") {
+ r_ret=filters[idx].mouse_button.doubleclick;
+
+ } else if (what=="mod_alt") {
+ r_ret=filters[idx].mouse_button.mod.alt;
+
+ } else if (what=="mod_shift") {
+ r_ret=filters[idx].mouse_button.mod.shift;
+
+ } else if (what=="mod_ctrl") {
+ r_ret=filters[idx].mouse_button.mod.control;
+
+ } else if (what=="mod_meta") {
+ r_ret=filters[idx].mouse_button.mod.meta;
+ } else {
+ return false;
+ }
+ return true;
+
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ if (what=="axis_index") {
+ r_ret=filters[idx].joy_motion.axis>>1;
+ } else if (what=="mode") {
+ r_ret=filters[idx].joy_motion.axis&1;
+ } else if (what=="treshold") {
+ r_ret=filters[idx].joy_motion.axis_value;
+ } else {
+ return false;
+ }
+ return true;
+
+
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ if (what=="button_index") {
+ r_ret=filters[idx].joy_button.button_index;
+ } else if (what=="pressed") {
+ r_ret=filters[idx].joy_button.pressed;
+ } else {
+ return false;
+ }
+ return true;
+
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+
+ if (what=="finger_index") {
+ r_ret=filters[idx].screen_touch.index;
+ } else if (what=="pressed") {
+ r_ret=filters[idx].screen_touch.pressed;
+ } else {
+ return false;
+ }
+ return true;
+ } break;
+ case InputEvent::SCREEN_DRAG: {
+ if (what=="finger_index") {
+ r_ret=filters[idx].screen_drag.index;
+ } else {
+ return false;
+ }
+ return true;
+ } break;
+ case InputEvent::ACTION: {
+
+
+ if (what=="action_name") {
+
+ List<PropertyInfo> pinfo;
+ Globals::get_singleton()->get_property_list(&pinfo);
+ int index=1;
+
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ const PropertyInfo &pi=E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+
+ if (filters[idx].action.action==index) {
+ r_ret=pi.name.substr(pi.name.find("/")+1,pi.name.length());
+ return true;
+ }
+ index++;
+ }
+
+ r_ret="None"; //no index
+ return false;
+
+ } else if (what=="pressed") {
+
+ r_ret=filters[idx].action.pressed;
+ return true;
+ }
+
+
+ } break;
+
+ }
+ }
+ return false;
+}
+void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) const {
+
+ p_list->push_back(PropertyInfo(Variant::INT,"filter_count",PROPERTY_HINT_RANGE,"0,64"));
+
+ String et;
+ for(int i=0;i<InputEvent::TYPE_MAX;i++) {
+ if (i>0)
+ et+=",";
+
+ et+=event_type_names[i];
+ }
+
+ String kc;
+ String actions;
+
+
+
+ for(int i=0;i<filters.size();i++) {
+
+ String base = "filter_"+itos(i)+"/";
+ p_list->push_back(PropertyInfo(Variant::INT,base+"type",PROPERTY_HINT_ENUM,et));
+ p_list->push_back(PropertyInfo(Variant::INT,base+"device"));
+ switch(filters[i].type) {
+
+ case InputEvent::NONE: {
+
+ } break;
+ case InputEvent::KEY: {
+ if (kc==String()) {
+ int kcc = keycode_get_count();
+ kc="None";
+ for(int i=0;i<kcc;i++) {
+ kc+=",";
+ kc+=String(keycode_get_name_by_index(i));
+ }
+ }
+ p_list->push_back(PropertyInfo(Variant::STRING,base+"scancode",PROPERTY_HINT_ENUM,kc));
+ p_list->push_back(PropertyInfo(Variant::STRING,base+"unicode"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"echo"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta"));
+
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+ p_list->push_back(PropertyInfo(Variant::INT,base+"button_mask",PROPERTY_HINT_FLAGS,"Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta"));
+
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+ p_list->push_back(PropertyInfo(Variant::INT,base+"button_index",PROPERTY_HINT_ENUM,"Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"doubleclicked"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta"));
+
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ p_list->push_back(PropertyInfo(Variant::INT,base+"axis_index"));
+ p_list->push_back(PropertyInfo(Variant::INT,base+"mode",PROPERTY_HINT_ENUM,"Min,Max"));
+ p_list->push_back(PropertyInfo(Variant::REAL,base+"treshold",PROPERTY_HINT_RANGE,"0,1,0.01"));
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+ p_list->push_back(PropertyInfo(Variant::INT,base+"button_index"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
+
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+ p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
+
+ } break;
+ case InputEvent::SCREEN_DRAG: {
+ p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index"));
+ } break;
+ case InputEvent::ACTION: {
+
+
+
+ if (actions==String()) {
+
+ actions="None";
+
+ List<PropertyInfo> pinfo;
+ Globals::get_singleton()->get_property_list(&pinfo);
+ Vector<String> al;
+
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ const PropertyInfo &pi=E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+ String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
+
+
+ al.push_back(name);
+ }
+
+ for(int i=0;i<al.size();i++) {
+ actions+=",";
+ actions+=al[i];
+ }
+ }
+
+ p_list->push_back(PropertyInfo(Variant::STRING,base+"action_name",PROPERTY_HINT_ENUM,actions));
+ p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed"));
+
+ } break;
+
+ }
+ }
+}
+
+class VisualScriptNodeInstanceInputFilter : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ Vector<InputEvent> filters;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (p_inputs[0]->get_type()!=Variant::INPUT_EVENT) {
+ r_error_str="Input value not of type event";
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+
+ InputEvent event = *p_inputs[0];
+
+
+ for(int i=0;i<filters.size();i++) {
+
+ const InputEvent &ie = filters[i];
+ if (ie.type!=event.type)
+ continue;
+
+ bool match=false;
+
+ switch(ie.type) {
+
+ case InputEvent::NONE: {
+
+ match=true;
+ } break;
+ case InputEvent::KEY: {
+
+ InputEventKey k = ie.key;
+ InputEventKey k2 = event.key;
+
+ if (k.scancode==0 && k.unicode==0 && k2.scancode==0 && k2.unicode==0) {
+ match=true;
+
+ } else {
+
+ if ( (k.scancode!=0 && k.scancode==k2.scancode) || (k.unicode!=0 && k.unicode==k2.unicode)) {
+ //key valid
+
+ if (
+ k.pressed==k2.pressed &&
+ k.echo==k2.echo &&
+ k.mod == k2.mod
+ ) {
+ match=true;
+ }
+ }
+
+ }
+
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+ InputEventMouseMotion mm = ie.mouse_motion;
+ InputEventMouseMotion mm2 = event.mouse_motion;
+
+ if ( mm.button_mask==mm2.button_mask &&
+ mm.mod==mm2.mod
+ ) {
+ match=true;
+ }
+
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ InputEventMouseButton mb = ie.mouse_button;
+ InputEventMouseButton mb2 = event.mouse_button;
+
+ if ( mb.button_index==mb2.button_index &&
+ mb.pressed==mb2.pressed &&
+ mb.doubleclick==mb2.doubleclick &&
+ mb.mod==mb2.mod) {
+ match=true;
+ }
+
+
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ InputEventJoystickMotion jm = ie.joy_motion;
+ InputEventJoystickMotion jm2 = event.joy_motion;
+
+ int axis = jm.axis>>1;
+
+ if (axis==jm2.axis) {
+
+ if (jm.axis&1) {
+ //greater
+ if (jm2.axis_value > jm.axis_value) {
+ match=true;
+ }
+ } else {
+ //less
+ if (jm2.axis_value < -jm.axis_value) {
+ match=true;
+ }
+ }
+ }
+
+
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+ InputEventJoystickButton jb = ie.joy_button;
+ InputEventJoystickButton jb2 = event.joy_button;
+
+ if ( jb.button_index==jb2.button_index &&
+ jb.pressed == jb2.pressed
+ ) {
+ match=true;
+ }
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+ InputEventScreenTouch st = ie.screen_touch;
+ InputEventScreenTouch st2 = event.screen_touch;
+
+ if ( st.index==st2.index &&
+ st.pressed==st2.pressed) {
+ match=true;
+ }
+
+ } break;
+ case InputEvent::SCREEN_DRAG: {
+ InputEventScreenDrag sd = ie.screen_drag;
+ InputEventScreenDrag sd2 = event.screen_drag;
+
+ if (sd.index==sd2.index) {
+ match=true;
+ }
+ } break;
+ case InputEvent::ACTION: {
+
+ InputEventAction ia = ie.action;
+ InputEventAction ia2 = event.action;
+
+ if ( ia.action==ia2.action &&
+ ia.pressed==ia2.pressed) {
+ match=true;
+ }
+ } break;
+
+ }
+
+ *p_outputs[0] = event;
+
+ if (match)
+ return i; //go through match output
+
+ }
+
+ return STEP_NO_ADVANCE_BIT; //none found, don't advance
+
+
+ }
+
+
+};
+
+
+VisualScriptNodeInstance* VisualScriptInputFilter::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceInputFilter * instance = memnew(VisualScriptNodeInstanceInputFilter );
+ instance->instance=p_instance;
+ instance->filters=filters;
+ return instance;
+}
+
+
+
+
+VisualScriptInputFilter::VisualScriptInputFilter() {
+
+
+}
+
+
+//////////////////////////////////////////
+////////////////TYPE CAST///////////
+//////////////////////////////////////////
+
+
+int VisualScriptTypeCast::get_output_sequence_port_count() const {
+
+ return 2;
+}
+
+bool VisualScriptTypeCast::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptTypeCast::get_input_value_port_count() const{
+
+
+ return 1;
+}
+int VisualScriptTypeCast::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptTypeCast::get_output_sequence_port_text(int p_port) const {
+
+ return p_port==0 ? "yes" : "no";
+}
+
+PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::OBJECT,"instance");
+}
+
+PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::OBJECT,"");
+}
+
+
+String VisualScriptTypeCast::get_caption() const {
+
+ return "TypeCast";
+}
+
+String VisualScriptTypeCast::get_text() const {
+
+ if (script!=String())
+ return "Is "+script.get_file()+"?";
+ else
+ return "Is "+base_type+"?";
+}
+
+void VisualScriptTypeCast::set_base_type(const StringName& p_type) {
+
+ if (base_type==p_type)
+ return;
+
+ base_type=p_type;
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptTypeCast::get_base_type() const{
+
+ return base_type;
+}
+
+void VisualScriptTypeCast::set_base_script(const String& p_path){
+
+ if (script==p_path)
+ return;
+
+ script=p_path;
+ _change_notify();
+ ports_changed_notify();
+
+}
+String VisualScriptTypeCast::get_base_script() const{
+
+ return script;
+}
+
+
+class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ StringName base_type;
+ String script;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ Object *obj = *p_inputs[0];
+
+ *p_outputs[0]=Variant();
+
+ if (!obj) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Instance is null";
+ return 0;
+ }
+
+ if (script!=String()) {
+
+ Ref<Script> obj_script = obj->get_script();
+ if (!obj_script.is_valid()) {
+ return 1; //well, definitely not the script because object we got has no script.
+ }
+
+ if (!ResourceCache::has(script)) {
+ //if the script is not in use by anyone, we can safely assume whathever we got is not casting to it.
+ return 1;
+ }
+ Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script));
+ if (!cast_script.is_valid()) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Script path is not a script: "+script;
+ return 1;
+ }
+
+ while(obj_script.is_valid()) {
+
+ if (cast_script==obj_script) {
+ *p_outputs[0]=*p_inputs[0]; //copy
+ return 0; // it is the script, yey
+ }
+
+ obj_script=obj_script->get_base_script();
+ }
+
+ return 1; //not found sorry
+ }
+
+ if (ObjectTypeDB::is_type(obj->get_type_name(),base_type)) {
+ *p_outputs[0]=*p_inputs[0]; //copy
+ return 0;
+ } else
+ return 1;
+
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptTypeCast::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceTypeCast * instance = memnew(VisualScriptNodeInstanceTypeCast );
+ instance->instance=p_instance;
+ instance->base_type=base_type;
+ instance->script=script;
+ return instance;
+}
+
+
+
+void VisualScriptTypeCast::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_base_type","type"),&VisualScriptTypeCast::set_base_type);
+ ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptTypeCast::get_base_type);
+
+ ObjectTypeDB::bind_method(_MD("set_base_script","path"),&VisualScriptTypeCast::set_base_script);
+ ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptTypeCast::get_base_script);
+
+
+ List<String> script_extensions;
+ for(int i=0;i>ScriptServer::get_language_count();i++) {
+ ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
+ }
+
+ String script_ext_hint;
+ for (List<String>::Element *E=script_extensions.front();E;E=E->next()) {
+ if (script_ext_hint!=String())
+ script_ext_hint+=",";
+ script_ext_hint+="*."+E->get();
+ }
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script"));
+
+}
+
+VisualScriptTypeCast::VisualScriptTypeCast() {
+
+ base_type="Object";
+}
+
+
+void register_visual_script_flow_control_nodes() {
+
+ VisualScriptLanguage::singleton->add_register_func("flow_control/return",create_return_node<false>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/return_with_value",create_return_node<true>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/condition",create_node_generic<VisualScriptCondition>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/while",create_node_generic<VisualScriptWhile>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/iterator",create_node_generic<VisualScriptIterator>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/sequence",create_node_generic<VisualScriptSequence>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/input_select",create_node_generic<VisualScriptInputSelector>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/input_filter",create_node_generic<VisualScriptInputFilter>);
+ VisualScriptLanguage::singleton->add_register_func("flow_control/type_cast",create_node_generic<VisualScriptTypeCast>);
+
+
+
+}
diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h
new file mode 100644
index 0000000000..42fab2e44d
--- /dev/null
+++ b/modules/visual_script/visual_script_flow_control.h
@@ -0,0 +1,330 @@
+#ifndef VISUAL_SCRIPT_FLOW_CONTROL_H
+#define VISUAL_SCRIPT_FLOW_CONTROL_H
+
+#include "visual_script.h"
+
+class VisualScriptReturn : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptReturn,VisualScriptNode)
+
+
+ Variant::Type type;
+ bool with_value;
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+ void set_return_type(Variant::Type);
+ Variant::Type get_return_type() const;
+
+ void set_enable_return_value(bool p_enable);
+ bool is_return_value_enabled() const;
+
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptReturn();
+};
+
+
+class VisualScriptCondition : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptCondition,VisualScriptNode)
+
+
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptCondition();
+};
+
+
+class VisualScriptWhile : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptWhile,VisualScriptNode)
+
+
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptWhile();
+};
+
+
+
+class VisualScriptIterator : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptIterator,VisualScriptNode)
+
+
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptIterator();
+};
+
+
+
+class VisualScriptSequence : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptSequence,VisualScriptNode)
+
+
+ int steps;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+ void set_steps(int p_steps);
+ int get_steps() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptSequence();
+};
+
+
+
+
+class VisualScriptInputSelector : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptInputSelector,VisualScriptNode)
+
+
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+
+ VisualScriptInputSelector();
+};
+
+
+
+
+class VisualScriptInputFilter : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptInputFilter,VisualScriptNode)
+
+ Vector<InputEvent> filters;
+
+
+protected:
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+
+ VisualScriptInputFilter();
+};
+
+
+
+
+
+class VisualScriptTypeCast : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptTypeCast,VisualScriptNode)
+
+
+ StringName base_type;
+ String script;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+ void set_base_type(const StringName& p_type);
+ StringName get_base_type() const;
+
+ void set_base_script(const String& p_path);
+ String get_base_script() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+
+ VisualScriptTypeCast();
+};
+
+
+
+
+void register_visual_script_flow_control_nodes();
+
+
+
+#endif // VISUAL_SCRIPT_FLOW_CONTROL_H
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
new file mode 100644
index 0000000000..7414447279
--- /dev/null
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -0,0 +1,2470 @@
+#include "visual_script_func_nodes.h"
+#include "scene/main/scene_main_loop.h"
+#include "os/os.h"
+#include "scene/main/node.h"
+#include "visual_script_nodes.h"
+#include "io/resource_loader.h"
+#include "globals.h"
+
+//////////////////////////////////////////
+////////////////CALL//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptFunctionCall::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptFunctionCall::has_input_sequence_port() const{
+
+ return true;
+}
+#ifdef TOOLS_ENABLED
+
+static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) {
+
+ if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene)
+ return NULL;
+
+ Ref<Script> scr = p_current_node->get_script();
+
+ if (scr.is_valid() && scr==script)
+ return p_current_node;
+
+ for(int i=0;i<p_current_node->get_child_count();i++) {
+ Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script);
+ if (n)
+ return n;
+ }
+
+ return NULL;
+}
+
+#endif
+Node *VisualScriptFunctionCall::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_visual_script();
+ if (!script.is_valid())
+ return NULL;
+
+ MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+ if (!main_loop)
+ return NULL;
+
+ SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+ if (!scene_tree)
+ return NULL;
+
+ Node *edited_scene = scene_tree->get_edited_scene_root();
+
+ if (!edited_scene)
+ return NULL;
+
+ Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+ if (!script_node)
+ return NULL;
+
+ if (!script_node->has_node(base_path))
+ return NULL;
+
+ Node *path_to = script_node->get_node(base_path);
+
+ return path_to;
+#else
+
+ return NULL;
+#endif
+}
+
+StringName VisualScriptFunctionCall::_get_base_type() const {
+
+ if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid())
+ return get_visual_script()->get_instance_base_type();
+ else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
+ Node *path = _get_base_node();
+ if (path)
+ return path->get_type();
+
+ }
+
+ return base_type;
+}
+
+
+int VisualScriptFunctionCall::get_input_value_port_count() const{
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+
+ Vector<StringName> names = Variant::get_method_argument_names(basic_type,function);
+ return names.size() + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) + 1;
+
+ } else {
+
+ MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+ if (mb) {
+ return mb->get_argument_count() + (call_mode==CALL_MODE_INSTANCE?1:0) + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) - use_default_args;
+ }
+
+ return method_cache.arguments.size() + (call_mode==CALL_MODE_INSTANCE?1:0) + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) - use_default_args;
+ }
+
+}
+int VisualScriptFunctionCall::get_output_value_port_count() const{
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+ bool returns=false;
+ Variant::get_method_return_type(basic_type,function,&returns);
+ return returns?1:0;
+
+ } else {
+ int ret;
+ MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+ if (mb) {
+ ret = mb->has_return() ? 1 : 0;
+ } else
+ ret = 1; //it is assumed that script always returns something
+
+ if (call_mode==CALL_MODE_INSTANCE) {
+ ret++;
+ }
+
+ return ret;
+ }
+}
+
+String VisualScriptFunctionCall::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) const{
+
+ if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) {
+ if (p_idx==0) {
+ PropertyInfo pi;
+ pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type);
+ pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower());
+ return pi;
+ } else {
+ p_idx--;
+ }
+ }
+
+ if (rpc_call_mode>=RPC_RELIABLE_TO_ID) {
+
+ if (p_idx==0) {
+ return PropertyInfo(Variant::INT,"peer_id");
+ } else {
+ p_idx--;
+ }
+
+ }
+
+#ifdef DEBUG_METHODS_ENABLED
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+
+ Vector<StringName> names = Variant::get_method_argument_names(basic_type,function);
+ Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type,function);
+ return PropertyInfo(types[p_idx],names[p_idx]);
+
+ } else {
+
+ MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+ if (mb) {
+ return mb->get_argument_info(p_idx);
+ }
+
+ if (p_idx>=0 && p_idx < method_cache.arguments.size()) {
+ return method_cache.arguments[p_idx];
+ }
+
+ return PropertyInfo();
+ }
+#else
+ return PropertyInfo();
+#endif
+
+}
+
+PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) const{
+
+
+#ifdef DEBUG_METHODS_ENABLED
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+
+ return PropertyInfo(Variant::get_method_return_type(basic_type,function),"");
+ } else {
+
+ if (call_mode==CALL_MODE_INSTANCE) {
+ if (p_idx==0) {
+ return PropertyInfo(Variant::OBJECT,"pass");
+ } else {
+ p_idx--;
+ }
+ }
+
+ PropertyInfo ret;
+
+ /*MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+ if (mb) {
+
+ ret = mb->get_argument_info(-1);
+ } else {*/
+
+ ret = method_cache.return_val;
+
+ //}
+
+ if (call_mode==CALL_MODE_INSTANCE) {
+ ret.name="return";
+ } else {
+ ret.name="";
+ }
+ return ret;
+
+
+ }
+#else
+ return PropertyInfo();
+#endif
+}
+
+
+String VisualScriptFunctionCall::get_caption() const {
+
+ static const char*cname[5]= {
+ "CallSelf",
+ "CallNode",
+ "CallInstance",
+ "CallBasic",
+ "CallSingleton"
+ };
+
+ String caption = cname[call_mode];
+
+ if (rpc_call_mode) {
+ caption+=" (RPC)";
+ }
+
+ return caption;
+}
+
+String VisualScriptFunctionCall::get_text() const {
+
+ if (call_mode==CALL_MODE_SELF)
+ return " "+String(function)+"()";
+ if (call_mode==CALL_MODE_SINGLETON)
+ return String(singleton)+":"+String(function)+"()";
+ else if (call_mode==CALL_MODE_BASIC_TYPE)
+ return Variant::get_type_name(basic_type)+"."+String(function)+"()";
+ else if (call_mode==CALL_MODE_NODE_PATH)
+ return " ["+String(base_path.simplified())+"]."+String(function)+"()";
+ else
+ return " "+base_type+"."+String(function)+"()";
+
+}
+
+
+void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) {
+
+ if (basic_type==p_type)
+ return;
+ basic_type=p_type;
+
+
+ _change_notify();
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptFunctionCall::get_basic_type() const{
+
+ return basic_type;
+}
+
+void VisualScriptFunctionCall::set_base_type(const StringName& p_type) {
+
+ if (base_type==p_type)
+ return;
+
+ base_type=p_type;
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptFunctionCall::get_base_type() const{
+
+ return base_type;
+}
+
+void VisualScriptFunctionCall::set_base_script(const String& p_path) {
+
+ if (base_script==p_path)
+ return;
+
+ base_script=p_path;
+ _change_notify();
+ ports_changed_notify();
+}
+
+String VisualScriptFunctionCall::get_base_script() const {
+
+ return base_script;
+}
+
+void VisualScriptFunctionCall::set_singleton(const StringName& p_path) {
+
+ if (singleton==p_path)
+ return;
+
+ singleton=p_path;
+ Object *obj = Globals::get_singleton()->get_singleton_object(singleton);
+ if (obj) {
+ base_type=obj->get_type();
+ }
+
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptFunctionCall::get_singleton() const {
+
+ return singleton;
+}
+
+
+
+void VisualScriptFunctionCall::_update_method_cache() {
+ StringName type;
+ Ref<Script> script;
+
+ if (call_mode==CALL_MODE_NODE_PATH) {
+
+ Node* node=_get_base_node();
+ if (node) {
+ type=node->get_type();
+ base_type=type; //cache, too
+ script = node->get_script();
+ }
+ } else if (call_mode==CALL_MODE_SELF) {
+
+ if (get_visual_script().is_valid()) {
+ type=get_visual_script()->get_instance_base_type();
+ base_type=type; //cache, too
+ script=get_visual_script();
+ }
+
+ } else if (call_mode==CALL_MODE_SINGLETON) {
+
+ Object *obj = Globals::get_singleton()->get_singleton_object(singleton);
+ if (obj) {
+ type=obj->get_type();
+ script=obj->get_script();
+ }
+
+ } else if (call_mode==CALL_MODE_INSTANCE) {
+
+ type=base_type;
+ if (base_script!=String()) {
+
+ if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
+
+ ScriptServer::edit_request_func(base_script); //make sure it's loaded
+ }
+
+ if (ResourceCache::has(base_script)) {
+
+ script = Ref<Resource>( ResourceCache::get(base_script) );
+ } else {
+ return;
+ }
+ }
+ }
+
+
+// print_line("BASE: "+String(type)+" FUNC: "+String(function));
+ MethodBind *mb = ObjectTypeDB::get_method(type,function);
+ if (mb) {
+ use_default_args=mb->get_default_argument_count();
+ method_cache = MethodInfo();
+ for(int i=0;i<mb->get_argument_count();i++) {
+#ifdef DEBUG_METHODS_ENABLED
+ method_cache.arguments.push_back(mb->get_argument_info(i));
+#else
+ method_cache.arguments.push_back(PropertyInfo());
+#endif
+ }
+
+#ifdef DEBUG_METHODS_ENABLED
+
+ method_cache.return_val = mb->get_argument_info(-1);
+#endif
+ } else if (script.is_valid() && script->has_method(function)) {
+
+ method_cache = script->get_method_info(function);
+ use_default_args=method_cache.default_arguments.size();
+ }
+}
+
+void VisualScriptFunctionCall::set_function(const StringName& p_type){
+
+ if (function==p_type)
+ return;
+
+ function=p_type;
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+ use_default_args = Variant::get_method_default_arguments(basic_type,function).size();
+ } else {
+ //update all caches
+
+ _update_method_cache();
+
+ }
+
+
+ _change_notify();
+ ports_changed_notify();
+}
+StringName VisualScriptFunctionCall::get_function() const {
+
+
+ return function;
+}
+
+void VisualScriptFunctionCall::set_base_path(const NodePath& p_type) {
+
+ if (base_path==p_type)
+ return;
+
+ base_path=p_type;
+ _change_notify();
+ ports_changed_notify();
+}
+
+NodePath VisualScriptFunctionCall::get_base_path() const {
+
+ return base_path;
+}
+
+
+void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) {
+
+ if (call_mode==p_mode)
+ return;
+
+ call_mode=p_mode;
+ _change_notify();
+ ports_changed_notify();
+
+}
+VisualScriptFunctionCall::CallMode VisualScriptFunctionCall::get_call_mode() const {
+
+ return call_mode;
+}
+
+void VisualScriptFunctionCall::set_use_default_args(int p_amount) {
+
+ if (use_default_args==p_amount)
+ return;
+
+ use_default_args=p_amount;
+ ports_changed_notify();
+
+
+}
+
+void VisualScriptFunctionCall::set_rpc_call_mode(VisualScriptFunctionCall::RPCCallMode p_mode) {
+
+ if (rpc_call_mode==p_mode)
+ return;
+ rpc_call_mode=p_mode;
+ ports_changed_notify();
+ _change_notify();
+}
+
+VisualScriptFunctionCall::RPCCallMode VisualScriptFunctionCall::get_rpc_call_mode() const{
+
+ return rpc_call_mode;
+}
+
+
+int VisualScriptFunctionCall::get_use_default_args() const{
+
+ return use_default_args;
+}
+
+
+
+
+void VisualScriptFunctionCall::_set_argument_cache(const Dictionary& p_cache) {
+ //so everything works in case all else fails
+ method_cache=MethodInfo::from_dict(p_cache);
+
+}
+
+Dictionary VisualScriptFunctionCall::_get_argument_cache() const {
+
+ return method_cache;
+}
+
+void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="function/base_type") {
+ if (call_mode!=CALL_MODE_INSTANCE) {
+ property.usage=PROPERTY_USAGE_NOEDITOR;
+ }
+ }
+
+ if (property.name=="function/base_script") {
+ if (call_mode!=CALL_MODE_INSTANCE) {
+ property.usage=0;
+ }
+ }
+
+ if (property.name=="function/basic_type") {
+ if (call_mode!=CALL_MODE_BASIC_TYPE) {
+ property.usage=0;
+ }
+ }
+
+ if (property.name=="function/singleton") {
+ if (call_mode!=CALL_MODE_SINGLETON) {
+ property.usage=0;
+ } else {
+ List<Globals::Singleton> names;
+ Globals::get_singleton()->get_singletons(&names);
+ property.hint=PROPERTY_HINT_ENUM;
+ String sl;
+ for (List<Globals::Singleton>::Element *E=names.front();E;E=E->next()) {
+ if (sl!=String())
+ sl+=",";
+ sl+=E->get().name;
+ }
+ property.hint_string=sl;
+
+ }
+ }
+
+ if (property.name=="function/node_path") {
+ if (call_mode!=CALL_MODE_NODE_PATH) {
+ property.usage=0;
+ } else {
+
+ Node *bnode = _get_base_node();
+ if (bnode) {
+ property.hint_string=bnode->get_path(); //convert to loong string
+ } else {
+
+ }
+ }
+ }
+
+ if (property.name=="function/function") {
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+ property.hint=PROPERTY_HINT_METHOD_OF_VARIANT_TYPE;
+ property.hint_string=Variant::get_type_name(basic_type);
+
+ } else if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) {
+ property.hint=PROPERTY_HINT_METHOD_OF_SCRIPT;
+ property.hint_string=itos(get_visual_script()->get_instance_ID());
+ } else if (call_mode==CALL_MODE_SINGLETON) {
+
+ Object *obj = Globals::get_singleton()->get_singleton_object(singleton);
+ if (obj) {
+ property.hint=PROPERTY_HINT_METHOD_OF_INSTANCE;
+ property.hint_string=itos(obj->get_instance_ID());
+ } else {
+
+ property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE;
+ property.hint_string=base_type;//should be cached
+ }
+ } else if (call_mode==CALL_MODE_INSTANCE) {
+ property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE;
+ property.hint_string=base_type;
+
+ if (base_script!=String()) {
+ if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
+
+ ScriptServer::edit_request_func(base_script); //make sure it's loaded
+ }
+
+ if (ResourceCache::has(base_script)) {
+
+ Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) );
+ if (script.is_valid()) {
+
+ property.hint=PROPERTY_HINT_METHOD_OF_SCRIPT;
+ property.hint_string=itos(script->get_instance_ID());
+ }
+ }
+ }
+
+ } else if (call_mode==CALL_MODE_NODE_PATH) {
+ Node *node = _get_base_node();
+ if (node) {
+ property.hint=PROPERTY_HINT_METHOD_OF_INSTANCE;
+ property.hint_string=itos(node->get_instance_ID());
+ } else {
+ property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE;
+ property.hint_string=get_base_type();
+ }
+
+ }
+
+ }
+
+ if (property.name=="function/use_default_args") {
+
+ property.hint=PROPERTY_HINT_RANGE;
+
+ int mc=0;
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+ mc = Variant::get_method_default_arguments(basic_type,function).size();
+ } else {
+ MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+ if (mb) {
+
+ mc=mb->get_default_argument_count();
+ }
+ }
+
+ if (mc==0) {
+ property.usage=0; //do not show
+ } else {
+
+ property.hint_string="0,"+itos(mc)+",1";
+ }
+ }
+
+ if (property.name=="rpc/call_mode") {
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+ property.usage=0;
+ }
+ }
+
+}
+
+
+void VisualScriptFunctionCall::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptFunctionCall::set_base_type);
+ ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptFunctionCall::get_base_type);
+
+ ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptFunctionCall::set_base_script);
+ ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptFunctionCall::get_base_script);
+
+ ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptFunctionCall::set_basic_type);
+ ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptFunctionCall::get_basic_type);
+
+ ObjectTypeDB::bind_method(_MD("set_singleton","singleton"),&VisualScriptFunctionCall::set_singleton);
+ ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptFunctionCall::get_singleton);
+
+ ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptFunctionCall::set_function);
+ ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptFunctionCall::get_function);
+
+ ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptFunctionCall::set_call_mode);
+ ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptFunctionCall::get_call_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptFunctionCall::set_base_path);
+ ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptFunctionCall::get_base_path);
+
+ ObjectTypeDB::bind_method(_MD("set_use_default_args","amount"),&VisualScriptFunctionCall::set_use_default_args);
+ ObjectTypeDB::bind_method(_MD("get_use_default_args"),&VisualScriptFunctionCall::get_use_default_args);
+
+ ObjectTypeDB::bind_method(_MD("_set_argument_cache","argument_cache"),&VisualScriptFunctionCall::_set_argument_cache);
+ ObjectTypeDB::bind_method(_MD("_get_argument_cache"),&VisualScriptFunctionCall::_get_argument_cache);
+
+ ObjectTypeDB::bind_method(_MD("set_rpc_call_mode","mode"),&VisualScriptFunctionCall::set_rpc_call_mode);
+ ObjectTypeDB::bind_method(_MD("get_rpc_call_mode"),&VisualScriptFunctionCall::get_rpc_call_mode);
+
+ String bt;
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ if (i>0)
+ bt+=",";
+
+ bt+=Variant::get_type_name(Variant::Type(i));
+ }
+
+
+ List<String> script_extensions;
+ for(int i=0;i<ScriptServer::get_language_count();i++) {
+ ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
+ }
+
+ String script_ext_hint;
+ for (List<String>::Element *E=script_extensions.front();E;E=E->next()) {
+ if (script_ext_hint!=String())
+ script_ext_hint+=",";
+ script_ext_hint+="*."+E->get();
+ }
+
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type,Singleton"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/singleton"),_SCS("set_singleton"),_SCS("get_singleton"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"function/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"function/argument_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_argument_cache"),_SCS("_get_argument_cache"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); //when set, if loaded properly, will override argument count.
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),_SCS("set_use_default_args"),_SCS("get_use_default_args"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"rpc/call_mode",PROPERTY_HINT_ENUM,"Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"),_SCS("set_rpc_call_mode"),_SCS("get_rpc_call_mode")); //when set, if loaded properly, will override argument count.
+
+ BIND_CONSTANT( CALL_MODE_SELF );
+ BIND_CONSTANT( CALL_MODE_NODE_PATH);
+ BIND_CONSTANT( CALL_MODE_INSTANCE);
+ BIND_CONSTANT( CALL_MODE_BASIC_TYPE );
+}
+
+class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance {
+public:
+
+
+ VisualScriptFunctionCall::CallMode call_mode;
+ NodePath node_path;
+ int input_args;
+ bool returns;
+ VisualScriptFunctionCall::RPCCallMode rpc_mode;
+ StringName function;
+ StringName singleton;
+
+ VisualScriptFunctionCall *node;
+ VisualScriptInstance *instance;
+
+
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+
+ _FORCE_INLINE_ bool call_rpc(Object* p_base,const Variant** p_args,int p_argcount) {
+
+ if (!p_base)
+ return false;
+
+ Node * node = p_base->cast_to<Node>();
+ if (!node)
+ return false;
+
+ int to_id=0;
+ bool reliable=true;
+
+ if (rpc_mode>=VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) {
+ to_id = *p_args[0];
+ p_args+=1;
+ p_argcount-=1;
+ if (rpc_mode==VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) {
+ reliable=false;
+ }
+ } else if (rpc_mode==VisualScriptFunctionCall::RPC_UNRELIABLE) {
+ reliable=false;
+ }
+
+ node->rpcp(to_id,!reliable,function,p_args,p_argcount);
+
+ return true;
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ switch(call_mode) {
+
+ case VisualScriptFunctionCall::CALL_MODE_SELF: {
+
+ Object *object=instance->get_owner_ptr();
+
+ if (rpc_mode) {
+ call_rpc(object,p_inputs,input_args);
+ } else if (returns) {
+ *p_outputs[0] = object->call(function,p_inputs,input_args,r_error);
+ } else {
+ object->call(function,p_inputs,input_args,r_error);
+ }
+ } break;
+ case VisualScriptFunctionCall::CALL_MODE_NODE_PATH: {
+
+ Node* node = instance->get_owner_ptr()->cast_to<Node>();
+ if (!node) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Base object is not a Node!";
+ return 0;
+ }
+
+ Node* another = node->get_node(node_path);
+ if (!node) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Path does not lead Node!";
+ return 0;
+ }
+
+ if (rpc_mode) {
+ call_rpc(node,p_inputs,input_args);
+ } else if (returns) {
+ *p_outputs[0] = another->call(function,p_inputs,input_args,r_error);
+ } else {
+ another->call(function,p_inputs,input_args,r_error);
+ }
+
+ } break;
+ case VisualScriptFunctionCall::CALL_MODE_INSTANCE:
+ case VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE: {
+
+ Variant v = *p_inputs[0];
+
+ if (rpc_mode) {
+ Object *obj = v;
+ if (obj) {
+ call_rpc(obj,p_inputs+1,input_args-1);
+ }
+ } else if (returns) {
+ if (call_mode==VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
+ *p_outputs[1] = v.call(function,p_inputs+1,input_args,r_error);
+ } else {
+ *p_outputs[0] = v.call(function,p_inputs+1,input_args,r_error);
+ }
+ } else {
+ v.call(function,p_inputs+1,input_args,r_error);
+ }
+
+ if (call_mode==VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
+ *p_outputs[0]=*p_inputs[0];
+ }
+
+ } break;
+ case VisualScriptFunctionCall::CALL_MODE_SINGLETON: {
+
+ Object *object=Globals::get_singleton()->get_singleton_object(singleton);
+ if (!object) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Invalid singleton name: '"+String(singleton)+"'";
+ return 0;
+ }
+
+ if (rpc_mode) {
+ call_rpc(object,p_inputs,input_args);
+ } else if (returns) {
+ *p_outputs[0] = object->call(function,p_inputs,input_args,r_error);
+ } else {
+ object->call(function,p_inputs,input_args,r_error);
+ }
+ } break;
+ }
+ return 0;
+
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceFunctionCall * instance = memnew(VisualScriptNodeInstanceFunctionCall );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->singleton=singleton;
+ instance->function=function;
+ instance->call_mode=call_mode;
+ instance->returns=get_output_value_port_count();
+ instance->node_path=base_path;
+ instance->input_args = get_input_value_port_count() - ( (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE) ? 1: 0 );
+ instance->rpc_mode=rpc_call_mode;
+ return instance;
+}
+VisualScriptFunctionCall::VisualScriptFunctionCall() {
+
+ call_mode=CALL_MODE_SELF;
+ basic_type=Variant::NIL;
+ use_default_args=0;
+ base_type="Object";
+ rpc_call_mode=RPC_DISABLED;
+
+
+}
+
+template<VisualScriptFunctionCall::CallMode cmode>
+static Ref<VisualScriptNode> create_function_call_node(const String& p_name) {
+
+ Ref<VisualScriptFunctionCall> node;
+ node.instance();
+ node->set_call_mode(cmode);
+ return node;
+}
+
+
+//////////////////////////////////////////
+////////////////SET//////////////////////
+//////////////////////////////////////////
+
+static const char* event_type_names[InputEvent::TYPE_MAX]={
+ "None",
+ "Key",
+ "MouseMotion",
+ "MouseButton",
+ "JoystickMotion",
+ "JoystickButton",
+ "ScreenTouch",
+ "ScreenDrag",
+ "Action"
+};
+
+
+int VisualScriptPropertySet::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptPropertySet::has_input_sequence_port() const{
+
+ return true;
+}
+
+Node *VisualScriptPropertySet::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_visual_script();
+ if (!script.is_valid())
+ return NULL;
+
+ MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+ if (!main_loop)
+ return NULL;
+
+ SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+ if (!scene_tree)
+ return NULL;
+
+ Node *edited_scene = scene_tree->get_edited_scene_root();
+
+ if (!edited_scene)
+ return NULL;
+
+ Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+ if (!script_node)
+ return NULL;
+
+ if (!script_node->has_node(base_path))
+ return NULL;
+
+ Node *path_to = script_node->get_node(base_path);
+
+ return path_to;
+#else
+
+ return NULL;
+#endif
+}
+
+StringName VisualScriptPropertySet::_get_base_type() const {
+
+ if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid())
+ return get_visual_script()->get_instance_base_type();
+ else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
+ Node *path = _get_base_node();
+ if (path)
+ return path->get_type();
+
+ }
+
+ return base_type;
+}
+
+int VisualScriptPropertySet::get_input_value_port_count() const{
+
+ int pc = (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?2:1;
+
+ return pc;
+}
+int VisualScriptPropertySet::get_output_value_port_count() const{
+
+ return (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE) ? 1 : 0;
+}
+
+String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const{
+
+ if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) {
+ if (p_idx==0) {
+ PropertyInfo pi;
+ pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type);
+ pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower());
+ return pi;
+ } else {
+ p_idx--;
+ }
+ }
+
+ PropertyInfo pinfo=type_cache;
+ pinfo.name="value";
+ return pinfo;
+}
+
+PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const{
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+ return PropertyInfo(basic_type,"out");
+ } else if (call_mode==CALL_MODE_INSTANCE) {
+ return PropertyInfo(Variant::OBJECT,"pass");
+ } else {
+ return PropertyInfo();
+ }
+
+}
+
+
+String VisualScriptPropertySet::get_caption() const {
+
+ static const char*cname[4]= {
+ "SelfSet",
+ "NodeSet",
+ "InstanceSet",
+ "BasicSet"
+ };
+
+ return cname[call_mode];
+}
+
+String VisualScriptPropertySet::get_text() const {
+
+ String prop;
+
+ if (call_mode==CALL_MODE_BASIC_TYPE)
+ prop=Variant::get_type_name(basic_type)+"."+property;
+ else if (call_mode==CALL_MODE_NODE_PATH)
+ prop=String(base_path)+":"+property;
+ else if (call_mode==CALL_MODE_SELF)
+ prop=property;
+ else if (call_mode==CALL_MODE_INSTANCE)
+ prop=String(base_type)+":"+property;
+
+ return prop;
+
+}
+
+void VisualScriptPropertySet::_update_base_type() {
+ //cache it because this information may not be available on load
+ if (call_mode==CALL_MODE_NODE_PATH) {
+
+ Node* node=_get_base_node();
+ if (node) {
+ base_type=node->get_type();
+ }
+ } else if (call_mode==CALL_MODE_SELF) {
+
+ if (get_visual_script().is_valid()) {
+ base_type=get_visual_script()->get_instance_base_type();
+ }
+ }
+
+}
+void VisualScriptPropertySet::set_basic_type(Variant::Type p_type) {
+
+ if (basic_type==p_type)
+ return;
+ basic_type=p_type;
+
+
+ _change_notify();
+ _update_base_type();
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptPropertySet::get_basic_type() const{
+
+ return basic_type;
+}
+
+void VisualScriptPropertySet::set_event_type(InputEvent::Type p_type) {
+
+ if (event_type==p_type)
+ return;
+ event_type=p_type;
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+ _update_cache();
+ }
+ _change_notify();
+ _update_base_type();
+ ports_changed_notify();
+}
+
+InputEvent::Type VisualScriptPropertySet::get_event_type() const{
+
+ return event_type;
+}
+
+
+void VisualScriptPropertySet::set_base_type(const StringName& p_type) {
+
+ if (base_type==p_type)
+ return;
+
+ base_type=p_type;
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptPropertySet::get_base_type() const{
+
+ return base_type;
+}
+
+
+void VisualScriptPropertySet::set_base_script(const String& p_path) {
+
+ if (base_script==p_path)
+ return;
+
+ base_script=p_path;
+ _change_notify();
+ ports_changed_notify();
+}
+
+String VisualScriptPropertySet::get_base_script() const {
+
+ return base_script;
+}
+
+
+void VisualScriptPropertySet::_update_cache() {
+
+
+ if (!OS::get_singleton()->get_main_loop())
+ return;
+ if (!OS::get_singleton()->get_main_loop()->cast_to<SceneTree>())
+ return;
+
+ if (!OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()->is_editor_hint()) //only update cache if editor exists, it's pointless otherwise
+ return;
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+ //not super efficient..
+
+ Variant v;
+ if (basic_type==Variant::INPUT_EVENT) {
+ InputEvent ev;
+ ev.type=event_type;
+ v=ev;
+ } else {
+ Variant::CallError ce;
+ v = Variant::construct(basic_type,NULL,0,ce);
+ }
+
+ List<PropertyInfo> pinfo;
+ v.get_property_list(&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+ if (E->get().name==property) {
+
+ type_cache=E->get();
+ }
+ }
+
+ } else {
+
+
+ StringName type;
+ Ref<Script> script;
+ Node *node=NULL;
+
+ if (call_mode==CALL_MODE_NODE_PATH) {
+
+ node=_get_base_node();
+ if (node) {
+ type=node->get_type();
+ base_type=type; //cache, too
+ script = node->get_script();
+ }
+ } else if (call_mode==CALL_MODE_SELF) {
+
+ if (get_visual_script().is_valid()) {
+ type=get_visual_script()->get_instance_base_type();
+ base_type=type; //cache, too
+ script=get_visual_script();
+ }
+ } else if (call_mode==CALL_MODE_INSTANCE) {
+
+ type=base_type;
+ if (base_script!=String()) {
+
+ if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
+
+ ScriptServer::edit_request_func(base_script); //make sure it's loaded
+ }
+
+ if (ResourceCache::has(base_script)) {
+
+ script = Ref<Resource>( ResourceCache::get(base_script) );
+ } else {
+ return;
+ }
+ }
+ }
+
+ List<PropertyInfo> pinfo;
+
+
+ if (node) {
+
+ node->get_property_list(&pinfo);
+ } else {
+ ObjectTypeDB::get_property_list(type,&pinfo);
+ }
+
+ if (script.is_valid()) {
+
+ script->get_script_property_list(&pinfo);
+ }
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+ if (E->get().name==property) {
+ type_cache=E->get();
+ return;
+ }
+ }
+
+ }
+}
+
+void VisualScriptPropertySet::set_property(const StringName& p_type){
+
+ if (property==p_type)
+ return;
+
+ property=p_type;
+ _update_cache();
+ _change_notify();
+ ports_changed_notify();
+}
+StringName VisualScriptPropertySet::get_property() const {
+
+
+ return property;
+}
+
+void VisualScriptPropertySet::set_base_path(const NodePath& p_type) {
+
+ if (base_path==p_type)
+ return;
+
+ base_path=p_type;
+ _update_base_type();
+ _change_notify();
+ ports_changed_notify();
+}
+
+NodePath VisualScriptPropertySet::get_base_path() const {
+
+ return base_path;
+}
+
+
+void VisualScriptPropertySet::set_call_mode(CallMode p_mode) {
+
+ if (call_mode==p_mode)
+ return;
+
+ call_mode=p_mode;
+ _update_base_type();
+ _change_notify();
+ ports_changed_notify();
+
+}
+VisualScriptPropertySet::CallMode VisualScriptPropertySet::get_call_mode() const {
+
+ return call_mode;
+}
+
+
+
+
+void VisualScriptPropertySet::_set_type_cache(const Dictionary &p_type) {
+ type_cache=PropertyInfo::from_dict(p_type);
+}
+
+Dictionary VisualScriptPropertySet::_get_type_cache() const {
+
+ return type_cache;
+}
+
+void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="property/base_type") {
+ if (call_mode!=CALL_MODE_INSTANCE) {
+ property.usage=PROPERTY_USAGE_NOEDITOR;
+ }
+ }
+
+ if (property.name=="property/base_script") {
+ if (call_mode!=CALL_MODE_INSTANCE) {
+ property.usage=0;
+ }
+ }
+
+ if (property.name=="property/basic_type") {
+ if (call_mode!=CALL_MODE_BASIC_TYPE) {
+ property.usage=0;
+ }
+ }
+
+ if (property.name=="property/event_type") {
+ if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) {
+ property.usage=0;
+ }
+ }
+
+ if (property.name=="property/node_path") {
+ if (call_mode!=CALL_MODE_NODE_PATH) {
+ property.usage=0;
+ } else {
+
+ Node *bnode = _get_base_node();
+ if (bnode) {
+ property.hint_string=bnode->get_path(); //convert to loong string
+ } else {
+
+ }
+ }
+ }
+
+ if (property.name=="property/property") {
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+ property.hint=PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE;
+ property.hint_string=Variant::get_type_name(basic_type);
+
+ } else if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT;
+ property.hint_string=itos(get_visual_script()->get_instance_ID());
+ } else if (call_mode==CALL_MODE_INSTANCE) {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
+ property.hint_string=base_type;
+
+ if (base_script!=String()) {
+ if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
+
+ ScriptServer::edit_request_func(base_script); //make sure it's loaded
+ }
+
+ if (ResourceCache::has(base_script)) {
+
+ Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) );
+ if (script.is_valid()) {
+
+ property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT;
+ property.hint_string=itos(script->get_instance_ID());
+ }
+ }
+ }
+
+ } else if (call_mode==CALL_MODE_NODE_PATH) {
+ Node *node = _get_base_node();
+ if (node) {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_INSTANCE;
+ property.hint_string=itos(node->get_instance_ID());
+ } else {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
+ property.hint_string=get_base_type();
+ }
+
+ }
+
+ }
+
+}
+
+void VisualScriptPropertySet::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertySet::set_base_type);
+ ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertySet::get_base_type);
+
+ ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertySet::set_base_script);
+ ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertySet::get_base_script);
+
+ ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertySet::set_basic_type);
+ ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertySet::get_basic_type);
+
+ ObjectTypeDB::bind_method(_MD("_set_type_cache","type_cache"),&VisualScriptPropertySet::_set_type_cache);
+ ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertySet::_get_type_cache);
+
+ ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertySet::set_event_type);
+ ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertySet::get_event_type);
+
+ ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertySet::set_property);
+ ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertySet::get_property);
+
+ ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertySet::set_call_mode);
+ ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertySet::get_call_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertySet::set_base_path);
+ ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertySet::get_base_path);
+
+
+
+ String bt;
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ if (i>0)
+ bt+=",";
+
+ bt+=Variant::get_type_name(Variant::Type(i));
+ }
+
+ String et;
+ for(int i=0;i<InputEvent::TYPE_MAX;i++) {
+ if (i>0)
+ et+=",";
+
+ et+=event_type_names[i];
+ }
+
+ List<String> script_extensions;
+ for(int i=0;i<ScriptServer::get_language_count();i++) {
+ ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
+ }
+
+ String script_ext_hint;
+ for (List<String>::Element *E=script_extensions.front();E;E=E->next()) {
+ if (script_ext_hint!=String())
+ script_ext_hint+=",";
+ script_ext_hint+="*."+E->get();
+ }
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property"));
+
+ BIND_CONSTANT( CALL_MODE_SELF );
+ BIND_CONSTANT( CALL_MODE_NODE_PATH);
+ BIND_CONSTANT( CALL_MODE_INSTANCE);
+
+}
+
+class VisualScriptNodeInstancePropertySet : public VisualScriptNodeInstance {
+public:
+
+
+ VisualScriptPropertySet::CallMode call_mode;
+ NodePath node_path;
+ StringName property;
+
+ VisualScriptPropertySet *node;
+ VisualScriptInstance *instance;
+
+
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ switch(call_mode) {
+
+ case VisualScriptPropertySet::CALL_MODE_SELF: {
+
+ Object *object=instance->get_owner_ptr();
+
+ bool valid;
+
+ object->set(property,*p_inputs[0],&valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+object->get_type();
+ }
+ } break;
+ case VisualScriptPropertySet::CALL_MODE_NODE_PATH: {
+
+ Node* node = instance->get_owner_ptr()->cast_to<Node>();
+ if (!node) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Base object is not a Node!";
+ return 0;
+ }
+
+ Node* another = node->get_node(node_path);
+ if (!node) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Path does not lead Node!";
+ return 0;
+ }
+
+ bool valid;
+
+ another->set(property,*p_inputs[0],&valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+another->get_type();
+ }
+
+ } break;
+ case VisualScriptPropertySet::CALL_MODE_INSTANCE:
+ case VisualScriptPropertySet::CALL_MODE_BASIC_TYPE: {
+
+ Variant v = *p_inputs[0];
+
+ bool valid;
+
+ v.set(property,*p_inputs[1],&valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Invalid set value '"+String(*p_inputs[1])+"' ("+Variant::get_type_name(p_inputs[1]->get_type())+") on property '"+String(property)+"' of type "+Variant::get_type_name(v.get_type());
+ }
+
+ *p_outputs[0]=v;
+
+ } break;
+
+ }
+ return 0;
+
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptPropertySet::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstancePropertySet * instance = memnew(VisualScriptNodeInstancePropertySet );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->property=property;
+ instance->call_mode=call_mode;
+ instance->node_path=base_path;
+ return instance;
+}
+
+VisualScriptPropertySet::VisualScriptPropertySet() {
+
+ call_mode=CALL_MODE_SELF;
+ base_type="Object";
+ basic_type=Variant::NIL;
+ event_type=InputEvent::NONE;
+
+}
+
+template<VisualScriptPropertySet::CallMode cmode>
+static Ref<VisualScriptNode> create_property_set_node(const String& p_name) {
+
+ Ref<VisualScriptPropertySet> node;
+ node.instance();
+ node->set_call_mode(cmode);
+ return node;
+}
+
+
+//////////////////////////////////////////
+////////////////GET//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptPropertyGet::get_output_sequence_port_count() const {
+
+ return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1;
+}
+
+bool VisualScriptPropertyGet::has_input_sequence_port() const{
+
+ return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?false:true;
+}
+void VisualScriptPropertyGet::_update_base_type() {
+ //cache it because this information may not be available on load
+ if (call_mode==CALL_MODE_NODE_PATH) {
+
+ Node* node=_get_base_node();
+ if (node) {
+ base_type=node->get_type();
+ }
+ } else if (call_mode==CALL_MODE_SELF) {
+
+ if (get_visual_script().is_valid()) {
+ base_type=get_visual_script()->get_instance_base_type();
+ }
+ }
+
+}
+Node *VisualScriptPropertyGet::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_visual_script();
+ if (!script.is_valid())
+ return NULL;
+
+ MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+ if (!main_loop)
+ return NULL;
+
+ SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+ if (!scene_tree)
+ return NULL;
+
+ Node *edited_scene = scene_tree->get_edited_scene_root();
+
+ if (!edited_scene)
+ return NULL;
+
+ Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+ if (!script_node)
+ return NULL;
+
+ if (!script_node->has_node(base_path))
+ return NULL;
+
+ Node *path_to = script_node->get_node(base_path);
+
+ return path_to;
+#else
+
+ return NULL;
+#endif
+}
+
+StringName VisualScriptPropertyGet::_get_base_type() const {
+
+ if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid())
+ return get_visual_script()->get_instance_base_type();
+ else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
+ Node *path = _get_base_node();
+ if (path)
+ return path->get_type();
+
+ }
+
+ return base_type;
+}
+
+
+int VisualScriptPropertyGet::get_input_value_port_count() const{
+
+ return (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?1:0;
+
+}
+int VisualScriptPropertyGet::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptPropertyGet::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const{
+
+ if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) {
+ if (p_idx==0) {
+ PropertyInfo pi;
+ pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type);
+ pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower());
+ return pi;
+ } else {
+ p_idx--;
+ }
+ }
+ return PropertyInfo();
+
+}
+
+PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(type_cache,"value");
+}
+
+
+String VisualScriptPropertyGet::get_caption() const {
+
+ static const char*cname[4]= {
+ "SelfGet",
+ "NodeGet",
+ "InstanceGet",
+ "BasicGet"
+ };
+
+ return cname[call_mode];
+}
+
+String VisualScriptPropertyGet::get_text() const {
+
+ String prop;
+
+ if (call_mode==CALL_MODE_BASIC_TYPE)
+ prop=Variant::get_type_name(basic_type)+"."+property;
+ else if (call_mode==CALL_MODE_NODE_PATH)
+ prop=String(base_path)+":"+property;
+ else if (call_mode==CALL_MODE_SELF)
+ prop=property;
+ else if (call_mode==CALL_MODE_INSTANCE)
+ prop=String(base_type)+":"+property;
+
+ return prop;
+}
+
+void VisualScriptPropertyGet::set_base_type(const StringName& p_type) {
+
+ if (base_type==p_type)
+ return;
+
+ base_type=p_type;
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptPropertyGet::get_base_type() const{
+
+ return base_type;
+}
+
+void VisualScriptPropertyGet::set_base_script(const String& p_path) {
+
+ if (base_script==p_path)
+ return;
+
+ base_script=p_path;
+ _change_notify();
+ ports_changed_notify();
+}
+
+String VisualScriptPropertyGet::get_base_script() const {
+
+ return base_script;
+}
+
+
+void VisualScriptPropertyGet::_update_cache() {
+
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+ //not super efficient..
+
+ Variant v;
+ if (basic_type==Variant::INPUT_EVENT) {
+ InputEvent ev;
+ ev.type=event_type;
+ v=ev;
+ } else {
+ Variant::CallError ce;
+ v = Variant::construct(basic_type,NULL,0,ce);
+ }
+
+ List<PropertyInfo> pinfo;
+ v.get_property_list(&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+ if (E->get().name==property) {
+
+ type_cache=E->get().type;
+ return;
+ }
+ }
+
+ } else {
+
+
+ StringName type;
+ Ref<Script> script;
+ Node *node=NULL;
+
+ if (call_mode==CALL_MODE_NODE_PATH) {
+
+ node=_get_base_node();
+ if (node) {
+ type=node->get_type();
+ base_type=type; //cache, too
+ script = node->get_script();
+ }
+ } else if (call_mode==CALL_MODE_SELF) {
+
+ if (get_visual_script().is_valid()) {
+ type=get_visual_script()->get_instance_base_type();
+ base_type=type; //cache, too
+ script=get_visual_script();
+ }
+ } else if (call_mode==CALL_MODE_INSTANCE) {
+
+ type=base_type;
+ if (base_script!=String()) {
+
+ if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
+
+ ScriptServer::edit_request_func(base_script); //make sure it's loaded
+ }
+
+ if (ResourceCache::has(base_script)) {
+
+ script = Ref<Resource>( ResourceCache::get(base_script) );
+ } else {
+ return;
+ }
+ }
+ }
+
+
+ bool valid=false;
+
+ Variant::Type type_ret;
+
+ type_ret=ObjectTypeDB::get_property_type(base_type,property,&valid);
+
+ if (valid) {
+ type_cache=type_ret;
+ return; //all dandy
+ }
+
+ if (node) {
+
+ Variant prop = node->get(property,&valid);
+ if (valid) {
+ type_cache=prop.get_type();
+ return; //all dandy again
+ }
+ }
+
+ if (script.is_valid()) {
+
+ type_ret=script->get_static_property_type(property,&valid);
+
+ if (valid) {
+ type_cache=type_ret;
+ return; //all dandy
+ }
+ }
+ }
+}
+
+void VisualScriptPropertyGet::set_property(const StringName& p_type){
+
+ if (property==p_type)
+ return;
+
+ property=p_type;
+
+
+ _update_cache();
+ _change_notify();
+ ports_changed_notify();
+}
+StringName VisualScriptPropertyGet::get_property() const {
+
+
+ return property;
+}
+
+void VisualScriptPropertyGet::set_base_path(const NodePath& p_type) {
+
+ if (base_path==p_type)
+ return;
+
+ base_path=p_type;
+ _change_notify();
+ _update_base_type();
+ ports_changed_notify();
+}
+
+NodePath VisualScriptPropertyGet::get_base_path() const {
+
+ return base_path;
+}
+
+
+void VisualScriptPropertyGet::set_call_mode(CallMode p_mode) {
+
+ if (call_mode==p_mode)
+ return;
+
+ call_mode=p_mode;
+ _change_notify();
+ _update_base_type();
+ ports_changed_notify();
+
+}
+VisualScriptPropertyGet::CallMode VisualScriptPropertyGet::get_call_mode() const {
+
+ return call_mode;
+}
+
+
+
+void VisualScriptPropertyGet::set_basic_type(Variant::Type p_type) {
+
+ if (basic_type==p_type)
+ return;
+ basic_type=p_type;
+
+
+ _change_notify();
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptPropertyGet::get_basic_type() const{
+
+ return basic_type;
+}
+
+
+void VisualScriptPropertyGet::set_event_type(InputEvent::Type p_type) {
+
+ if (event_type==p_type)
+ return;
+ event_type=p_type;
+ if(call_mode==CALL_MODE_BASIC_TYPE) {
+ _update_cache();
+ }
+ _change_notify();
+ _update_base_type();
+ ports_changed_notify();
+}
+
+InputEvent::Type VisualScriptPropertyGet::get_event_type() const{
+
+ return event_type;
+}
+
+
+void VisualScriptPropertyGet::_set_type_cache(Variant::Type p_type) {
+ type_cache=p_type;
+}
+
+Variant::Type VisualScriptPropertyGet::_get_type_cache() const {
+
+ return type_cache;
+}
+
+
+void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="property/base_type") {
+ if (call_mode!=CALL_MODE_INSTANCE) {
+ property.usage=PROPERTY_USAGE_NOEDITOR;
+ }
+ }
+
+ if (property.name=="property/base_script") {
+ if (call_mode!=CALL_MODE_INSTANCE) {
+ property.usage=0;
+ }
+ }
+
+ if (property.name=="property/basic_type") {
+ if (call_mode!=CALL_MODE_BASIC_TYPE) {
+ property.usage=0;
+ }
+ }
+ if (property.name=="property/event_type") {
+ if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) {
+ property.usage=0;
+ }
+ }
+
+ if (property.name=="property/node_path") {
+ if (call_mode!=CALL_MODE_NODE_PATH) {
+ property.usage=0;
+ } else {
+
+ Node *bnode = _get_base_node();
+ if (bnode) {
+ property.hint_string=bnode->get_path(); //convert to loong string
+ } else {
+
+ }
+ }
+ }
+
+ if (property.name=="property/property") {
+
+ if (call_mode==CALL_MODE_BASIC_TYPE) {
+
+ property.hint=PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE;
+ property.hint_string=Variant::get_type_name(basic_type);
+
+ } else if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT;
+ property.hint_string=itos(get_visual_script()->get_instance_ID());
+ } else if (call_mode==CALL_MODE_INSTANCE) {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
+ property.hint_string=base_type;
+
+ if (base_script!=String()) {
+ if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
+
+ ScriptServer::edit_request_func(base_script); //make sure it's loaded
+ }
+
+ if (ResourceCache::has(base_script)) {
+
+ Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) );
+ if (script.is_valid()) {
+
+ property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT;
+ property.hint_string=itos(script->get_instance_ID());
+ }
+ }
+ }
+ } else if (call_mode==CALL_MODE_NODE_PATH) {
+ Node *node = _get_base_node();
+ if (node) {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_INSTANCE;
+ property.hint_string=itos(node->get_instance_ID());
+ } else {
+ property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
+ property.hint_string=get_base_type();
+ }
+
+ }
+
+ }
+
+}
+
+void VisualScriptPropertyGet::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertyGet::set_base_type);
+ ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertyGet::get_base_type);
+
+ ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertyGet::set_base_script);
+ ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertyGet::get_base_script);
+
+ ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertyGet::set_basic_type);
+ ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertyGet::get_basic_type);
+
+ ObjectTypeDB::bind_method(_MD("_set_type_cache","type_cache"),&VisualScriptPropertyGet::_set_type_cache);
+ ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertyGet::_get_type_cache);
+
+ ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertyGet::set_event_type);
+ ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertyGet::get_event_type);
+
+
+ ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertyGet::set_property);
+ ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertyGet::get_property);
+
+ ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertyGet::set_call_mode);
+ ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertyGet::get_call_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertyGet::set_base_path);
+ ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertyGet::get_base_path);
+
+ String bt;
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ if (i>0)
+ bt+=",";
+
+ bt+=Variant::get_type_name(Variant::Type(i));
+ }
+
+ String et;
+ for(int i=0;i<InputEvent::TYPE_MAX;i++) {
+ if (i>0)
+ et+=",";
+
+ et+=event_type_names[i];
+ }
+
+ List<String> script_extensions;
+ for(int i=0;i<ScriptServer::get_language_count();i++) {
+ ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
+ }
+
+ String script_ext_hint;
+ for (List<String>::Element *E=script_extensions.front();E;E=E->next()) {
+ if (script_ext_hint!=String())
+ script_ext_hint+=",";
+ script_ext_hint+="."+E->get();
+ }
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property"));
+
+ BIND_CONSTANT( CALL_MODE_SELF );
+ BIND_CONSTANT( CALL_MODE_NODE_PATH);
+ BIND_CONSTANT( CALL_MODE_INSTANCE);
+}
+
+class VisualScriptNodeInstancePropertyGet : public VisualScriptNodeInstance {
+public:
+
+
+ VisualScriptPropertyGet::CallMode call_mode;
+ NodePath node_path;
+ StringName property;
+
+ VisualScriptPropertyGet *node;
+ VisualScriptInstance *instance;
+
+
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return (call_mode==VisualScriptPropertyGet::CALL_MODE_SELF || call_mode==VisualScriptPropertyGet::CALL_MODE_NODE_PATH); }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ //these two modes can be get directly, so they use unsequenced mode
+ switch(call_mode) {
+
+ case VisualScriptPropertyGet::CALL_MODE_SELF: {
+
+ Object *object=instance->get_owner_ptr();
+
+ bool valid;
+
+ *r_value = object->get(property,&valid);
+
+ if (!valid) {
+ //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error=RTR("Invalid index property name.");
+ return false;
+ }
+ } break;
+ case VisualScriptPropertyGet::CALL_MODE_NODE_PATH: {
+
+ Node* node = instance->get_owner_ptr()->cast_to<Node>();
+ if (!node) {
+ //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error=RTR("Base object is not a Node!");
+ return false;
+ }
+
+ Node* another = node->get_node(node_path);
+ if (!node) {
+ //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error=RTR("Path does not lead Node!");
+ return false;
+ }
+
+ bool valid;
+
+
+ *r_value = another->get(property,&valid);
+
+ if (!valid) {
+ //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error=vformat(RTR("Invalid index property name '%s' in node %s."),String(property),another->get_name());
+ return false;
+ }
+
+ } break;
+ default: {};
+ }
+ return true;
+
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ bool valid;
+ Variant v = *p_inputs[0];
+
+ *p_outputs[0] = v.get(property,&valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Invalid index property name.");
+
+ }
+
+
+ return 0;
+ }
+
+
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptPropertyGet::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstancePropertyGet * instance = memnew(VisualScriptNodeInstancePropertyGet );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->property=property;
+ instance->call_mode=call_mode;
+ instance->node_path=base_path;
+
+ return instance;
+}
+
+VisualScriptPropertyGet::VisualScriptPropertyGet() {
+
+ call_mode=CALL_MODE_SELF;
+ base_type="Object";
+ basic_type=Variant::NIL;
+ event_type=InputEvent::NONE;
+ type_cache=Variant::NIL;
+
+}
+
+template<VisualScriptPropertyGet::CallMode cmode>
+static Ref<VisualScriptNode> create_property_get_node(const String& p_name) {
+
+ Ref<VisualScriptPropertyGet> node;
+ node.instance();
+ node->set_call_mode(cmode);
+ return node;
+}
+
+
+//////////////////////////////////////////
+////////////////EMIT//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptEmitSignal::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptEmitSignal::has_input_sequence_port() const{
+
+ return true;
+}
+
+
+int VisualScriptEmitSignal::get_input_value_port_count() const{
+
+ Ref<VisualScript> vs = get_visual_script();
+ if (vs.is_valid()) {
+
+ if (!vs->has_custom_signal(name))
+ return 0;
+
+ return vs->custom_signal_get_argument_count(name);
+ }
+
+ return 0;
+
+}
+int VisualScriptEmitSignal::get_output_value_port_count() const{
+ return 0;
+}
+
+String VisualScriptEmitSignal::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptEmitSignal::get_input_value_port_info(int p_idx) const{
+
+ Ref<VisualScript> vs = get_visual_script();
+ if (vs.is_valid()) {
+
+ if (!vs->has_custom_signal(name))
+ return PropertyInfo();
+
+ return PropertyInfo(vs->custom_signal_get_argument_type(name,p_idx),vs->custom_signal_get_argument_name(name,p_idx));
+ }
+
+ return PropertyInfo();
+
+}
+
+PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+
+String VisualScriptEmitSignal::get_caption() const {
+
+ return "EmitSignal";
+}
+
+String VisualScriptEmitSignal::get_text() const {
+
+ return "emit "+String(name);
+}
+
+
+
+void VisualScriptEmitSignal::set_signal(const StringName& p_type){
+
+ if (name==p_type)
+ return;
+
+ name=p_type;
+
+ _change_notify();
+ ports_changed_notify();
+}
+StringName VisualScriptEmitSignal::get_signal() const {
+
+
+ return name;
+}
+
+
+void VisualScriptEmitSignal::_validate_property(PropertyInfo& property) const {
+
+
+
+ if (property.name=="signal/signal") {
+ property.hint=PROPERTY_HINT_ENUM;
+
+
+ List<StringName> sigs;
+
+ Ref<VisualScript> vs = get_visual_script();
+ if (vs.is_valid()) {
+
+ vs->get_custom_signal_list(&sigs);
+
+ }
+
+ String ml;
+ for (List<StringName>::Element *E=sigs.front();E;E=E->next()) {
+
+ if (ml!=String())
+ ml+=",";
+ ml+=E->get();
+ }
+
+ property.hint_string=ml;
+ }
+
+}
+
+
+void VisualScriptEmitSignal::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_signal","name"),&VisualScriptEmitSignal::set_signal);
+ ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptEmitSignal::get_signal);
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal"));
+
+
+}
+
+class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptEmitSignal *node;
+ VisualScriptInstance *instance;
+ int argcount;
+ StringName name;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ Object *obj = instance->get_owner_ptr();
+
+ obj->emit_signal(name,p_inputs,argcount);
+
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptEmitSignal::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceEmitSignal * instance = memnew(VisualScriptNodeInstanceEmitSignal );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->name=name;
+ instance->argcount=get_input_value_port_count();
+ return instance;
+}
+
+VisualScriptEmitSignal::VisualScriptEmitSignal() {
+}
+
+
+
+static Ref<VisualScriptNode> create_basic_type_call_node(const String& p_name) {
+
+ Vector<String> path = p_name.split("/");
+ ERR_FAIL_COND_V(path.size()<4,Ref<VisualScriptNode>());
+ String base_type = path[2];
+ String method = path[3];
+
+ Ref<VisualScriptFunctionCall> node;
+ node.instance();
+
+ Variant::Type type=Variant::VARIANT_MAX;
+
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+
+ if (Variant::get_type_name(Variant::Type(i))==base_type) {
+ type=Variant::Type(i);
+ break;
+ }
+ }
+
+ ERR_FAIL_COND_V(type==Variant::VARIANT_MAX,Ref<VisualScriptNode>());
+
+
+ node->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
+ node->set_basic_type(type);
+ node->set_function(method);
+
+ return node;
+}
+
+
+void register_visual_script_func_nodes() {
+
+ VisualScriptLanguage::singleton->add_register_func("functions/call",create_node_generic<VisualScriptFunctionCall>);
+ VisualScriptLanguage::singleton->add_register_func("functions/set",create_node_generic<VisualScriptPropertySet>);
+ VisualScriptLanguage::singleton->add_register_func("functions/get",create_node_generic<VisualScriptPropertyGet>);
+
+ //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_self",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>);
+// VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>);
+ VisualScriptLanguage::singleton->add_register_func("functions/emit_signal",create_node_generic<VisualScriptEmitSignal>);
+
+
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+
+ Variant::Type t = Variant::Type(i);
+ String type_name = Variant::get_type_name(t);
+ Variant::CallError ce;
+ Variant vt = Variant::construct(t,NULL,0,ce);
+ List<MethodInfo> ml;
+ vt.get_method_list(&ml);
+
+ for (List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
+ VisualScriptLanguage::singleton->add_register_func("functions/by_type/"+type_name+"/"+E->get().name,create_basic_type_call_node);
+ }
+ }
+}
diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h
new file mode 100644
index 0000000000..f958da8222
--- /dev/null
+++ b/modules/visual_script/visual_script_func_nodes.h
@@ -0,0 +1,338 @@
+#ifndef VISUAL_SCRIPT_FUNC_NODES_H
+#define VISUAL_SCRIPT_FUNC_NODES_H
+
+#include "visual_script.h"
+
+
+class VisualScriptFunctionCall : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptFunctionCall,VisualScriptNode)
+public:
+ enum CallMode {
+ CALL_MODE_SELF,
+ CALL_MODE_NODE_PATH,
+ CALL_MODE_INSTANCE,
+ CALL_MODE_BASIC_TYPE,
+ CALL_MODE_SINGLETON,
+ };
+
+ enum RPCCallMode {
+ RPC_DISABLED,
+ RPC_RELIABLE,
+ RPC_UNRELIABLE,
+ RPC_RELIABLE_TO_ID,
+ RPC_UNRELIABLE_TO_ID
+ };
+
+private:
+
+ CallMode call_mode;
+ StringName base_type;
+ String base_script;
+ Variant::Type basic_type;
+ NodePath base_path;
+ StringName function;
+ int use_default_args;
+ RPCCallMode rpc_call_mode;
+ StringName singleton;
+
+
+ Node *_get_base_node() const;
+ StringName _get_base_type() const;
+
+ MethodInfo method_cache;
+ void _update_method_cache();
+
+ void _set_argument_cache(const Dictionary& p_args);
+ Dictionary _get_argument_cache() const;
+
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "functions"; }
+
+ void set_basic_type(Variant::Type p_type);
+ Variant::Type get_basic_type() const;
+
+ void set_base_type(const StringName& p_type);
+ StringName get_base_type() const;
+
+ void set_base_script(const String& p_path);
+ String get_base_script() const;
+
+ void set_singleton(const StringName& p_type);
+ StringName get_singleton() const;
+
+ void set_function(const StringName& p_type);
+ StringName get_function() const;
+
+ void set_base_path(const NodePath& p_type);
+ NodePath get_base_path() const;
+
+
+ void set_call_mode(CallMode p_mode);
+ CallMode get_call_mode() const;
+
+ void set_use_default_args(int p_amount);
+ int get_use_default_args() const;
+
+ void set_rpc_call_mode(RPCCallMode p_mode);
+ RPCCallMode get_rpc_call_mode() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptFunctionCall();
+};
+
+VARIANT_ENUM_CAST(VisualScriptFunctionCall::CallMode );
+VARIANT_ENUM_CAST(VisualScriptFunctionCall::RPCCallMode );
+
+
+class VisualScriptPropertySet : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptPropertySet,VisualScriptNode)
+public:
+ enum CallMode {
+ CALL_MODE_SELF,
+ CALL_MODE_NODE_PATH,
+ CALL_MODE_INSTANCE,
+ CALL_MODE_BASIC_TYPE,
+
+
+ };
+private:
+
+ PropertyInfo type_cache;
+
+ CallMode call_mode;
+ Variant::Type basic_type;
+ StringName base_type;
+ String base_script;
+ NodePath base_path;
+ StringName property;
+ InputEvent::Type event_type;
+
+ Node *_get_base_node() const;
+ StringName _get_base_type() const;
+
+ void _update_base_type();
+
+ void _update_cache();
+
+ void _set_type_cache(const Dictionary& p_type);
+ Dictionary _get_type_cache() const;
+
+
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "functions"; }
+
+ void set_base_type(const StringName& p_type);
+ StringName get_base_type() const;
+
+ void set_base_script(const String& p_path);
+ String get_base_script() const;
+
+ void set_basic_type(Variant::Type p_type);
+ Variant::Type get_basic_type() const;
+
+ void set_event_type(InputEvent::Type p_type);
+ InputEvent::Type get_event_type() const;
+
+ void set_property(const StringName& p_type);
+ StringName get_property() const;
+
+ void set_base_path(const NodePath& p_type);
+ NodePath get_base_path() const;
+
+ void set_call_mode(CallMode p_mode);
+ CallMode get_call_mode() const;
+
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptPropertySet();
+};
+
+VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode );
+
+
+class VisualScriptPropertyGet : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptPropertyGet,VisualScriptNode)
+public:
+ enum CallMode {
+ CALL_MODE_SELF,
+ CALL_MODE_NODE_PATH,
+ CALL_MODE_INSTANCE,
+ CALL_MODE_BASIC_TYPE,
+
+ };
+private:
+
+ Variant::Type type_cache;
+
+ CallMode call_mode;
+ Variant::Type basic_type;
+ StringName base_type;
+ String base_script;
+ NodePath base_path;
+ StringName property;
+ InputEvent::Type event_type;
+
+ void _update_base_type();
+ Node *_get_base_node() const;
+ StringName _get_base_type() const;
+
+ void _update_cache();
+
+ void _set_type_cache(Variant::Type p_type);
+ Variant::Type _get_type_cache() const;
+
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "functions"; }
+
+ void set_base_type(const StringName& p_type);
+ StringName get_base_type() const;
+
+ void set_base_script(const String& p_path);
+ String get_base_script() const;
+
+ void set_basic_type(Variant::Type p_type);
+ Variant::Type get_basic_type() const;
+
+ void set_event_type(InputEvent::Type p_type);
+ InputEvent::Type get_event_type() const;
+
+ void set_property(const StringName& p_type);
+ StringName get_property() const;
+
+ void set_base_path(const NodePath& p_type);
+ NodePath get_base_path() const;
+
+ void set_call_mode(CallMode p_mode);
+ CallMode get_call_mode() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptPropertyGet();
+};
+
+
+
+
+
+VARIANT_ENUM_CAST(VisualScriptPropertyGet::CallMode );
+
+
+
+class VisualScriptEmitSignal : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptEmitSignal,VisualScriptNode)
+
+private:
+
+ StringName name;
+
+
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "functions"; }
+
+ void set_signal(const StringName& p_type);
+ StringName get_signal() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptEmitSignal();
+};
+
+
+
+void register_visual_script_func_nodes();
+
+#endif // VISUAL_SCRIPT_FUNC_NODES_H
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
new file mode 100644
index 0000000000..21a27b91a3
--- /dev/null
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -0,0 +1,3509 @@
+#include "visual_script_nodes.h"
+#include "global_constants.h"
+#include "globals.h"
+#include "scene/main/scene_main_loop.h"
+#include "os/os.h"
+#include "scene/main/node.h"
+#include "os/input.h"
+
+//////////////////////////////////////////
+////////////////FUNCTION//////////////////
+//////////////////////////////////////////
+
+
+bool VisualScriptFunction::_set(const StringName& p_name, const Variant& p_value) {
+
+
+ if (p_name=="argument_count") {
+
+ int new_argc=p_value;
+ int argc = arguments.size();
+ if (argc==new_argc)
+ return true;
+
+ arguments.resize(new_argc);
+
+ for(int i=argc;i<new_argc;i++) {
+ arguments[i].name="arg"+itos(i+1);
+ arguments[i].type=Variant::NIL;
+ }
+ ports_changed_notify();
+ _change_notify();
+ return true;
+ }
+ if (String(p_name).begins_with("argument/")) {
+ int idx = String(p_name).get_slice("/",1).to_int()-1;
+ ERR_FAIL_INDEX_V(idx,arguments.size(),false);
+ String what = String(p_name).get_slice("/",2);
+ if (what=="type") {
+
+ Variant::Type new_type = Variant::Type(int(p_value));
+ arguments[idx].type=new_type;
+ ports_changed_notify();
+
+ return true;
+ }
+
+ if (what=="name") {
+
+ arguments[idx].name=p_value;
+ ports_changed_notify();
+ return true;
+ }
+
+
+ }
+
+ if (p_name=="stack/stackless") {
+ set_stack_less(p_value);
+ return true;
+ }
+
+ if (p_name=="stack/size") {
+ stack_size=p_value;
+ return true;
+ }
+
+ if (p_name=="rpc/mode") {
+ rpc_mode=ScriptInstance::RPCMode(int(p_value));
+ return true;
+ }
+
+ return false;
+}
+
+bool VisualScriptFunction::_get(const StringName& p_name,Variant &r_ret) const {
+
+
+ if (p_name=="argument_count") {
+ r_ret = arguments.size();
+ return true;
+ }
+ if (String(p_name).begins_with("argument/")) {
+ int idx = String(p_name).get_slice("/",1).to_int()-1;
+ ERR_FAIL_INDEX_V(idx,arguments.size(),false);
+ String what = String(p_name).get_slice("/",2);
+ if (what=="type") {
+ r_ret = arguments[idx].type;
+ return true;
+ }
+ if (what=="name") {
+ r_ret = arguments[idx].name;
+ return true;
+ }
+
+
+
+ }
+
+ if (p_name=="stack/stackless") {
+ r_ret=stack_less;
+ return true;
+ }
+
+ if (p_name=="stack/size") {
+ r_ret=stack_size;
+ return true;
+ }
+
+ if (p_name=="rpc/mode") {
+ r_ret=rpc_mode;
+ return true;
+ }
+
+ return false;
+}
+void VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) const {
+
+
+ p_list->push_back(PropertyInfo(Variant::INT,"argument_count",PROPERTY_HINT_RANGE,"0,256"));
+ String argt="Any";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+ for(int i=0;i<arguments.size();i++) {
+ p_list->push_back(PropertyInfo(Variant::INT,"argument/"+itos(i+1)+"/type",PROPERTY_HINT_ENUM,argt));
+ p_list->push_back(PropertyInfo(Variant::STRING,"argument/"+itos(i+1)+"/name"));
+ }
+ if (!stack_less) {
+ p_list->push_back(PropertyInfo(Variant::INT,"stack/size",PROPERTY_HINT_RANGE,"1,100000"));
+ }
+ p_list->push_back(PropertyInfo(Variant::BOOL,"stack/stackless"));
+ p_list->push_back(PropertyInfo(Variant::INT,"rpc/mode",PROPERTY_HINT_ENUM,"Disabled,Remote,Sync,Master,Slave"));
+
+}
+
+
+int VisualScriptFunction::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptFunction::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptFunction::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptFunction::get_output_value_port_count() const{
+
+ return arguments.size();
+}
+
+String VisualScriptFunction::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptFunction::get_input_value_port_info(int p_idx) const{
+
+ ERR_FAIL_V(PropertyInfo());
+ return PropertyInfo();
+}
+PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,arguments.size(),PropertyInfo());
+ PropertyInfo out;
+ out.type=arguments[p_idx].type;
+ out.name=arguments[p_idx].name;
+ return out;
+}
+
+String VisualScriptFunction::get_caption() const {
+
+ return "Function";
+}
+
+String VisualScriptFunction::get_text() const {
+
+ return get_name(); //use name as function name I guess
+}
+
+void VisualScriptFunction::add_argument(Variant::Type p_type,const String& p_name,int p_index){
+
+ Argument arg;
+ arg.name=p_name;
+ arg.type=p_type;
+ if (p_index>=0)
+ arguments.insert(p_index,arg);
+ else
+ arguments.push_back(arg);
+
+ ports_changed_notify();
+
+}
+void VisualScriptFunction::set_argument_type(int p_argidx,Variant::Type p_type){
+
+ ERR_FAIL_INDEX(p_argidx,arguments.size());
+
+ arguments[p_argidx].type=p_type;
+ ports_changed_notify();
+}
+Variant::Type VisualScriptFunction::get_argument_type(int p_argidx) const {
+
+ ERR_FAIL_INDEX_V(p_argidx,arguments.size(),Variant::NIL);
+ return arguments[p_argidx].type;
+
+}
+void VisualScriptFunction::set_argument_name(int p_argidx,const String& p_name) {
+
+ ERR_FAIL_INDEX(p_argidx,arguments.size());
+
+ arguments[p_argidx].name=p_name;
+ ports_changed_notify();
+
+}
+String VisualScriptFunction::get_argument_name(int p_argidx) const {
+
+ ERR_FAIL_INDEX_V(p_argidx,arguments.size(),String());
+ return arguments[p_argidx].name;
+
+}
+void VisualScriptFunction::remove_argument(int p_argidx) {
+
+ ERR_FAIL_INDEX(p_argidx,arguments.size());
+
+ arguments.remove(p_argidx);
+ ports_changed_notify();
+
+}
+
+int VisualScriptFunction::get_argument_count() const {
+
+ return arguments.size();
+}
+
+
+void VisualScriptFunction::set_rpc_mode(ScriptInstance::RPCMode p_mode) {
+ rpc_mode=p_mode;
+}
+
+ScriptInstance::RPCMode VisualScriptFunction::get_rpc_mode() const {
+ return rpc_mode;
+}
+
+
+class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptFunction *node;
+ VisualScriptInstance *instance;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ int ac = node->get_argument_count();
+
+ for(int i=0;i<ac;i++) {
+#ifdef DEBUG_ENABLED
+ Variant::Type expected = node->get_argument_type(i);
+ if (expected!=Variant::NIL) {
+ if (!Variant::can_convert_strict(p_inputs[i]->get_type(),expected)) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected=expected;
+ r_error.argument=i;
+ return 0;
+ }
+ }
+#endif
+
+ *p_outputs[i]=*p_inputs[i];
+ }
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptFunction::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceFunction * instance = memnew(VisualScriptNodeInstanceFunction );
+ instance->node=this;
+ instance->instance=p_instance;
+ return instance;
+}
+
+VisualScriptFunction::VisualScriptFunction() {
+
+ stack_size=256;
+ stack_less=false;
+ rpc_mode=ScriptInstance::RPC_MODE_DISABLED;
+}
+
+
+void VisualScriptFunction::set_stack_less(bool p_enable) {
+ stack_less=p_enable;
+ _change_notify();
+}
+
+bool VisualScriptFunction::is_stack_less() const {
+ return stack_less;
+}
+
+void VisualScriptFunction::set_stack_size(int p_size) {
+
+ ERR_FAIL_COND(p_size <1 || p_size>100000);
+ stack_size=p_size;
+}
+
+int VisualScriptFunction::get_stack_size() const {
+
+ return stack_size;
+}
+
+
+//////////////////////////////////////////
+////////////////OPERATOR//////////////////
+//////////////////////////////////////////
+
+int VisualScriptOperator::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptOperator::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptOperator::get_input_value_port_count() const{
+
+ return (op==Variant::OP_BIT_NEGATE || op==Variant::OP_NOT || op==Variant::OP_NEGATE) ? 1 : 2;
+}
+int VisualScriptOperator::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptOperator::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const{
+
+ static const Variant::Type port_types[Variant::OP_MAX][2]={
+ {Variant::NIL,Variant::NIL}, //OP_EQUAL,
+ {Variant::NIL,Variant::NIL}, //OP_NOT_EQUAL,
+ {Variant::NIL,Variant::NIL}, //OP_LESS,
+ {Variant::NIL,Variant::NIL}, //OP_LESS_EQUAL,
+ {Variant::NIL,Variant::NIL}, //OP_GREATER,
+ {Variant::NIL,Variant::NIL}, //OP_GREATER_EQUAL,
+ //mathematic
+ {Variant::NIL,Variant::NIL}, //OP_ADD,
+ {Variant::NIL,Variant::NIL}, //OP_SUBSTRACT,
+ {Variant::NIL,Variant::NIL}, //OP_MULTIPLY,
+ {Variant::NIL,Variant::NIL}, //OP_DIVIDE,
+ {Variant::NIL,Variant::NIL}, //OP_NEGATE,
+ {Variant::INT,Variant::INT}, //OP_MODULE,
+ {Variant::STRING,Variant::STRING}, //OP_STRING_CONCAT,
+ //bitwise
+ {Variant::INT,Variant::INT}, //OP_SHIFT_LEFT,
+ {Variant::INT,Variant::INT}, //OP_SHIFT_RIGHT,
+ {Variant::INT,Variant::INT}, //OP_BIT_AND,
+ {Variant::INT,Variant::INT}, //OP_BIT_OR,
+ {Variant::INT,Variant::INT}, //OP_BIT_XOR,
+ {Variant::INT,Variant::INT}, //OP_BIT_NEGATE,
+ //logic
+ {Variant::BOOL,Variant::BOOL}, //OP_AND,
+ {Variant::BOOL,Variant::BOOL}, //OP_OR,
+ {Variant::BOOL,Variant::BOOL}, //OP_XOR,
+ {Variant::BOOL,Variant::BOOL}, //OP_NOT,
+ //containment
+ {Variant::NIL,Variant::NIL} //OP_IN,
+ };
+
+ ERR_FAIL_INDEX_V(p_idx,Variant::OP_MAX,PropertyInfo());
+
+ PropertyInfo pinfo;
+ pinfo.name=p_idx==0?"A":"B";
+ pinfo.type=port_types[op][p_idx];
+ if (pinfo.type==Variant::NIL)
+ pinfo.type=typed;
+ return pinfo;
+}
+PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const{
+ static const Variant::Type port_types[Variant::OP_MAX]={
+ //comparation
+ Variant::BOOL, //OP_EQUAL,
+ Variant::BOOL, //OP_NOT_EQUAL,
+ Variant::BOOL, //OP_LESS,
+ Variant::BOOL, //OP_LESS_EQUAL,
+ Variant::BOOL, //OP_GREATER,
+ Variant::BOOL, //OP_GREATER_EQUAL,
+ //mathematic
+ Variant::NIL, //OP_ADD,
+ Variant::NIL, //OP_SUBSTRACT,
+ Variant::NIL, //OP_MULTIPLY,
+ Variant::NIL, //OP_DIVIDE,
+ Variant::NIL, //OP_NEGATE,
+ Variant::INT, //OP_MODULE,
+ Variant::STRING, //OP_STRING_CONCAT,
+ //bitwise
+ Variant::INT, //OP_SHIFT_LEFT,
+ Variant::INT, //OP_SHIFT_RIGHT,
+ Variant::INT, //OP_BIT_AND,
+ Variant::INT, //OP_BIT_OR,
+ Variant::INT, //OP_BIT_XOR,
+ Variant::INT, //OP_BIT_NEGATE,
+ //logic
+ Variant::BOOL, //OP_AND,
+ Variant::BOOL, //OP_OR,
+ Variant::BOOL, //OP_XOR,
+ Variant::BOOL, //OP_NOT,
+ //containment
+ Variant::BOOL //OP_IN,
+ };
+
+ PropertyInfo pinfo;
+ pinfo.name="";
+ pinfo.type=port_types[op];
+ if (pinfo.type==Variant::NIL)
+ pinfo.type=typed;
+ return pinfo;
+
+}
+
+static const char* op_names[]={
+ //comparation
+ "Equal", //OP_EQUAL,
+ "NotEqual", //OP_NOT_EQUAL,
+ "Less", //OP_LESS,
+ "LessEqual", //OP_LESS_EQUAL,
+ "Greater", //OP_GREATER,
+ "GreaterEq", //OP_GREATER_EQUAL,
+ //mathematic
+ "Add", //OP_ADD,
+ "Subtract", //OP_SUBSTRACT,
+ "Multiply", //OP_MULTIPLY,
+ "Divide", //OP_DIVIDE,
+ "Negate", //OP_NEGATE,
+ "Remainder", //OP_MODULE,
+ "Concat", //OP_STRING_CONCAT,
+ //bitwise
+ "ShiftLeft", //OP_SHIFT_LEFT,
+ "ShiftRight", //OP_SHIFT_RIGHT,
+ "BitAnd", //OP_BIT_AND,
+ "BitOr", //OP_BIT_OR,
+ "BitXor", //OP_BIT_XOR,
+ "BitNeg", //OP_BIT_NEGATE,
+ //logic
+ "And", //OP_AND,
+ "Or", //OP_OR,
+ "Xor", //OP_XOR,
+ "Not", //OP_NOT,
+ //containment
+ "In", //OP_IN,
+};
+
+String VisualScriptOperator::get_caption() const {
+
+
+
+ return op_names[op];
+}
+
+String VisualScriptOperator::get_text() const {
+
+ static const wchar_t* op_names[]={
+ //comparation
+ L"A = B", //OP_EQUAL,
+ L"A \u2260 B", //OP_NOT_EQUAL,
+ L"A < B", //OP_LESS,
+ L"A \u2264 B", //OP_LESS_EQUAL,
+ L"A > B", //OP_GREATER,
+ L"A \u2265 B", //OP_GREATER_EQUAL,
+ //mathematic
+ L"A + B", //OP_ADD,
+ L"A - B", //OP_SUBSTRACT,
+ L"A x B", //OP_MULTIPLY,
+ L"A \u00F7 B", //OP_DIVIDE,
+ L"\u00AC A", //OP_NEGATE,
+ L"A mod B", //OP_MODULE,
+ L"A .. B", //OP_STRING_CONCAT,
+ //bitwise
+ L"A << B", //OP_SHIFT_LEFT,
+ L"A >> B", //OP_SHIFT_RIGHT,
+ L"A & B", //OP_BIT_AND,
+ L"A | B", //OP_BIT_OR,
+ L"A ^ B", //OP_BIT_XOR,
+ L"~A", //OP_BIT_NEGATE,
+ //logic
+ L"A and B", //OP_AND,
+ L"A or B", //OP_OR,
+ L"A xor B", //OP_XOR,
+ L"not A", //OP_NOT,
+
+ };
+ return op_names[op];
+}
+
+void VisualScriptOperator::set_operator(Variant::Operator p_op) {
+
+ if (op==p_op)
+ return;
+ op=p_op;
+ ports_changed_notify();
+
+}
+
+Variant::Operator VisualScriptOperator::get_operator() const{
+
+ return op;
+}
+
+void VisualScriptOperator::set_typed(Variant::Type p_op) {
+
+ if (typed==p_op)
+ return;
+
+ typed=p_op;
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptOperator::get_typed() const {
+
+ return typed;
+}
+
+
+void VisualScriptOperator::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_operator","op"),&VisualScriptOperator::set_operator);
+ ObjectTypeDB::bind_method(_MD("get_operator"),&VisualScriptOperator::get_operator);
+
+ ObjectTypeDB::bind_method(_MD("set_typed","type"),&VisualScriptOperator::set_typed);
+ ObjectTypeDB::bind_method(_MD("get_typed"),&VisualScriptOperator::get_typed);
+
+ String types;
+ for(int i=0;i<Variant::OP_MAX;i++) {
+ if (i>0)
+ types+=",";
+ types+=op_names[i];
+ }
+
+ String argt="Any";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"operator_value/type",PROPERTY_HINT_ENUM,types,PROPERTY_USAGE_NOEDITOR),_SCS("set_operator"),_SCS("get_operator"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"typed_value/typed",PROPERTY_HINT_ENUM,argt),_SCS("set_typed"),_SCS("get_typed"));
+
+}
+
+class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance {
+public:
+
+ bool unary;
+ Variant::Operator op;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ bool valid;
+ if (unary) {
+
+ Variant::evaluate(op,*p_inputs[0],Variant(),*p_outputs[0],valid);
+ } else {
+ Variant::evaluate(op,*p_inputs[0],*p_inputs[1],*p_outputs[0],valid);
+ }
+
+ if (!valid) {
+
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ if (p_outputs[0]->get_type()==Variant::STRING) {
+ r_error_str=*p_outputs[0];
+ } else {
+ if (unary)
+ r_error_str=String(op_names[op])+RTR(": Invalid argument of type: ")+Variant::get_type_name(p_inputs[0]->get_type());
+ else
+ r_error_str=String(op_names[op])+RTR(": Invalid arguments: ")+"A: "+Variant::get_type_name(p_inputs[0]->get_type())+" B: "+Variant::get_type_name(p_inputs[1]->get_type());
+ }
+ }
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptOperator::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceOperator * instance = memnew(VisualScriptNodeInstanceOperator );
+ instance->unary=get_input_value_port_count()==1;
+ instance->op=op;
+ return instance;
+}
+
+VisualScriptOperator::VisualScriptOperator() {
+
+ op=Variant::OP_ADD;
+ typed=Variant::NIL;
+}
+
+
+
+template<Variant::Operator OP>
+static Ref<VisualScriptNode> create_op_node(const String& p_name) {
+
+ Ref<VisualScriptOperator> node;
+ node.instance();
+ node->set_operator(OP);
+ return node;
+}
+
+//////////////////////////////////////////
+////////////////VARIABLE GET//////////////////
+//////////////////////////////////////////
+
+int VisualScriptVariableGet::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptVariableGet::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptVariableGet::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptVariableGet::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptVariableGet::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptVariableGet::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) const{
+
+ PropertyInfo pinfo;
+ pinfo.name="value";
+ if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) {
+ PropertyInfo vinfo = get_visual_script()->get_variable_info(variable);
+ pinfo.type=vinfo.type;
+ pinfo.hint=vinfo.hint;
+ pinfo.hint_string=vinfo.hint_string;
+ }
+ return pinfo;
+}
+
+
+String VisualScriptVariableGet::get_caption() const {
+
+ return "Variable";
+}
+
+String VisualScriptVariableGet::get_text() const {
+
+ return variable;
+}
+
+void VisualScriptVariableGet::set_variable(StringName p_variable) {
+
+ if (variable==p_variable)
+ return;
+ variable=p_variable;
+ ports_changed_notify();
+
+}
+
+StringName VisualScriptVariableGet::get_variable() const{
+
+ return variable;
+}
+
+void VisualScriptVariableGet::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="variable/name" && get_visual_script().is_valid()) {
+ Ref<VisualScript> vs = get_visual_script();
+ List<StringName> vars;
+ vs->get_variable_list(&vars);
+
+ String vhint;
+ for (List<StringName>::Element *E=vars.front();E;E=E->next()) {
+ if (vhint!=String())
+ vhint+=",";
+
+ vhint+=E->get().operator String();
+ }
+
+ property.hint=PROPERTY_HINT_ENUM;
+ property.hint_string=vhint;
+ }
+}
+
+void VisualScriptVariableGet::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableGet::set_variable);
+ ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableGet::get_variable);
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable"));
+
+}
+
+class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptVariableGet *node;
+ VisualScriptInstance *instance;
+ StringName variable;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ if (instance->get_variable(variable,r_value)==false) {
+ r_error=RTR("VariableGet not found in script: ")+"'"+String(variable)+"'";
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptVariableGet::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceVariableGet * instance = memnew(VisualScriptNodeInstanceVariableGet );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->variable=variable;
+ return instance;
+}
+VisualScriptVariableGet::VisualScriptVariableGet() {
+
+
+}
+
+
+//////////////////////////////////////////
+////////////////VARIABLE GET//////////////////
+//////////////////////////////////////////
+
+int VisualScriptVariableSet::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptVariableSet::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptVariableSet::get_input_value_port_count() const{
+
+ return 1;
+}
+int VisualScriptVariableSet::get_output_value_port_count() const{
+
+ return 0;
+}
+
+String VisualScriptVariableSet::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptVariableSet::get_input_value_port_info(int p_idx) const{
+
+ PropertyInfo pinfo;
+ pinfo.name="set";
+ if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) {
+ PropertyInfo vinfo = get_visual_script()->get_variable_info(variable);
+ pinfo.type=vinfo.type;
+ pinfo.hint=vinfo.hint;
+ pinfo.hint_string=vinfo.hint_string;
+ }
+ return pinfo;
+}
+
+PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+
+String VisualScriptVariableSet::get_caption() const {
+
+ return "VariableSet";
+}
+
+String VisualScriptVariableSet::get_text() const {
+
+ return variable;
+}
+
+void VisualScriptVariableSet::set_variable(StringName p_variable) {
+
+ if (variable==p_variable)
+ return;
+ variable=p_variable;
+ ports_changed_notify();
+
+}
+
+StringName VisualScriptVariableSet::get_variable() const{
+
+ return variable;
+}
+
+void VisualScriptVariableSet::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="variable/name" && get_visual_script().is_valid()) {
+ Ref<VisualScript> vs = get_visual_script();
+ List<StringName> vars;
+ vs->get_variable_list(&vars);
+
+ String vhint;
+ for (List<StringName>::Element *E=vars.front();E;E=E->next()) {
+ if (vhint!=String())
+ vhint+=",";
+
+ vhint+=E->get().operator String();
+ }
+
+ property.hint=PROPERTY_HINT_ENUM;
+ property.hint_string=vhint;
+ }
+}
+
+void VisualScriptVariableSet::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableSet::set_variable);
+ ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableSet::get_variable);
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable"));
+
+}
+
+class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptVariableSet *node;
+ VisualScriptInstance *instance;
+ StringName variable;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (instance->set_variable(variable,*p_inputs[0])==false) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD ;
+ r_error_str=RTR("VariableSet not found in script: ")+"'"+String(variable)+"'";
+ }
+
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptVariableSet::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceVariableSet * instance = memnew(VisualScriptNodeInstanceVariableSet );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->variable=variable;
+ return instance;
+}
+VisualScriptVariableSet::VisualScriptVariableSet() {
+
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////CONSTANT//////////////////
+//////////////////////////////////////////
+
+int VisualScriptConstant::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptConstant::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptConstant::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptConstant::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptConstant::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptConstant::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const{
+
+ PropertyInfo pinfo;
+ pinfo.name="get";
+ pinfo.type=type;
+ return pinfo;
+}
+
+
+String VisualScriptConstant::get_caption() const {
+
+ return "Constant";
+}
+
+String VisualScriptConstant::get_text() const {
+
+ return String(value);
+}
+
+void VisualScriptConstant::set_constant_type(Variant::Type p_type) {
+
+ if (type==p_type)
+ return;
+
+ type=p_type;
+ ports_changed_notify();
+ Variant::CallError ce;
+ value=Variant::construct(type,NULL,0,ce);
+ _change_notify();
+
+}
+
+Variant::Type VisualScriptConstant::get_constant_type() const{
+
+ return type;
+}
+
+void VisualScriptConstant::set_constant_value(Variant p_value){
+
+ if (value==p_value)
+ return;
+
+ value=p_value;
+ ports_changed_notify();
+}
+Variant VisualScriptConstant::get_constant_value() const{
+
+ return value;
+}
+
+void VisualScriptConstant::_validate_property(PropertyInfo& property) const {
+
+
+ if (property.name=="constant/value") {
+ property.type=type;
+ if (type==Variant::NIL)
+ property.usage=0; //do not save if nil
+ }
+}
+
+void VisualScriptConstant::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_constant_type","type"),&VisualScriptConstant::set_constant_type);
+ ObjectTypeDB::bind_method(_MD("get_constant_type"),&VisualScriptConstant::get_constant_type);
+
+ ObjectTypeDB::bind_method(_MD("set_constant_value","value"),&VisualScriptConstant::set_constant_value);
+ ObjectTypeDB::bind_method(_MD("get_constant_value"),&VisualScriptConstant::get_constant_value);
+
+ String argt="Null";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"constant/type",PROPERTY_HINT_ENUM,argt),_SCS("set_constant_type"),_SCS("get_constant_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::NIL,"constant/value"),_SCS("set_constant_value"),_SCS("get_constant_value"));
+
+}
+
+class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance {
+public:
+
+ Variant constant;
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ *r_value=constant;
+
+ return true;
+
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptConstant::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceConstant * instance = memnew(VisualScriptNodeInstanceConstant );
+ instance->constant=value;
+ return instance;
+}
+
+VisualScriptConstant::VisualScriptConstant() {
+
+ type=Variant::NIL;
+
+}
+
+//////////////////////////////////////////
+////////////////PRELOAD//////////////////
+//////////////////////////////////////////
+
+int VisualScriptPreload::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptPreload::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptPreload::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptPreload::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptPreload::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptPreload::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::OBJECT,"res");
+}
+
+
+String VisualScriptPreload::get_caption() const {
+
+ return "Preload";
+}
+
+String VisualScriptPreload::get_text() const {
+
+ if (preload.is_valid()) {
+ if (preload->get_path().is_resource_file()) {
+ return preload->get_path();
+ } else if (preload->get_name()!=String()) {
+ return preload->get_name();
+ } else {
+ return preload->get_type();
+ }
+ } else {
+ return "<empty>";
+ }
+}
+
+
+void VisualScriptPreload::set_preload(const Ref<Resource>& p_preload){
+
+ if (preload==p_preload)
+ return;
+
+ preload=p_preload;
+ ports_changed_notify();
+}
+Ref<Resource> VisualScriptPreload::get_preload() const{
+
+ return preload;
+}
+
+
+void VisualScriptPreload::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_preload","resource"),&VisualScriptPreload::set_preload);
+ ObjectTypeDB::bind_method(_MD("get_preload"),&VisualScriptPreload::get_preload);
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"resource",PROPERTY_HINT_RESOURCE_TYPE,"Resource"),_SCS("set_preload"),_SCS("get_preload"));
+
+}
+
+class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance {
+public:
+
+ Ref<Resource> preload;
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ *r_value=preload;
+
+ return true;
+
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptPreload::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstancePreload * instance = memnew(VisualScriptNodeInstancePreload );
+ instance->preload=preload;
+ return instance;
+}
+
+VisualScriptPreload::VisualScriptPreload() {
+
+}
+
+
+
+
+//////////////////////////////////////////
+////////////////INDEX////////////////////
+//////////////////////////////////////////
+
+int VisualScriptIndexGet::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptIndexGet::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptIndexGet::get_input_value_port_count() const{
+
+ return 2;
+}
+int VisualScriptIndexGet::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptIndexGet::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptIndexGet::get_input_value_port_info(int p_idx) const{
+
+ if (p_idx==0) {
+ return PropertyInfo(Variant::NIL,"base");
+ } else {
+ return PropertyInfo(Variant::NIL,"index");
+
+ }
+}
+
+PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+
+String VisualScriptIndexGet::get_caption() const {
+
+ return "IndexGet";
+}
+
+String VisualScriptIndexGet::get_text() const {
+
+ return String("get");
+}
+
+
+class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance {
+public:
+
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ bool valid;
+ *p_outputs[0] = p_inputs[0]->get(*p_inputs[1],&valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Invalid get: "+p_inputs[0]->get_construct_string();
+ }
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptIndexGet::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceIndexGet * instance = memnew(VisualScriptNodeInstanceIndexGet );
+ return instance;
+}
+VisualScriptIndexGet::VisualScriptIndexGet() {
+
+
+
+}
+
+//////////////////////////////////////////
+////////////////INDEXSET//////////////////
+//////////////////////////////////////////
+
+int VisualScriptIndexSet::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptIndexSet::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptIndexSet::get_input_value_port_count() const{
+
+ return 3;
+}
+int VisualScriptIndexSet::get_output_value_port_count() const{
+
+ return 0;
+}
+
+String VisualScriptIndexSet::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptIndexSet::get_input_value_port_info(int p_idx) const{
+
+ if (p_idx==0) {
+ return PropertyInfo(Variant::NIL,"base");
+ } else if (p_idx==1){
+ return PropertyInfo(Variant::NIL,"index");
+
+ } else {
+ return PropertyInfo(Variant::NIL,"value");
+
+ }
+}
+
+PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+
+String VisualScriptIndexSet::get_caption() const {
+
+ return "IndexSet";
+}
+
+String VisualScriptIndexSet::get_text() const {
+
+ return String("set");
+}
+
+
+class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance {
+public:
+
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ bool valid;
+ *p_outputs[0]=*p_inputs[0];
+ p_outputs[0]->set(*p_inputs[1],*p_inputs[2],&valid);
+
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Invalid set: "+p_inputs[1]->get_construct_string();
+ }
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptIndexSet::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceIndexSet * instance = memnew(VisualScriptNodeInstanceIndexSet );
+ return instance;
+}
+VisualScriptIndexSet::VisualScriptIndexSet() {
+
+
+
+}
+
+
+//////////////////////////////////////////
+////////////////GLOBALCONSTANT///////////
+//////////////////////////////////////////
+
+int VisualScriptGlobalConstant::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptGlobalConstant::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptGlobalConstant::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptGlobalConstant::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptGlobalConstant::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptGlobalConstant::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::REAL,"value");
+}
+
+
+String VisualScriptGlobalConstant::get_caption() const {
+
+ return "GlobalConst";
+}
+
+String VisualScriptGlobalConstant::get_text() const {
+
+ return GlobalConstants::get_global_constant_name(index);
+}
+
+void VisualScriptGlobalConstant::set_global_constant(int p_which) {
+
+ index=p_which;
+ _change_notify();
+ ports_changed_notify();
+}
+
+int VisualScriptGlobalConstant::get_global_constant() {
+ return index;
+}
+
+
+class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance {
+public:
+
+ int index;
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ *r_value = GlobalConstants::get_global_constant_value(index);
+ return true;
+
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptGlobalConstant::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceGlobalConstant * instance = memnew(VisualScriptNodeInstanceGlobalConstant );
+ instance->index=index;
+ return instance;
+}
+
+void VisualScriptGlobalConstant::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_global_constant","index"),&VisualScriptGlobalConstant::set_global_constant);
+ ObjectTypeDB::bind_method(_MD("get_global_constant"),&VisualScriptGlobalConstant::get_global_constant);
+
+ String cc;
+
+ for(int i=0;i<GlobalConstants::get_global_constant_count();i++) {
+
+ if (i>0)
+ cc+=",";
+ cc+=GlobalConstants::get_global_constant_name(i);
+ }
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_global_constant"),_SCS("get_global_constant"));
+}
+
+VisualScriptGlobalConstant::VisualScriptGlobalConstant() {
+
+ index=0;
+}
+
+
+
+//////////////////////////////////////////
+////////////////MATHCONSTANT///////////
+//////////////////////////////////////////
+
+
+const char* VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX]={
+ "One",
+ "PI",
+ "PIx2",
+ "PI/2",
+ "E",
+ "Sqrt2",
+};
+
+double VisualScriptMathConstant::const_value[MATH_CONSTANT_MAX]={
+ 1.0,
+ Math_PI,
+ Math_PI*2,
+ Math_PI*0.5,
+ 2.71828182845904523536,
+ Math::sqrt(2.0)
+};
+
+
+int VisualScriptMathConstant::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptMathConstant::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptMathConstant::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptMathConstant::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptMathConstant::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptMathConstant::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::REAL,"value");
+}
+
+
+String VisualScriptMathConstant::get_caption() const {
+
+ return "MathConst";
+}
+
+String VisualScriptMathConstant::get_text() const {
+
+ return const_name[constant];
+}
+
+void VisualScriptMathConstant::set_math_constant(MathConstant p_which) {
+
+ constant=p_which;
+ _change_notify();
+ ports_changed_notify();
+}
+
+VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_constant() {
+ return constant;
+}
+
+class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance {
+public:
+
+ float value;
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ *r_value = value;
+ return true;
+
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptMathConstant::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceMathConstant * instance = memnew(VisualScriptNodeInstanceMathConstant );
+ instance->value=const_value[constant];
+ return instance;
+}
+
+
+void VisualScriptMathConstant::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_math_constant","which"),&VisualScriptMathConstant::set_math_constant);
+ ObjectTypeDB::bind_method(_MD("get_math_constant"),&VisualScriptMathConstant::get_math_constant);
+
+ String cc;
+
+ for(int i=0;i<MATH_CONSTANT_MAX;i++) {
+
+ if (i>0)
+ cc+=",";
+ cc+=const_name[i];
+ }
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_math_constant"),_SCS("get_math_constant"));
+}
+
+VisualScriptMathConstant::VisualScriptMathConstant() {
+
+ constant=MATH_CONSTANT_ONE;
+}
+
+
+
+//////////////////////////////////////////
+////////////////GLOBALSINGLETON///////////
+//////////////////////////////////////////
+
+int VisualScriptEngineSingleton::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptEngineSingleton::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptEngineSingleton::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptEngineSingleton::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptEngineSingleton::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptEngineSingleton::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptEngineSingleton::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::OBJECT,"instance");
+}
+
+
+String VisualScriptEngineSingleton::get_caption() const {
+
+ return "EngineSingleton";
+}
+
+String VisualScriptEngineSingleton::get_text() const {
+
+ return singleton;
+}
+
+void VisualScriptEngineSingleton::set_singleton(const String& p_string) {
+
+ singleton=p_string;
+
+ _change_notify();
+ ports_changed_notify();
+}
+
+String VisualScriptEngineSingleton::get_singleton() {
+ return singleton;
+}
+
+
+
+class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance {
+public:
+
+ Object* singleton;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ *r_value=singleton;
+ return true;
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ return 0;
+ }
+
+};
+
+VisualScriptNodeInstance* VisualScriptEngineSingleton::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceEngineSingleton * instance = memnew(VisualScriptNodeInstanceEngineSingleton );
+ instance->singleton=Globals::get_singleton()->get_singleton_object(singleton);
+ return instance;
+}
+
+
+void VisualScriptEngineSingleton::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_singleton","name"),&VisualScriptEngineSingleton::set_singleton);
+ ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptEngineSingleton::get_singleton);
+
+ String cc;
+
+ List<Globals::Singleton> singletons;
+
+ Globals::get_singleton()->get_singletons(&singletons);
+
+ for (List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) {
+ if (E->get().name=="VS" || E->get().name=="PS" || E->get().name=="PS2D" || E->get().name=="AS" || E->get().name=="TS" || E->get().name=="SS" || E->get().name=="SS2D")
+ continue; //skip these, too simple named
+
+ if (cc!=String())
+ cc+=",";
+ cc+=E->get().name;
+ }
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_singleton"),_SCS("get_singleton"));
+}
+
+VisualScriptEngineSingleton::VisualScriptEngineSingleton() {
+
+ singleton=String();
+}
+
+
+
+//////////////////////////////////////////
+////////////////GETNODE///////////
+//////////////////////////////////////////
+
+int VisualScriptSceneNode::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptSceneNode::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptSceneNode::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptSceneNode::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptSceneNode::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptSceneNode::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::OBJECT,"node");
+}
+
+
+String VisualScriptSceneNode::get_caption() const {
+
+ return "SceneNode";
+}
+
+String VisualScriptSceneNode::get_text() const {
+
+ return path.simplified();
+}
+
+void VisualScriptSceneNode::set_node_path(const NodePath& p_path) {
+
+ path=p_path;
+ _change_notify();
+ ports_changed_notify();
+}
+
+NodePath VisualScriptSceneNode::get_node_path() {
+ return path;
+}
+
+
+class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptSceneNode *node;
+ VisualScriptInstance *instance;
+ NodePath path;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ Node* node = instance->get_owner_ptr()->cast_to<Node>();
+ if (!node) {
+ r_error="Base object is not a Node!";
+ return false;
+ }
+
+
+
+ Node* another = node->get_node(path);
+ if (!node) {
+ r_error="Path does not lead Node!";
+ return false;
+ }
+
+ *r_value=another;
+ return true;
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptSceneNode::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceSceneNode * instance = memnew(VisualScriptNodeInstanceSceneNode );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->path=path;
+ return instance;
+}
+
+
+#ifdef TOOLS_ENABLED
+
+static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) {
+
+ if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene)
+ return NULL;
+
+ Ref<Script> scr = p_current_node->get_script();
+
+ if (scr.is_valid() && scr==script)
+ return p_current_node;
+
+ for(int i=0;i<p_current_node->get_child_count();i++) {
+ Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script);
+ if (n)
+ return n;
+ }
+
+ return NULL;
+}
+
+#endif
+
+void VisualScriptSceneNode::_validate_property(PropertyInfo& property) const {
+
+#ifdef TOOLS_ENABLED
+ if (property.name=="node_path") {
+
+ Ref<Script> script = get_visual_script();
+ if (!script.is_valid())
+ return;
+
+ MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+ if (!main_loop)
+ return;
+
+ SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+ if (!scene_tree)
+ return;
+
+ Node *edited_scene = scene_tree->get_edited_scene_root();
+
+ if (!edited_scene)
+ return;
+
+ Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+ if (!script_node)
+ return;
+
+ property.hint_string=script_node->get_path();
+ }
+#endif
+}
+
+void VisualScriptSceneNode::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_node_path","path"),&VisualScriptSceneNode::set_node_path);
+ ObjectTypeDB::bind_method(_MD("get_node_path"),&VisualScriptSceneNode::get_node_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_node_path"),_SCS("get_node_path"));
+}
+
+VisualScriptSceneNode::VisualScriptSceneNode() {
+
+ path=String(".");
+}
+
+
+//////////////////////////////////////////
+////////////////SceneTree///////////
+//////////////////////////////////////////
+
+int VisualScriptSceneTree::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptSceneTree::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptSceneTree::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptSceneTree::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptSceneTree::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptSceneTree::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::OBJECT,"instance");
+}
+
+
+String VisualScriptSceneTree::get_caption() const {
+
+ return "SceneTree";
+}
+
+String VisualScriptSceneTree::get_text() const {
+
+ return "";
+}
+
+
+class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptSceneTree *node;
+ VisualScriptInstance *instance;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ Node* node = instance->get_owner_ptr()->cast_to<Node>();
+ if (!node) {
+ r_error="Base object is not a Node!";
+ return false;
+ }
+
+ SceneTree* tree = node->get_tree();
+ if (!tree) {
+ r_error="Attempt to get SceneTree while node is not in the active tree.";
+ return false;
+ }
+
+ *r_value=tree;
+ return true;
+
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptSceneTree::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceSceneTree * instance = memnew(VisualScriptNodeInstanceSceneTree );
+ instance->node=this;
+ instance->instance=p_instance;
+ return instance;
+}
+
+
+void VisualScriptSceneTree::_validate_property(PropertyInfo& property) const {
+
+}
+
+void VisualScriptSceneTree::_bind_methods() {
+
+}
+
+VisualScriptSceneTree::VisualScriptSceneTree() {
+
+}
+
+
+//////////////////////////////////////////
+////////////////RESPATH///////////
+//////////////////////////////////////////
+
+int VisualScriptResourcePath::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptResourcePath::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptResourcePath::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptResourcePath::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptResourcePath::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptResourcePath::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptResourcePath::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::STRING,"path");
+}
+
+
+String VisualScriptResourcePath::get_caption() const {
+
+ return "ResourcePath";
+}
+
+String VisualScriptResourcePath::get_text() const {
+
+ return path;
+}
+
+void VisualScriptResourcePath::set_resource_path(const String& p_path) {
+
+ path=p_path;
+ _change_notify();
+ ports_changed_notify();
+}
+
+String VisualScriptResourcePath::get_resource_path() {
+ return path;
+}
+
+
+class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance {
+public:
+
+ String path;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+ *r_value = path;
+ return true;
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptResourcePath::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceResourcePath * instance = memnew(VisualScriptNodeInstanceResourcePath );
+ instance->path=path;
+ return instance;
+}
+
+
+
+void VisualScriptResourcePath::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_resource_path","path"),&VisualScriptResourcePath::set_resource_path);
+ ObjectTypeDB::bind_method(_MD("get_resource_path"),&VisualScriptResourcePath::get_resource_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"path",PROPERTY_HINT_FILE),_SCS("set_resource_path"),_SCS("get_resource_path"));
+}
+
+VisualScriptResourcePath::VisualScriptResourcePath() {
+
+ path="";
+}
+
+
+
+//////////////////////////////////////////
+////////////////SELF///////////
+//////////////////////////////////////////
+
+int VisualScriptSelf::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptSelf::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptSelf::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptSelf::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptSelf::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptSelf::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptSelf::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::OBJECT,"instance");
+}
+
+
+String VisualScriptSelf::get_caption() const {
+
+ return "Self";
+}
+
+String VisualScriptSelf::get_text() const {
+
+ if (get_visual_script().is_valid())
+ return get_visual_script()->get_instance_base_type();
+ else
+ return "";
+}
+
+
+class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ *r_value = instance->get_owner_ptr();
+ return true;
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptSelf::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceSelf * instance = memnew(VisualScriptNodeInstanceSelf );
+ instance->instance=p_instance;
+ return instance;
+}
+
+
+
+void VisualScriptSelf::_bind_methods() {
+
+}
+
+VisualScriptSelf::VisualScriptSelf() {
+
+
+}
+
+//////////////////////////////////////////
+////////////////CUSTOM (SCRIPTED)///////////
+//////////////////////////////////////////
+
+int VisualScriptCustomNode::get_output_sequence_port_count() const {
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_count")) {
+ return get_script_instance()->call("_get_output_sequence_port_count");
+ }
+ return 0;
+}
+
+bool VisualScriptCustomNode::has_input_sequence_port() const{
+
+ if (get_script_instance() && get_script_instance()->has_method("_has_input_sequence_port")) {
+ return get_script_instance()->call("_has_input_sequence_port");
+ }
+ return false;
+}
+
+int VisualScriptCustomNode::get_input_value_port_count() const{
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_count")) {
+ return get_script_instance()->call("_get_input_value_port_count");
+ }
+ return 0;
+}
+int VisualScriptCustomNode::get_output_value_port_count() const{
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_count")) {
+ return get_script_instance()->call("_get_output_value_port_count");
+ }
+ return 0;
+}
+
+String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const {
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_text")) {
+ return get_script_instance()->call("_get_output_sequence_port_text",p_port);
+ }
+
+ return String();
+}
+
+PropertyInfo VisualScriptCustomNode::get_input_value_port_info(int p_idx) const{
+
+ PropertyInfo info;
+ if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_type")) {
+ info.type=Variant::Type(int(get_script_instance()->call("_get_input_value_port_type",p_idx)));
+ }
+ if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_name")) {
+ info.name=get_script_instance()->call("_get_input_value_port_name",p_idx);
+ }
+ return info;
+}
+
+PropertyInfo VisualScriptCustomNode::get_output_value_port_info(int p_idx) const{
+
+ PropertyInfo info;
+ if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_type")) {
+ info.type=Variant::Type(int(get_script_instance()->call("_get_output_value_port_type",p_idx)));
+ }
+ if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_name")) {
+ info.name=get_script_instance()->call("_get_output_value_port_name",p_idx);
+ }
+ return info;
+}
+
+
+String VisualScriptCustomNode::get_caption() const {
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_caption")) {
+ return get_script_instance()->call("_get_caption");
+ }
+ return "CustomNode";
+}
+
+String VisualScriptCustomNode::get_text() const {
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_text")) {
+ return get_script_instance()->call("_get_text");
+ }
+ return "";
+}
+
+String VisualScriptCustomNode::get_category() const {
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_category")) {
+ return get_script_instance()->call("_get_category");
+ }
+ return "custom";
+}
+
+class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ VisualScriptCustomNode *node;
+ int in_count;
+ int out_count;
+ int work_mem_size;
+ Vector<bool> out_unsequenced;
+
+ virtual int get_working_memory_size() const { return work_mem_size; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return out_unsequenced[p_idx]; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+
+ if (!node->get_script_instance() || !node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_get_output_port_unsequenced)) {
+#ifdef DEBUG_ENABLED
+ r_error=RTR("Custom node has no _get_output_port_unsequenced(idx,wmem), but unsequenced ports were specified.");
+ return false;
+ }
+#endif
+
+ Array work_mem(true);
+ work_mem.resize(work_mem_size);
+
+ *r_value = node->get_script_instance()->call(VisualScriptLanguage::singleton->_get_output_port_unsequenced,p_idx,work_mem);
+
+
+ for(int i=0;i<work_mem_size;i++) {
+ if (i<work_mem.size()) {
+ p_working_mem[i]=work_mem[i];
+ }
+ }
+
+ return true;
+
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (node->get_script_instance()) {
+#ifdef DEBUG_ENABLED
+ if (!node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_step)) {
+ r_error_str=RTR("Custom node has no _step() method, can't process graph.");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+#endif
+ Array in_values(true);
+ Array out_values(true);
+ Array work_mem(true);
+
+ in_values.resize(in_count);
+
+ for(int i=0;i<in_count;i++) {
+ in_values[i]=p_inputs[i];
+ }
+
+ out_values.resize(in_count);
+
+ work_mem.resize(work_mem_size);
+
+ for(int i=0;i<work_mem_size;i++) {
+ work_mem[i]=p_working_mem[i];
+ }
+
+ int ret_out;
+
+ Variant ret = node->get_script_instance()->call(VisualScriptLanguage::singleton->_step,in_values,out_values,p_start_mode,work_mem);
+ if (ret.get_type()==Variant::STRING) {
+ r_error_str=ret;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ } else if (ret.is_num()) {
+ ret_out=ret;
+ } else {
+ r_error_str=RTR("Invalid return value from _step(), must be integer (seq out), or string (error).");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+
+ for(int i=0;i<out_count;i++) {
+ if (i<out_values.size()) {
+ *p_outputs[i]=out_values[i];
+ }
+ }
+
+ for(int i=0;i<work_mem_size;i++) {
+ if (i<work_mem.size()) {
+ p_working_mem[i]=work_mem[i];
+ }
+ }
+
+ return ret_out;
+
+ }
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptCustomNode::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceCustomNode * instance = memnew(VisualScriptNodeInstanceCustomNode );
+ instance->instance=p_instance;
+ instance->in_count=get_input_value_port_count();
+ instance->out_count=get_output_value_port_count();
+
+ for(int i=0;i<instance->out_count;i++) {
+ bool unseq = get_script_instance() && get_script_instance()->has_method("_is_output_port_unsequenced") && bool(get_script_instance()->call("_is_output_port_unsequenced",i));
+ instance->out_unsequenced.push_back(unseq);
+ }
+
+ if (get_script_instance() && get_script_instance()->has_method("_get_working_memory_size")) {
+ instance->work_mem_size = get_script_instance()->call("_get_working_memory_size");
+ } else {
+ instance->work_mem_size=0;
+ }
+
+ return instance;
+}
+
+
+
+void VisualScriptCustomNode::_bind_methods() {
+
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_sequence_port_count") );
+ BIND_VMETHOD( MethodInfo(Variant::BOOL,"_has_input_sequence_port") );
+
+ BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_sequence_port_text",PropertyInfo(Variant::INT,"idx")) );
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_count") );
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_count") );
+
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_type",PropertyInfo(Variant::INT,"idx")) );
+ BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_input_value_port_name",PropertyInfo(Variant::INT,"idx")) );
+
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_type",PropertyInfo(Variant::INT,"idx")) );
+ BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_value_port_name",PropertyInfo(Variant::INT,"idx")) );
+
+ BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_caption") );
+ BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_text") );
+ BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_category") );
+
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_get_working_memory_size") );
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_is_output_port_unsequenced",PropertyInfo(Variant::INT,"idx")) );
+ BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_port_unsequenced",PropertyInfo(Variant::INT,"idx"),PropertyInfo(Variant::ARRAY,"work_mem")) );
+ BIND_VMETHOD( MethodInfo(Variant::NIL,"_step:Variant",PropertyInfo(Variant::ARRAY,"inputs"),PropertyInfo(Variant::ARRAY,"outputs"),PropertyInfo(Variant::INT,"start_mode"),PropertyInfo(Variant::ARRAY,"working_mem")) );
+
+ BIND_CONSTANT( START_MODE_BEGIN_SEQUENCE );
+ BIND_CONSTANT( START_MODE_CONTINUE_SEQUENCE );
+ BIND_CONSTANT( START_MODE_RESUME_YIELD );
+
+ BIND_CONSTANT( STEP_PUSH_STACK_BIT );
+ BIND_CONSTANT( STEP_GO_BACK_BIT );
+ BIND_CONSTANT( STEP_NO_ADVANCE_BIT );
+ BIND_CONSTANT( STEP_EXIT_FUNCTION_BIT );
+ BIND_CONSTANT( STEP_YIELD_BIT );
+
+}
+
+VisualScriptCustomNode::VisualScriptCustomNode() {
+
+
+}
+
+//////////////////////////////////////////
+////////////////SUBCALL///////////
+//////////////////////////////////////////
+
+int VisualScriptSubCall::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptSubCall::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptSubCall::get_input_value_port_count() const{
+
+ Ref<Script> script = get_script();
+
+ if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
+
+ MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall);
+ return mi.arguments.size();
+ }
+
+ return 0;
+}
+int VisualScriptSubCall::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptSubCall::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptSubCall::get_input_value_port_info(int p_idx) const{
+
+ Ref<Script> script = get_script();
+ if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
+
+ MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall);
+ return mi.arguments[p_idx];
+ }
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptSubCall::get_output_value_port_info(int p_idx) const{
+
+ Ref<Script> script = get_script();
+ if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
+ MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall);
+ return mi.return_val;
+ }
+ return PropertyInfo();
+}
+
+
+String VisualScriptSubCall::get_caption() const {
+
+ return "SubCall";
+}
+
+
+String VisualScriptSubCall::get_text() const {
+
+ Ref<Script> script = get_script();
+ if (script.is_valid()) {
+ if (script->get_name()!=String())
+ return script->get_name();
+ if (script->get_path().is_resource_file())
+ return script->get_path().get_file();
+ return script->get_type();
+ }
+ return "";
+}
+
+String VisualScriptSubCall::get_category() const {
+
+ return "custom";
+}
+
+class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ VisualScriptSubCall *subcall;
+ int input_args;
+ bool valid;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; };
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (!valid) {
+ r_error_str="Node requires a script with a _subcall(<args>) method to work.";
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+ *p_outputs[0]=subcall->call(VisualScriptLanguage::singleton->_subcall,p_inputs,input_args,r_error_str);
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptSubCall::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceSubCall * instance = memnew(VisualScriptNodeInstanceSubCall );
+ instance->instance=p_instance;
+ Ref<Script> script = get_script();
+ if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
+ instance->valid=true;
+ instance->input_args=get_input_value_port_count();
+ } else {
+ instance->valid=false;
+ }
+ return instance;
+}
+
+
+
+void VisualScriptSubCall::_bind_methods() {
+
+ BIND_VMETHOD( MethodInfo(Variant::NIL,"_subcall",PropertyInfo(Variant::NIL,"arguments:Variant")) );
+
+}
+
+VisualScriptSubCall::VisualScriptSubCall() {
+
+
+}
+
+//////////////////////////////////////////
+////////////////Comment///////////
+//////////////////////////////////////////
+
+int VisualScriptComment::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptComment::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptComment::get_input_value_port_count() const{
+ return 0;
+}
+int VisualScriptComment::get_output_value_port_count() const{
+
+ return 0;
+}
+
+String VisualScriptComment::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptComment::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptComment::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+
+String VisualScriptComment::get_caption() const {
+
+ return title;
+}
+
+
+String VisualScriptComment::get_text() const {
+
+ return description;
+}
+
+void VisualScriptComment::set_title(const String& p_title) {
+
+
+ if (title==p_title)
+ return;
+ title=p_title;
+ ports_changed_notify();
+}
+
+String VisualScriptComment::get_title() const{
+
+ return title;
+}
+
+void VisualScriptComment::set_description(const String& p_description){
+
+ if (description==p_description)
+ return;
+ description=p_description;
+ ports_changed_notify();
+
+}
+String VisualScriptComment::get_description() const{
+
+ return description;
+}
+
+void VisualScriptComment::set_size(const Size2& p_size){
+
+ if (size==p_size)
+ return;
+ size=p_size;
+ ports_changed_notify();
+
+}
+Size2 VisualScriptComment::get_size() const{
+
+ return size;
+}
+
+
+String VisualScriptComment::get_category() const {
+
+ return "data";
+}
+
+class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; };
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptComment::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceComment * instance = memnew(VisualScriptNodeInstanceComment );
+ instance->instance=p_instance;
+ return instance;
+}
+
+
+
+void VisualScriptComment::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_title","title"),&VisualScriptComment::set_title);
+ ObjectTypeDB::bind_method(_MD("get_title"),&VisualScriptComment::get_title);
+
+ ObjectTypeDB::bind_method(_MD("set_description","description"),&VisualScriptComment::set_description);
+ ObjectTypeDB::bind_method(_MD("get_description"),&VisualScriptComment::get_description);
+
+ ObjectTypeDB::bind_method(_MD("set_size","size"),&VisualScriptComment::set_size);
+ ObjectTypeDB::bind_method(_MD("get_size"),&VisualScriptComment::get_size);
+
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title"));
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"description",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_description"),_SCS("get_description"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"size"),_SCS("set_size"),_SCS("get_size"));
+
+}
+
+VisualScriptComment::VisualScriptComment() {
+
+ title="Comment";
+ size=Size2(150,150);
+}
+
+
+//////////////////////////////////////////
+////////////////Constructor///////////
+//////////////////////////////////////////
+
+int VisualScriptConstructor::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptConstructor::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptConstructor::get_input_value_port_count() const{
+ return constructor.arguments.size();
+}
+int VisualScriptConstructor::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptConstructor::get_output_sequence_port_text(int p_port) const {
+
+ return "";
+}
+
+PropertyInfo VisualScriptConstructor::get_input_value_port_info(int p_idx) const{
+
+ return constructor.arguments[p_idx];
+}
+
+PropertyInfo VisualScriptConstructor::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(type,"value");
+}
+
+
+String VisualScriptConstructor::get_caption() const {
+
+ return "Construct";
+}
+
+
+String VisualScriptConstructor::get_text() const {
+
+ return "new "+Variant::get_type_name(type)+"()";
+}
+
+
+String VisualScriptConstructor::get_category() const {
+
+ return "functions";
+}
+
+void VisualScriptConstructor::set_constructor_type(Variant::Type p_type) {
+
+ if (type==p_type)
+ return;
+
+ type=p_type;
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptConstructor::get_constructor_type() const {
+
+ return type;
+}
+
+void VisualScriptConstructor::set_constructor(const Dictionary& p_info) {
+
+ constructor=MethodInfo::from_dict(p_info);
+}
+
+Dictionary VisualScriptConstructor::get_constructor() const {
+
+ return constructor;
+}
+
+
+class VisualScriptNodeInstanceConstructor : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ Variant::Type type;
+ int argcount;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; };
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ Variant::CallError ce;
+ *p_outputs[0]=Variant::construct(type,p_inputs,argcount,ce);
+ if (ce.error!=Variant::CallError::CALL_OK) {
+ r_error_str="Invalid arguments for constructor";
+ }
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptConstructor::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceConstructor * instance = memnew(VisualScriptNodeInstanceConstructor );
+ instance->instance=p_instance;
+ instance->type=type;
+ instance->argcount=constructor.arguments.size();
+ return instance;
+}
+
+
+
+void VisualScriptConstructor::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_constructor_type","type"),&VisualScriptConstructor::set_constructor_type);
+ ObjectTypeDB::bind_method(_MD("get_constructor_type"),&VisualScriptConstructor::get_constructor_type);
+
+ ObjectTypeDB::bind_method(_MD("set_constructor","constructor"),&VisualScriptConstructor::set_constructor);
+ ObjectTypeDB::bind_method(_MD("get_constructor"),&VisualScriptConstructor::get_constructor);
+
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_constructor_type"),_SCS("get_constructor_type"));
+ ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"constructor",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_constructor"),_SCS("get_constructor"));
+
+}
+
+VisualScriptConstructor::VisualScriptConstructor() {
+
+ type=Variant::NIL;
+
+}
+
+static Map<String,Pair<Variant::Type,MethodInfo> > constructor_map;
+
+static Ref<VisualScriptNode> create_constructor_node(const String& p_name) {
+
+ ERR_FAIL_COND_V(!constructor_map.has(p_name),Ref<VisualScriptNode>());
+
+ Ref<VisualScriptConstructor> vsc;
+ vsc.instance();
+ vsc->set_constructor_type(constructor_map[p_name].first);
+ vsc->set_constructor(constructor_map[p_name].second);
+
+ return vsc;
+}
+
+//////////////////////////////////////////
+////////////////LocalVar///////////
+//////////////////////////////////////////
+
+int VisualScriptLocalVar::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptLocalVar::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptLocalVar::get_input_value_port_count() const{
+ return 1;
+}
+int VisualScriptLocalVar::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptLocalVar::get_output_sequence_port_text(int p_port) const {
+
+ return "";
+}
+
+PropertyInfo VisualScriptLocalVar::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo(type,"set");
+}
+PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(type,"get");
+}
+
+
+String VisualScriptLocalVar::get_caption() const {
+
+ return "LocalVar";
+}
+
+
+String VisualScriptLocalVar::get_text() const {
+
+ return name;
+}
+
+
+String VisualScriptLocalVar::get_category() const {
+
+ return "data";
+}
+
+
+void VisualScriptLocalVar::set_var_name(const StringName& p_name) {
+
+ if (name==p_name)
+ return;
+
+ name=p_name;
+ ports_changed_notify();
+
+}
+
+StringName VisualScriptLocalVar::get_var_name() const {
+
+ return name;
+}
+
+void VisualScriptLocalVar::set_var_type(Variant::Type p_type) {
+
+ type=p_type;
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptLocalVar::get_var_type() const {
+
+ return type;
+}
+
+
+class VisualScriptNodeInstanceLocalVar : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ StringName name;
+
+
+ virtual int get_working_memory_size() const { return 1; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+ *r_value=*p_working_mem;
+ return true;
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ *p_working_mem=*p_inputs[0];
+ *p_outputs[0]=*p_working_mem;
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptLocalVar::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceLocalVar * instance = memnew(VisualScriptNodeInstanceLocalVar );
+ instance->instance=p_instance;
+ instance->name=name;
+
+ return instance;
+}
+
+
+
+void VisualScriptLocalVar::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_var_name","name"),&VisualScriptLocalVar::set_var_name);
+ ObjectTypeDB::bind_method(_MD("get_var_name"),&VisualScriptLocalVar::get_var_name);
+
+ ObjectTypeDB::bind_method(_MD("set_var_type","type"),&VisualScriptLocalVar::set_var_type);
+ ObjectTypeDB::bind_method(_MD("get_var_type"),&VisualScriptLocalVar::get_var_type);
+
+ String argt="Any";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_var_name"),_SCS("get_var_name"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"variable/type",PROPERTY_HINT_ENUM,argt),_SCS("set_var_type"),_SCS("get_var_type"));
+
+
+}
+
+VisualScriptLocalVar::VisualScriptLocalVar() {
+
+ name="new_local";
+ type=Variant::NIL;
+
+}
+
+//////////////////////////////////////////
+////////////////LocalVar///////////
+//////////////////////////////////////////
+
+int VisualScriptInputAction::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptInputAction::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptInputAction::get_input_value_port_count() const{
+ return 0;
+}
+int VisualScriptInputAction::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptInputAction::get_output_sequence_port_text(int p_port) const {
+
+ return "";
+}
+
+PropertyInfo VisualScriptInputAction::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::BOOL,"pressed");
+}
+
+
+String VisualScriptInputAction::get_caption() const {
+
+ return "Action";
+}
+
+
+String VisualScriptInputAction::get_text() const {
+
+ return name;
+}
+
+
+String VisualScriptInputAction::get_category() const {
+
+ return "data";
+}
+
+
+void VisualScriptInputAction::set_action_name(const StringName& p_name) {
+
+ if (name==p_name)
+ return;
+
+ name=p_name;
+ ports_changed_notify();
+
+}
+
+StringName VisualScriptInputAction::get_action_name() const {
+
+ return name;
+}
+
+
+class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ StringName action;
+
+
+ virtual int get_working_memory_size() const { return 1; }
+ virtual bool is_output_port_unsequenced(int p_idx) const { return true; }
+ virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const {
+ *r_value=Input::get_singleton()->is_action_pressed(action);
+ return true;
+ }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptInputAction::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceInputAction * instance = memnew(VisualScriptNodeInstanceInputAction );
+ instance->instance=p_instance;
+ instance->action=name;
+
+ return instance;
+}
+
+void VisualScriptInputAction::_validate_property(PropertyInfo& property) const {
+
+
+ if (property.name=="action") {
+
+ property.hint=PROPERTY_HINT_ENUM;
+ String actions;
+
+ List<PropertyInfo> pinfo;
+ Globals::get_singleton()->get_property_list(&pinfo);
+ Vector<String> al;
+
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ const PropertyInfo &pi=E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+ String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
+
+
+ al.push_back(name);
+ }
+
+ al.sort();;
+
+ for(int i=0;i<al.size();i++) {
+ if (actions!=String())
+ actions+=",";
+ actions+=al[i];
+ }
+
+ property.hint_string=actions;
+ }
+}
+
+
+void VisualScriptInputAction::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_action_name","name"),&VisualScriptInputAction::set_action_name);
+ ObjectTypeDB::bind_method(_MD("get_action_name"),&VisualScriptInputAction::get_action_name);
+
+ ADD_PROPERTY( PropertyInfo(Variant::STRING,"action"),_SCS("set_action_name"),_SCS("get_action_name"));
+
+}
+
+VisualScriptInputAction::VisualScriptInputAction() {
+
+ name="";
+
+}
+
+//////////////////////////////////////////
+////////////////Constructor///////////
+//////////////////////////////////////////
+
+int VisualScriptDeconstruct::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptDeconstruct::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptDeconstruct::get_input_value_port_count() const{
+ return 1;
+}
+int VisualScriptDeconstruct::get_output_value_port_count() const{
+
+ return elements.size();
+}
+
+String VisualScriptDeconstruct::get_output_sequence_port_text(int p_port) const {
+
+ return "";
+}
+
+PropertyInfo VisualScriptDeconstruct::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo(type,"value");
+}
+
+PropertyInfo VisualScriptDeconstruct::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(elements[p_idx].type,elements[p_idx].name);
+}
+
+
+String VisualScriptDeconstruct::get_caption() const {
+
+ return "Deconstruct";
+}
+
+
+String VisualScriptDeconstruct::get_text() const {
+
+ return "from "+Variant::get_type_name(type)+":";
+}
+
+
+String VisualScriptDeconstruct::get_category() const {
+
+ return "functions";
+}
+
+void VisualScriptDeconstruct::_update_elements() {
+
+ elements.clear();;
+ Variant v;
+ if (type==Variant::INPUT_EVENT) {
+ InputEvent ie;
+ ie.type=input_type;
+ v=ie;
+ } else {
+ Variant::CallError ce;
+ v = Variant::construct(type,NULL,0,ce);
+ }
+
+ List<PropertyInfo> pinfo;
+ v.get_property_list(&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+ Element e;
+ e.name=E->get().name;
+ e.type=E->get().type;
+ elements.push_back(e);
+ }
+}
+
+void VisualScriptDeconstruct::set_deconstruct_type(Variant::Type p_type) {
+
+ if (type==p_type)
+ return;
+
+ type=p_type;
+ _update_elements();
+ ports_changed_notify();
+ _change_notify(); //to make input appear/disappear
+}
+
+Variant::Type VisualScriptDeconstruct::get_deconstruct_type() const {
+
+ return type;
+}
+
+void VisualScriptDeconstruct::set_deconstruct_input_type(InputEvent::Type p_input_type) {
+
+ if (input_type==p_input_type)
+ return;
+
+ input_type=p_input_type;
+ _update_elements();
+ ports_changed_notify();
+}
+
+InputEvent::Type VisualScriptDeconstruct::get_deconstruct_input_type() const {
+
+ return input_type;
+}
+
+void VisualScriptDeconstruct::_set_elem_cache(const Array& p_elements) {
+
+ ERR_FAIL_COND(p_elements.size()%2==1);
+ elements.resize(p_elements.size()/2);
+ for(int i=0;i<elements.size();i++) {
+ elements[i].name=p_elements[i*2+0];
+ elements[i].type=Variant::Type(int(p_elements[i*2+1]));
+ }
+}
+
+Array VisualScriptDeconstruct::_get_elem_cache() const {
+
+ Array ret;
+ for(int i=0;i<elements.size();i++) {
+ ret.push_back(elements[i].name);
+ ret.push_back(elements[i].type);
+ }
+ return ret;
+}
+
+class VisualScriptNodeInstanceDeconstruct : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ Vector<StringName> outputs;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; };
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ Variant in=*p_inputs[0];
+
+ for(int i=0;i<outputs.size();i++) {
+ bool valid;
+ *p_outputs[i]=in.get(outputs[i],&valid);
+ if (!valid) {
+ r_error_str="Can't obtain element '"+String(outputs[i])+"' from "+Variant::get_type_name(in.get_type());
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+
+ }
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptDeconstruct::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceDeconstruct * instance = memnew(VisualScriptNodeInstanceDeconstruct );
+ instance->instance=p_instance;
+ instance->outputs.resize(elements.size());
+ for(int i=0;i<elements.size();i++) {
+ instance->outputs[i]=elements[i].name;
+ }
+
+ return instance;
+}
+
+
+
+void VisualScriptDeconstruct::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="input_type") {
+ if (type!=Variant::INPUT_EVENT) {
+ property.usage=0;
+ }
+ }
+}
+
+
+void VisualScriptDeconstruct::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_deconstruct_type","type"),&VisualScriptDeconstruct::set_deconstruct_type);
+ ObjectTypeDB::bind_method(_MD("get_deconstruct_type"),&VisualScriptDeconstruct::get_deconstruct_type);
+
+ ObjectTypeDB::bind_method(_MD("set_deconstruct_input_type","input_type"),&VisualScriptDeconstruct::set_deconstruct_input_type);
+ ObjectTypeDB::bind_method(_MD("get_deconstruct_input_type"),&VisualScriptDeconstruct::get_deconstruct_input_type);
+
+ ObjectTypeDB::bind_method(_MD("_set_elem_cache","_cache"),&VisualScriptDeconstruct::_set_elem_cache);
+ ObjectTypeDB::bind_method(_MD("_get_elem_cache"),&VisualScriptDeconstruct::_get_elem_cache);
+
+ String argt="Any";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+ String iet="None,Key,MouseMotion,MouseButton,JoystickMotion,JoystickButton,ScreenTouch,ScreenDrag,Action";
+
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_ENUM,argt),_SCS("set_deconstruct_type"),_SCS("get_deconstruct_type"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"input_type",PROPERTY_HINT_ENUM,iet),_SCS("set_deconstruct_input_type"),_SCS("get_deconstruct_input_type"));
+ ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"elem_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_elem_cache"),_SCS("_get_elem_cache"));
+
+}
+
+VisualScriptDeconstruct::VisualScriptDeconstruct() {
+
+ type=Variant::NIL;
+ input_type=InputEvent::NONE;
+
+}
+
+
+void register_visual_script_nodes() {
+
+ VisualScriptLanguage::singleton->add_register_func("data/set_variable",create_node_generic<VisualScriptVariableGet>);
+ VisualScriptLanguage::singleton->add_register_func("data/get_variable",create_node_generic<VisualScriptVariableSet>);
+ VisualScriptLanguage::singleton->add_register_func("data/constant",create_node_generic<VisualScriptConstant>);
+ VisualScriptLanguage::singleton->add_register_func("data/global_constant",create_node_generic<VisualScriptGlobalConstant>);
+ VisualScriptLanguage::singleton->add_register_func("data/math_constant",create_node_generic<VisualScriptMathConstant>);
+ VisualScriptLanguage::singleton->add_register_func("data/engine_singleton",create_node_generic<VisualScriptEngineSingleton>);
+ VisualScriptLanguage::singleton->add_register_func("data/scene_node",create_node_generic<VisualScriptSceneNode>);
+ VisualScriptLanguage::singleton->add_register_func("data/scene_tree",create_node_generic<VisualScriptSceneTree>);
+ VisualScriptLanguage::singleton->add_register_func("data/resource_path",create_node_generic<VisualScriptResourcePath>);
+ VisualScriptLanguage::singleton->add_register_func("data/self",create_node_generic<VisualScriptSelf>);
+ VisualScriptLanguage::singleton->add_register_func("custom/custom_node",create_node_generic<VisualScriptCustomNode>);
+ VisualScriptLanguage::singleton->add_register_func("custom/sub_call",create_node_generic<VisualScriptSubCall>);
+ VisualScriptLanguage::singleton->add_register_func("data/comment",create_node_generic<VisualScriptComment>);
+ VisualScriptLanguage::singleton->add_register_func("data/local_var",create_node_generic<VisualScriptLocalVar>);
+ VisualScriptLanguage::singleton->add_register_func("data/preload",create_node_generic<VisualScriptPreload>);
+ VisualScriptLanguage::singleton->add_register_func("data/action",create_node_generic<VisualScriptInputAction>);
+
+
+ VisualScriptLanguage::singleton->add_register_func("index/get_index",create_node_generic<VisualScriptIndexGet>);
+ VisualScriptLanguage::singleton->add_register_func("index/set_index",create_node_generic<VisualScriptIndexSet>);
+
+
+ VisualScriptLanguage::singleton->add_register_func("operators/compare/equal",create_op_node<Variant::OP_EQUAL>);
+ VisualScriptLanguage::singleton->add_register_func("operators/compare/not_equal",create_op_node<Variant::OP_NOT_EQUAL>);
+ VisualScriptLanguage::singleton->add_register_func("operators/compare/less",create_op_node<Variant::OP_LESS>);
+ VisualScriptLanguage::singleton->add_register_func("operators/compare/less_equal",create_op_node<Variant::OP_LESS_EQUAL>);
+ VisualScriptLanguage::singleton->add_register_func("operators/compare/greater",create_op_node<Variant::OP_GREATER>);
+ VisualScriptLanguage::singleton->add_register_func("operators/compare/greater_equal",create_op_node<Variant::OP_GREATER_EQUAL>);
+ //mathematic
+ VisualScriptLanguage::singleton->add_register_func("operators/math/add",create_op_node<Variant::OP_ADD>);
+ VisualScriptLanguage::singleton->add_register_func("operators/math/subtract",create_op_node<Variant::OP_SUBSTRACT>);
+ VisualScriptLanguage::singleton->add_register_func("operators/math/multiply",create_op_node<Variant::OP_MULTIPLY>);
+ VisualScriptLanguage::singleton->add_register_func("operators/math/divide",create_op_node<Variant::OP_DIVIDE>);
+ VisualScriptLanguage::singleton->add_register_func("operators/math/negate",create_op_node<Variant::OP_NEGATE>);
+ VisualScriptLanguage::singleton->add_register_func("operators/math/remainder",create_op_node<Variant::OP_MODULE>);
+ VisualScriptLanguage::singleton->add_register_func("operators/math/string_concat",create_op_node<Variant::OP_STRING_CONCAT>);
+ //bitwise
+ VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left",create_op_node<Variant::OP_SHIFT_LEFT>);
+ VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right",create_op_node<Variant::OP_SHIFT_RIGHT>);
+ VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_and",create_op_node<Variant::OP_BIT_AND>);
+ VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_or",create_op_node<Variant::OP_BIT_OR>);
+ VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_xor",create_op_node<Variant::OP_BIT_XOR>);
+ VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_negate",create_op_node<Variant::OP_BIT_NEGATE>);
+ //logic
+ VisualScriptLanguage::singleton->add_register_func("operators/logic/and",create_op_node<Variant::OP_AND>);
+ VisualScriptLanguage::singleton->add_register_func("operators/logic/or",create_op_node<Variant::OP_OR>);
+ VisualScriptLanguage::singleton->add_register_func("operators/logic/xor",create_op_node<Variant::OP_XOR>);
+ VisualScriptLanguage::singleton->add_register_func("operators/logic/not",create_op_node<Variant::OP_NOT>);
+ VisualScriptLanguage::singleton->add_register_func("operators/logic/in",create_op_node<Variant::OP_IN>);
+
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct",create_node_generic<VisualScriptDeconstruct>);
+
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+
+ List<MethodInfo> constructors;
+ Variant::get_constructor_list(Variant::Type(i),&constructors);
+
+ for(List<MethodInfo>::Element *E=constructors.front();E;E=E->next()) {
+
+ if (E->get().arguments.size()>0) {
+
+
+ String name = "functions/constructors/"+Variant::get_type_name(Variant::Type(i))+" ( ";
+ for(int j=0;j<E->get().arguments.size();j++) {
+ if (j>0)
+ name+=", ";
+ if (E->get().arguments.size()==1)
+ name+=Variant::get_type_name(E->get().arguments[j].type);
+ else
+ name+=E->get().arguments[j].name;
+ }
+ name+=") ";
+
+ VisualScriptLanguage::singleton->add_register_func(name,create_constructor_node);
+ Pair<Variant::Type,MethodInfo> pair;
+ pair.first=Variant::Type(i);
+ pair.second=E->get();
+ constructor_map[name]=pair;
+ }
+ }
+ }
+}
+
+
+
+void unregister_visual_script_nodes() {
+
+ constructor_map.clear();
+}
+
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
new file mode 100644
index 0000000000..28f99a16e1
--- /dev/null
+++ b/modules/visual_script/visual_script_nodes.h
@@ -0,0 +1,926 @@
+#ifndef VISUAL_SCRIPT_NODES_H
+#define VISUAL_SCRIPT_NODES_H
+
+#include "visual_script.h"
+
+class VisualScriptFunction : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptFunction,VisualScriptNode)
+
+
+ struct Argument {
+ String name;
+ Variant::Type type;
+ };
+
+ Vector<Argument> arguments;
+
+ bool stack_less;
+ int stack_size;
+ ScriptInstance::RPCMode rpc_mode;
+
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "flow_control"; }
+
+ void add_argument(Variant::Type p_type,const String& p_name,int p_index=-1);
+ void set_argument_type(int p_argidx,Variant::Type p_type);
+ Variant::Type get_argument_type(int p_argidx) const;
+ void set_argument_name(int p_argidx,const String& p_name);
+ String get_argument_name(int p_argidx) const;
+ void remove_argument(int p_argidx);
+ int get_argument_count() const;
+
+
+ void set_stack_less(bool p_enable);
+ bool is_stack_less() const;
+
+ void set_stack_size(int p_size);
+ int get_stack_size() const;
+
+ void set_rpc_mode(ScriptInstance::RPCMode p_mode);
+ ScriptInstance::RPCMode get_rpc_mode() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptFunction();
+};
+
+
+class VisualScriptOperator : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptOperator,VisualScriptNode)
+
+
+ Variant::Type typed;
+ Variant::Operator op;
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "operators"; }
+
+ void set_operator(Variant::Operator p_op);
+ Variant::Operator get_operator() const;
+
+ void set_typed(Variant::Type p_op);
+ Variant::Type get_typed() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptOperator();
+};
+
+
+class VisualScriptVariableGet : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptVariableGet,VisualScriptNode)
+
+
+ StringName variable;
+protected:
+
+ virtual void _validate_property(PropertyInfo& property) const;
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_variable(StringName p_var);
+ StringName get_variable() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptVariableGet();
+};
+
+
+class VisualScriptVariableSet : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptVariableSet,VisualScriptNode)
+
+
+ StringName variable;
+protected:
+
+ virtual void _validate_property(PropertyInfo& property) const;
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_variable(StringName p_var);
+ StringName get_variable() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptVariableSet();
+};
+
+
+class VisualScriptConstant : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptConstant,VisualScriptNode)
+
+
+ Variant::Type type;
+ Variant value;
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+ static void _bind_methods();
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_constant_type(Variant::Type p_type);
+ Variant::Type get_constant_type() const;
+
+ void set_constant_value(Variant p_value);
+ Variant get_constant_value() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptConstant();
+};
+
+
+
+class VisualScriptPreload : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptPreload,VisualScriptNode)
+
+
+ Ref<Resource> preload;
+protected:
+
+ static void _bind_methods();
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_preload(const Ref<Resource>& p_value);
+ Ref<Resource> get_preload() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptPreload();
+};
+
+class VisualScriptIndexGet : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptIndexGet,VisualScriptNode)
+
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "operators"; }
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptIndexGet();
+};
+
+
+class VisualScriptIndexSet : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptIndexSet,VisualScriptNode)
+
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "operators"; }
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptIndexSet();
+};
+
+
+
+class VisualScriptGlobalConstant : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptGlobalConstant,VisualScriptNode)
+
+ int index;
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_global_constant(int p_which);
+ int get_global_constant();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptGlobalConstant();
+};
+
+
+
+class VisualScriptMathConstant : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptMathConstant,VisualScriptNode)
+public:
+
+ enum MathConstant {
+ MATH_CONSTANT_ONE,
+ MATH_CONSTANT_PI,
+ MATH_CONSTANT_2PI,
+ MATH_CONSTANT_HALF_PI,
+ MATH_CONSTANT_E,
+ MATH_CONSTANT_SQRT2,
+ MATH_CONSTANT_MAX,
+ };
+
+private:
+ static const char* const_name[MATH_CONSTANT_MAX];
+ static double const_value[MATH_CONSTANT_MAX];
+ MathConstant constant;
+protected:
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_math_constant(MathConstant p_which);
+ MathConstant get_math_constant();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptMathConstant();
+};
+
+VARIANT_ENUM_CAST( VisualScriptMathConstant::MathConstant )
+
+class VisualScriptEngineSingleton : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptEngineSingleton,VisualScriptNode)
+
+ String singleton;
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_singleton(const String &p_string);
+ String get_singleton();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptEngineSingleton();
+};
+
+
+
+
+class VisualScriptSceneNode : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptSceneNode,VisualScriptNode)
+
+ NodePath path;
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_node_path(const NodePath &p_path);
+ NodePath get_node_path();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptSceneNode();
+};
+
+
+
+
+class VisualScriptSceneTree : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptSceneTree,VisualScriptNode)
+
+
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptSceneTree();
+};
+
+
+
+class VisualScriptResourcePath : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptResourcePath,VisualScriptNode)
+
+ String path;
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+ void set_resource_path(const String &p_path);
+ String get_resource_path();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptResourcePath();
+};
+
+
+class VisualScriptSelf : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptSelf,VisualScriptNode)
+
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "data"; }
+
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptSelf();
+};
+
+
+class VisualScriptCustomNode: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptCustomNode,VisualScriptNode)
+
+
+protected:
+
+ virtual bool _use_builtin_script() const { return true; }
+
+ static void _bind_methods();
+public:
+
+ enum StartMode { //replicated for step
+ START_MODE_BEGIN_SEQUENCE,
+ START_MODE_CONTINUE_SEQUENCE,
+ START_MODE_RESUME_YIELD
+ };
+
+ enum { //replicated for step
+ STEP_SHIFT=1<<24,
+ STEP_MASK=STEP_SHIFT-1,
+ STEP_PUSH_STACK_BIT=STEP_SHIFT, //push bit to stack
+ STEP_GO_BACK_BIT=STEP_SHIFT<<1, //go back to previous node
+ STEP_NO_ADVANCE_BIT=STEP_SHIFT<<2, //do not advance past this node
+ STEP_EXIT_FUNCTION_BIT=STEP_SHIFT<<3, //return from function
+ STEP_YIELD_BIT=STEP_SHIFT<<4, //yield (will find VisualScriptFunctionState state in first working memory)
+ };
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptCustomNode();
+};
+
+class VisualScriptSubCall: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptSubCall,VisualScriptNode)
+
+
+protected:
+
+
+ static void _bind_methods();
+public:
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptSubCall();
+};
+
+class VisualScriptComment: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptComment,VisualScriptNode)
+
+
+ String title;
+ String description;
+ Size2 size;
+protected:
+
+ static void _bind_methods();
+public:
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const;
+
+ void set_title(const String& p_title);
+ String get_title() const;
+
+ void set_description(const String& p_description);
+ String get_description() const;
+
+ void set_size(const Size2& p_size);
+ Size2 get_size() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptComment();
+};
+
+class VisualScriptConstructor: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptConstructor,VisualScriptNode)
+
+
+ Variant::Type type;
+ MethodInfo constructor;
+
+protected:
+
+
+ static void _bind_methods();
+public:
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const;
+
+ void set_constructor_type(Variant::Type p_type);
+ Variant::Type get_constructor_type() const;
+
+ void set_constructor(const Dictionary& p_info);
+ Dictionary get_constructor() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptConstructor();
+};
+
+
+
+
+class VisualScriptLocalVar: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptLocalVar,VisualScriptNode)
+
+ StringName name;
+ Variant::Type type;
+
+protected:
+
+ static void _bind_methods();
+public:
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const;
+
+ void set_var_name(const StringName& p_name);
+ StringName get_var_name() const;
+
+ void set_var_type(Variant::Type p_type);
+ Variant::Type get_var_type() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptLocalVar();
+};
+
+
+
+
+class VisualScriptInputAction: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptInputAction,VisualScriptNode)
+
+ StringName name;
+
+protected:
+
+ virtual void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+public:
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const;
+
+ void set_action_name(const StringName& p_name);
+ StringName get_action_name() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptInputAction();
+};
+
+
+
+class VisualScriptDeconstruct: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptDeconstruct,VisualScriptNode)
+
+
+ struct Element {
+ StringName name;
+ Variant::Type type;
+ };
+
+
+ Vector<Element> elements;
+
+ void _update_elements();
+ Variant::Type type;
+ InputEvent::Type input_type;
+
+ void _set_elem_cache(const Array& p_elements);
+ Array _get_elem_cache() const;
+
+ virtual void _validate_property(PropertyInfo& property) const;
+
+protected:
+
+
+ static void _bind_methods();
+public:
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const;
+
+ void set_deconstruct_type(Variant::Type p_type);
+ Variant::Type get_deconstruct_type() const;
+
+ void set_deconstruct_input_type(InputEvent::Type p_input_type);
+ InputEvent::Type get_deconstruct_input_type() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptDeconstruct();
+};
+
+
+void register_visual_script_nodes();
+void unregister_visual_script_nodes();
+
+#endif // VISUAL_SCRIPT_NODES_H
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
new file mode 100644
index 0000000000..221c46b6fd
--- /dev/null
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -0,0 +1,625 @@
+#include "visual_script_yield_nodes.h"
+#include "scene/main/scene_main_loop.h"
+#include "os/os.h"
+#include "scene/main/node.h"
+#include "visual_script_nodes.h"
+
+//////////////////////////////////////////
+////////////////YIELD///////////
+//////////////////////////////////////////
+
+int VisualScriptYield::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptYield::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptYield::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptYield::get_output_value_port_count() const{
+
+ return 0;
+}
+
+String VisualScriptYield::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptYield::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+
+String VisualScriptYield::get_caption() const {
+
+ return yield_mode==YIELD_RETURN?"Yield":"Wait";
+}
+
+String VisualScriptYield::get_text() const {
+
+ switch (yield_mode) {
+ case YIELD_RETURN: return ""; break;
+ case YIELD_FRAME: return "Next Frame"; break;
+ case YIELD_FIXED_FRAME: return "Next Fixed Frame"; break;
+ case YIELD_WAIT: return rtos(wait_time)+" sec(s)"; break;
+ }
+
+ return String();
+}
+
+
+class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptYield::YieldMode mode;
+ float wait_time;
+
+ virtual int get_working_memory_size() const { return 1; } //yield needs at least 1
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (p_start_mode==START_MODE_RESUME_YIELD) {
+ return 0; //resuming yield
+ } else {
+ //yield
+
+
+ SceneTree *tree = OS::get_singleton()->get_main_loop()->cast_to<SceneTree>();
+ if (!tree) {
+ r_error_str="Main Loop is not SceneTree";
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+
+ Ref<VisualScriptFunctionState> state;
+ state.instance();
+
+ int ret = STEP_YIELD_BIT;
+ switch(mode) {
+
+ case VisualScriptYield::YIELD_RETURN: ret=STEP_EXIT_FUNCTION_BIT; break; //return the yield
+ case VisualScriptYield::YIELD_FRAME: state->connect_to_signal(tree,"idle_frame",Array()); break;
+ case VisualScriptYield::YIELD_FIXED_FRAME: state->connect_to_signal(tree,"fixed_frame",Array()); break;
+ case VisualScriptYield::YIELD_WAIT: state->connect_to_signal(tree->create_timer(wait_time).ptr(),"timeout",Array()); break;
+
+ }
+
+ *p_working_mem=state;
+
+ return ret;
+ }
+ }
+
+};
+
+VisualScriptNodeInstance* VisualScriptYield::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceYield * instance = memnew(VisualScriptNodeInstanceYield );
+ //instance->instance=p_instance;
+ instance->mode=yield_mode;
+ instance->wait_time=wait_time;
+ return instance;
+}
+
+void VisualScriptYield::set_yield_mode(YieldMode p_mode) {
+
+ if (yield_mode==p_mode)
+ return;
+ yield_mode=p_mode;
+ ports_changed_notify();
+ _change_notify();
+}
+
+VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode(){
+
+ return yield_mode;
+}
+
+void VisualScriptYield::set_wait_time(float p_time) {
+
+ if (wait_time==p_time)
+ return;
+ wait_time=p_time;
+ ports_changed_notify();
+
+}
+
+float VisualScriptYield::get_wait_time(){
+
+ return wait_time;
+}
+
+
+void VisualScriptYield::_validate_property(PropertyInfo& property) const {
+
+
+ if (property.name=="wait_time") {
+ if (yield_mode!=YIELD_WAIT) {
+ property.usage=0;
+ }
+ }
+}
+
+void VisualScriptYield::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_yield_mode","mode"),&VisualScriptYield::set_yield_mode);
+ ObjectTypeDB::bind_method(_MD("get_yield_mode"),&VisualScriptYield::get_yield_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_wait_time","sec"),&VisualScriptYield::set_wait_time);
+ ObjectTypeDB::bind_method(_MD("get_wait_time"),&VisualScriptYield::get_wait_time);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Frame,FixedFrame,Time",PROPERTY_USAGE_NOEDITOR),_SCS("set_yield_mode"),_SCS("get_yield_mode"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"wait_time"),_SCS("set_wait_time"),_SCS("get_wait_time"));
+
+
+ BIND_CONSTANT( YIELD_FRAME );
+ BIND_CONSTANT( YIELD_FIXED_FRAME );
+ BIND_CONSTANT( YIELD_WAIT );
+
+}
+
+VisualScriptYield::VisualScriptYield() {
+
+ yield_mode=YIELD_FRAME;
+ wait_time=1;
+
+}
+
+
+template<VisualScriptYield::YieldMode MODE>
+static Ref<VisualScriptNode> create_yield_node(const String& p_name) {
+
+ Ref<VisualScriptYield> node;
+ node.instance();
+ node->set_yield_mode(MODE);
+ return node;
+}
+
+///////////////////////////////////////////////////
+////////////////YIELD SIGNAL//////////////////////
+//////////////////////////////////////////////////
+
+int VisualScriptYieldSignal::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptYieldSignal::has_input_sequence_port() const{
+
+ return true;
+}
+#ifdef TOOLS_ENABLED
+
+static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) {
+
+ if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene)
+ return NULL;
+
+ Ref<Script> scr = p_current_node->get_script();
+
+ if (scr.is_valid() && scr==script)
+ return p_current_node;
+
+ for(int i=0;i<p_current_node->get_child_count();i++) {
+ Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script);
+ if (n)
+ return n;
+ }
+
+ return NULL;
+}
+
+#endif
+Node *VisualScriptYieldSignal::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_visual_script();
+ if (!script.is_valid())
+ return NULL;
+
+ MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+ if (!main_loop)
+ return NULL;
+
+ SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+ if (!scene_tree)
+ return NULL;
+
+ Node *edited_scene = scene_tree->get_edited_scene_root();
+
+ if (!edited_scene)
+ return NULL;
+
+ Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+ if (!script_node)
+ return NULL;
+
+ if (!script_node->has_node(base_path))
+ return NULL;
+
+ Node *path_to = script_node->get_node(base_path);
+
+ return path_to;
+#else
+
+ return NULL;
+#endif
+}
+
+StringName VisualScriptYieldSignal::_get_base_type() const {
+
+ if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid())
+ return get_visual_script()->get_instance_base_type();
+ else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
+ Node *path = _get_base_node();
+ if (path)
+ return path->get_type();
+
+ }
+
+ return base_type;
+}
+
+int VisualScriptYieldSignal::get_input_value_port_count() const{
+
+ if (call_mode==CALL_MODE_INSTANCE)
+ return 1;
+ else
+ return 0;
+
+}
+int VisualScriptYieldSignal::get_output_value_port_count() const{
+
+
+ MethodInfo sr;
+
+ if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr))
+ return 0;
+
+ return sr.arguments.size();
+
+}
+
+String VisualScriptYieldSignal::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptYieldSignal::get_input_value_port_info(int p_idx) const{
+
+ if (call_mode==CALL_MODE_INSTANCE)
+ return PropertyInfo(Variant::OBJECT,"instance");
+ else
+ return PropertyInfo();
+
+}
+
+PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) const{
+
+ MethodInfo sr;
+
+ if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr))
+ return PropertyInfo(); //no signal
+ ERR_FAIL_INDEX_V(p_idx,sr.arguments.size(),PropertyInfo());
+ return sr.arguments[p_idx];
+
+}
+
+
+String VisualScriptYieldSignal::get_caption() const {
+
+ static const char*cname[3]= {
+ "WaitSignal",
+ "WaitNodeSignal",
+ "WaitInstanceSigna;",
+ };
+
+ return cname[call_mode];
+}
+
+String VisualScriptYieldSignal::get_text() const {
+
+ if (call_mode==CALL_MODE_SELF)
+ return " "+String(signal)+"()";
+ else
+ return " "+_get_base_type()+"."+String(signal)+"()";
+
+}
+
+
+void VisualScriptYieldSignal::set_base_type(const StringName& p_type) {
+
+ if (base_type==p_type)
+ return;
+
+ base_type=p_type;
+
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptYieldSignal::get_base_type() const{
+
+ return base_type;
+}
+
+void VisualScriptYieldSignal::set_signal(const StringName& p_type){
+
+ if (signal==p_type)
+ return;
+
+ signal=p_type;
+
+ _change_notify();
+ ports_changed_notify();
+}
+StringName VisualScriptYieldSignal::get_signal() const {
+
+
+ return signal;
+}
+
+void VisualScriptYieldSignal::set_base_path(const NodePath& p_type) {
+
+ if (base_path==p_type)
+ return;
+
+ base_path=p_type;
+
+ _change_notify();
+ ports_changed_notify();
+}
+
+NodePath VisualScriptYieldSignal::get_base_path() const {
+
+ return base_path;
+}
+
+
+void VisualScriptYieldSignal::set_call_mode(CallMode p_mode) {
+
+ if (call_mode==p_mode)
+ return;
+
+ call_mode=p_mode;
+
+ _change_notify();
+ ports_changed_notify();
+
+}
+
+VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const {
+
+ return call_mode;
+}
+
+
+void VisualScriptYieldSignal::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="signal/base_type") {
+ if (call_mode!=CALL_MODE_INSTANCE) {
+ property.usage=PROPERTY_USAGE_NOEDITOR;
+ }
+ }
+
+
+ if (property.name=="signal/node_path") {
+ if (call_mode!=CALL_MODE_NODE_PATH) {
+ property.usage=0;
+ } else {
+
+ Node *bnode = _get_base_node();
+ if (bnode) {
+ property.hint_string=bnode->get_path(); //convert to loong string
+ } else {
+
+ }
+ }
+ }
+
+ if (property.name=="signal/signal") {
+ property.hint=PROPERTY_HINT_ENUM;
+
+
+ List<MethodInfo> methods;
+
+ ObjectTypeDB::get_signal_list(_get_base_type(),&methods);
+
+ List<String> mstring;
+ for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+ if (E->get().name.begins_with("_"))
+ continue;
+ mstring.push_back(E->get().name.get_slice(":",0));
+ }
+
+ mstring.sort();
+
+ String ml;
+ for (List<String>::Element *E=mstring.front();E;E=E->next()) {
+
+ if (ml!=String())
+ ml+=",";
+ ml+=E->get();
+ }
+
+ property.hint_string=ml;
+ }
+
+
+}
+
+
+void VisualScriptYieldSignal::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptYieldSignal::set_base_type);
+ ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptYieldSignal::get_base_type);
+
+ ObjectTypeDB::bind_method(_MD("set_signal","signal"),&VisualScriptYieldSignal::set_signal);
+ ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptYieldSignal::get_signal);
+
+ ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptYieldSignal::set_call_mode);
+ ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptYieldSignal::get_call_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptYieldSignal::set_base_path);
+ ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptYieldSignal::get_base_path);
+
+
+
+ String bt;
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ if (i>0)
+ bt+=",";
+
+ bt+=Variant::get_type_name(Variant::Type(i));
+ }
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"signal/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal"));
+
+
+ BIND_CONSTANT( CALL_MODE_SELF );
+ BIND_CONSTANT( CALL_MODE_NODE_PATH);
+ BIND_CONSTANT( CALL_MODE_INSTANCE);
+
+}
+
+class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance {
+public:
+
+
+ VisualScriptYieldSignal::CallMode call_mode;
+ NodePath node_path;
+ int output_args;
+ StringName signal;
+
+ VisualScriptYieldSignal *node;
+ VisualScriptInstance *instance;
+
+
+
+ virtual int get_working_memory_size() const { return 1; }
+ //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+ //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+ virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+ if (p_start_mode==START_MODE_RESUME_YIELD) {
+ return 0; //resuming yield
+ } else {
+ //yield
+
+ Object * object;
+
+ switch(call_mode) {
+
+ case VisualScriptYieldSignal::CALL_MODE_SELF: {
+
+ object=instance->get_owner_ptr();
+
+ } break;
+ case VisualScriptYieldSignal::CALL_MODE_NODE_PATH: {
+
+ Node* node = instance->get_owner_ptr()->cast_to<Node>();
+ if (!node) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Base object is not a Node!";
+ return 0;
+ }
+
+ Node* another = node->get_node(node_path);
+ if (!node) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Path does not lead Node!";
+ return 0;
+ }
+
+ object=another;
+
+ } break;
+ case VisualScriptYieldSignal::CALL_MODE_INSTANCE: {
+
+ object = *p_inputs[0];
+ if (!object) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Supplied instance input is null.";
+ return 0;
+
+ }
+
+ } break;
+
+ }
+
+ Ref<VisualScriptFunctionState> state;
+ state.instance();
+
+ state->connect_to_signal(object,signal,Array());
+
+ *p_working_mem=state;
+
+ return STEP_YIELD_BIT;
+ }
+
+
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptYieldSignal::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceYieldSignal * instance = memnew(VisualScriptNodeInstanceYieldSignal );
+ instance->node=this;
+ instance->instance=p_instance;
+ instance->signal=signal;
+ instance->call_mode=call_mode;
+ instance->node_path=base_path;
+ instance->output_args = get_output_value_port_count();
+ return instance;
+}
+VisualScriptYieldSignal::VisualScriptYieldSignal() {
+
+ call_mode=CALL_MODE_SELF;
+ base_type="Object";
+
+}
+
+template<VisualScriptYieldSignal::CallMode cmode>
+static Ref<VisualScriptNode> create_yield_signal_node(const String& p_name) {
+
+ Ref<VisualScriptYieldSignal> node;
+ node.instance();
+ node->set_call_mode(cmode);
+ return node;
+}
+
+void register_visual_script_yield_nodes() {
+
+ VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_frame",create_yield_node<VisualScriptYield::YIELD_FRAME>);
+ VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_fixed_frame",create_yield_node<VisualScriptYield::YIELD_FIXED_FRAME>);
+ VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_time",create_yield_node<VisualScriptYield::YIELD_WAIT>);
+
+
+ VisualScriptLanguage::singleton->add_register_func("functions/yield",create_yield_node<VisualScriptYield::YIELD_RETURN>);
+ VisualScriptLanguage::singleton->add_register_func("functions/yield_signal",create_node_generic<VisualScriptYieldSignal>);
+
+}
diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h
new file mode 100644
index 0000000000..ae7f8c15c1
--- /dev/null
+++ b/modules/visual_script/visual_script_yield_nodes.h
@@ -0,0 +1,128 @@
+#ifndef VISUAL_SCRIPT_YIELD_NODES_H
+#define VISUAL_SCRIPT_YIELD_NODES_H
+
+#include "visual_script.h"
+
+class VisualScriptYield : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptYield,VisualScriptNode)
+public:
+
+ enum YieldMode {
+ YIELD_RETURN,
+ YIELD_FRAME,
+ YIELD_FIXED_FRAME,
+ YIELD_WAIT
+
+ };
+private:
+
+ YieldMode yield_mode;
+ float wait_time;
+
+
+protected:
+
+ virtual void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "functions"; }
+
+ void set_yield_mode(YieldMode p_mode);
+ YieldMode get_yield_mode();
+
+ void set_wait_time(float p_time);
+ float get_wait_time();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptYield();
+};
+VARIANT_ENUM_CAST( VisualScriptYield::YieldMode )
+
+class VisualScriptYieldSignal : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptYieldSignal,VisualScriptNode)
+public:
+ enum CallMode {
+ CALL_MODE_SELF,
+ CALL_MODE_NODE_PATH,
+ CALL_MODE_INSTANCE,
+
+ };
+private:
+
+ CallMode call_mode;
+ StringName base_type;
+ NodePath base_path;
+ StringName signal;
+
+ Node *_get_base_node() const;
+ StringName _get_base_type() const;
+
+
+protected:
+ virtual void _validate_property(PropertyInfo& property) const;
+
+ static void _bind_methods();
+
+public:
+
+ virtual int get_output_sequence_port_count() const;
+ virtual bool has_input_sequence_port() const;
+
+
+ virtual String get_output_sequence_port_text(int p_port) const;
+
+
+ virtual int get_input_value_port_count() const;
+ virtual int get_output_value_port_count() const;
+
+
+ virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+ virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+ virtual String get_caption() const;
+ virtual String get_text() const;
+ virtual String get_category() const { return "functions"; }
+
+ void set_base_type(const StringName& p_type);
+ StringName get_base_type() const;
+
+ void set_signal(const StringName& p_type);
+ StringName get_signal() const;
+
+ void set_base_path(const NodePath& p_type);
+ NodePath get_base_path() const;
+
+ void set_call_mode(CallMode p_mode);
+ CallMode get_call_mode() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptYieldSignal();
+};
+
+VARIANT_ENUM_CAST(VisualScriptYieldSignal::CallMode );
+
+void register_visual_script_yield_nodes();
+
+#endif // VISUAL_SCRIPT_YIELD_NODES_H