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.cpp13
-rw-r--r--modules/visual_script/visual_script.cpp316
-rw-r--r--modules/visual_script/visual_script.h45
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp15
-rw-r--r--modules/visual_script/visual_script_editor.cpp460
-rw-r--r--modules/visual_script/visual_script_editor.h34
-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.cpp151
-rw-r--r--modules/visual_script/visual_script_flow_control.h17
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp128
-rw-r--r--modules/visual_script/visual_script_func_nodes.h11
-rw-r--r--modules/visual_script/visual_script_nodes.cpp797
-rw-r--r--modules/visual_script/visual_script_nodes.h150
15 files changed, 3450 insertions, 408 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 50c3a4075f..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;
@@ -58,7 +59,9 @@ void register_visual_script_types() {
ObjectTypeDB::register_type<VisualScriptIndexGet>();
ObjectTypeDB::register_type<VisualScriptIndexSet>();
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>();
@@ -69,9 +72,11 @@ void register_visual_script_types() {
ObjectTypeDB::register_type<VisualScriptComment>();
ObjectTypeDB::register_type<VisualScriptConstructor>();
ObjectTypeDB::register_type<VisualScriptLocalVar>();
+ ObjectTypeDB::register_type<VisualScriptLocalVarSet>();
ObjectTypeDB::register_type<VisualScriptInputAction>();
ObjectTypeDB::register_type<VisualScriptDeconstruct>();
ObjectTypeDB::register_type<VisualScriptPreload>();
+ ObjectTypeDB::register_type<VisualScriptTypeCast>();
ObjectTypeDB::register_type<VisualScriptFunctionCall>();
@@ -86,7 +91,7 @@ void register_visual_script_types() {
ObjectTypeDB::register_type<VisualScriptIterator>();
ObjectTypeDB::register_type<VisualScriptSequence>();
ObjectTypeDB::register_type<VisualScriptInputFilter>();
- ObjectTypeDB::register_type<VisualScriptInputSelector>();
+ ObjectTypeDB::register_type<VisualScriptSwitch >();
ObjectTypeDB::register_type<VisualScriptYield>();
ObjectTypeDB::register_type<VisualScriptYieldSignal>();
@@ -94,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();
@@ -114,6 +122,9 @@ void unregister_visual_script_types() {
ScriptServer::unregister_language(visual_script_language);
+#ifdef TOOLS_ENABLED
+ VisualScriptEditor::free_clipboard();
+#endif
if (visual_script_language)
memdelete( visual_script_language );
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index f2fb371d6b..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
@@ -35,6 +35,7 @@ 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) {
@@ -42,6 +43,13 @@ 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;
+
+#ifdef TOOLS_ENABLED
+ for (Set<VisualScript*>::Element *E=scripts_used.front();E;E=E->next()) {
+ E->get()->set_edited(true);
+ }
+#endif
+
}
Variant VisualScriptNode::get_default_input_value(int p_port) const {
@@ -106,6 +114,19 @@ void VisualScriptNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("ports_changed"));
}
+VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess* p_inputs,int p_output) const {
+
+ PropertyInfo pinfo = get_output_value_port_info(p_output);
+
+ TypeGuess tg;
+
+ tg.type=pinfo.type;
+ if (pinfo.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+ tg.obj_type=pinfo.hint_string;
+ }
+
+ return tg;
+}
Ref<VisualScript> VisualScriptNode::get_visual_script() const {
@@ -113,7 +134,6 @@ Ref<VisualScript> VisualScriptNode::get_visual_script() const {
return Ref<VisualScript>(scripts_used.front()->get());
return Ref<VisualScript>();
-
}
VisualScriptNode::VisualScriptNode() {
@@ -133,15 +153,15 @@ VisualScriptNodeInstance::VisualScriptNodeInstance() {
VisualScriptNodeInstance::~VisualScriptNodeInstance() {
if (sequence_outputs) {
- memdelete(sequence_outputs);
+ memdelete_arr(sequence_outputs);
}
if (input_ports) {
- memdelete(input_ports);
+ memdelete_arr(input_ports);
}
if (output_ports) {
- memdelete(output_ports);
+ memdelete_arr(output_ports);
}
}
@@ -554,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));
@@ -564,7 +601,7 @@ void VisualScript::get_data_connection_list(const StringName& p_func,List<DataCo
}
}
-void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value) {
+void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value,bool p_export) {
ERR_FAIL_COND( instances.size() );
ERR_FAIL_COND(!String(p_name).is_valid_identifier());
@@ -575,10 +612,9 @@ void VisualScript::add_variable(const StringName& p_name,const Variant& p_defaul
v.info.type=p_default_value.get_type();
v.info.name=p_name;
v.info.hint=PROPERTY_HINT_NONE;
+ v._export=p_export;
variables[p_name]=v;
- script_variable_remap[SCRIPT_VARIABLES_PREFIX+String(p_name)]=p_name;
-
#ifdef TOOLS_ENABLED
_update_placeholders();
@@ -595,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();
@@ -612,6 +647,7 @@ void VisualScript::set_variable_default_value(const StringName& p_name,const Var
_update_placeholders();
#endif
+
}
Variant VisualScript::get_variable_default_value(const StringName& p_name) const{
@@ -638,6 +674,21 @@ PropertyInfo VisualScript::get_variable_info(const StringName& p_name) const{
return variables[p_name].info;
}
+void VisualScript::set_variable_export(const StringName& p_name,bool p_export) {
+
+ ERR_FAIL_COND(!variables.has(p_name));
+
+ variables[p_name]._export=p_export;
+}
+
+bool VisualScript::get_variable_export(const StringName& p_name) const {
+
+ ERR_FAIL_COND_V(!variables.has(p_name),false);
+ return variables[p_name]._export;
+
+}
+
+
void VisualScript::_set_variable_info(const StringName& p_name,const Dictionary& p_info) {
PropertyInfo pinfo;
@@ -870,8 +921,11 @@ void VisualScript::_update_placeholders() {
for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+ if (!E->get()._export)
+ 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;
}
@@ -903,8 +957,11 @@ ScriptInstance* VisualScript::instance_create(Object *p_this) {
for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+ if (!E->get()._export)
+ 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;
}
@@ -1002,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 {
@@ -1067,11 +1124,27 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const {
get_variable_list(&vars);
for (List<StringName>::Element *E=vars.front();E;E=E->next()) {
-
+ if (!variables[E->get()]._export)
+ continue;
p_list->push_back(variables[E->get()].info);
}
}
+#ifdef TOOLS_ENABLED
+bool VisualScript::are_subnodes_edited() const {
+
+ for(const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+ for (const Map<int,Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) {
+ if (F->get().node->is_edited()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+#endif
void VisualScript::_set_data(const Dictionary& p_data) {
@@ -1088,6 +1161,7 @@ void VisualScript::_set_data(const Dictionary& p_data) {
add_variable(name);
_set_variable_info(name,v);
set_variable_default_value(name,v["default_value"]);
+ set_variable_export(name,v.has("export") && bool(v["export"]));
}
@@ -1158,6 +1232,7 @@ Dictionary VisualScript::_get_data() const{
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;
+ var["export"]=E->get()._export;
vars.push_back(var);
}
d["variables"]=vars;
@@ -1268,13 +1343,15 @@ void VisualScript::_bind_methods() {
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("add_variable","name","default_value","export"),&VisualScript::add_variable,DEFVAL(Variant()),DEFVAL(false));
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("set_variable_export","name","enable"),&VisualScript::set_variable_export);
+ ObjectTypeDB::bind_method(_MD("get_variable_export","name"),&VisualScript::get_variable_export);
ObjectTypeDB::bind_method(_MD("rename_variable","name","new_name"),&VisualScript::rename_variable);
ObjectTypeDB::bind_method(_MD("add_custom_signal","name"),&VisualScript::add_custom_signal);
@@ -1323,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;
@@ -1338,35 +1413,28 @@ 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{
for (const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) {
+ 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;
@@ -1416,7 +1484,59 @@ bool VisualScriptInstance::has_method(const StringName& p_method) const{
//#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) {
+void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance* node,int p_pass,int *pass_stack,const Variant **input_args,Variant **output_args,Variant *variant_stack,Variant::CallError& r_error,String& error_str,VisualScriptNodeInstance** r_error_node) {
+
+ ERR_FAIL_COND(node->pass_idx==-1);
+
+ if (pass_stack[node->pass_idx]==p_pass)
+ return;
+
+ pass_stack[node->pass_idx]=p_pass;
+
+ if (!node->dependencies.empty()) {
+
+ int dc = node->dependencies.size();
+ VisualScriptNodeInstance **deps=node->dependencies.ptr();
+
+ for(int i=0;i<dc;i++) {
+
+ _dependency_step(deps[i],p_pass,pass_stack,input_args,output_args,variant_stack,r_error,error_str,r_error_node);
+ if (r_error.error!=Variant::CallError::CALL_OK)
+ return;
+
+ }
+ }
+
+
+ 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];
+ } else {
+ //regular temporary in stack
+ input_args[i]=&variant_stack[index];
+
+ }
+ }
+ for(int i=0 ; i<node->output_port_count ; i++) {
+ output_args[i] = &variant_stack[ node->output_ports[i] ];
+ }
+
+ Variant *working_mem=node->working_mem_idx>=0 ? &variant_stack[node->working_mem_idx] : (Variant*)NULL;
+
+ node->step(input_args,output_args,VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE,working_mem,r_error,error_str);
+ //ignore return
+ if (r_error.error!=Variant::CallError::CALL_OK) {
+ *r_error_node=node;
+ }
+
+}
+
+Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p_stack, int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Variant::CallError &r_error) {
Map<StringName,Function>::Element *F = functions.find(p_method);
ERR_FAIL_COND_V(!F,Variant());
@@ -1429,6 +1549,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p
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;
+ int *pass_stack = flow_stack + flow_max;
String error_str;
@@ -1448,6 +1569,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p
while(true) {
+ p_pass++; //increment pass
current_node_id=node->get_id();
VSDEBUG("==========AT NODE: "+itos(current_node_id)+" base: "+node->get_base_node()->get_type());
@@ -1466,41 +1588,46 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p
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++) {
+ //run dependencies first
- int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK;
+ if (!node->dependencies.empty()) {
- 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];
+ int dc = node->dependencies.size();
+ VisualScriptNodeInstance **deps=node->dependencies.ptr();
- Variant* ug_working_mem=ug->from->working_mem_idx>=0 ? &variant_stack[ug->from->working_mem_idx] : (Variant*)NULL;
+ for(int i=0;i<dc;i++) {
-
- 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();
+ _dependency_step(deps[i],p_pass,pass_stack,input_args,output_args,variant_stack,r_error,error_str,&node);
+ if (r_error.error!=Variant::CallError::CALL_OK) {
error=true;
- working_mem=NULL;
+ current_node_id=node->id;
break;
}
+ }
+ }
+
+ if (!error) {
+
+ //setup input pointers normally
+ VSDEBUG("INPUT PORTS: "+itos(node->input_port_count));
+
+ for(int i=0 ; i<node->input_port_count ; i++) {
- 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));
+ 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 {
+ //regular temporary in stack
+ input_args[i]=&variant_stack[index];
+ VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(index));
+
+ }
}
}
}
@@ -1567,6 +1694,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p
state->node=node;
state->flow_stack_pos=flow_stack_pos;
state->stack.resize(p_stack_size);
+ state->pass=p_pass;
copymem(state->stack.ptr(),p_stack,p_stack_size);
//step 2, run away, return directly
r_error.error=Variant::CallError::CALL_OK;
@@ -1768,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";
}
}
@@ -1834,6 +1966,7 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p
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
+ total_stack_size+=f->pass_stack_size*sizeof(int);
VSDEBUG("STACK SIZE: "+itos(total_stack_size));
VSDEBUG("STACK VARIANTS: : "+itos(f->max_stack));
@@ -1841,6 +1974,7 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p
VSDEBUG("MAX INPUT: "+itos(max_input_args));
VSDEBUG("MAX OUTPUT: "+itos(max_output_args));
VSDEBUG("FLOW STACK SIZE: "+itos(f->flow_stack_size));
+ VSDEBUG("PASS STACK SIZE: "+itos(f->pass_stack_size));
void *stack = alloca(total_stack_size);
@@ -1850,11 +1984,13 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p
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;
+ int *pass_stack = flow_stack + flow_max;
for(int i=0;i<f->node_count;i++) {
sequence_bits[i]=false; //all starts as false
}
+ zeromem(pass_stack,f->pass_stack_size*sizeof(int));
Map<int,VisualScriptNodeInstance*>::Element *E = instances.find(f->node);
if (!E) {
@@ -1897,7 +2033,7 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p
variant_stack[i]=*p_args[i];
}
- return _call_internal(p_method,stack,total_stack_size,node,0,false,r_error);
+ return _call_internal(p_method,stack,total_stack_size,node,0,0,false,r_error);
}
@@ -1969,6 +2105,7 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
for(const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) {
variables[E->key()]=E->get().default_value;
+ //no hacer que todo exporte, solo las que queres!
}
@@ -1978,6 +2115,7 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
function.node=E->get().function_id;
function.max_stack=0;
function.flow_stack_size=0;
+ function.pass_stack_size=0;
function.node_count=0;
Map<StringName,int> local_var_indices;
@@ -2018,15 +2156,20 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
instance->id=F->key();
instance->input_port_count = node->get_input_value_port_count();
+ instance->input_ports=NULL;
instance->output_port_count = node->get_output_value_port_count();
+ instance->output_ports=NULL;
instance->sequence_output_count = node->get_output_sequence_port_count();
instance->sequence_index=function.node_count++;
+ instance->sequence_outputs=NULL;
+ instance->pass_idx=-1;
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) {
@@ -2043,11 +2186,16 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
}
}
- if (node->cast_to<VisualScriptLocalVar>()) {
+ if (node->cast_to<VisualScriptLocalVar>() || node->cast_to<VisualScriptLocalVarSet>()) {
//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();
+ StringName var_name;
+
+ if (node->cast_to<VisualScriptLocalVar>())
+ var_name = String(node->cast_to<VisualScriptLocalVar>()->get_var_name()).strip_edges();
+ else
+ var_name = String(node->cast_to<VisualScriptLocalVarSet>()->get_var_name()).strip_edges();
if (!local_var_indices.has(var_name)) {
local_var_indices[var_name]=function.max_stack;
@@ -2092,24 +2240,17 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
}
- 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
+ if (from->get_sequence_output_count()==0 && to->dependencies.find(from)==-1) {
+ //if the node we are reading from has no output sequence, we must call step() before reading from it.
+ if (from->pass_idx==-1) {
+ from->pass_idx=function.pass_stack_size;
+ function.pass_stack_size++;
+ }
+ to->dependencies.push_back(from);
}
+ to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; //read from wherever the stack is
+
}
//third pass, do sequence connections
@@ -2244,7 +2385,7 @@ Variant VisualScriptFunctionState::_signal_callback(const Variant** p_args, int
*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);
+ Variant ret = instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,pass,true,r_error);
function=StringName(); //invalidate
return ret;
}
@@ -2286,7 +2427,7 @@ Variant VisualScriptFunctionState::resume(Array p_args) {
*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);
+ Variant ret= instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,pass,true,r_error);
function=StringName(); //invalidate
return ret;
}
@@ -2489,7 +2630,7 @@ void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String>
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];
+// 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);
@@ -2512,8 +2653,6 @@ void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String>
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] );
}
@@ -2664,7 +2803,6 @@ void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) {
VisualScriptLanguage::VisualScriptLanguage() {
notification="_notification";
- _get_output_port_unsequenced="_get_output_port_unsequenced";
_step="_step";
_subcall="_subcall";
singleton=this;
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index c9734d1b11..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;
@@ -58,6 +60,18 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance)=0;
+ struct TypeGuess {
+
+ Variant::Type type;
+ InputEvent::Type ev_type;
+ StringName obj_type;
+ Ref<Script> script;
+
+ TypeGuess() { type=Variant::NIL; ev_type=InputEvent::NONE; }
+ };
+
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
VisualScriptNode();
};
@@ -71,7 +85,6 @@ friend class VisualScriptLanguage; //for debugger
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).
};
@@ -79,11 +92,13 @@ friend class VisualScriptLanguage; //for debugger
int sequence_index;
VisualScriptNodeInstance **sequence_outputs;
int sequence_output_count;
+ Vector<VisualScriptNodeInstance*> dependencies;
int *input_ports;
int input_port_count;
int *output_ports;
int output_port_count;
int working_mem_idx;
+ int pass_idx;
VisualScriptNode *base;
@@ -117,10 +132,6 @@ public:
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 ); }
@@ -209,13 +220,13 @@ friend class VisualScriptInstance;
struct Variable {
PropertyInfo info;
Variant default_value;
+ bool _export;
};
Map<StringName,Function> functions;
Map<StringName,Variable> variables;
- Map<StringName,StringName> script_variable_remap;
Map<StringName,Vector<Argument> > custom_signals;
Map<Object*,VisualScriptInstance*> instances;
@@ -269,14 +280,17 @@ 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());
+ 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;
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 set_variable_export(const StringName& p_name,bool p_export);
+ bool get_variable_export(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);
@@ -330,6 +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();
@@ -349,18 +366,10 @@ class VisualScriptInstance : public ScriptInstance {
int trash_pos;
int return_pos;
int flow_stack_size;
+ int pass_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;
@@ -370,7 +379,8 @@ class VisualScriptInstance : public ScriptInstance {
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);
+ void _dependency_step(VisualScriptNodeInstance* node, int p_pass, int *pass_stack, const Variant **input_args, Variant **output_args, Variant *variant_stack, Variant::CallError& r_error, String& error_str, VisualScriptNodeInstance **r_error_node);
+ Variant _call_internal(const StringName& p_method, void* p_stack,int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield,Variant::CallError &r_error);
//Map<StringName,Function> functions;
@@ -439,6 +449,7 @@ friend class VisualScriptInstance;
int variant_stack_size;
VisualScriptNodeInstance *node;
int flow_stack_pos;
+ int pass;
Variant _signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
protected:
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index e813d9ea84..1d0bca0b30 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -69,12 +69,23 @@ const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
int VisualScriptBuiltinFunc::get_output_sequence_port_count() const {
- return 1;
+ return has_input_sequence_port() ? 1 : 0;
}
bool VisualScriptBuiltinFunc::has_input_sequence_port() const{
- return true;
+ switch(func) {
+
+ case MATH_RANDOMIZE:
+ case TEXT_PRINT:
+ case TEXT_PRINTERR:
+ case TEXT_PRINTRAW:
+ return true;
+ default:
+ return false;
+
+ }
+
}
int VisualScriptBuiltinFunc::get_input_value_port_count() const{
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index f10e4db9c9..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"
@@ -242,6 +243,11 @@ protected:
return true;
}
+ if (String(p_name)=="export") {
+ script->set_variable_export(var,p_value);
+ return true;
+ }
+
return false;
}
@@ -271,6 +277,11 @@ protected:
return true;
}
+ if (String(p_name)=="export") {
+ r_ret=script->get_variable_export(var);
+ return true;
+ }
+
return false;
}
void _get_property_list( List<PropertyInfo> *p_list) const {
@@ -286,6 +297,7 @@ protected:
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"));
+ p_list->push_back(PropertyInfo(Variant::BOOL,"export"));
}
@@ -494,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;
@@ -512,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;
@@ -543,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;
@@ -609,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)));
@@ -628,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++;
}
@@ -685,12 +720,48 @@ void VisualScriptEditor::_update_members() {
variables->add_button(0,Control::get_icon("Add","EditorIcons"));
variables->set_custom_bg_color(0,Control::get_color("prop_section","Editor"));
+ 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")
+ };
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());
+ Variant var = script->get_variable_default_value(E->get());
+ ti->set_suffix(0,"="+String(var));
+ ti->set_icon(0,type_icons[script->get_variable_info(E->get()).type]);
+
ti->set_selectable(0,true);
ti->set_editable(0,true);
ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0);
@@ -2080,7 +2151,8 @@ Ref<Texture> VisualScriptEditor::get_icon(){
bool VisualScriptEditor::is_unsaved(){
#ifdef TOOLS_ENABLED
- return script->is_edited();
+
+ return script->is_edited() || script->are_subnodes_edited();
#else
return false;
#endif
@@ -2510,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() {
@@ -2675,9 +3056,9 @@ void VisualScriptEditor::_menu_option(int p_what) {
if (!script->has_function(edited_func))
break;
- clipboard.nodes.clear();
- clipboard.data_connections.clear();
- clipboard.sequence_connections.clear();
+ 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>();
@@ -2691,15 +3072,15 @@ void VisualScriptEditor::_menu_option(int p_what) {
return;
}
if (node.is_valid()) {
- clipboard.nodes[id]=node->duplicate();
- clipboard.nodes_positions[id]=script->get_node_pos(edited_func,id);
+ clipboard->nodes[id]=node->duplicate();
+ clipboard->nodes_positions[id]=script->get_node_pos(edited_func,id);
}
}
}
}
- if (clipboard.nodes.empty())
+ if (clipboard->nodes.empty())
break;
List<VisualScript::SequenceConnection> sequence_connections;
@@ -2708,9 +3089,9 @@ void VisualScriptEditor::_menu_option(int p_what) {
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)) {
+ if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
- clipboard.sequence_connections.insert(E->get());
+ clipboard->sequence_connections.insert(E->get());
}
}
@@ -2720,9 +3101,9 @@ void VisualScriptEditor::_menu_option(int p_what) {
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)) {
+ if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
- clipboard.data_connections.insert(E->get());
+ clipboard->data_connections.insert(E->get());
}
}
@@ -2736,7 +3117,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
if (!script->has_function(edited_func))
break;
- if (clipboard.nodes.empty()) {
+ if (clipboard->nodes.empty()) {
EditorNode::get_singleton()->show_warning("Clipboard is empty!");
break;
}
@@ -2759,7 +3140,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
}
- for (Map<int,Ref<VisualScriptNode> >::Element *E=clipboard.nodes.front();E;E=E->next()) {
+ for (Map<int,Ref<VisualScriptNode> >::Element *E=clipboard->nodes.front();E;E=E->next()) {
Ref<VisualScriptNode> node = E->get()->duplicate();
@@ -2769,7 +3150,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
remap[E->key()]=new_id;
- Vector2 paste_pos = clipboard.nodes_positions[E->key()];
+ Vector2 paste_pos = clipboard->nodes_positions[E->key()];
while(existing_positions.has(paste_pos.snapped(Vector2(2,2)))) {
paste_pos+=Vector2(20,20)*EDSCALE;
@@ -2781,7 +3162,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
- for (Set<VisualScript::SequenceConnection>::Element *E=clipboard.sequence_connections.front();E;E=E->next()) {
+ 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]);
@@ -2789,7 +3170,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
- for (Set<VisualScript::DataConnection>::Element *E=clipboard.data_connections.front();E;E=E->next()) {
+ 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);
@@ -2841,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);
@@ -2874,6 +3257,9 @@ void VisualScriptEditor::_bind_methods() {
VisualScriptEditor::VisualScriptEditor() {
+ if (!clipboard) {
+ clipboard = memnew( Clipboard );
+ }
updating_graph=false;
edit_menu = memnew( MenuButton );
@@ -2898,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);
@@ -3042,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() {
@@ -3060,6 +3455,14 @@ static ScriptEditorBase * create_editor(const Ref<Script>& p_script) {
return NULL;
}
+
+VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard=NULL;
+
+void VisualScriptEditor::free_clipboard() {
+ if (clipboard)
+ memdelete(clipboard);
+}
+
static void register_editor_callback() {
ScriptEditor::register_create_script_editor_function(create_editor);
@@ -3068,6 +3471,7 @@ static void register_editor_callback() {
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));
+ EditorSettings::get_singleton()->set("visual_script_editor/color_constants",Color(1.0,0.8,1.0));
ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"));
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 735eaae446..5191ed540a 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -13,6 +13,7 @@ class VisualScriptEditorVariableEdit;
#ifdef TOOLS_ENABLED
+
class VisualScriptEditor : public ScriptEditorBase {
OBJ_TYPE(VisualScriptEditor,ScriptEditorBase)
@@ -32,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;
@@ -52,6 +66,7 @@ class VisualScriptEditor : public ScriptEditorBase {
PropertyEditor *edit_signal_edit;
PropertySelector *method_select;
+ PropertySelector *new_connect_node_select;
VisualScriptEditorVariableEdit *variable_editor;
@@ -109,7 +124,19 @@ class VisualScriptEditor : public ScriptEditorBase {
Set<VisualScript::SequenceConnection> sequence_connections;
Set<VisualScript::DataConnection> data_connections;
- } clipboard;
+ };
+
+ 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;
@@ -142,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);
@@ -170,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:
@@ -203,6 +233,8 @@ public:
static void register_editor();
+ static void free_clipboard();
+
VisualScriptEditor();
~VisualScriptEditor();
};
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 700d5d57ff..97338da187 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -603,70 +603,64 @@ VisualScriptSequence::VisualScriptSequence() {
////////////////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 {
+int VisualScriptSwitch::get_output_sequence_port_count() const {
- return InputEvent::TYPE_MAX;
+ return case_values.size()+1;
}
-bool VisualScriptInputSelector::has_input_sequence_port() const{
+bool VisualScriptSwitch::has_input_sequence_port() const{
return true;
}
-int VisualScriptInputSelector::get_input_value_port_count() const{
+int VisualScriptSwitch::get_input_value_port_count() const{
- return 1;
+ return case_values.size()+1;
}
-int VisualScriptInputSelector::get_output_value_port_count() const{
+int VisualScriptSwitch::get_output_value_port_count() const{
- return 1;
+ return 0;
}
-String VisualScriptInputSelector::get_output_sequence_port_text(int p_port) const {
+String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const {
- return event_type_names[p_port];
+ if (p_port==case_values.size())
+ return "done";
+
+ return String();
}
-PropertyInfo VisualScriptInputSelector::get_input_value_port_info(int p_idx) const{
+PropertyInfo VisualScriptSwitch::get_input_value_port_info(int p_idx) const{
- return PropertyInfo(Variant::INPUT_EVENT,"event");
+ if (p_idx<case_values.size()) {
+ return PropertyInfo(case_values[p_idx].type," =");
+ } else
+ return PropertyInfo(Variant::NIL,"input");
}
-PropertyInfo VisualScriptInputSelector::get_output_value_port_info(int p_idx) const{
+PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const{
- return PropertyInfo(Variant::INPUT_EVENT,"");
+ return PropertyInfo();
}
-String VisualScriptInputSelector::get_caption() const {
+String VisualScriptSwitch::get_caption() const {
- return "InputSelector";
+ return "Switch";
}
-String VisualScriptInputSelector::get_text() const {
+String VisualScriptSwitch::get_text() const {
- return "";
+ return "'input' is:";
}
-class VisualScriptNodeInstanceInputSelector : public VisualScriptNodeInstance {
+class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance {
public:
VisualScriptInstance* instance;
- InputEvent::Type type;
+ int case_count;
//virtual int get_working_memory_size() const { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
@@ -674,37 +668,95 @@ 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_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;
+ if (p_start_mode==START_MODE_CONTINUE_SEQUENCE) {
+ return case_count; //exit
}
- InputEvent event = *p_inputs[0];
+ for(int i=0;i<case_count;i++) {
- *p_outputs[0] = event;
+ if (*p_inputs[i]==*p_inputs[case_count]) {
+ return i|STEP_FLAG_PUSH_STACK_BIT;
+ }
+ }
- return event.type;
+ return case_count;
}
};
-VisualScriptNodeInstance* VisualScriptInputSelector::instance(VisualScriptInstance* p_instance) {
+VisualScriptNodeInstance* VisualScriptSwitch::instance(VisualScriptInstance* p_instance) {
- VisualScriptNodeInstanceInputSelector * instance = memnew(VisualScriptNodeInstanceInputSelector );
+ VisualScriptNodeInstanceSwitch * instance = memnew(VisualScriptNodeInstanceSwitch );
instance->instance=p_instance;
+ instance->case_count=case_values.size();
return instance;
}
+bool VisualScriptSwitch::_set(const StringName& p_name, const Variant& p_value) {
+
+ if (String(p_name)=="case_count") {
+ case_values.resize(p_value);
+ _change_notify();
+ ports_changed_notify();
+ return true;
+ }
+
+ if (String(p_name).begins_with("case/")) {
+
+ int idx = String(p_name).get_slice("/",1).to_int();
+ ERR_FAIL_INDEX_V(idx,case_values.size(),false);
+
+ case_values[idx].type=Variant::Type(int(p_value));
+ _change_notify();
+ ports_changed_notify();
+
+ return true;
+ }
+
+ return false;
+}
+
+bool VisualScriptSwitch::_get(const StringName& p_name,Variant &r_ret) const {
+
+ if (String(p_name)=="case_count") {
+ r_ret=case_values.size();
+ return true;
+ }
+
+ if (String(p_name).begins_with("case/")) {
+
+ int idx = String(p_name).get_slice("/",1).to_int();
+ ERR_FAIL_INDEX_V(idx,case_values.size(),false);
+
+ r_ret=case_values[idx].type;
+ return true;
+ }
+
+ return false;
+
+}
+void VisualScriptSwitch::_get_property_list( List<PropertyInfo> *p_list) const {
+
+ p_list->push_back(PropertyInfo(Variant::INT,"case_count",PROPERTY_HINT_RANGE,"0,128"));
+
+ 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<case_values.size();i++) {
+ p_list->push_back(PropertyInfo(Variant::INT,"case/"+itos(i),PROPERTY_HINT_ENUM,argt));
+ }
+}
-void VisualScriptInputSelector::_bind_methods() {
+void VisualScriptSwitch::_bind_methods() {
}
-VisualScriptInputSelector::VisualScriptInputSelector() {
+VisualScriptSwitch::VisualScriptSwitch() {
}
@@ -1359,6 +1411,19 @@ bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) cons
}
return false;
}
+
+static const char* event_type_names[InputEvent::TYPE_MAX]={
+ "None",
+ "Key",
+ "MouseMotion",
+ "MouseButton",
+ "JoystickMotion",
+ "JoystickButton",
+ "ScreenTouch",
+ "ScreenDrag",
+ "Action"
+};
+
void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT,"filter_count",PROPERTY_HINT_RANGE,"0,64"));
@@ -1866,7 +1931,7 @@ void register_visual_script_flow_control_nodes() {
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/switch",create_node_generic<VisualScriptSwitch>);
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
index 42fab2e44d..e0da84a534 100644
--- a/modules/visual_script/visual_script_flow_control.h
+++ b/modules/visual_script/visual_script_flow_control.h
@@ -197,14 +197,24 @@ public:
-class VisualScriptInputSelector : public VisualScriptNode {
+class VisualScriptSwitch : public VisualScriptNode {
- OBJ_TYPE(VisualScriptInputSelector,VisualScriptNode)
+ OBJ_TYPE(VisualScriptSwitch,VisualScriptNode)
+ struct Case {
+ Variant::Type type;
+ Case() { type=Variant::NIL; }
+ };
+ Vector<Case> case_values;
+friend class VisualScriptNodeInstanceSwitch;
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;
+
static void _bind_methods();
public:
@@ -213,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;
@@ -229,7 +240,7 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
- VisualScriptInputSelector();
+ VisualScriptSwitch();
};
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 7414447279..de99beacaf 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -12,12 +12,18 @@
int VisualScriptFunctionCall::get_output_sequence_port_count() const {
- return 1;
+ if (method_cache.flags&METHOD_FLAG_CONST || call_mode==CALL_MODE_BASIC_TYPE)
+ return 0;
+ else
+ return 1;
}
bool VisualScriptFunctionCall::has_input_sequence_port() const{
- return true;
+ if (method_cache.flags&METHOD_FLAG_CONST || call_mode==CALL_MODE_BASIC_TYPE)
+ return false;
+ else
+ return true;
}
#ifdef TOOLS_ENABLED
@@ -403,6 +409,10 @@ void VisualScriptFunctionCall::_update_method_cache() {
#endif
}
+ if (mb->is_const()) {
+ method_cache.flags|=METHOD_FLAG_CONST;
+ }
+
#ifdef DEBUG_METHODS_ENABLED
method_cache.return_val = mb->get_argument_info(-1);
@@ -503,6 +513,15 @@ int VisualScriptFunctionCall::get_use_default_args() const{
}
+void VisualScriptFunctionCall::set_validate(bool p_amount) {
+
+ validate=p_amount;
+}
+
+bool VisualScriptFunctionCall::get_validate() const {
+
+ return validate;
+}
void VisualScriptFunctionCall::_set_argument_cache(const Dictionary& p_cache) {
@@ -690,6 +709,9 @@ void VisualScriptFunctionCall::_bind_methods() {
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);
+ ObjectTypeDB::bind_method(_MD("set_validate","enable"),&VisualScriptFunctionCall::set_validate);
+ ObjectTypeDB::bind_method(_MD("get_validate"),&VisualScriptFunctionCall::get_validate);
+
String bt;
for(int i=0;i<Variant::VARIANT_MAX;i++) {
if (i>0)
@@ -722,6 +744,7 @@ void VisualScriptFunctionCall::_bind_methods() {
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::BOOL,"function/validate"),_SCS("set_validate"),_SCS("get_validate"));
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 );
@@ -737,6 +760,7 @@ public:
VisualScriptFunctionCall::CallMode call_mode;
NodePath node_path;
int input_args;
+ bool validate;
bool returns;
VisualScriptFunctionCall::RPCCallMode rpc_mode;
StringName function;
@@ -864,7 +888,16 @@ public:
object->call(function,p_inputs,input_args,r_error);
}
} break;
+
}
+
+ if (!validate) {
+
+ //ignore call errors if validation is disabled
+ r_error.error=Variant::CallError::CALL_OK;
+ r_error_str=String();
+ }
+
return 0;
}
@@ -884,10 +917,24 @@ VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstanc
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;
+ 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;
call_mode=CALL_MODE_SELF;
basic_type=Variant::NIL;
use_default_args=0;
@@ -926,12 +973,12 @@ static const char* event_type_names[InputEvent::TYPE_MAX]={
int VisualScriptPropertySet::get_output_sequence_port_count() const {
- return 1;
+ return call_mode!=CALL_MODE_BASIC_TYPE ? 1 : 0;
}
bool VisualScriptPropertySet::has_input_sequence_port() const{
- return true;
+ return call_mode!=CALL_MODE_BASIC_TYPE ? true : false;
}
Node *VisualScriptPropertySet::_get_base_node() const {
@@ -1565,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;
@@ -1590,12 +1648,12 @@ static Ref<VisualScriptNode> create_property_set_node(const String& p_name) {
int VisualScriptPropertyGet::get_output_sequence_port_count() const {
- return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1;
+ return 0;// (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;
+ return false;//(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
@@ -2130,12 +2188,10 @@ public:
VisualScriptInstance *instance;
+ 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) {
+
- //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: {
@@ -2144,63 +2200,57 @@ public:
bool valid;
- *r_value = object->get(property,&valid);
+ *p_outputs[0] = object->get(property,&valid);
if (!valid) {
- //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
- r_error=RTR("Invalid index property name.");
- return false;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Invalid index property name.");
+ return 0;
}
} 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;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("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=RTR("Path does not lead Node!");
- return false;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Path does not lead Node!");
+ return 0;
}
bool valid;
- *r_value = another->get(property,&valid);
+ *p_outputs[0] = 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;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=vformat(RTR("Invalid index property name '%s' in node %s."),String(property),another->get_name());
+ return 0;
}
} 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) {
+ default: {
+ bool valid;
+ Variant v = *p_inputs[0];
- bool valid;
- Variant v = *p_inputs[0];
-
- *p_outputs[0] = v.get(property,&valid);
+ *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.");
+ if (!valid) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("Invalid index property name.");
+ }
+ };
}
-
return 0;
}
diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h
index f958da8222..43ef276cf4 100644
--- a/modules/visual_script/visual_script_func_nodes.h
+++ b/modules/visual_script/visual_script_func_nodes.h
@@ -35,6 +35,7 @@ private:
int use_default_args;
RPCCallMode rpc_call_mode;
StringName singleton;
+ bool validate;
Node *_get_base_node() const;
@@ -96,11 +97,17 @@ public:
void set_use_default_args(int p_amount);
int get_use_default_args() const;
+ void set_validate(bool p_amount);
+ bool get_validate() const;
+
void set_rpc_call_mode(RPCCallMode p_mode);
RPCCallMode get_rpc_call_mode() const;
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
+
VisualScriptFunctionCall();
};
@@ -191,6 +198,7 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
VisualScriptPropertySet();
};
@@ -328,6 +336,9 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+
+
VisualScriptEmitSignal();
};
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index 21a27b91a3..7ada292b13 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -254,8 +254,6 @@ 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 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) {
@@ -326,12 +324,12 @@ int VisualScriptFunction::get_stack_size() const {
int VisualScriptOperator::get_output_sequence_port_count() const {
- return 1;
+ return 0;
}
bool VisualScriptOperator::has_input_sequence_port() const{
- return true;
+ return false;
}
int VisualScriptOperator::get_input_value_port_count() const{
@@ -555,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"));
}
@@ -567,8 +565,6 @@ public:
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) {
@@ -732,20 +728,14 @@ public:
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) {
+ if (instance->get_variable(variable,p_outputs[0])==false) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str=RTR("VariableGet not found in script: ")+"'"+String(variable)+"'";
+ return false;
+ }
return 0;
}
@@ -767,7 +757,7 @@ VisualScriptVariableGet::VisualScriptVariableGet() {
//////////////////////////////////////////
-////////////////VARIABLE GET//////////////////
+////////////////VARIABLE SET//////////////////
//////////////////////////////////////////
int VisualScriptVariableSet::get_output_sequence_port_count() const {
@@ -875,17 +865,16 @@ public:
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.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str=RTR("VariableSet not found in script: ")+"'"+String(variable)+"'";
}
-
return 0;
}
@@ -1024,17 +1013,10 @@ 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) {
+ *p_outputs[0]=constant;
return 0;
}
@@ -1089,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;
}
@@ -1144,17 +1132,10 @@ 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) {
+ *p_outputs[0]=preload;
return 0;
}
@@ -1181,12 +1162,12 @@ VisualScriptPreload::VisualScriptPreload() {
int VisualScriptIndexGet::get_output_sequence_port_count() const {
- return 1;
+ return 0;
}
bool VisualScriptIndexGet::has_input_sequence_port() const{
- return true;
+ return false;
}
int VisualScriptIndexGet::get_input_value_port_count() const{
@@ -1235,8 +1216,6 @@ 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) {
@@ -1327,8 +1306,6 @@ 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) {
@@ -1424,17 +1401,11 @@ 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) {
+ *p_outputs[0] = GlobalConstants::get_global_constant_value(index);
return 0;
}
@@ -1469,6 +1440,286 @@ VisualScriptGlobalConstant::VisualScriptGlobalConstant() {
index=0;
}
+//////////////////////////////////////////
+////////////////CLASSCONSTANT///////////
+//////////////////////////////////////////
+
+int VisualScriptClassConstant::get_output_sequence_port_count() const {
+
+ return 0;
+}
+
+bool VisualScriptClassConstant::has_input_sequence_port() const{
+
+ return false;
+}
+
+int VisualScriptClassConstant::get_input_value_port_count() const{
+
+ return 0;
+}
+int VisualScriptClassConstant::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptClassConstant::get_output_sequence_port_text(int p_port) const {
+
+ return String();
+}
+
+PropertyInfo VisualScriptClassConstant::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo();
+}
+
+PropertyInfo VisualScriptClassConstant::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(Variant::INT,"value");
+}
+
+
+String VisualScriptClassConstant::get_caption() const {
+
+ return "ClassConst";
+}
+
+String VisualScriptClassConstant::get_text() const {
+
+ return String(base_type)+"."+String(name);
+}
+
+void VisualScriptClassConstant::set_class_constant(const StringName& p_which) {
+
+ name=p_which;
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptClassConstant::get_class_constant() {
+ return name;
+}
+
+
+void VisualScriptClassConstant::set_base_type(const StringName& p_which) {
+
+ base_type=p_which;
+ _change_notify();
+ ports_changed_notify();
+}
+
+StringName VisualScriptClassConstant::get_base_type() {
+ return base_type;
+}
+
+class VisualScriptNodeInstanceClassConstant : 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 class constant.";
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ }
+
+ *p_outputs[0] = value;
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptClassConstant::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceClassConstant * instance = memnew(VisualScriptNodeInstanceClassConstant );
+ instance->value=ObjectTypeDB::get_integer_constant(base_type,name,&instance->valid);
+ return instance;
+}
+
+void VisualScriptClassConstant::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="constant") {
+
+ List<String> constants;
+ ObjectTypeDB::get_integer_constant_list(base_type,&constants,true);
+
+ property.hint_string="";
+ for(List<String>::Element *E=constants.front();E;E=E->next()) {
+ if (property.hint_string!=String()) {
+ property.hint_string+=",";
+ }
+ property.hint_string+=E->get();
+ }
+ }
+}
+
+void VisualScriptClassConstant::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_class_constant","name"),&VisualScriptClassConstant::set_class_constant);
+ ObjectTypeDB::bind_method(_MD("get_class_constant"),&VisualScriptClassConstant::get_class_constant);
+
+ ObjectTypeDB::bind_method(_MD("set_base_type","name"),&VisualScriptClassConstant::set_base_type);
+ ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptClassConstant::get_base_type);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+ ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),_SCS("set_class_constant"),_SCS("get_class_constant"));
+}
+
+VisualScriptClassConstant::VisualScriptClassConstant() {
+
+ base_type="Object";
+}
+
+
+//////////////////////////////////////////
+////////////////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;
+}
+
//////////////////////////////////////////
@@ -1556,17 +1807,10 @@ 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) {
-
+ *p_outputs[0]=value;
return 0;
}
@@ -1673,16 +1917,10 @@ 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) {
-
+ *p_outputs[0]=singleton;
return 0;
}
@@ -1695,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() {
@@ -1795,28 +2046,26 @@ public:
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 {
+
+ 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) {
Node* node = instance->get_owner_ptr()->cast_to<Node>();
if (!node) {
- r_error="Base object is not a Node!";
- return false;
+ 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(path);
if (!node) {
- r_error="Path does not lead Node!";
- return false;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Path does not lead Node!";
+ return 0;
}
- *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) {
+ *p_outputs[0]=another;
return 0;
}
@@ -1834,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) {
@@ -1857,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
@@ -1961,28 +2255,24 @@ 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 {
+
+ 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) {
Node* node = instance->get_owner_ptr()->cast_to<Node>();
if (!node) {
- r_error="Base object is not a Node!";
- return false;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Base object is not a Node!";
+ return 0;
}
SceneTree* tree = node->get_tree();
if (!tree) {
- r_error="Attempt to get SceneTree while node is not in the active tree.";
- return false;
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error_str="Attempt to get SceneTree while node is not in the active tree.";
+ return 0;
}
- *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) {
-
+ *p_outputs[0]=tree;
return 0;
}
@@ -1998,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 {
@@ -2079,14 +2376,10 @@ 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) {
+ *p_outputs[0] = path;
return 0;
}
@@ -2176,15 +2469,10 @@ 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) {
+ *p_outputs[0] = instance->get_owner_ptr();
return 0;
}
@@ -2198,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() {
@@ -2310,35 +2615,8 @@ public:
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()) {
@@ -2411,10 +2689,6 @@ VisualScriptNodeInstance* VisualScriptCustomNode::instance(VisualScriptInstance*
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");
@@ -2447,8 +2721,6 @@ void VisualScriptCustomNode::_bind_methods() {
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 );
@@ -2560,8 +2832,6 @@ public:
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) {
@@ -2705,8 +2975,6 @@ 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) {
@@ -2757,12 +3025,12 @@ VisualScriptComment::VisualScriptComment() {
int VisualScriptConstructor::get_output_sequence_port_count() const {
- return 1;
+ return 0;
}
bool VisualScriptConstructor::has_input_sequence_port() const{
- return true;
+ return false;
}
int VisualScriptConstructor::get_input_value_port_count() const{
@@ -2823,6 +3091,7 @@ Variant::Type VisualScriptConstructor::get_constructor_type() const {
void VisualScriptConstructor::set_constructor(const Dictionary& p_info) {
constructor=MethodInfo::from_dict(p_info);
+ ports_changed_notify();
}
Dictionary VisualScriptConstructor::get_constructor() const {
@@ -2839,8 +3108,6 @@ public:
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) {
@@ -2906,16 +3173,16 @@ static Ref<VisualScriptNode> create_constructor_node(const String& p_name) {
int VisualScriptLocalVar::get_output_sequence_port_count() const {
- return 1;
+ return 0;
}
bool VisualScriptLocalVar::has_input_sequence_port() const{
- return true;
+ return false;
}
int VisualScriptLocalVar::get_input_value_port_count() const{
- return 1;
+ return 0;
}
int VisualScriptLocalVar::get_output_value_port_count() const{
@@ -2929,7 +3196,7 @@ String VisualScriptLocalVar::get_output_sequence_port_text(int p_port) const {
PropertyInfo VisualScriptLocalVar::get_input_value_port_info(int p_idx) const{
- return PropertyInfo(type,"set");
+ return PropertyInfo();
}
PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const{
@@ -2939,7 +3206,7 @@ PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const{
String VisualScriptLocalVar::get_caption() const {
- return "LocalVar";
+ return "LocalVarGet";
}
@@ -2990,15 +3257,8 @@ public:
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;
}
@@ -3047,6 +3307,144 @@ VisualScriptLocalVar::VisualScriptLocalVar() {
////////////////LocalVar///////////
//////////////////////////////////////////
+int VisualScriptLocalVarSet::get_output_sequence_port_count() const {
+
+ return 1;
+}
+
+bool VisualScriptLocalVarSet::has_input_sequence_port() const{
+
+ return true;
+}
+
+int VisualScriptLocalVarSet::get_input_value_port_count() const{
+ return 1;
+}
+int VisualScriptLocalVarSet::get_output_value_port_count() const{
+
+ return 1;
+}
+
+String VisualScriptLocalVarSet::get_output_sequence_port_text(int p_port) const {
+
+ return "";
+}
+
+PropertyInfo VisualScriptLocalVarSet::get_input_value_port_info(int p_idx) const{
+
+ return PropertyInfo(type,"set");
+}
+PropertyInfo VisualScriptLocalVarSet::get_output_value_port_info(int p_idx) const{
+
+ return PropertyInfo(type,"get");
+}
+
+
+String VisualScriptLocalVarSet::get_caption() const {
+
+ return "LocalVarSet";
+}
+
+
+String VisualScriptLocalVarSet::get_text() const {
+
+ return name;
+}
+
+
+String VisualScriptLocalVarSet::get_category() const {
+
+ return "data";
+}
+
+
+void VisualScriptLocalVarSet::set_var_name(const StringName& p_name) {
+
+ if (name==p_name)
+ return;
+
+ name=p_name;
+ ports_changed_notify();
+
+}
+
+StringName VisualScriptLocalVarSet::get_var_name() const {
+
+ return name;
+}
+
+void VisualScriptLocalVarSet::set_var_type(Variant::Type p_type) {
+
+ type=p_type;
+ ports_changed_notify();
+}
+
+Variant::Type VisualScriptLocalVarSet::get_var_type() const {
+
+ return type;
+}
+
+
+class VisualScriptNodeInstanceLocalVarSet : public VisualScriptNodeInstance {
+public:
+
+ VisualScriptInstance* instance;
+ StringName name;
+
+
+ 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_working_mem=*p_inputs[0];
+ *p_outputs[0]=*p_working_mem;
+ return 0;
+ }
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptLocalVarSet::instance(VisualScriptInstance* p_instance) {
+
+ VisualScriptNodeInstanceLocalVarSet * instance = memnew(VisualScriptNodeInstanceLocalVarSet );
+ instance->instance=p_instance;
+ instance->name=name;
+
+ return instance;
+}
+
+
+
+void VisualScriptLocalVarSet::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_var_name","name"),&VisualScriptLocalVarSet::set_var_name);
+ ObjectTypeDB::bind_method(_MD("get_var_name"),&VisualScriptLocalVarSet::get_var_name);
+
+ ObjectTypeDB::bind_method(_MD("set_var_type","type"),&VisualScriptLocalVarSet::set_var_type);
+ ObjectTypeDB::bind_method(_MD("get_var_type"),&VisualScriptLocalVarSet::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"));
+
+
+}
+
+VisualScriptLocalVarSet::VisualScriptLocalVarSet() {
+
+ name="new_local";
+ type=Variant::NIL;
+
+}
+
+
+//////////////////////////////////////////
+////////////////LocalVar///////////
+//////////////////////////////////////////
+
int VisualScriptInputAction::get_output_sequence_port_count() const {
return 0;
@@ -3082,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();
}
@@ -3113,23 +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 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) {
+ 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;
}
@@ -3141,6 +3582,7 @@ VisualScriptNodeInstance* VisualScriptInputAction::instance(VisualScriptInstance
VisualScriptNodeInstanceInputAction * instance = memnew(VisualScriptNodeInstanceInputAction );
instance->instance=p_instance;
instance->action=name;
+ instance->mode=mode;
return instance;
}
@@ -3187,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;
}
@@ -3203,12 +3650,12 @@ VisualScriptInputAction::VisualScriptInputAction() {
int VisualScriptDeconstruct::get_output_sequence_port_count() const {
- return 1;
+ return 0;
}
bool VisualScriptDeconstruct::has_input_sequence_port() const{
- return true;
+ return false;
}
int VisualScriptDeconstruct::get_input_value_port_count() const{
@@ -3335,8 +3782,6 @@ public:
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) {
@@ -3417,23 +3862,27 @@ VisualScriptDeconstruct::VisualScriptDeconstruct() {
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/set_variable",create_node_generic<VisualScriptVariableSet>);
+ VisualScriptLanguage::singleton->add_register_func("data/get_variable",create_node_generic<VisualScriptVariableGet>);
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/get_local_variable",create_node_generic<VisualScriptLocalVar>);
+ VisualScriptLanguage::singleton->add_register_func("data/set_local_variable",create_node_generic<VisualScriptLocalVarSet>);
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("constants/constant",create_node_generic<VisualScriptConstant>);
+ 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>);
VisualScriptLanguage::singleton->add_register_func("index/get_index",create_node_generic<VisualScriptIndexGet>);
VisualScriptLanguage::singleton->add_register_func("index/set_index",create_node_generic<VisualScriptIndexSet>);
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
index 28f99a16e1..94eeadca57 100644
--- a/modules/visual_script/visual_script_nodes.h
+++ b/modules/visual_script/visual_script_nodes.h
@@ -219,7 +219,7 @@ public:
virtual String get_caption() const;
virtual String get_text() const;
- virtual String get_category() const { return "data"; }
+ virtual String get_category() const { return "constants"; }
void set_constant_type(Variant::Type p_type);
Variant::Type get_constant_type() const;
@@ -360,7 +360,7 @@ public:
virtual String get_caption() const;
virtual String get_text() const;
- virtual String get_category() const { return "data"; }
+ virtual String get_category() const { return "constants"; }
void set_global_constant(int p_which);
int get_global_constant();
@@ -371,6 +371,89 @@ public:
};
+class VisualScriptClassConstant : public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptClassConstant,VisualScriptNode)
+
+ StringName base_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_class_constant(const StringName& p_which);
+ StringName get_class_constant();
+
+ void set_base_type(const StringName& p_which);
+ StringName get_base_type();
+
+ virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+ 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 {
@@ -411,7 +494,7 @@ public:
virtual String get_caption() const;
virtual String get_text() const;
- virtual String get_category() const { return "data"; }
+ virtual String get_category() const { return "constants"; }
void set_math_constant(MathConstant p_which);
MathConstant get_math_constant();
@@ -455,6 +538,9 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
+
VisualScriptEngineSingleton();
};
@@ -494,6 +580,8 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
VisualScriptSceneNode();
};
@@ -530,6 +618,8 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
VisualScriptSceneTree();
};
@@ -603,6 +693,8 @@ public:
virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+ virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const;
+
VisualScriptSelf();
};
@@ -820,14 +912,61 @@ public:
VisualScriptLocalVar();
};
+class VisualScriptLocalVarSet: public VisualScriptNode {
+
+ OBJ_TYPE(VisualScriptLocalVarSet,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);
+
+ VisualScriptLocalVarSet();
+};
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:
@@ -856,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 {