summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gd_editor.cpp12
-rw-r--r--modules/visual_script/register_types.cpp5
-rw-r--r--modules/visual_script/visual_script.cpp72
-rw-r--r--modules/visual_script/visual_script.h8
-rw-r--r--modules/visual_script/visual_script_editor.cpp368
-rw-r--r--modules/visual_script/visual_script_editor.h27
-rw-r--r--modules/visual_script/visual_script_expression.cpp1440
-rw-r--r--modules/visual_script/visual_script_expression.h269
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp60
-rw-r--r--modules/visual_script/visual_script_flow_control.h2
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp27
-rw-r--r--modules/visual_script/visual_script_func_nodes.h4
-rw-r--r--modules/visual_script/visual_script_nodes.cpp295
-rw-r--r--modules/visual_script/visual_script_nodes.h64
14 files changed, 2551 insertions, 102 deletions
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index 5b74dab889..2a80531ec5 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -47,16 +47,14 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
Ref<Script> GDScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const {
String _template = String()+
- "\nextends %BASE%\n\n"+
- "# member variables here, example:\n"+
- "# var a=2\n"+
- "# var b=\"textvar\"\n\n"+
+ "extends %BASE%\n\n"+
+ "# class member variables go here, for example:\n"+
+ "# var a = 2\n"+
+ "# var b = \"textvar\"\n\n"+
"func _ready():\n"+
"\t# Called every time the node is added to the scene.\n"+
"\t# Initialization here\n"+
- "\tpass\n"+
- "\n"+
- "\n";
+ "\tpass\n";
_template = _template.replace("%BASE%",p_base_class_name);
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
index 58afeef3e3..ad54149b51 100644
--- a/modules/visual_script/register_types.cpp
+++ b/modules/visual_script/register_types.cpp
@@ -36,6 +36,7 @@
#include "visual_script_builtin_funcs.h"
#include "visual_script_flow_control.h"
#include "visual_script_yield_nodes.h"
+#include "visual_script_expression.h"
VisualScriptLanguage *visual_script_language=NULL;
@@ -60,6 +61,7 @@ void register_visual_script_types() {
ObjectTypeDB::register_type<VisualScriptGlobalConstant>();
ObjectTypeDB::register_type<VisualScriptClassConstant>();
ObjectTypeDB::register_type<VisualScriptMathConstant>();
+ ObjectTypeDB::register_type<VisualScriptBasicTypeConstant>();
ObjectTypeDB::register_type<VisualScriptEngineSingleton>();
ObjectTypeDB::register_type<VisualScriptSceneNode>();
ObjectTypeDB::register_type<VisualScriptSceneTree>();
@@ -97,11 +99,14 @@ void register_visual_script_types() {
ObjectTypeDB::register_type<VisualScriptBuiltinFunc>();
+ ObjectTypeDB::register_type<VisualScriptExpression>();
+
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();
+ register_visual_script_expression_node();
#ifdef TOOLS_ENABLED
VisualScriptEditor::register_editor();
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index aa09e7f005..d0a933a11c 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -3,7 +3,7 @@
#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
@@ -574,6 +574,23 @@ bool VisualScript::is_input_value_port_connected(const StringName& p_func,int p_
return false;
}
+bool VisualScript::get_input_value_port_connection_source(const StringName& p_func,int p_node,int p_port,int *r_node,int *r_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) {
+ *r_node=E->get().from_node;
+ *r_port=E->get().from_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));
@@ -598,8 +615,6 @@ void VisualScript::add_variable(const StringName& p_name,const Variant& p_defaul
v._export=p_export;
variables[p_name]=v;
- script_variable_remap[SCRIPT_VARIABLES_PREFIX+String(p_name)]=p_name;
-
#ifdef TOOLS_ENABLED
_update_placeholders();
@@ -616,7 +631,6 @@ 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();
@@ -911,7 +925,7 @@ void VisualScript::_update_placeholders() {
continue;
PropertyInfo p = E->get().info;
- p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
+ p.name=String(E->key());
pinfo.push_back(p);
values[p.name]=E->get().default_value;
}
@@ -947,7 +961,7 @@ ScriptInstance* VisualScript::instance_create(Object *p_this) {
continue;
PropertyInfo p = E->get().info;
- p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
+ p.name=String(E->key());
pinfo.push_back(p);
values[p.name]=E->get().default_value;
}
@@ -1045,10 +1059,10 @@ void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
bool VisualScript::get_property_default_value(const StringName& p_property,Variant& r_value) const {
- if (!script_variable_remap.has(p_property))
+ if (!variables.has(p_property))
return false;
- r_value=variables[ script_variable_remap[p_property] ].default_value;
+ r_value=variables[ p_property ].default_value;
return true;
}
void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const {
@@ -1116,6 +1130,7 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const {
}
}
+#ifdef TOOLS_ENABLED
bool VisualScript::are_subnodes_edited() const {
for(const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
@@ -1129,7 +1144,7 @@ bool VisualScript::are_subnodes_edited() const {
return false;
}
-
+#endif
void VisualScript::_set_data(const Dictionary& p_data) {
@@ -1385,12 +1400,10 @@ VisualScript::~VisualScript() {
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);
+ Map<StringName,Variant>::Element *E=variables.find(p_name);
+ if (!E)
+ return false;
E->get()=p_value;
@@ -1400,13 +1413,10 @@ bool VisualScriptInstance::set(const StringName& p_name, const Variant& p_value)
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)
+ const Map<StringName,Variant>::Element *E=variables.find(p_name);
+ if (!E)
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{
@@ -1416,21 +1426,15 @@ void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) c
if (!E->get()._export)
continue;
PropertyInfo p = E->get().info;
- p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
+ p.name=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());
+ const Map<StringName,VisualScript::Variable>::Element *E=script->variables.find(p_name);
if (!E) {
if (r_is_valid)
*r_is_valid=false;
@@ -1892,17 +1896,21 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p
if (node && (r_error.error!=Variant::CallError::CALL_ERROR_INVALID_METHOD || error_str==String())) {
+ if (error_str!=String()) {
+ error_str+=" ";
+ }
+
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)+".";
+ 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.";
+ 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.";
+ error_str+="Expected "+itos(r_error.argument)+" arguments.";
} else if (r_error.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) {
- error_str="Invalid Call.";
+ error_str+="Invalid Call.";
} else if (r_error.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
- error_str="Instance is null";
+ error_str+="Base Instance is null";
}
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 9e96967c6f..63b018b0c2 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -38,6 +38,8 @@ public:
virtual String get_output_sequence_port_text(int p_port) const=0;
+ virtual bool has_mixed_input_and_sequence_ports() const { return false; }
+
virtual int get_input_value_port_count() const=0;
virtual int get_output_value_port_count() const=0;
@@ -63,7 +65,7 @@ public:
Variant::Type type;
InputEvent::Type ev_type;
StringName obj_type;
- String script_type;
+ Ref<Script> script;
TypeGuess() { type=Variant::NIL; ev_type=InputEvent::NONE; }
};
@@ -225,7 +227,6 @@ friend class VisualScriptInstance;
Map<StringName,Function> functions;
Map<StringName,Variable> variables;
- Map<StringName,StringName> script_variable_remap;
Map<StringName,Vector<Argument> > custom_signals;
Map<Object*,VisualScriptInstance*> instances;
@@ -279,6 +280,7 @@ public:
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;
+ bool get_input_value_port_connection_source(const StringName& p_name,int p_node,int p_port,int *r_node,int *r_port) const;
void add_variable(const StringName& p_name,const Variant& p_default_value=Variant(),bool p_export=false);
bool has_variable(const StringName& p_name) const;
@@ -342,7 +344,9 @@ public:
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
+#ifdef TOOLS_ENABLED
virtual bool are_subnodes_edited() const;
+#endif
VisualScript();
~VisualScript();
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 7f09a265fb..14708799af 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -3,6 +3,7 @@
#include "visual_script_nodes.h"
#include "visual_script_flow_control.h"
#include "visual_script_func_nodes.h"
+#include "visual_script_expression.h"
#include "os/input.h"
#include "tools/editor/editor_resource_preview.h"
#include "os/keyboard.h"
@@ -505,6 +506,9 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
Label *text = memnew( Label );
text->set_text(node->get_text());
gnode->add_child(text);
+ if (node->cast_to<VisualScriptExpression>()) {
+ text->add_font_override("font",get_font("source","EditorFonts"));
+ }
if (node->cast_to<VisualScriptComment>()) {
Ref<VisualScriptComment> vsc=node;
@@ -523,19 +527,27 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
gnode->set_offset(pos*EDSCALE);
slot_idx++;
+
+ int mixed_seq_ports=0;
+
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++;
+ if (node->has_mixed_input_and_sequence_ports()) {
+ mixed_seq_ports=node->get_output_sequence_port_count();
+ } else {
+ 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++) {
+ for(int i=0;i<MAX(node->get_output_value_port_count(),MAX(mixed_seq_ports,node->get_input_value_port_count()));i++) {
bool left_ok=false;
Variant::Type left_type=Variant::NIL;
@@ -554,8 +566,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
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);
+ if (i>=mixed_seq_ports && i<node->get_output_value_port_count()+mixed_seq_ports) {
+ PropertyInfo pi = node->get_output_value_port_info(i-mixed_seq_ports);
right_ok=true;
right_type=pi.type;
right_name=pi.name;
@@ -620,6 +632,14 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
hbc->add_spacer();
+ if (i<mixed_seq_ports) {
+
+ Label *text2 = memnew( Label );
+ text2->set_text(node->get_output_sequence_port_text(i));
+ text2->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child(text2);
+ }
+
if (right_ok) {
hbc->add_child(memnew(Label(right_name)));
@@ -639,7 +659,11 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
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));
+ if (i<mixed_seq_ports) {
+ gnode->set_slot(slot_idx,left_ok,left_type,_color_from_type(left_type),true,TYPE_SEQUENCE,Color(1,1,1,1),Ref<Texture>(),seq_port);
+ } else {
+ 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++;
}
@@ -2558,11 +2582,320 @@ void VisualScriptEditor::_graph_disconnected(const String& p_from,int p_from_slo
}
+
void VisualScriptEditor::_graph_connect_to_empty(const String& p_from,int p_from_slot,const Vector2& p_release_pos) {
+ Node* node = graph->get_node(p_from);
+ if (!node)
+ return;
+ GraphNode *gn = node->cast_to<GraphNode>();
+ if (!gn)
+ return;
+
+ Ref<VisualScriptNode> vsn = script->get_node(edited_func,p_from.to_int());
+ if (!vsn.is_valid())
+ return;
+
+ if (p_from_slot<vsn->get_output_sequence_port_count()) {
+
+ port_action_popup->clear();
+ port_action_popup->add_item(TTR("Condition"),CREATE_COND);
+ port_action_popup->add_item(TTR("Sequence"),CREATE_SEQUENCE);
+ port_action_popup->add_item(TTR("Switch"),CREATE_SWITCH);
+ port_action_popup->add_item(TTR("Iterator"),CREATE_ITERATOR);
+ port_action_popup->add_item(TTR("While"),CREATE_WHILE);
+ port_action_popup->add_item(TTR("Return"),CREATE_RETURN);
+
+ port_action_node=p_from.to_int();
+ port_action_output=p_from_slot;
+
+ } else {
+ port_action_popup->clear();
+ port_action_popup->add_item(TTR("Call"),CREATE_CALL);
+ port_action_popup->add_item(TTR("Get"),CREATE_GET);
+ port_action_popup->add_item(TTR("Set"),CREATE_SET);
+
+
+ port_action_output=p_from_slot-vsn->get_output_sequence_port_count();
+ port_action_node=p_from.to_int();
+
+
+ }
+
+ port_action_pos=p_release_pos;
+ port_action_popup->set_size(Size2(1,1));
+ port_action_popup->set_pos(graph->get_global_pos()+p_release_pos);
+ port_action_popup->popup();
}
+VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_node,int p_output,Set<int> &visited_nodes) {
+
+
+ VisualScriptNode::TypeGuess tg;
+ tg.type=Variant::NIL;
+
+ if (visited_nodes.has(p_node))
+ return tg; //no loop
+
+ visited_nodes.insert(p_node);
+
+ Ref<VisualScriptNode> node = script->get_node(edited_func,p_node);
+
+ if (!node.is_valid()) {
+
+ return tg;
+ }
+
+ Vector<VisualScriptNode::TypeGuess> in_guesses;
+
+ for(int i=0;i<node->get_input_value_port_count();i++) {
+ PropertyInfo pi = node->get_input_value_port_info(i);
+ VisualScriptNode::TypeGuess g;
+ g.type=pi.type;
+
+ if (g.type==Variant::NIL || g.type==Variant::OBJECT) {
+ //any or object input, must further guess what this is
+ int from_node;
+ int from_port;
+
+ if (script->get_input_value_port_connection_source(edited_func,p_node,i,&from_node,&from_port)) {
+
+ g = _guess_output_type(from_node,from_port,visited_nodes);
+ } else {
+ Variant defval = node->get_default_input_value(i);
+ if (defval.get_type()==Variant::OBJECT) {
+
+ Object *obj = defval;
+
+ if (obj) {
+
+ g.type=Variant::OBJECT;
+ g.obj_type=obj->get_type();
+ g.script=obj->get_script();
+ }
+ }
+ }
+
+ }
+
+ in_guesses.push_back(g);
+ }
+
+ return node->guess_output_type(in_guesses.ptr(),p_output);
+}
+
+void VisualScriptEditor::_port_action_menu(int p_option) {
+
+ Vector2 ofs = graph->get_scroll_ofs() + port_action_pos;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap,snap));
+ }
+ ofs/=EDSCALE;
+
+ bool seq_connect=false;
+
+ Ref<VisualScriptNode> vnode;
+ Set<int> vn;
+
+ switch(p_option) {
+
+ case CREATE_CALL: {
+
+ Ref<VisualScriptFunctionCall> n;
+ n.instance();
+ vnode=n;
+
+ VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node,port_action_output,vn);
+
+ if (tg.type==Variant::OBJECT) {
+ n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
+
+ if (tg.obj_type!=StringName()) {
+ n->set_base_type(tg.obj_type);
+ } else {
+ n->set_base_type("Object");
+ }
+
+ if (tg.script.is_valid()) {
+ n->set_base_script(tg.script->get_path());
+ new_connect_node_select->select_method_from_script(tg.script);
+ } else {
+ new_connect_node_select->select_method_from_base_type(n->get_base_type());
+ }
+
+
+ } else {
+ n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
+ n->set_basic_type(tg.type);
+ new_connect_node_select->select_method_from_basic_type(tg.type);
+ }
+
+
+
+ } break;
+ case CREATE_SET: {
+
+ Ref<VisualScriptPropertySet> n;
+ n.instance();
+ vnode=n;
+
+
+ VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node,port_action_output,vn);
+
+ if (tg.type==Variant::OBJECT) {
+ n->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
+
+ if (tg.obj_type!=StringName()) {
+ n->set_base_type(tg.obj_type);
+ } else {
+ n->set_base_type("Object");
+ }
+
+ if (tg.script.is_valid()) {
+ n->set_base_script(tg.script->get_path());
+ new_connect_node_select->select_property_from_script(tg.script);
+ } else {
+ new_connect_node_select->select_property_from_base_type(n->get_base_type());
+ }
+
+
+ } else {
+ n->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE);
+ n->set_basic_type(tg.type);
+ new_connect_node_select->select_property_from_basic_type(tg.type,tg.ev_type);
+ }
+ } break;
+ case CREATE_GET: {
+
+ Ref<VisualScriptPropertyGet> n;
+ n.instance();
+ vnode=n;
+
+ VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node,port_action_output,vn);
+
+ if (tg.type==Variant::OBJECT) {
+ n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
+
+ if (tg.obj_type!=StringName()) {
+ n->set_base_type(tg.obj_type);
+ } else {
+ n->set_base_type("Object");
+ }
+
+ if (tg.script.is_valid()) {
+ n->set_base_script(tg.script->get_path());
+ new_connect_node_select->select_property_from_script(tg.script);
+ } else {
+ new_connect_node_select->select_property_from_base_type(n->get_base_type());
+ }
+
+
+ } else {
+ n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE);
+ n->set_basic_type(tg.type);
+ new_connect_node_select->select_property_from_basic_type(tg.type,tg.ev_type);
+ }
+
+ } break;
+ case CREATE_COND: {
+
+ Ref<VisualScriptCondition> n;
+ n.instance();
+ vnode=n;
+ seq_connect=true;
+
+ } break;
+ case CREATE_SEQUENCE: {
+
+ Ref<VisualScriptSequence> n;
+ n.instance();
+ vnode=n;
+ seq_connect=true;
+
+ } break;
+ case CREATE_SWITCH: {
+
+ Ref<VisualScriptSwitch> n;
+ n.instance();
+ vnode=n;
+ seq_connect=true;
+
+ } break;
+ case CREATE_ITERATOR: {
+
+ Ref<VisualScriptIterator> n;
+ n.instance();
+ vnode=n;
+ seq_connect=true;
+
+ } break;
+ case CREATE_WHILE: {
+
+ Ref<VisualScriptWhile> n;
+ n.instance();
+ vnode=n;
+ seq_connect=true;
+
+ } break;
+ case CREATE_RETURN: {
+
+ Ref<VisualScriptReturn> n;
+ n.instance();
+ vnode=n;
+ seq_connect=true;
+
+ } break;
+
+ }
+
+ 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);
+ if (seq_connect) {
+ undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,port_action_node,port_action_output,new_id);
+ }
+ undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+ undo_redo->add_do_method(this,"_update_graph",new_id);
+ undo_redo->add_undo_method(this,"_update_graph",new_id);
+ undo_redo->commit_action();
+
+ port_action_new_node=new_id;
+
+}
+
+void VisualScriptEditor::_selected_connect_node_method_or_setget(const String& p_text) {
+
+ Ref<VisualScriptNode> vsn = script->get_node(edited_func,port_action_new_node);
+
+ if (vsn->cast_to<VisualScriptFunctionCall>()) {
+
+ Ref<VisualScriptFunctionCall> vsfc = vsn;
+ vsfc->set_function(p_text);
+ script->data_connect(edited_func,port_action_node,port_action_output,port_action_new_node,0);
+ }
+
+ if (vsn->cast_to<VisualScriptPropertySet>()) {
+
+ Ref<VisualScriptPropertySet> vsp = vsn;
+ vsp->set_property(p_text);
+ script->data_connect(edited_func,port_action_node,port_action_output,port_action_new_node,0);
+ }
+
+ if (vsn->cast_to<VisualScriptPropertyGet>()) {
+
+ Ref<VisualScriptPropertyGet> vsp = vsn;
+ vsp->set_property(p_text);
+ script->data_connect(edited_func,port_action_node,port_action_output,port_action_new_node,0);
+ }
+
+ _update_graph(port_action_new_node);
+ _update_graph_connections();
+
+}
+
+
void VisualScriptEditor::_default_value_changed() {
@@ -2889,6 +3222,8 @@ void VisualScriptEditor::_bind_methods() {
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("_port_action_menu",&VisualScriptEditor::_port_action_menu);
+ ObjectTypeDB::bind_method("_selected_connect_node_method_or_setget",&VisualScriptEditor::_selected_connect_node_method_or_setget);
@@ -2949,7 +3284,7 @@ VisualScriptEditor::VisualScriptEditor() {
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);
+ left_vb->set_custom_minimum_size(Size2(230,1)*EDSCALE);
base_type_select = memnew( Button );
left_vb->add_margin_child(TTR("Base Type:"),base_type_select);
@@ -3093,6 +3428,15 @@ VisualScriptEditor::VisualScriptEditor() {
method_select->connect("selected",this,"_selected_method");
error_line=-1;
+ new_connect_node_select = memnew( PropertySelector );
+ add_child(new_connect_node_select);
+ new_connect_node_select->connect("selected",this,"_selected_connect_node_method_or_setget");
+
+ port_action_popup = memnew( PopupMenu );
+ add_child(port_action_popup);
+ port_action_popup->connect("item_pressed",this,"_port_action_menu");
+
+
}
VisualScriptEditor::~VisualScriptEditor() {
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 5a40822bfe..5191ed540a 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -33,6 +33,19 @@ class VisualScriptEditor : public ScriptEditorBase {
EDIT_PASTE_NODES,
};
+ enum PortAction {
+
+ CREATE_CALL,
+ CREATE_SET,
+ CREATE_GET,
+ CREATE_COND,
+ CREATE_SEQUENCE,
+ CREATE_SWITCH,
+ CREATE_ITERATOR,
+ CREATE_WHILE,
+ CREATE_RETURN,
+ };
+
MenuButton *edit_menu;
Ref<VisualScript> script;
@@ -53,6 +66,7 @@ class VisualScriptEditor : public ScriptEditorBase {
PropertyEditor *edit_signal_edit;
PropertySelector *method_select;
+ PropertySelector *new_connect_node_select;
VisualScriptEditorVariableEdit *variable_editor;
@@ -114,6 +128,16 @@ class VisualScriptEditor : public ScriptEditorBase {
static Clipboard *clipboard;
+ PopupMenu *port_action_popup;
+
+ PortAction port_action;
+ int port_action_node;
+ int port_action_output;
+ Vector2 port_action_pos;
+ int port_action_new_node;
+ void _port_action_menu(int p_option);
+ void _selected_connect_node_method_or_setget(const String& p_text);
+
int error_line;
@@ -145,6 +169,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _member_button(Object *p_item, int p_column, int p_button);
+
String revert_on_drag;
void _input(const InputEvent& p_event);
@@ -173,6 +198,8 @@ class VisualScriptEditor : public ScriptEditorBase {
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);
+ VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node,int p_port_action_output,Set<int> &visited_nodes);
+
protected:
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
new file mode 100644
index 0000000000..b53e81f23f
--- /dev/null
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -0,0 +1,1440 @@
+#include "visual_script_expression.h"
+
+
+bool VisualScriptExpression::_set(const StringName& p_name, const Variant& p_value) {
+
+ if (String(p_name)=="expression") {
+ expression=p_value;
+ expression_dirty=true;
+ ports_changed_notify();
+ return true;
+ }
+
+ if (String(p_name)=="out_type") {
+ output_type=Variant::Type(int(p_value));
+ expression_dirty=true;
+ ports_changed_notify();
+ return true;
+ }
+ if (String(p_name)=="sequenced") {
+ sequenced=p_value;
+ ports_changed_notify();
+ return true;
+ }
+
+ if (String(p_name)=="input_count") {
+
+ int from=inputs.size();
+ inputs.resize(int(p_value));
+ for(int i=from;i<inputs.size();i++) {
+ inputs[i].name=String::chr('a'+i);
+ if (from==0) {
+ inputs[i].type=output_type;
+ } else {
+ inputs[i].type=inputs[from-1].type;
+ }
+ }
+ expression_dirty=true;
+ ports_changed_notify();
+ _change_notify();
+ return true;
+ }
+
+ if (String(p_name).begins_with("input/")) {
+
+ int idx=String(p_name).get_slice("/",1).to_int();
+ ERR_FAIL_INDEX_V(idx,inputs.size(),false);
+
+ String what=String(p_name).get_slice("/",2);
+
+ if (what=="type") {
+
+ inputs[idx].type=Variant::Type(int(p_value));
+ } else if (what=="name") {
+
+ inputs[idx].name=p_value;
+ } else {
+ return false;
+ }
+
+ expression_dirty=true;
+ ports_changed_notify();
+ return true;
+ }
+
+
+ return false;
+
+}
+
+bool VisualScriptExpression::_get(const StringName& p_name,Variant &r_ret) const {
+
+ if (String(p_name)=="expression") {
+ r_ret=expression;
+ return true;
+ }
+
+ if (String(p_name)=="out_type") {
+ r_ret=output_type;
+ return true;
+ }
+
+ if (String(p_name)=="sequenced") {
+ r_ret=sequenced;
+ return true;
+ }
+
+ if (String(p_name)=="input_count") {
+ r_ret=inputs.size();
+ return true;
+ }
+
+ if (String(p_name).begins_with("input/")) {
+
+ int idx=String(p_name).get_slice("/",1).to_int();
+ ERR_FAIL_INDEX_V(idx,inputs.size(),false);
+
+ String what=String(p_name).get_slice("/",2);
+
+ if (what=="type") {
+
+ r_ret=inputs[idx].type;
+ } else if (what=="name") {
+
+ r_ret=inputs[idx].name;
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ return false;
+}
+void VisualScriptExpression::_get_property_list( List<PropertyInfo> *p_list) const {
+
+
+ String argt="Any";
+ for(int i=1;i<Variant::VARIANT_MAX;i++) {
+ argt+=","+Variant::get_type_name(Variant::Type(i));
+ }
+
+ p_list->push_back(PropertyInfo(Variant::STRING,"expression"));
+ p_list->push_back(PropertyInfo(Variant::INT,"out_type",PROPERTY_HINT_ENUM,argt));
+ p_list->push_back(PropertyInfo(Variant::INT,"input_count",PROPERTY_HINT_RANGE,"0,64,1"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,"sequenced"));
+
+ for(int i=0;i<inputs.size();i++) {
+
+ p_list->push_back(PropertyInfo(Variant::INT,"input/"+itos(i)+"/type",PROPERTY_HINT_ENUM,argt));
+ p_list->push_back(PropertyInfo(Variant::STRING,"input/"+itos(i)+"/name"));
+ }
+}
+
+int VisualScriptExpression::get_output_sequence_port_count() const {
+
+ return sequenced?1:0;
+}
+bool VisualScriptExpression::has_input_sequence_port() const{
+
+ return sequenced;
+}
+
+
+String VisualScriptExpression::get_output_sequence_port_text(int p_port) const{
+
+ return String();
+}
+
+
+int VisualScriptExpression::get_input_value_port_count() const{
+
+ return inputs.size();
+
+}
+int VisualScriptExpression::get_output_value_port_count() const{
+
+ return 1;
+}
+
+
+PropertyInfo VisualScriptExpression::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo(inputs[p_idx].type,inputs[p_idx].name);
+}
+PropertyInfo VisualScriptExpression::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(output_type,"result");
+}
+
+String VisualScriptExpression::get_caption() const{
+
+ return "Expression";
+}
+String VisualScriptExpression::get_text() const{
+
+ return expression;
+}
+
+
+Error VisualScriptExpression::_get_token(Token& r_token) {
+
+ while (true) {
+#define GET_CHAR() (str_ofs>=expression.length()?0:expression[str_ofs++])
+
+ CharType cchar = GET_CHAR();
+ if (cchar==0) {
+ r_token.type=TK_EOF;
+ return OK;
+ }
+
+
+ switch(cchar) {
+
+ case 0: {
+ r_token.type=TK_EOF;
+ return OK;
+ } break;
+ case '{': {
+
+ r_token.type=TK_CURLY_BRACKET_OPEN;
+ return OK;
+ };
+ case '}': {
+
+ r_token.type=TK_CURLY_BRACKET_CLOSE;
+ return OK;
+ };
+ case '[': {
+
+ r_token.type=TK_BRACKET_OPEN;
+ return OK;
+ };
+ case ']': {
+
+ r_token.type=TK_BRACKET_CLOSE;
+ return OK;
+ };
+ case '(': {
+
+ r_token.type=TK_PARENTHESIS_OPEN;
+ return OK;
+ };
+ case ')': {
+
+ r_token.type=TK_PARENTHESIS_CLOSE;
+ return OK;
+ };
+ case ',': {
+
+ r_token.type=TK_COMMA;
+ return OK;
+ };
+ case ':': {
+
+ r_token.type=TK_COLON;
+ return OK;
+ };
+ case '.': {
+
+ r_token.type=TK_PERIOD;
+ return OK;
+ };
+ case '=': {
+
+ cchar=GET_CHAR();
+ if (cchar=='=') {
+ r_token.type=TK_OP_EQUAL;
+ } else {
+ _set_error("Expected '='");
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ return OK;
+ };
+ case '!': {
+
+ if (expression[str_ofs]=='=') {
+ r_token.type=TK_OP_NOT_EQUAL;
+ str_ofs++;
+ } else {
+ r_token.type=TK_OP_NOT;
+ }
+ return OK;
+ };
+ case '>': {
+
+ if (expression[str_ofs]=='=') {
+ r_token.type=TK_OP_GREATER_EQUAL;
+ str_ofs++;
+ } else if (expression[str_ofs]=='>') {
+ r_token.type=TK_OP_SHIFT_RIGHT;
+ str_ofs++;
+ } else {
+ r_token.type=TK_OP_GREATER;
+ }
+ return OK;
+ };
+ case '<': {
+
+ if (expression[str_ofs]=='=') {
+ r_token.type=TK_OP_LESS_EQUAL;
+ str_ofs++;
+ } else if (expression[str_ofs]=='<') {
+ r_token.type=TK_OP_SHIFT_LEFT;
+ str_ofs++;
+ } else {
+ r_token.type=TK_OP_LESS;
+ }
+ return OK;
+ };
+ case '+': {
+ r_token.type=TK_OP_ADD;
+ return OK;
+ };
+ case '-': {
+ r_token.type=TK_OP_SUB;
+ return OK;
+ };
+ case '/': {
+ r_token.type=TK_OP_DIV;
+ return OK;
+ };
+ case '*': {
+ r_token.type=TK_OP_MUL;
+ return OK;
+ };
+ case '%': {
+ r_token.type=TK_OP_MOD;
+ return OK;
+ };
+ case '&': {
+
+ if (expression[str_ofs]=='&') {
+ r_token.type=TK_OP_AND;
+ str_ofs++;
+ } else {
+ r_token.type=TK_OP_BIT_AND;
+ }
+ return OK;
+ };
+ case '|': {
+
+ if (expression[str_ofs]=='|') {
+ r_token.type=TK_OP_OR;
+ str_ofs++;
+ } else {
+ r_token.type=TK_OP_BIT_OR;
+ }
+ return OK;
+ };
+ case '^': {
+
+ r_token.type=TK_OP_BIT_XOR;
+
+ return OK;
+ };
+ case '~': {
+
+ r_token.type=TK_OP_BIT_INVERT;
+
+ return OK;
+ };
+ case '"': {
+
+
+ String str;
+ while(true) {
+
+ CharType ch=GET_CHAR();
+
+ if (ch==0) {
+ _set_error("Unterminated String");
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ } else if (ch=='"') {
+ break;
+ } else if (ch=='\\') {
+ //escaped characters...
+
+ CharType next = GET_CHAR();
+ if (next==0) {
+ _set_error("Unterminated String");
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ CharType res=0;
+
+ switch(next) {
+
+ case 'b': res=8; break;
+ case 't': res=9; break;
+ case 'n': res=10; break;
+ case 'f': res=12; break;
+ case 'r': res=13; break;
+ case 'u': {
+ //hexnumbarh - oct is deprecated
+
+
+ for(int j=0;j<4;j++) {
+ CharType c = GET_CHAR();
+
+ if (c==0) {
+ _set_error("Unterminated String");
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {
+
+ _set_error("Malformed hex constant in string");
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ CharType v;
+ if (c>='0' && c<='9') {
+ v=c-'0';
+ } else if (c>='a' && c<='f') {
+ v=c-'a';
+ v+=10;
+ } else if (c>='A' && c<='F') {
+ v=c-'A';
+ v+=10;
+ } else {
+ ERR_PRINT("BUG");
+ v=0;
+ }
+
+ res<<=4;
+ res|=v;
+
+
+ }
+
+
+
+ } break;
+ //case '\"': res='\"'; break;
+ //case '\\': res='\\'; break;
+ //case '/': res='/'; break;
+ default: {
+ res = next;
+ //r_err_str="Invalid escape sequence";
+ //return ERR_PARSE_ERROR;
+ } break;
+ }
+
+ str+=res;
+
+ } else {
+ str+=ch;
+ }
+ }
+
+ r_token.type=TK_CONSTANT;
+ r_token.value=str;
+ return OK;
+
+ } break;
+ default: {
+
+ if (cchar<=32) {
+ break;
+ }
+
+ if (cchar=='-' || (cchar>='0' && cchar<='9')) {
+ //a number
+
+
+ String num;
+#define READING_SIGN 0
+#define READING_INT 1
+#define READING_DEC 2
+#define READING_EXP 3
+#define READING_DONE 4
+ int reading=READING_INT;
+
+ if (cchar=='-') {
+ num+='-';
+ cchar=GET_CHAR();
+
+ }
+
+
+
+ CharType c = cchar;
+ bool exp_sign=false;
+ bool exp_beg=false;
+ bool is_float=false;
+
+ while(true) {
+
+ switch(reading) {
+ case READING_INT: {
+
+ if (c>='0' && c<='9') {
+ //pass
+ } else if (c=='.') {
+ reading=READING_DEC;
+ is_float=true;
+ } else if (c=='e') {
+ reading=READING_EXP;
+ } else {
+ reading=READING_DONE;
+ }
+
+ } break;
+ case READING_DEC: {
+
+ if (c>='0' && c<='9') {
+
+ } else if (c=='e') {
+ reading=READING_EXP;
+
+ } else {
+ reading=READING_DONE;
+ }
+
+ } break;
+ case READING_EXP: {
+
+ if (c>='0' && c<='9') {
+ exp_beg=true;
+
+ } else if ((c=='-' || c=='+') && !exp_sign && !exp_beg) {
+ if (c=='-')
+ is_float=true;
+ exp_sign=true;
+
+ } else {
+ reading=READING_DONE;
+ }
+ } break;
+ }
+
+ if (reading==READING_DONE)
+ break;
+ num+=String::chr(c);
+ c = GET_CHAR();
+
+
+ }
+
+ str_ofs--;
+
+ r_token.type=TK_CONSTANT;
+
+ if (is_float)
+ r_token.value=num.to_double();
+ else
+ r_token.value=num.to_int();
+ return OK;
+
+ } else if ((cchar>='A' && cchar<='Z') || (cchar>='a' && cchar<='z') || cchar=='_') {
+
+ String id;
+ bool first=true;
+
+ while((cchar>='A' && cchar<='Z') || (cchar>='a' && cchar<='z') || cchar=='_' || (!first && cchar>='0' && cchar<='9')) {
+
+ id+=String::chr(cchar);
+ cchar=GET_CHAR();
+ first=false;
+ }
+
+ str_ofs--; //go back one
+
+ if (id=="in") {
+ r_token.type=TK_OP_IN;
+ } else if (id=="null") {
+ r_token.type=TK_CONSTANT;
+ r_token.value=Variant();
+ } else if (id=="true") {
+ r_token.type=TK_CONSTANT;
+ r_token.value=true;
+ } else if (id=="false") {
+ r_token.type=TK_CONSTANT;
+ r_token.value=false;
+ } else if (id=="PI") {
+ r_token.type=TK_CONSTANT;
+ r_token.value=Math_PI;
+ } else if (id=="not") {
+ r_token.type=TK_OP_NOT;
+ } else if (id=="or") {
+ r_token.type=TK_OP_OR;
+ } else if (id=="and") {
+ r_token.type=TK_OP_AND;
+ } else if (id=="self") {
+ r_token.type=TK_SELF;
+ } else {
+
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ if (id==Variant::get_type_name(Variant::Type(i))) {
+ r_token.type=TK_BASIC_TYPE;
+ r_token.value=i;
+ return OK;
+ break;
+ }
+ }
+
+ r_token.type=TK_IDENTIFIER;
+ r_token.value=id;
+ }
+
+ return OK;
+ } else {
+ _set_error("Unexpected character.");
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ }
+ }
+ }
+
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+}
+
+const char* VisualScriptExpression::token_name[TK_MAX]={
+"CURLY BRACKET OPEN",
+"CURLY BRACKET CLOSE",
+"BRACKET OPEN",
+"BRACKET CLOSE",
+"PARENTHESIS OPEN",
+"PARENTHESIS CLOSE",
+"IDENTIFIER",
+"SELF",
+"CONSTANT",
+"BASIC TYPE",
+"COLON",
+"COMMA",
+"PERIOD",
+"OP IN",
+"OP EQUAL",
+"OP NOT EQUAL",
+"OP LESS",
+"OP LESS EQUAL",
+"OP GREATER",
+"OP GREATER EQUAL",
+"OP AND",
+"OP OR",
+"OP NOT",
+"OP ADD",
+"OP SUB",
+"OP MUL",
+"OP DIV",
+"OP MOD",
+"OP SHIFT LEFT",
+"OP SHIFT RIGHT",
+"OP BIT AND",
+"OP BIT OR",
+"OP BIT XOR",
+"OP BIT INVERT",
+"EOF",
+"ERROR"
+};
+
+VisualScriptExpression::ENode* VisualScriptExpression::_parse_expression() {
+
+
+ Vector<Expression> expression;
+
+ while(true) {
+ //keep appending stuff to expression
+ ENode*expr=NULL;
+
+ Token tk;
+ _get_token(tk);
+ if (error_set)
+ return NULL;
+
+
+
+ switch(tk.type) {
+ case TK_CURLY_BRACKET_OPEN: {
+ //a dictionary
+ DictionaryNode *dn = alloc_node<DictionaryNode>();
+
+
+ while(true) {
+
+ int cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_CURLY_BRACKET_CLOSE) {
+ break;
+ }
+ str_ofs=cofs; //revert
+ //parse an expression
+ ENode* expr=_parse_expression();
+ if (!expr)
+ return NULL;
+ dn->dict.push_back(expr);
+
+ _get_token(tk);
+ if (tk.type!=TK_COLON) {
+ _set_error("Expected ':'");
+ return NULL;
+ }
+
+ expr=_parse_expression();
+ if (!expr)
+ return NULL;
+
+ dn->dict.push_back(expr);
+
+ cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_COMMA) {
+ //all good
+ } else if (tk.type==TK_CURLY_BRACKET_CLOSE) {
+ str_ofs=cofs;
+ } else {
+ _set_error("Expected ',' or '}'");
+ }
+ }
+
+ expr=dn;
+ } break;
+ case TK_BRACKET_OPEN: {
+ //an array
+
+ ArrayNode *an = alloc_node<ArrayNode>();
+
+
+ while(true) {
+
+ int cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_BRACKET_CLOSE) {
+ break;
+ }
+ str_ofs=cofs; //revert
+ //parse an expression
+ ENode* expr=_parse_expression();
+ if (!expr)
+ return NULL;
+ an->array.push_back(expr);
+
+ cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_COMMA) {
+ //all good
+ } else if (tk.type==TK_BRACKET_CLOSE) {
+ str_ofs=cofs;
+ } else {
+ _set_error("Expected ',' or ']'");
+ }
+ }
+
+ expr=an;
+ } break;
+ case TK_PARENTHESIS_OPEN: {
+ //a suexpression
+ ENode* e=_parse_expression();
+ if (error_set)
+ return NULL;
+ _get_token(tk);
+ if (tk.type!=TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')'");
+ return NULL;
+ }
+
+ expr=e;
+
+ } break;
+ case TK_IDENTIFIER: {
+
+ String what = tk.value;
+ int index=-1;
+ for(int i=0;i<inputs.size();i++) {
+ if (what==inputs[i].name) {
+ index=i;
+ break;
+ }
+ }
+
+ if (index!=-1) {
+ InputNode *input = alloc_node<InputNode>();
+ input->index=index;
+ expr=input;
+ } else {
+ _set_error("Invalid input identifier '"+what+"'. For script variables, use self (locals are for inputs)."+what);
+ return NULL;
+ }
+ } break;
+ case TK_SELF: {
+
+ SelfNode *self = alloc_node<SelfNode>();
+ expr=self;
+ } break;
+ case TK_CONSTANT: {
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ constant->value=tk.value;
+ expr=constant;
+ } break;
+ case TK_BASIC_TYPE: {
+ //constructor..
+
+ Variant::Type bt = Variant::Type(int(tk.value));
+ _get_token(tk);
+ if (tk.type!=TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '('");
+ return NULL;
+ }
+
+ ConstructorNode *constructor = alloc_node<ConstructorNode>();
+ constructor->data_type=bt;
+
+ while(true) {
+
+ int cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+ str_ofs=cofs; //revert
+ //parse an expression
+ ENode* expr=_parse_expression();
+ if (!expr)
+ return NULL;
+
+ constructor->arguments.push_back(expr);
+
+ cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_COMMA) {
+ //all good
+ } else if (tk.type==TK_PARENTHESIS_CLOSE) {
+ str_ofs=cofs;
+ } else {
+ _set_error("Expected ',' or ')'");
+ }
+ }
+
+ expr=constructor;
+
+ } break;
+ case TK_OP_SUB: {
+
+ Expression e;
+ e.is_op=true;
+ e.op=Variant::OP_NEGATE;
+ expression.push_back(e);
+ continue;
+ } break;
+ case TK_OP_NOT: {
+
+ Expression e;
+ e.is_op=true;
+ e.op=Variant::OP_NOT;
+ expression.push_back(e);
+ continue;
+ } break;
+
+ default: {
+ _set_error("Expected expression.");
+ return NULL;
+ } break;
+
+ }
+
+ //before going to operators, must check indexing!
+
+ while(true) {
+ int cofs2=str_ofs;
+ _get_token(tk);
+ if (error_set)
+ return NULL;
+
+ bool done=false;
+
+ switch(tk.type) {
+ case TK_BRACKET_OPEN: {
+ //value indexing
+
+ IndexNode *index = alloc_node<IndexNode>();
+ index->base=expr;
+
+ ENode* what=_parse_expression();
+ if (!what)
+ return NULL;
+
+ index->index=what;
+
+ _get_token(tk);
+ if (tk.type!=TK_BRACKET_CLOSE) {
+ _set_error("Expected ']' at end of index.");
+ return NULL;
+ }
+ expr=index;
+
+ } break;
+ case TK_PERIOD: {
+ //named indexing or function call
+ _get_token(tk);
+ if (tk.type!=TK_IDENTIFIER) {
+ _set_error("Expected identifier after '.'");
+ return NULL;
+ }
+
+ StringName identifier=tk.value;
+
+ int cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_PARENTHESIS_OPEN) {
+ //function call
+ CallNode *func_call = alloc_node<CallNode>();
+ func_call->method=identifier;
+ func_call->base=expr;
+
+ while(true) {
+
+ int cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+ str_ofs=cofs; //revert
+ //parse an expression
+ ENode* expr=_parse_expression();
+ if (!expr)
+ return NULL;
+
+ func_call->arguments.push_back(expr);
+
+ cofs=str_ofs;
+ _get_token(tk);
+ if (tk.type==TK_COMMA) {
+ //all good
+ } else if (tk.type==TK_PARENTHESIS_CLOSE) {
+ str_ofs=cofs;
+ } else {
+ _set_error("Expected ',' or ')'");
+ }
+ }
+
+ expr=func_call;
+ } else {
+ //named indexing
+ str_ofs=cofs;
+
+ NamedIndexNode *index = alloc_node<NamedIndexNode>();
+ index->base=expr;
+ index->name=identifier;
+ expr=index;
+
+ }
+
+ } break;
+ default: {
+ str_ofs=cofs2;
+ done=true;
+ } break;
+ }
+
+ if (done)
+ break;
+ }
+
+ //push expression
+ {
+ Expression e;
+ e.is_op=false;
+ e.node=expr;
+ expression.push_back(e);
+ }
+
+ //ok finally look for an operator
+
+
+ int cofs=str_ofs;
+ _get_token(tk);
+ if (error_set)
+ return NULL;
+
+
+ Variant::Operator op = Variant::OP_MAX;
+
+ switch(tk.type) {
+ case TK_OP_IN: op=Variant::OP_IN; break;
+ case TK_OP_EQUAL: op=Variant::OP_EQUAL; break;
+ case TK_OP_NOT_EQUAL: op=Variant::OP_NOT_EQUAL; break;
+ case TK_OP_LESS: op=Variant::OP_LESS; break;
+ case TK_OP_LESS_EQUAL: op=Variant::OP_LESS_EQUAL; break;
+ case TK_OP_GREATER: op=Variant::OP_GREATER; break;
+ case TK_OP_GREATER_EQUAL: op=Variant::OP_GREATER_EQUAL; break;
+ case TK_OP_AND: op=Variant::OP_AND; break;
+ case TK_OP_OR: op=Variant::OP_OR; break;
+ case TK_OP_NOT: op=Variant::OP_NOT; break;
+ case TK_OP_ADD: op=Variant::OP_ADD; break;
+ case TK_OP_SUB: op=Variant::OP_SUBSTRACT; break;
+ case TK_OP_MUL: op=Variant::OP_MULTIPLY; break;
+ case TK_OP_DIV: op=Variant::OP_DIVIDE; break;
+ case TK_OP_MOD: op=Variant::OP_MODULE; break;
+ case TK_OP_SHIFT_LEFT: op=Variant::OP_SHIFT_LEFT; break;
+ case TK_OP_SHIFT_RIGHT: op=Variant::OP_SHIFT_RIGHT; break;
+ case TK_OP_BIT_AND: op=Variant::OP_BIT_AND; break;
+ case TK_OP_BIT_OR: op=Variant::OP_BIT_OR; break;
+ case TK_OP_BIT_XOR: op=Variant::OP_BIT_XOR; break;
+ case TK_OP_BIT_INVERT: op=Variant::OP_BIT_NEGATE; break;
+ default: {};
+ }
+
+ if (op==Variant::OP_MAX) { //stop appending stuff
+ str_ofs=cofs;
+ break;
+ }
+
+ //push operator and go on
+ {
+ Expression e;
+ e.is_op=true;
+ e.op=op;
+ expression.push_back(e);
+ }
+ }
+
+
+ /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
+
+
+ while(expression.size()>1) {
+
+ int next_op=-1;
+ int min_priority=0xFFFFF;
+ bool is_unary=false;
+
+ for(int i=0;i<expression.size();i++) {
+
+
+
+ if (!expression[i].is_op) {
+
+ continue;
+ }
+
+ int priority;
+
+ bool unary=false;
+
+ switch(expression[i].op) {
+
+
+ case Variant::OP_BIT_NEGATE: priority=0; unary=true; break;
+ case Variant::OP_NEGATE: priority=1; unary=true; break;
+
+ case Variant::OP_MULTIPLY: priority=2; break;
+ case Variant::OP_DIVIDE: priority=2; break;
+ case Variant::OP_MODULE: priority=2; break;
+
+ case Variant::OP_ADD: priority=3; break;
+ case Variant::OP_SUBSTRACT: priority=3; break;
+
+ case Variant::OP_SHIFT_LEFT: priority=4; break;
+ case Variant::OP_SHIFT_RIGHT: priority=4; break;
+
+ case Variant::OP_BIT_AND: priority=5; break;
+ case Variant::OP_BIT_XOR: priority=6; break;
+ case Variant::OP_BIT_OR: priority=7; break;
+
+ case Variant::OP_LESS: priority=8; break;
+ case Variant::OP_LESS_EQUAL: priority=8; break;
+ case Variant::OP_GREATER: priority=8; break;
+ case Variant::OP_GREATER_EQUAL: priority=8; break;
+
+ case Variant::OP_EQUAL: priority=8; break;
+ case Variant::OP_NOT_EQUAL: priority=8; break;
+
+ case Variant::OP_IN: priority=10; break;
+
+ case Variant::OP_NOT: priority=11; unary=true; break;
+ case Variant::OP_AND: priority=12; break;
+ case Variant::OP_OR: priority=13; break;
+
+
+ default: {
+ _set_error("Parser bug, invalid operator in expression: "+itos(expression[i].op));
+ return NULL;
+ }
+
+ }
+
+ if (priority<min_priority) {
+ // < is used for left to right (default)
+ // <= is used for right to left
+
+ next_op=i;
+ min_priority=priority;
+ is_unary=unary;
+ }
+
+ }
+
+ if (next_op==-1) {
+
+
+ _set_error("Yet another parser bug....");
+ ERR_FAIL_COND_V(next_op==-1,NULL);
+ }
+
+
+ // OK! create operator..
+ if (is_unary) {
+
+ int expr_pos=next_op;
+ while(expression[expr_pos].is_op) {
+
+ expr_pos++;
+ if (expr_pos==expression.size()) {
+ //can happen..
+ _set_error("Unexpected end of expression..");
+ return NULL;
+ }
+ }
+
+ //consecutively do unary opeators
+ for(int i=expr_pos-1;i>=next_op;i--) {
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op=expression[i].op;
+ op->nodes[0]=expression[i+1].node;
+ op->nodes[1]=NULL;
+ expression[i].is_op=false;
+ expression[i].node=op;
+ expression.remove(i+1);
+ }
+
+
+ } else {
+
+ if (next_op <1 || next_op>=(expression.size()-1)) {
+ _set_error("Parser bug..");
+ ERR_FAIL_V(NULL);
+ }
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op=expression[next_op].op;
+
+ if (expression[next_op-1].is_op) {
+
+ _set_error("Parser bug..");
+ ERR_FAIL_V(NULL);
+ }
+
+ if (expression[next_op+1].is_op) {
+ // this is not invalid and can really appear
+ // but it becomes invalid anyway because no binary op
+ // can be followed by an unary op in a valid combination,
+ // due to how precedence works, unaries will always dissapear first
+
+ _set_error("Unexpected two consecutive operators.");
+ return NULL;
+ }
+
+
+ op->nodes[0]=expression[next_op-1].node; //expression goes as left
+ op->nodes[1]=expression[next_op+1].node; //next expression goes as right
+
+ //replace all 3 nodes by this operator and make it an expression
+ expression[next_op-1].node=op;
+ expression.remove(next_op);
+ expression.remove(next_op);
+ }
+ }
+
+ return expression[0].node;
+}
+
+bool VisualScriptExpression::_compile_expression() {
+
+ if (!expression_dirty)
+ return error_set;
+
+ if (nodes) {
+ memdelete(nodes);
+ nodes=NULL;
+ root=NULL;
+
+ }
+
+ error_str=String();
+ error_set=false;
+ str_ofs=0;
+
+ root=_parse_expression();
+
+ if (error_set) {
+ root=NULL;
+ if (nodes) {
+ memdelete(nodes);
+ }
+ nodes=NULL;
+ return true;
+ }
+
+ expression_dirty=false;
+ return false;
+}
+
+
+class VisualScriptNodeInstanceExpression : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ VisualScriptExpression *expression;
+
+ //virtual int get_working_memory_size() const { return 0; }
+ //execute by parsing the tree directly
+ virtual bool _execute(const Variant** p_inputs,VisualScriptExpression::ENode *p_node,Variant& r_ret,String& r_error_str,Variant::CallError &ce) {
+
+ switch(p_node->type) {
+ case VisualScriptExpression::ENode::TYPE_INPUT: {
+
+ const VisualScriptExpression::InputNode *in = static_cast<const VisualScriptExpression::InputNode*>(p_node);
+ r_ret=*p_inputs[in->index];
+ } break;
+ case VisualScriptExpression::ENode::TYPE_CONSTANT: {
+
+ const VisualScriptExpression::ConstantNode *c = static_cast<const VisualScriptExpression::ConstantNode*>(p_node);
+ r_ret=c->value;
+
+ } break;
+ case VisualScriptExpression::ENode::TYPE_SELF: {
+
+ r_ret=instance->get_owner_ptr();
+ } break;
+ case VisualScriptExpression::ENode::TYPE_OPERATOR: {
+
+
+ const VisualScriptExpression::OperatorNode *op = static_cast<const VisualScriptExpression::OperatorNode*>(p_node);
+
+ Variant a;
+ bool ret = _execute(p_inputs,op->nodes[0],a,r_error_str,ce);
+ if (ret)
+ return true;
+
+ Variant b;
+
+ if (op->nodes[1]) {
+ ret = _execute(p_inputs,op->nodes[1],b,r_error_str,ce);
+ if (ret)
+ return true;
+ }
+
+ bool valid=true;
+ Variant::evaluate(op->op,a,b,r_ret,valid);
+ if (!valid) {
+ r_error_str="Invalid operands to operator "+Variant::get_operator_name(op->op)+": "+Variant::get_type_name(a.get_type())+" and "+Variant::get_type_name(b.get_type())+".";
+ return true;
+ }
+
+ } break;
+ case VisualScriptExpression::ENode::TYPE_INDEX: {
+
+ const VisualScriptExpression::IndexNode *index = static_cast<const VisualScriptExpression::IndexNode*>(p_node);
+
+ Variant base;
+ bool ret = _execute(p_inputs,index->base,base,r_error_str,ce);
+ if (ret)
+ return true;
+
+ Variant idx;
+
+ ret = _execute(p_inputs,index->index,idx,r_error_str,ce);
+ if (ret)
+ return true;
+
+ bool valid;
+ r_ret=base.get(idx,&valid);
+ if (!valid) {
+ r_error_str="Invalid index of type "+Variant::get_type_name(idx.get_type())+" for base of type "+Variant::get_type_name(base.get_type())+".";
+ return true;
+ }
+
+
+
+ } break;
+ case VisualScriptExpression::ENode::TYPE_NAMED_INDEX: {
+
+ const VisualScriptExpression::NamedIndexNode *index = static_cast<const VisualScriptExpression::NamedIndexNode*>(p_node);
+
+ Variant base;
+ bool ret = _execute(p_inputs,index->base,base,r_error_str,ce);
+ if (ret)
+ return true;
+
+ bool valid;
+ r_ret=base.get_named(index->name,&valid);
+ if (!valid) {
+ r_error_str="Invalid index '"+String(index->name)+"' for base of type "+Variant::get_type_name(base.get_type())+".";
+ return true;
+ }
+
+ } break;
+ case VisualScriptExpression::ENode::TYPE_ARRAY: {
+ const VisualScriptExpression::ArrayNode *array = static_cast<const VisualScriptExpression::ArrayNode*>(p_node);
+
+ Array arr;
+ arr.resize(array->array.size());
+ for (int i=0;i<array->array.size();i++) {
+
+ Variant value;
+ bool ret = _execute(p_inputs,array->array[i],value,r_error_str,ce);
+ if (ret)
+ return true;
+ arr[i]=value;
+ }
+
+ r_ret=arr;
+
+ } break;
+ case VisualScriptExpression::ENode::TYPE_DICTIONARY: {
+ const VisualScriptExpression::DictionaryNode *dictionary = static_cast<const VisualScriptExpression::DictionaryNode*>(p_node);
+
+ Dictionary d;
+ for (int i=0;i<dictionary->dict.size();i+=2) {
+
+ Variant key;
+ bool ret = _execute(p_inputs,dictionary->dict[i+0],key,r_error_str,ce);
+ if (ret)
+ return true;
+
+ Variant value;
+ ret = _execute(p_inputs,dictionary->dict[i+1],value,r_error_str,ce);
+ if (ret)
+ return true;
+
+ d[key]=value;
+ }
+
+ r_ret=d;
+ } break;
+ case VisualScriptExpression::ENode::TYPE_CONSTRUCTOR: {
+
+ const VisualScriptExpression::ConstructorNode *constructor = static_cast<const VisualScriptExpression::ConstructorNode*>(p_node);
+
+ Vector<Variant> arr;
+ Vector<const Variant*> argp;
+ arr.resize(constructor->arguments.size());
+ argp.resize(constructor->arguments.size());
+
+ for (int i=0;i<constructor->arguments.size();i++) {
+
+ Variant value;
+ bool ret = _execute(p_inputs,constructor->arguments[i],value,r_error_str,ce);
+ if (ret)
+ return true;
+ arr[i]=value;
+ argp[i]=&arr[i];
+ }
+
+
+ r_ret=Variant::construct(constructor->data_type,argp.ptr(),argp.size(),ce);
+
+ if (ce.error!=Variant::CallError::CALL_OK) {
+ r_error_str="Invalid arguments to construct '"+Variant::get_type_name(constructor->data_type)+"'.";
+ return true;
+ }
+
+
+ } break;
+ case VisualScriptExpression::ENode::TYPE_CALL: {
+
+ const VisualScriptExpression::CallNode *call = static_cast<const VisualScriptExpression::CallNode*>(p_node);
+
+
+ Variant base;
+ bool ret = _execute(p_inputs,call->base,base,r_error_str,ce);
+ if (ret)
+ return true;
+
+ Vector<Variant> arr;
+ Vector<const Variant*> argp;
+ arr.resize(call->arguments.size());
+ argp.resize(call->arguments.size());
+
+ for (int i=0;i<call->arguments.size();i++) {
+
+ Variant value;
+ bool ret = _execute(p_inputs,call->arguments[i],value,r_error_str,ce);
+ if (ret)
+ return true;
+ arr[i]=value;
+ argp[i]=&arr[i];
+ }
+
+
+ r_ret=base.call(call->method,argp.ptr(),argp.size(),ce);
+
+ if (ce.error!=Variant::CallError::CALL_OK) {
+ r_error_str="On call to '"+String(call->method)+"':";
+ return true;
+ }
+
+ } break;
+ }
+ 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 (!expression->root || expression->error_set) {
+ r_error_str=expression->error_str;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return 0;
+ }
+
+
+ bool error = _execute(p_inputs,expression->root,*p_outputs[0],r_error_str,r_error);
+ if (error && r_error.error==Variant::CallError::CALL_OK) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ }
+
+#ifdef DEBUG_ENABLED
+ if (!error && expression->output_type!=Variant::NIL && !Variant::can_convert_strict(p_outputs[0]->get_type(),expression->output_type)) {
+
+ r_error_str+="Can't convert expression result from "+Variant::get_type_name(p_outputs[0]->get_type())+" to "+Variant::get_type_name(expression->output_type)+".";
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+
+ }
+#endif
+
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptExpression::instance(VisualScriptInstance* p_instance){
+
+ _compile_expression();
+ VisualScriptNodeInstanceExpression *instance = memnew( VisualScriptNodeInstanceExpression );
+ instance->instance=p_instance;
+ instance->expression=this;
+ return instance;
+}
+
+
+VisualScriptExpression::VisualScriptExpression()
+{
+ output_type=Variant::NIL;
+ expression_dirty=true;
+ error_set=true;
+ root=NULL;
+ nodes=NULL;
+ sequenced=false;
+}
+
+VisualScriptExpression::~VisualScriptExpression() {
+
+ if (nodes) {
+ memdelete(nodes);
+ }
+}
+
+
+void register_visual_script_expression_node() {
+
+ VisualScriptLanguage::singleton->add_register_func("operators/expression",create_node_generic<VisualScriptExpression>);
+
+}
diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h
new file mode 100644
index 0000000000..90b955b5da
--- /dev/null
+++ b/modules/visual_script/visual_script_expression.h
@@ -0,0 +1,269 @@
+#ifndef VISUALSCRIPTEXPRESSION_H
+#define VISUALSCRIPTEXPRESSION_H
+
+#include "visual_script.h"
+
+class VisualScriptExpression : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptExpression,VisualScriptNode)
+friend class VisualScriptNodeInstanceExpression;
+
+ struct Input {
+
+ Variant::Type type;
+ String name;
+
+ Input() { type=Variant::NIL; }
+ };
+
+ Vector<Input> inputs;
+ Variant::Type output_type;
+
+ String expression;
+
+ bool sequenced;
+ int str_ofs;
+ bool expression_dirty;
+
+ bool _compile_expression();
+
+ enum TokenType {
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_PARENTHESIS_OPEN,
+ TK_PARENTHESIS_CLOSE,
+ TK_IDENTIFIER,
+ TK_SELF,
+ TK_CONSTANT,
+ TK_BASIC_TYPE,
+ TK_COLON,
+ TK_COMMA,
+ TK_PERIOD,
+ TK_OP_IN,
+ TK_OP_EQUAL,
+ TK_OP_NOT_EQUAL,
+ TK_OP_LESS,
+ TK_OP_LESS_EQUAL,
+ TK_OP_GREATER,
+ TK_OP_GREATER_EQUAL,
+ TK_OP_AND,
+ TK_OP_OR,
+ TK_OP_NOT,
+ TK_OP_ADD,
+ TK_OP_SUB,
+ TK_OP_MUL,
+ TK_OP_DIV,
+ TK_OP_MOD,
+ TK_OP_SHIFT_LEFT,
+ TK_OP_SHIFT_RIGHT,
+ TK_OP_BIT_AND,
+ TK_OP_BIT_OR,
+ TK_OP_BIT_XOR,
+ TK_OP_BIT_INVERT,
+ TK_EOF,
+ TK_ERROR,
+ TK_MAX
+ };
+
+ static const char* token_name[TK_MAX];
+ struct Token {
+
+ TokenType type;
+ Variant value;
+ };
+
+
+ void _set_error(const String& p_err) {
+ if (error_set)
+ return;
+ error_str=p_err;
+ error_set=true;
+ }
+
+ Error _get_token(Token& r_token);
+
+ String error_str;
+ bool error_set;
+
+
+
+ struct ENode {
+
+ enum Type {
+ TYPE_INPUT,
+ TYPE_CONSTANT,
+ TYPE_SELF,
+ TYPE_OPERATOR,
+ TYPE_INDEX,
+ TYPE_NAMED_INDEX,
+ TYPE_ARRAY,
+ TYPE_DICTIONARY,
+ TYPE_CONSTRUCTOR,
+ TYPE_CALL
+ };
+
+ ENode *next;
+
+ Type type;
+
+ ENode() { next=NULL; }
+ virtual ~ENode() { if (next) { memdelete(next); } }
+ };
+
+ struct Expression {
+
+ bool is_op;
+ union {
+ Variant::Operator op;
+ ENode *node;
+ };
+ };
+
+ ENode* _parse_expression();
+
+ struct InputNode : public ENode {
+
+ int index;
+ InputNode() {
+ type=TYPE_INPUT;
+ }
+ };
+
+
+ struct ConstantNode : public ENode {
+
+ Variant value;
+ ConstantNode() {
+ type=TYPE_CONSTANT;
+ }
+ };
+
+ struct OperatorNode : public ENode {
+
+ Variant::Operator op;
+
+ ENode* nodes[2];
+
+ OperatorNode() {
+ type=TYPE_OPERATOR;
+ }
+ };
+
+ struct SelfNode : public ENode {
+
+
+ SelfNode() {
+ type=TYPE_SELF;
+ }
+ };
+
+ struct IndexNode : public ENode {
+ ENode*base;
+ ENode*index;
+
+ IndexNode() {
+ type=TYPE_INDEX;
+ }
+ };
+
+ struct NamedIndexNode : public ENode {
+ ENode*base;
+ StringName name;
+
+ NamedIndexNode() {
+ type=TYPE_NAMED_INDEX;
+ }
+
+ };
+
+ struct ConstructorNode : public ENode {
+ Variant::Type data_type;
+ Vector<ENode*> arguments;
+
+ ConstructorNode() {
+ type=TYPE_CONSTRUCTOR;
+ }
+ };
+
+ struct CallNode : public ENode {
+ ENode*base;
+ StringName method;
+ Vector<ENode*> arguments;
+
+ CallNode() {
+ type=TYPE_CALL;
+ }
+
+ };
+
+ struct ArrayNode : public ENode {
+ Vector<ENode*> array;
+ ArrayNode() {
+ type=TYPE_ARRAY;
+ }
+
+ };
+
+ struct DictionaryNode : public ENode {
+ Vector<ENode*> dict;
+ DictionaryNode() {
+ type=TYPE_DICTIONARY;
+ }
+
+ };
+
+ template<class T>
+ T* alloc_node() {
+ T* node = memnew(T);
+ node->next=nodes;
+ nodes=node;
+ return node;
+ }
+
+ ENode *root;
+ ENode *nodes;
+
+
+
+
+
+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 "operators"; }
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptExpression();
+ ~VisualScriptExpression();
+};
+
+
+void register_visual_script_expression_node();
+
+
+#endif // VISUALSCRIPTEXPRESSION_H
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index 5066a4214d..97338da187 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -616,7 +616,7 @@ bool VisualScriptSwitch::has_input_sequence_port() const{
int VisualScriptSwitch::get_input_value_port_count() const{
- return 1;
+ return case_values.size()+1;
}
int VisualScriptSwitch::get_output_value_port_count() const{
@@ -628,14 +628,15 @@ String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const {
if (p_port==case_values.size())
return "done";
- if (case_values[p_port].value.get_type()==Variant::NIL)
- return "null";
- return case_values[p_port].value;
+ return String();
}
PropertyInfo VisualScriptSwitch::get_input_value_port_info(int p_idx) const{
- return PropertyInfo(Variant::NIL,"input");
+ if (p_idx<case_values.size()) {
+ return PropertyInfo(case_values[p_idx].type," =");
+ } else
+ return PropertyInfo(Variant::NIL,"input");
}
PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const{
@@ -659,7 +660,7 @@ class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance {
public:
VisualScriptInstance* instance;
- Vector<Variant> case_values;
+ int case_count;
//virtual int get_working_memory_size() const { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
@@ -668,17 +669,17 @@ public:
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 case_values.size(); //exit
+ return case_count; //exit
}
- for(int i=0;i<case_values.size();i++) {
+ for(int i=0;i<case_count;i++) {
- if (*p_inputs[0]==case_values[i]) {
+ if (*p_inputs[i]==*p_inputs[case_count]) {
return i|STEP_FLAG_PUSH_STACK_BIT;
}
}
- return case_values.size();
+ return case_count;
}
@@ -688,10 +689,7 @@ VisualScriptNodeInstance* VisualScriptSwitch::instance(VisualScriptInstance* p_i
VisualScriptNodeInstanceSwitch * instance = memnew(VisualScriptNodeInstanceSwitch );
instance->instance=p_instance;
- instance->case_values.resize(case_values.size());
- for(int i=0;i<case_values.size();i++) {
- instance->case_values[i]=case_values[i].value;
- }
+ instance->case_count=case_values.size();
return instance;
}
@@ -708,23 +706,12 @@ bool VisualScriptSwitch::_set(const StringName& p_name, const Variant& p_value)
int idx = String(p_name).get_slice("/",1).to_int();
ERR_FAIL_INDEX_V(idx,case_values.size(),false);
- String what = String(p_name).get_slice("/",2);
-
- if (what=="type") {
- case_values[idx].type=Variant::Type(int(p_value));
- Variant::CallError ce;
- case_values[idx].value=Variant::construct(case_values[idx].type,NULL,0,ce);
- _change_notify();
- ports_changed_notify();
- return true;
- }
+ case_values[idx].type=Variant::Type(int(p_value));
+ _change_notify();
+ ports_changed_notify();
- if (what=="value") {
- case_values[idx].value=p_value;
- ports_changed_notify();
- return true;
- }
+ return true;
}
return false;
@@ -741,17 +728,9 @@ bool VisualScriptSwitch::_get(const StringName& p_name,Variant &r_ret) const {
int idx = String(p_name).get_slice("/",1).to_int();
ERR_FAIL_INDEX_V(idx,case_values.size(),false);
- String what = String(p_name).get_slice("/",2);
-
- if (what=="type") {
- r_ret=case_values[idx].type;
- return true;
- }
- if (what=="value") {
- r_ret=case_values[idx].value;
- return true;
- }
+ r_ret=case_values[idx].type;
+ return true;
}
return false;
@@ -767,8 +746,7 @@ void VisualScriptSwitch::_get_property_list( List<PropertyInfo> *p_list) const {
}
for(int i=0;i<case_values.size();i++) {
- p_list->push_back(PropertyInfo(Variant::INT,"case/"+itos(i)+"/type",PROPERTY_HINT_ENUM,argt));
- p_list->push_back(PropertyInfo(case_values[i].type,"case/"+itos(i)+"/value"));
+ p_list->push_back(PropertyInfo(Variant::INT,"case/"+itos(i),PROPERTY_HINT_ENUM,argt));
}
}
diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h
index e1730a2264..e0da84a534 100644
--- a/modules/visual_script/visual_script_flow_control.h
+++ b/modules/visual_script/visual_script_flow_control.h
@@ -203,7 +203,6 @@ class VisualScriptSwitch : public VisualScriptNode {
struct Case {
Variant::Type type;
- Variant value;
Case() { type=Variant::NIL; }
};
@@ -224,6 +223,7 @@ public:
virtual String get_output_sequence_port_text(int p_port) const;
+ virtual bool has_mixed_input_and_sequence_ports() const { return true; }
virtual int get_input_value_port_count() const;
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 79910aa2bd..de99beacaf 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -12,7 +12,7 @@
int VisualScriptFunctionCall::get_output_sequence_port_count() const {
- if (method_cache.flags&METHOD_FLAG_CONST)
+ if (method_cache.flags&METHOD_FLAG_CONST || call_mode==CALL_MODE_BASIC_TYPE)
return 0;
else
return 1;
@@ -20,7 +20,7 @@ int VisualScriptFunctionCall::get_output_sequence_port_count() const {
bool VisualScriptFunctionCall::has_input_sequence_port() const{
- if (method_cache.flags&METHOD_FLAG_CONST)
+ if (method_cache.flags&METHOD_FLAG_CONST || call_mode==CALL_MODE_BASIC_TYPE)
return false;
else
return true;
@@ -920,6 +920,18 @@ VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstanc
instance->validate=validate;
return instance;
}
+
+
+VisualScriptFunctionCall::TypeGuess VisualScriptFunctionCall::guess_output_type(TypeGuess* p_inputs, int p_output) const {
+
+ if (p_output==0 && call_mode==CALL_MODE_INSTANCE) {
+ return p_inputs[0];
+ }
+
+ return VisualScriptNode::guess_output_type(p_inputs,p_output);
+
+}
+
VisualScriptFunctionCall::VisualScriptFunctionCall() {
validate=true;
@@ -1600,6 +1612,17 @@ VisualScriptNodeInstance* VisualScriptPropertySet::instance(VisualScriptInstance
return instance;
}
+
+
+VisualScriptPropertySet::TypeGuess VisualScriptPropertySet::guess_output_type(TypeGuess* p_inputs, int p_output) const {
+
+ if (p_output==0 && call_mode==CALL_MODE_INSTANCE) {
+ return p_inputs[0];
+ }
+
+ return VisualScriptNode::guess_output_type(p_inputs,p_output);
+
+}
VisualScriptPropertySet::VisualScriptPropertySet() {
call_mode=CALL_MODE_SELF;
diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h
index 5367deed7f..43ef276cf4 100644
--- a/modules/visual_script/visual_script_func_nodes.h
+++ b/modules/visual_script/visual_script_func_nodes.h
@@ -105,6 +105,9 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
+
VisualScriptFunctionCall();
};
@@ -195,6 +198,7 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
VisualScriptPropertySet();
};
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index f5c5159af7..7ada292b13 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -553,7 +553,7 @@ void VisualScriptOperator::_bind_methods() {
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,"operator_value/type",PROPERTY_HINT_ENUM,types),_SCS("set_operator"),_SCS("get_operator"));
ADD_PROPERTY(PropertyInfo(Variant::INT,"typed_value/typed",PROPERTY_HINT_ENUM,argt),_SCS("set_typed"),_SCS("get_typed"));
}
@@ -1071,7 +1071,13 @@ PropertyInfo VisualScriptPreload::get_input_value_port_info(int p_idx) const{
PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const{
- return PropertyInfo(Variant::OBJECT,"res");
+ PropertyInfo pinfo=PropertyInfo(Variant::OBJECT,"res");
+ if (preload.is_valid()) {
+ pinfo.hint=PROPERTY_HINT_RESOURCE_TYPE;
+ pinfo.hint_string=preload->get_type();
+ }
+
+ return pinfo;
}
@@ -1569,6 +1575,151 @@ VisualScriptClassConstant::VisualScriptClassConstant() {
}
+//////////////////////////////////////////
+////////////////BASICTYPECONSTANT///////////
+//////////////////////////////////////////
+
+int VisualScriptBasicTypeConstant::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptBasicTypeConstant::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptBasicTypeConstant::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptBasicTypeConstant::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptBasicTypeConstant::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptBasicTypeConstant::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptBasicTypeConstant::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::INT,"value");
+}
+
+
+String VisualScriptBasicTypeConstant::get_caption() const {
+
+ return "BasicConst";
+}
+
+String VisualScriptBasicTypeConstant::get_text() const {
+
+ return Variant::get_type_name(type)+"."+String(name);
+}
+
+void VisualScriptBasicTypeConstant::set_basic_type_constant(const StringName& p_which) {
+
+ name=p_which;
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptBasicTypeConstant::get_basic_type_constant() const {
+ return name;
+}
+
+
+void VisualScriptBasicTypeConstant::set_basic_type(Variant::Type p_which) {
+
+ type=p_which;
+ _change_notify();
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const {
+ return type;
+}
+
+class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance {
+public:
+
+ int value;
+ bool valid;
+ //virtual int get_working_memory_size() const { return 0; }
+
+ 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="Invalid constant name, pick a valid basic type constant.";
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ }
+
+ *p_outputs[0] = value;
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptBasicTypeConstant::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceBasicTypeConstant * instance = memnew(VisualScriptNodeInstanceBasicTypeConstant );
+ instance->value=Variant::get_numeric_constant_value(type,name,&instance->valid);
+ return instance;
+}
+
+void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="constant") {
+
+ List<StringName> constants;
+ Variant::get_numeric_constants_for_type(type,&constants);
+
+ if (constants.size()==0) {
+ property.usage=0;
+ return;
+ }
+ property.hint_string="";
+ for(List<StringName>::Element *E=constants.front();E;E=E->next()) {
+ if (property.hint_string!=String()) {
+ property.hint_string+=",";
+ }
+ property.hint_string+=String(E->get());
+ }
+
+ }
+}
+
+void VisualScriptBasicTypeConstant::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_basic_type","name"),&VisualScriptBasicTypeConstant::set_basic_type);
+ ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptBasicTypeConstant::get_basic_type);
+
+ ObjectTypeDB::bind_method(_MD("set_basic_type_constant","name"),&VisualScriptBasicTypeConstant::set_basic_type_constant);
+ ObjectTypeDB::bind_method(_MD("get_basic_type_constant"),&VisualScriptBasicTypeConstant::get_basic_type_constant);
+
+
+ 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,"basic_type",PROPERTY_HINT_ENUM,argt),_SCS("set_basic_type"),_SCS("get_basic_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),_SCS("set_basic_type_constant"),_SCS("get_basic_type_constant"));
+}
+
+VisualScriptBasicTypeConstant::VisualScriptBasicTypeConstant() {
+
+ type=Variant::NIL;
+}
+
//////////////////////////////////////////
@@ -1782,6 +1933,19 @@ VisualScriptNodeInstance* VisualScriptEngineSingleton::instance(VisualScriptInst
return instance;
}
+VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess* p_inputs, int p_output) const {
+
+ Object *obj=Globals::get_singleton()->get_singleton_object(singleton);
+ TypeGuess tg;
+ tg.type=Variant::OBJECT;
+ if (obj) {
+ tg.obj_type=obj->get_type();
+ tg.script=obj->get_script();
+ }
+
+ return tg;
+}
+
void VisualScriptEngineSingleton::_bind_methods() {
@@ -1919,6 +2083,8 @@ VisualScriptNodeInstance* VisualScriptSceneNode::instance(VisualScriptInstance*
}
+
+
#ifdef TOOLS_ENABLED
static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) {
@@ -1942,6 +2108,49 @@ static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const R
#endif
+VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGuess* p_inputs, int p_output) const {
+
+
+ VisualScriptSceneNode::TypeGuess tg;
+ tg.type=Variant::OBJECT;
+ tg.obj_type="Node";
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_visual_script();
+ if (!script.is_valid())
+ return tg;
+
+ MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+ if (!main_loop)
+ return tg;
+
+ SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+ if (!scene_tree)
+ return tg;
+
+ Node *edited_scene = scene_tree->get_edited_scene_root();
+
+ if (!edited_scene)
+ return tg;
+
+ Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+ if (!script_node)
+ return tg;
+
+ Node* another = script_node->get_node(path);
+
+ if (another) {
+ tg.obj_type=another->get_type();
+ tg.script=another->get_script();
+ }
+#endif
+ return tg;
+
+}
+
+
void VisualScriptSceneNode::_validate_property(PropertyInfo& property) const {
#ifdef TOOLS_ENABLED
@@ -2079,6 +2288,13 @@ VisualScriptNodeInstance* VisualScriptSceneTree::instance(VisualScriptInstance*
return instance;
}
+VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGuess* p_inputs, int p_output) const {
+
+ TypeGuess tg;
+ tg.type=Variant::OBJECT;
+ tg.obj_type="SceneTree";
+ return tg;
+}
void VisualScriptSceneTree::_validate_property(PropertyInfo& property) const {
@@ -2270,6 +2486,23 @@ VisualScriptNodeInstance* VisualScriptSelf::instance(VisualScriptInstance* p_ins
return instance;
}
+VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess* p_inputs, int p_output) const {
+
+ VisualScriptSceneNode::TypeGuess tg;
+ tg.type=Variant::OBJECT;
+ tg.obj_type="Object";
+
+ Ref<Script> script = get_visual_script();
+ if (!script.is_valid())
+ return tg;
+
+ tg.obj_type=script->get_instance_base_type();
+ tg.script=script;
+
+ return tg;
+
+
+}
void VisualScriptSelf::_bind_methods() {
@@ -3247,13 +3480,29 @@ PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) cons
String VisualScriptInputAction::get_caption() const {
+
return "Action";
}
String VisualScriptInputAction::get_text() const {
- return name;
+ switch(mode) {
+ case MODE_PRESSED: {
+ return name;
+ } break;
+ case MODE_RELEASED: {
+ return "not "+name;
+ } break;
+ case MODE_JUST_PRESSED: {
+ return String(name)+" "+TTR("just pressed");
+ } break;
+ case MODE_JUST_RELEASED: {
+ return String(name)+" "+TTR("just released");
+ } break;
+ }
+
+ return String();
}
@@ -3278,19 +3527,50 @@ StringName VisualScriptInputAction::get_action_name() const {
return name;
}
+void VisualScriptInputAction::set_action_mode(Mode p_mode) {
+
+ if (mode==p_mode)
+ return;
+
+ mode=p_mode;
+ ports_changed_notify();
+
+}
+VisualScriptInputAction::Mode VisualScriptInputAction::get_action_mode() const {
+
+ return mode;
+}
+
class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance {
public:
VisualScriptInstance* instance;
StringName action;
+ VisualScriptInputAction::Mode mode;
virtual int get_working_memory_size() const { return 1; }
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_outputs[0]=Input::get_singleton()->is_action_pressed(action);
+ switch(mode) {
+ case VisualScriptInputAction::MODE_PRESSED: {
+ *p_outputs[0]=Input::get_singleton()->is_action_pressed(action);
+ } break;
+ case VisualScriptInputAction::MODE_RELEASED: {
+ *p_outputs[0]=!Input::get_singleton()->is_action_pressed(action);
+ } break;
+ case VisualScriptInputAction::MODE_JUST_PRESSED: {
+ *p_outputs[0]=Input::get_singleton()->is_action_just_pressed(action);
+ } break;
+ case VisualScriptInputAction:: MODE_JUST_RELEASED: {
+ *p_outputs[0]=Input::get_singleton()->is_action_just_released(action);
+ } break;
+
+ }
+
+
return 0;
}
@@ -3302,6 +3582,7 @@ VisualScriptNodeInstance* VisualScriptInputAction::instance(VisualScriptInstance
VisualScriptNodeInstanceInputAction * instance = memnew(VisualScriptNodeInstanceInputAction );
instance->instance=p_instance;
instance->action=name;
+ instance->mode=mode;
return instance;
}
@@ -3348,13 +3629,18 @@ 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);
+ ObjectTypeDB::bind_method(_MD("set_action_mode","mode"),&VisualScriptInputAction::set_action_mode);
+ ObjectTypeDB::bind_method(_MD("get_action_mode"),&VisualScriptInputAction::get_action_mode);
+
ADD_PROPERTY( PropertyInfo(Variant::STRING,"action"),_SCS("set_action_name"),_SCS("get_action_name"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Pressed,Released,JustPressed,JustReleased"),_SCS("set_action_mode"),_SCS("get_action_mode"));
}
VisualScriptInputAction::VisualScriptInputAction() {
name="";
+ mode=MODE_PRESSED;
}
@@ -3593,6 +3879,7 @@ void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("constants/math_constant",create_node_generic<VisualScriptMathConstant>);
VisualScriptLanguage::singleton->add_register_func("constants/class_constant",create_node_generic<VisualScriptClassConstant>);
VisualScriptLanguage::singleton->add_register_func("constants/global_constant",create_node_generic<VisualScriptGlobalConstant>);
+ VisualScriptLanguage::singleton->add_register_func("constants/basic_type_constant",create_node_generic<VisualScriptBasicTypeConstant>);
VisualScriptLanguage::singleton->add_register_func("custom/custom_node",create_node_generic<VisualScriptCustomNode>);
VisualScriptLanguage::singleton->add_register_func("custom/sub_call",create_node_generic<VisualScriptSubCall>);
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
index c0ffb17e15..94eeadca57 100644
--- a/modules/visual_script/visual_script_nodes.h
+++ b/modules/visual_script/visual_script_nodes.h
@@ -412,6 +412,48 @@ public:
VisualScriptClassConstant();
};
+class VisualScriptBasicTypeConstant : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptBasicTypeConstant,VisualScriptNode)
+
+ Variant::Type type;
+ StringName name;
+protected:
+ static void _bind_methods();
+ virtual void _validate_property(PropertyInfo& property) 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 "constants"; }
+
+ void set_basic_type_constant(const StringName& p_which);
+ StringName get_basic_type_constant() const;
+
+ void set_basic_type(Variant::Type p_which);
+ Variant::Type get_basic_type() const;
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ VisualScriptBasicTypeConstant();
+};
+
+
class VisualScriptMathConstant : public VisualScriptNode {
@@ -496,6 +538,9 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
+
VisualScriptEngineSingleton();
};
@@ -535,6 +580,8 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
VisualScriptSceneNode();
};
@@ -571,6 +618,8 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
VisualScriptSceneTree();
};
@@ -644,6 +693,8 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
VisualScriptSelf();
};
@@ -906,8 +957,16 @@ public:
class VisualScriptInputAction: public VisualScriptNode {
OBJ_TYPE(VisualScriptInputAction,VisualScriptNode)
+public:
+ enum Mode {
+ MODE_PRESSED,
+ MODE_RELEASED,
+ MODE_JUST_PRESSED,
+ MODE_JUST_RELEASED,
+ };
StringName name;
+ Mode mode;
protected:
@@ -936,12 +995,15 @@ public:
void set_action_name(const StringName& p_name);
StringName get_action_name() const;
+ void set_action_mode(Mode p_mode);
+ Mode get_action_mode() const;
+
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
VisualScriptInputAction();
};
-
+VARIANT_ENUM_CAST( VisualScriptInputAction::Mode )
class VisualScriptDeconstruct: public VisualScriptNode {