#include "visual_script_func_nodes.h" #include "scene/main/scene_main_loop.h" #include "os/os.h" #include "scene/main/node.h" #include "visual_script_nodes.h" #include "io/resource_loader.h" #include "globals.h" ////////////////////////////////////////// ////////////////CALL////////////////////// ////////////////////////////////////////// int VisualScriptFunctionCall::get_output_sequence_port_count() const { 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{ if (method_cache.flags&METHOD_FLAG_CONST || call_mode==CALL_MODE_BASIC_TYPE) return false; else return true; } #ifdef TOOLS_ENABLED static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene) return NULL; Ref<Script> scr = p_current_node->get_script(); if (scr.is_valid() && scr==script) return p_current_node; for(int i=0;i<p_current_node->get_child_count();i++) { Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script); if (n) return n; } return NULL; } #endif Node *VisualScriptFunctionCall::_get_base_node() const { #ifdef TOOLS_ENABLED Ref<Script> script = get_visual_script(); if (!script.is_valid()) return NULL; MainLoop * main_loop = OS::get_singleton()->get_main_loop(); if (!main_loop) return NULL; SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); if (!scene_tree) return NULL; Node *edited_scene = scene_tree->get_edited_scene_root(); if (!edited_scene) return NULL; Node* script_node = _find_script_node(edited_scene,edited_scene,script); if (!script_node) return NULL; if (!script_node->has_node(base_path)) return NULL; Node *path_to = script_node->get_node(base_path); return path_to; #else return NULL; #endif } StringName VisualScriptFunctionCall::_get_base_type() const { if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) return get_visual_script()->get_instance_base_type(); else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { Node *path = _get_base_node(); if (path) return path->get_type(); } return base_type; } int VisualScriptFunctionCall::get_input_value_port_count() const{ if (call_mode==CALL_MODE_BASIC_TYPE) { Vector<StringName> names = Variant::get_method_argument_names(basic_type,function); return names.size() + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) + 1; } else { MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); if (mb) { return mb->get_argument_count() + (call_mode==CALL_MODE_INSTANCE?1:0) + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) - use_default_args; } return method_cache.arguments.size() + (call_mode==CALL_MODE_INSTANCE?1:0) + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) - use_default_args; } } int VisualScriptFunctionCall::get_output_value_port_count() const{ if (call_mode==CALL_MODE_BASIC_TYPE) { bool returns=false; Variant::get_method_return_type(basic_type,function,&returns); return returns?1:0; } else { int ret; MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); if (mb) { ret = mb->has_return() ? 1 : 0; } else ret = 1; //it is assumed that script always returns something if (call_mode==CALL_MODE_INSTANCE) { ret++; } return ret; } } String VisualScriptFunctionCall::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) const{ if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) { if (p_idx==0) { PropertyInfo pi; pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type); pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower()); return pi; } else { p_idx--; } } if (rpc_call_mode>=RPC_RELIABLE_TO_ID) { if (p_idx==0) { return PropertyInfo(Variant::INT,"peer_id"); } else { p_idx--; } } #ifdef DEBUG_METHODS_ENABLED if (call_mode==CALL_MODE_BASIC_TYPE) { Vector<StringName> names = Variant::get_method_argument_names(basic_type,function); Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type,function); return PropertyInfo(types[p_idx],names[p_idx]); } else { MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); if (mb) { return mb->get_argument_info(p_idx); } if (p_idx>=0 && p_idx < method_cache.arguments.size()) { return method_cache.arguments[p_idx]; } return PropertyInfo(); } #else return PropertyInfo(); #endif } PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) const{ #ifdef DEBUG_METHODS_ENABLED if (call_mode==CALL_MODE_BASIC_TYPE) { return PropertyInfo(Variant::get_method_return_type(basic_type,function),""); } else { if (call_mode==CALL_MODE_INSTANCE) { if (p_idx==0) { return PropertyInfo(Variant::OBJECT,"pass"); } else { p_idx--; } } PropertyInfo ret; /*MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); if (mb) { ret = mb->get_argument_info(-1); } else {*/ ret = method_cache.return_val; //} if (call_mode==CALL_MODE_INSTANCE) { ret.name="return"; } else { ret.name=""; } return ret; } #else return PropertyInfo(); #endif } String VisualScriptFunctionCall::get_caption() const { static const char*cname[5]= { "CallSelf", "CallNode", "CallInstance", "CallBasic", "CallSingleton" }; String caption = cname[call_mode]; if (rpc_call_mode) { caption+=" (RPC)"; } return caption; } String VisualScriptFunctionCall::get_text() const { if (call_mode==CALL_MODE_SELF) return " "+String(function)+"()"; if (call_mode==CALL_MODE_SINGLETON) return String(singleton)+":"+String(function)+"()"; else if (call_mode==CALL_MODE_BASIC_TYPE) return Variant::get_type_name(basic_type)+"."+String(function)+"()"; else if (call_mode==CALL_MODE_NODE_PATH) return " ["+String(base_path.simplified())+"]."+String(function)+"()"; else return " "+base_type+"."+String(function)+"()"; } void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) { if (basic_type==p_type) return; basic_type=p_type; _change_notify(); ports_changed_notify(); } Variant::Type VisualScriptFunctionCall::get_basic_type() const{ return basic_type; } void VisualScriptFunctionCall::set_base_type(const StringName& p_type) { if (base_type==p_type) return; base_type=p_type; _change_notify(); ports_changed_notify(); } StringName VisualScriptFunctionCall::get_base_type() const{ return base_type; } void VisualScriptFunctionCall::set_base_script(const String& p_path) { if (base_script==p_path) return; base_script=p_path; _change_notify(); ports_changed_notify(); } String VisualScriptFunctionCall::get_base_script() const { return base_script; } void VisualScriptFunctionCall::set_singleton(const StringName& p_path) { if (singleton==p_path) return; singleton=p_path; Object *obj = Globals::get_singleton()->get_singleton_object(singleton); if (obj) { base_type=obj->get_type(); } _change_notify(); ports_changed_notify(); } StringName VisualScriptFunctionCall::get_singleton() const { return singleton; } void VisualScriptFunctionCall::_update_method_cache() { StringName type; Ref<Script> script; if (call_mode==CALL_MODE_NODE_PATH) { Node* node=_get_base_node(); if (node) { type=node->get_type(); base_type=type; //cache, too script = node->get_script(); } } else if (call_mode==CALL_MODE_SELF) { if (get_visual_script().is_valid()) { type=get_visual_script()->get_instance_base_type(); base_type=type; //cache, too script=get_visual_script(); } } else if (call_mode==CALL_MODE_SINGLETON) { Object *obj = Globals::get_singleton()->get_singleton_object(singleton); if (obj) { type=obj->get_type(); script=obj->get_script(); } } else if (call_mode==CALL_MODE_INSTANCE) { type=base_type; if (base_script!=String()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { ScriptServer::edit_request_func(base_script); //make sure it's loaded } if (ResourceCache::has(base_script)) { script = Ref<Resource>( ResourceCache::get(base_script) ); } else { return; } } } // print_line("BASE: "+String(type)+" FUNC: "+String(function)); MethodBind *mb = ObjectTypeDB::get_method(type,function); if (mb) { use_default_args=mb->get_default_argument_count(); method_cache = MethodInfo(); for(int i=0;i<mb->get_argument_count();i++) { #ifdef DEBUG_METHODS_ENABLED method_cache.arguments.push_back(mb->get_argument_info(i)); #else method_cache.arguments.push_back(PropertyInfo()); #endif } if (mb->is_const()) { method_cache.flags|=METHOD_FLAG_CONST; } #ifdef DEBUG_METHODS_ENABLED method_cache.return_val = mb->get_argument_info(-1); #endif if (mb->is_vararg()) { //for vararg just give it 10 arguments (should be enough for most use cases) for(int i=0;i<10;i++) { method_cache.arguments.push_back(PropertyInfo(Variant::NIL,"arg"+itos(i))); use_default_args++; } } } else if (script.is_valid() && script->has_method(function)) { method_cache = script->get_method_info(function); use_default_args=method_cache.default_arguments.size(); } } void VisualScriptFunctionCall::set_function(const StringName& p_type){ if (function==p_type) return; function=p_type; if (call_mode==CALL_MODE_BASIC_TYPE) { use_default_args = Variant::get_method_default_arguments(basic_type,function).size(); } else { //update all caches _update_method_cache(); } _change_notify(); ports_changed_notify(); } StringName VisualScriptFunctionCall::get_function() const { return function; } void VisualScriptFunctionCall::set_base_path(const NodePath& p_type) { if (base_path==p_type) return; base_path=p_type; _change_notify(); ports_changed_notify(); } NodePath VisualScriptFunctionCall::get_base_path() const { return base_path; } void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) { if (call_mode==p_mode) return; call_mode=p_mode; _change_notify(); ports_changed_notify(); } VisualScriptFunctionCall::CallMode VisualScriptFunctionCall::get_call_mode() const { return call_mode; } void VisualScriptFunctionCall::set_use_default_args(int p_amount) { if (use_default_args==p_amount) return; use_default_args=p_amount; ports_changed_notify(); } void VisualScriptFunctionCall::set_rpc_call_mode(VisualScriptFunctionCall::RPCCallMode p_mode) { if (rpc_call_mode==p_mode) return; rpc_call_mode=p_mode; ports_changed_notify(); _change_notify(); } VisualScriptFunctionCall::RPCCallMode VisualScriptFunctionCall::get_rpc_call_mode() const{ return rpc_call_mode; } int VisualScriptFunctionCall::get_use_default_args() const{ return use_default_args; } void VisualScriptFunctionCall::set_validate(bool p_amount) { validate=p_amount; } bool VisualScriptFunctionCall::get_validate() const { return validate; } void VisualScriptFunctionCall::_set_argument_cache(const Dictionary& p_cache) { //so everything works in case all else fails method_cache=MethodInfo::from_dict(p_cache); } Dictionary VisualScriptFunctionCall::_get_argument_cache() const { return method_cache; } void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const { if (property.name=="function/base_type") { if (call_mode!=CALL_MODE_INSTANCE) { property.usage=PROPERTY_USAGE_NOEDITOR; } } if (property.name=="function/base_script") { if (call_mode!=CALL_MODE_INSTANCE) { property.usage=0; } } if (property.name=="function/basic_type") { if (call_mode!=CALL_MODE_BASIC_TYPE) { property.usage=0; } } if (property.name=="function/singleton") { if (call_mode!=CALL_MODE_SINGLETON) { property.usage=0; } else { List<Globals::Singleton> names; Globals::get_singleton()->get_singletons(&names); property.hint=PROPERTY_HINT_ENUM; String sl; for (List<Globals::Singleton>::Element *E=names.front();E;E=E->next()) { if (sl!=String()) sl+=","; sl+=E->get().name; } property.hint_string=sl; } } if (property.name=="function/node_path") { if (call_mode!=CALL_MODE_NODE_PATH) { property.usage=0; } else { Node *bnode = _get_base_node(); if (bnode) { property.hint_string=bnode->get_path(); //convert to loong string } else { } } } if (property.name=="function/function") { if (call_mode==CALL_MODE_BASIC_TYPE) { property.hint=PROPERTY_HINT_METHOD_OF_VARIANT_TYPE; property.hint_string=Variant::get_type_name(basic_type); } else if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) { property.hint=PROPERTY_HINT_METHOD_OF_SCRIPT; property.hint_string=itos(get_visual_script()->get_instance_ID()); } else if (call_mode==CALL_MODE_SINGLETON) { Object *obj = Globals::get_singleton()->get_singleton_object(singleton); if (obj) { property.hint=PROPERTY_HINT_METHOD_OF_INSTANCE; property.hint_string=itos(obj->get_instance_ID()); } else { property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE; property.hint_string=base_type;//should be cached } } else if (call_mode==CALL_MODE_INSTANCE) { property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE; property.hint_string=base_type; if (base_script!=String()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { ScriptServer::edit_request_func(base_script); //make sure it's loaded } if (ResourceCache::has(base_script)) { Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) ); if (script.is_valid()) { property.hint=PROPERTY_HINT_METHOD_OF_SCRIPT; property.hint_string=itos(script->get_instance_ID()); } } } } else if (call_mode==CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { property.hint=PROPERTY_HINT_METHOD_OF_INSTANCE; property.hint_string=itos(node->get_instance_ID()); } else { property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE; property.hint_string=get_base_type(); } } } if (property.name=="function/use_default_args") { property.hint=PROPERTY_HINT_RANGE; int mc=0; if (call_mode==CALL_MODE_BASIC_TYPE) { mc = Variant::get_method_default_arguments(basic_type,function).size(); } else { MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); if (mb) { mc=mb->get_default_argument_count(); } } if (mc==0) { property.usage=0; //do not show } else { property.hint_string="0,"+itos(mc)+",1"; } } if (property.name=="rpc/call_mode") { if (call_mode==CALL_MODE_BASIC_TYPE) { property.usage=0; } } } void VisualScriptFunctionCall::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptFunctionCall::set_base_type); ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptFunctionCall::get_base_type); ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptFunctionCall::set_base_script); ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptFunctionCall::get_base_script); ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptFunctionCall::set_basic_type); ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptFunctionCall::get_basic_type); ObjectTypeDB::bind_method(_MD("set_singleton","singleton"),&VisualScriptFunctionCall::set_singleton); ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptFunctionCall::get_singleton); ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptFunctionCall::set_function); ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptFunctionCall::get_function); ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptFunctionCall::set_call_mode); ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptFunctionCall::get_call_mode); ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptFunctionCall::set_base_path); ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptFunctionCall::get_base_path); ObjectTypeDB::bind_method(_MD("set_use_default_args","amount"),&VisualScriptFunctionCall::set_use_default_args); ObjectTypeDB::bind_method(_MD("get_use_default_args"),&VisualScriptFunctionCall::get_use_default_args); ObjectTypeDB::bind_method(_MD("_set_argument_cache","argument_cache"),&VisualScriptFunctionCall::_set_argument_cache); ObjectTypeDB::bind_method(_MD("_get_argument_cache"),&VisualScriptFunctionCall::_get_argument_cache); ObjectTypeDB::bind_method(_MD("set_rpc_call_mode","mode"),&VisualScriptFunctionCall::set_rpc_call_mode); ObjectTypeDB::bind_method(_MD("get_rpc_call_mode"),&VisualScriptFunctionCall::get_rpc_call_mode); 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) bt+=","; bt+=Variant::get_type_name(Variant::Type(i)); } List<String> script_extensions; for(int i=0;i<ScriptServer::get_language_count();i++) { ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); } String script_ext_hint; for (List<String>::Element *E=script_extensions.front();E;E=E->next()) { if (script_ext_hint!=String()) script_ext_hint+=","; script_ext_hint+="*."+E->get(); } ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type,Singleton"),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/singleton"),_SCS("set_singleton"),_SCS("get_singleton")); ADD_PROPERTY(PropertyInfo(Variant::INT,"function/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"function/argument_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_argument_cache"),_SCS("_get_argument_cache")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); //when set, if loaded properly, will override argument count. ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),_SCS("set_use_default_args"),_SCS("get_use_default_args")); ADD_PROPERTY(PropertyInfo(Variant::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 ); BIND_CONSTANT( CALL_MODE_NODE_PATH); BIND_CONSTANT( CALL_MODE_INSTANCE); BIND_CONSTANT( CALL_MODE_BASIC_TYPE ); } class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance { public: VisualScriptFunctionCall::CallMode call_mode; NodePath node_path; int input_args; bool validate; bool returns; VisualScriptFunctionCall::RPCCallMode rpc_mode; StringName function; StringName singleton; VisualScriptFunctionCall *node; VisualScriptInstance *instance; //virtual int get_working_memory_size() const { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } _FORCE_INLINE_ bool call_rpc(Object* p_base,const Variant** p_args,int p_argcount) { if (!p_base) return false; Node * node = p_base->cast_to<Node>(); if (!node) return false; int to_id=0; bool reliable=true; if (rpc_mode>=VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) { to_id = *p_args[0]; p_args+=1; p_argcount-=1; if (rpc_mode==VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) { reliable=false; } } else if (rpc_mode==VisualScriptFunctionCall::RPC_UNRELIABLE) { reliable=false; } node->rpcp(to_id,!reliable,function,p_args,p_argcount); return true; } virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { switch(call_mode) { case VisualScriptFunctionCall::CALL_MODE_SELF: { Object *object=instance->get_owner_ptr(); if (rpc_mode) { call_rpc(object,p_inputs,input_args); } else if (returns) { *p_outputs[0] = object->call(function,p_inputs,input_args,r_error); } else { object->call(function,p_inputs,input_args,r_error); } } break; case VisualScriptFunctionCall::CALL_MODE_NODE_PATH: { Node* node = instance->get_owner_ptr()->cast_to<Node>(); if (!node) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Base object is not a Node!"; return 0; } Node* another = node->get_node(node_path); if (!node) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Path does not lead Node!"; return 0; } if (rpc_mode) { call_rpc(node,p_inputs,input_args); } else if (returns) { *p_outputs[0] = another->call(function,p_inputs,input_args,r_error); } else { another->call(function,p_inputs,input_args,r_error); } } break; case VisualScriptFunctionCall::CALL_MODE_INSTANCE: case VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE: { Variant v = *p_inputs[0]; if (rpc_mode) { Object *obj = v; if (obj) { call_rpc(obj,p_inputs+1,input_args-1); } } else if (returns) { if (call_mode==VisualScriptFunctionCall::CALL_MODE_INSTANCE) { *p_outputs[1] = v.call(function,p_inputs+1,input_args,r_error); } else { *p_outputs[0] = v.call(function,p_inputs+1,input_args,r_error); } } else { v.call(function,p_inputs+1,input_args,r_error); } if (call_mode==VisualScriptFunctionCall::CALL_MODE_INSTANCE) { *p_outputs[0]=*p_inputs[0]; } } break; case VisualScriptFunctionCall::CALL_MODE_SINGLETON: { Object *object=Globals::get_singleton()->get_singleton_object(singleton); if (!object) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Invalid singleton name: '"+String(singleton)+"'"; return 0; } if (rpc_mode) { call_rpc(object,p_inputs,input_args); } else if (returns) { *p_outputs[0] = object->call(function,p_inputs,input_args,r_error); } else { object->call(function,p_inputs,input_args,r_error); } } break; } if (!validate) { //ignore call errors if validation is disabled r_error.error=Variant::CallError::CALL_OK; r_error_str=String(); } return 0; } }; VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstance* p_instance) { VisualScriptNodeInstanceFunctionCall * instance = memnew(VisualScriptNodeInstanceFunctionCall ); instance->node=this; instance->instance=p_instance; instance->singleton=singleton; instance->function=function; instance->call_mode=call_mode; instance->returns=get_output_value_port_count(); instance->node_path=base_path; instance->input_args = get_input_value_port_count() - ( (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE) ? 1: 0 ); instance->rpc_mode=rpc_call_mode; 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; base_type="Object"; rpc_call_mode=RPC_DISABLED; } template<VisualScriptFunctionCall::CallMode cmode> static Ref<VisualScriptNode> create_function_call_node(const String& p_name) { Ref<VisualScriptFunctionCall> node; node.instance(); node->set_call_mode(cmode); return node; } ////////////////////////////////////////// ////////////////SET////////////////////// ////////////////////////////////////////// static const char* event_type_names[InputEvent::TYPE_MAX]={ "None", "Key", "MouseMotion", "MouseButton", "JoystickMotion", "JoystickButton", "ScreenTouch", "ScreenDrag", "Action" }; int VisualScriptPropertySet::get_output_sequence_port_count() const { return call_mode!=CALL_MODE_BASIC_TYPE ? 1 : 0; } bool VisualScriptPropertySet::has_input_sequence_port() const{ return call_mode!=CALL_MODE_BASIC_TYPE ? true : false; } Node *VisualScriptPropertySet::_get_base_node() const { #ifdef TOOLS_ENABLED Ref<Script> script = get_visual_script(); if (!script.is_valid()) return NULL; MainLoop * main_loop = OS::get_singleton()->get_main_loop(); if (!main_loop) return NULL; SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); if (!scene_tree) return NULL; Node *edited_scene = scene_tree->get_edited_scene_root(); if (!edited_scene) return NULL; Node* script_node = _find_script_node(edited_scene,edited_scene,script); if (!script_node) return NULL; if (!script_node->has_node(base_path)) return NULL; Node *path_to = script_node->get_node(base_path); return path_to; #else return NULL; #endif } StringName VisualScriptPropertySet::_get_base_type() const { if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) return get_visual_script()->get_instance_base_type(); else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { Node *path = _get_base_node(); if (path) return path->get_type(); } return base_type; } int VisualScriptPropertySet::get_input_value_port_count() const{ int pc = (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?2:1; return pc; } int VisualScriptPropertySet::get_output_value_port_count() const{ return (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE) ? 1 : 0; } String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const{ if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) { if (p_idx==0) { PropertyInfo pi; pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type); pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower()); return pi; } else { p_idx--; } } PropertyInfo pinfo=type_cache; pinfo.name="value"; return pinfo; } PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const{ if (call_mode==CALL_MODE_BASIC_TYPE) { return PropertyInfo(basic_type,"out"); } else if (call_mode==CALL_MODE_INSTANCE) { return PropertyInfo(Variant::OBJECT,"pass"); } else { return PropertyInfo(); } } String VisualScriptPropertySet::get_caption() const { static const char*cname[4]= { "SelfSet", "NodeSet", "InstanceSet", "BasicSet" }; return cname[call_mode]; } String VisualScriptPropertySet::get_text() const { String prop; if (call_mode==CALL_MODE_BASIC_TYPE) prop=Variant::get_type_name(basic_type)+"."+property; else if (call_mode==CALL_MODE_NODE_PATH) prop=String(base_path)+":"+property; else if (call_mode==CALL_MODE_SELF) prop=property; else if (call_mode==CALL_MODE_INSTANCE) prop=String(base_type)+":"+property; return prop; } void VisualScriptPropertySet::_update_base_type() { //cache it because this information may not be available on load if (call_mode==CALL_MODE_NODE_PATH) { Node* node=_get_base_node(); if (node) { base_type=node->get_type(); } } else if (call_mode==CALL_MODE_SELF) { if (get_visual_script().is_valid()) { base_type=get_visual_script()->get_instance_base_type(); } } } void VisualScriptPropertySet::set_basic_type(Variant::Type p_type) { if (basic_type==p_type) return; basic_type=p_type; _change_notify(); _update_base_type(); ports_changed_notify(); } Variant::Type VisualScriptPropertySet::get_basic_type() const{ return basic_type; } void VisualScriptPropertySet::set_event_type(InputEvent::Type p_type) { if (event_type==p_type) return; event_type=p_type; if (call_mode==CALL_MODE_BASIC_TYPE) { _update_cache(); } _change_notify(); _update_base_type(); ports_changed_notify(); } InputEvent::Type VisualScriptPropertySet::get_event_type() const{ return event_type; } void VisualScriptPropertySet::set_base_type(const StringName& p_type) { if (base_type==p_type) return; base_type=p_type; _change_notify(); ports_changed_notify(); } StringName VisualScriptPropertySet::get_base_type() const{ return base_type; } void VisualScriptPropertySet::set_base_script(const String& p_path) { if (base_script==p_path) return; base_script=p_path; _change_notify(); ports_changed_notify(); } String VisualScriptPropertySet::get_base_script() const { return base_script; } void VisualScriptPropertySet::_update_cache() { if (!OS::get_singleton()->get_main_loop()) return; if (!OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()) return; if (!OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()->is_editor_hint()) //only update cache if editor exists, it's pointless otherwise return; if (call_mode==CALL_MODE_BASIC_TYPE) { //not super efficient.. Variant v; if (basic_type==Variant::INPUT_EVENT) { InputEvent ev; ev.type=event_type; v=ev; } else { Variant::CallError ce; v = Variant::construct(basic_type,NULL,0,ce); } List<PropertyInfo> pinfo; v.get_property_list(&pinfo); for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { if (E->get().name==property) { type_cache=E->get(); } } } else { StringName type; Ref<Script> script; Node *node=NULL; if (call_mode==CALL_MODE_NODE_PATH) { node=_get_base_node(); if (node) { type=node->get_type(); base_type=type; //cache, too script = node->get_script(); } } else if (call_mode==CALL_MODE_SELF) { if (get_visual_script().is_valid()) { type=get_visual_script()->get_instance_base_type(); base_type=type; //cache, too script=get_visual_script(); } } else if (call_mode==CALL_MODE_INSTANCE) { type=base_type; if (base_script!=String()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { ScriptServer::edit_request_func(base_script); //make sure it's loaded } if (ResourceCache::has(base_script)) { script = Ref<Resource>( ResourceCache::get(base_script) ); } else { return; } } } List<PropertyInfo> pinfo; if (node) { node->get_property_list(&pinfo); } else { ObjectTypeDB::get_property_list(type,&pinfo); } if (script.is_valid()) { script->get_script_property_list(&pinfo); } for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { if (E->get().name==property) { type_cache=E->get(); return; } } } } void VisualScriptPropertySet::set_property(const StringName& p_type){ if (property==p_type) return; property=p_type; _update_cache(); _change_notify(); ports_changed_notify(); } StringName VisualScriptPropertySet::get_property() const { return property; } void VisualScriptPropertySet::set_base_path(const NodePath& p_type) { if (base_path==p_type) return; base_path=p_type; _update_base_type(); _change_notify(); ports_changed_notify(); } NodePath VisualScriptPropertySet::get_base_path() const { return base_path; } void VisualScriptPropertySet::set_call_mode(CallMode p_mode) { if (call_mode==p_mode) return; call_mode=p_mode; _update_base_type(); _change_notify(); ports_changed_notify(); } VisualScriptPropertySet::CallMode VisualScriptPropertySet::get_call_mode() const { return call_mode; } void VisualScriptPropertySet::_set_type_cache(const Dictionary &p_type) { type_cache=PropertyInfo::from_dict(p_type); } Dictionary VisualScriptPropertySet::_get_type_cache() const { return type_cache; } void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { if (property.name=="property/base_type") { if (call_mode!=CALL_MODE_INSTANCE) { property.usage=PROPERTY_USAGE_NOEDITOR; } } if (property.name=="property/base_script") { if (call_mode!=CALL_MODE_INSTANCE) { property.usage=0; } } if (property.name=="property/basic_type") { if (call_mode!=CALL_MODE_BASIC_TYPE) { property.usage=0; } } if (property.name=="property/event_type") { if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) { property.usage=0; } } if (property.name=="property/node_path") { if (call_mode!=CALL_MODE_NODE_PATH) { property.usage=0; } else { Node *bnode = _get_base_node(); if (bnode) { property.hint_string=bnode->get_path(); //convert to loong string } else { } } } if (property.name=="property/property") { if (call_mode==CALL_MODE_BASIC_TYPE) { property.hint=PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; property.hint_string=Variant::get_type_name(basic_type); } else if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) { property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint_string=itos(get_visual_script()->get_instance_ID()); } else if (call_mode==CALL_MODE_INSTANCE) { property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; property.hint_string=base_type; if (base_script!=String()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { ScriptServer::edit_request_func(base_script); //make sure it's loaded } if (ResourceCache::has(base_script)) { Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) ); if (script.is_valid()) { property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint_string=itos(script->get_instance_ID()); } } } } else if (call_mode==CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { property.hint=PROPERTY_HINT_PROPERTY_OF_INSTANCE; property.hint_string=itos(node->get_instance_ID()); } else { property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; property.hint_string=get_base_type(); } } } } void VisualScriptPropertySet::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertySet::set_base_type); ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertySet::get_base_type); ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertySet::set_base_script); ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertySet::get_base_script); ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertySet::set_basic_type); ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertySet::get_basic_type); ObjectTypeDB::bind_method(_MD("_set_type_cache","type_cache"),&VisualScriptPropertySet::_set_type_cache); ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertySet::_get_type_cache); ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertySet::set_event_type); ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertySet::get_event_type); ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertySet::set_property); ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertySet::get_property); ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertySet::set_call_mode); ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertySet::get_call_mode); ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertySet::set_base_path); ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertySet::get_base_path); String bt; for(int i=0;i<Variant::VARIANT_MAX;i++) { if (i>0) bt+=","; bt+=Variant::get_type_name(Variant::Type(i)); } String et; for(int i=0;i<InputEvent::TYPE_MAX;i++) { if (i>0) et+=","; et+=event_type_names[i]; } List<String> script_extensions; for(int i=0;i<ScriptServer::get_language_count();i++) { ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); } String script_ext_hint; for (List<String>::Element *E=script_extensions.front();E;E=E->next()) { if (script_ext_hint!=String()) script_ext_hint+=","; script_ext_hint+="*."+E->get(); } ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); BIND_CONSTANT( CALL_MODE_INSTANCE); } class VisualScriptNodeInstancePropertySet : public VisualScriptNodeInstance { public: VisualScriptPropertySet::CallMode call_mode; NodePath node_path; StringName property; VisualScriptPropertySet *node; VisualScriptInstance *instance; //virtual int get_working_memory_size() const { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { switch(call_mode) { case VisualScriptPropertySet::CALL_MODE_SELF: { Object *object=instance->get_owner_ptr(); bool valid; object->set(property,*p_inputs[0],&valid); if (!valid) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+object->get_type(); } } break; case VisualScriptPropertySet::CALL_MODE_NODE_PATH: { Node* node = instance->get_owner_ptr()->cast_to<Node>(); if (!node) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Base object is not a Node!"; return 0; } Node* another = node->get_node(node_path); if (!node) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Path does not lead Node!"; return 0; } bool valid; another->set(property,*p_inputs[0],&valid); if (!valid) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+another->get_type(); } } break; case VisualScriptPropertySet::CALL_MODE_INSTANCE: case VisualScriptPropertySet::CALL_MODE_BASIC_TYPE: { Variant v = *p_inputs[0]; bool valid; v.set(property,*p_inputs[1],&valid); if (!valid) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str="Invalid set value '"+String(*p_inputs[1])+"' ("+Variant::get_type_name(p_inputs[1]->get_type())+") on property '"+String(property)+"' of type "+Variant::get_type_name(v.get_type()); } *p_outputs[0]=v; } break; } return 0; } }; VisualScriptNodeInstance* VisualScriptPropertySet::instance(VisualScriptInstance* p_instance) { VisualScriptNodeInstancePropertySet * instance = memnew(VisualScriptNodeInstancePropertySet ); instance->node=this; instance->instance=p_instance; instance->property=property; instance->call_mode=call_mode; instance->node_path=base_path; return instance; } VisualScriptPropertySet::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; base_type="Object"; basic_type=Variant::NIL; event_type=InputEvent::NONE; } template<VisualScriptPropertySet::CallMode cmode> static Ref<VisualScriptNode> create_property_set_node(const String& p_name) { Ref<VisualScriptPropertySet> node; node.instance(); node->set_call_mode(cmode); return node; } ////////////////////////////////////////// ////////////////GET////////////////////// ////////////////////////////////////////// int VisualScriptPropertyGet::get_output_sequence_port_count() const { return 0;// (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1; } bool VisualScriptPropertyGet::has_input_sequence_port() const{ 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 if (call_mode==CALL_MODE_NODE_PATH) { Node* node=_get_base_node(); if (node) { base_type=node->get_type(); } } else if (call_mode==CALL_MODE_SELF) { if (get_visual_script().is_valid()) { base_type=get_visual_script()->get_instance_base_type(); } } } Node *VisualScriptPropertyGet::_get_base_node() const { #ifdef TOOLS_ENABLED Ref<Script> script = get_visual_script(); if (!script.is_valid()) return NULL; MainLoop * main_loop = OS::get_singleton()->get_main_loop(); if (!main_loop) return NULL; SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); if (!scene_tree) return NULL; Node *edited_scene = scene_tree->get_edited_scene_root(); if (!edited_scene) return NULL; Node* script_node = _find_script_node(edited_scene,edited_scene,script); if (!script_node) return NULL; if (!script_node->has_node(base_path)) return NULL; Node *path_to = script_node->get_node(base_path); return path_to; #else return NULL; #endif } StringName VisualScriptPropertyGet::_get_base_type() const { if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) return get_visual_script()->get_instance_base_type(); else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { Node *path = _get_base_node(); if (path) return path->get_type(); } return base_type; } int VisualScriptPropertyGet::get_input_value_port_count() const{ return (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?1:0; } int VisualScriptPropertyGet::get_output_value_port_count() const{ return 1; } String VisualScriptPropertyGet::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const{ if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) { if (p_idx==0) { PropertyInfo pi; pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type); pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower()); return pi; } else { p_idx--; } } return PropertyInfo(); } PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const{ return PropertyInfo(type_cache,"value"); } String VisualScriptPropertyGet::get_caption() const { static const char*cname[4]= { "SelfGet", "NodeGet", "InstanceGet", "BasicGet" }; return cname[call_mode]; } String VisualScriptPropertyGet::get_text() const { String prop; if (call_mode==CALL_MODE_BASIC_TYPE) prop=Variant::get_type_name(basic_type)+"."+property; else if (call_mode==CALL_MODE_NODE_PATH) prop=String(base_path)+":"+property; else if (call_mode==CALL_MODE_SELF) prop=property; else if (call_mode==CALL_MODE_INSTANCE) prop=String(base_type)+":"+property; return prop; } void VisualScriptPropertyGet::set_base_type(const StringName& p_type) { if (base_type==p_type) return; base_type=p_type; _change_notify(); ports_changed_notify(); } StringName VisualScriptPropertyGet::get_base_type() const{ return base_type; } void VisualScriptPropertyGet::set_base_script(const String& p_path) { if (base_script==p_path) return; base_script=p_path; _change_notify(); ports_changed_notify(); } String VisualScriptPropertyGet::get_base_script() const { return base_script; } void VisualScriptPropertyGet::_update_cache() { if (call_mode==CALL_MODE_BASIC_TYPE) { //not super efficient.. Variant v; if (basic_type==Variant::INPUT_EVENT) { InputEvent ev; ev.type=event_type; v=ev; } else { Variant::CallError ce; v = Variant::construct(basic_type,NULL,0,ce); } List<PropertyInfo> pinfo; v.get_property_list(&pinfo); for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { if (E->get().name==property) { type_cache=E->get().type; return; } } } else { StringName type; Ref<Script> script; Node *node=NULL; if (call_mode==CALL_MODE_NODE_PATH) { node=_get_base_node(); if (node) { type=node->get_type(); base_type=type; //cache, too script = node->get_script(); } } else if (call_mode==CALL_MODE_SELF) { if (get_visual_script().is_valid()) { type=get_visual_script()->get_instance_base_type(); base_type=type; //cache, too script=get_visual_script(); } } else if (call_mode==CALL_MODE_INSTANCE) { type=base_type; if (base_script!=String()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { ScriptServer::edit_request_func(base_script); //make sure it's loaded } if (ResourceCache::has(base_script)) { script = Ref<Resource>( ResourceCache::get(base_script) ); } else { return; } } } bool valid=false; Variant::Type type_ret; type_ret=ObjectTypeDB::get_property_type(base_type,property,&valid); if (valid) { type_cache=type_ret; return; //all dandy } if (node) { Variant prop = node->get(property,&valid); if (valid) { type_cache=prop.get_type(); return; //all dandy again } } if (script.is_valid()) { type_ret=script->get_static_property_type(property,&valid); if (valid) { type_cache=type_ret; return; //all dandy } } } } void VisualScriptPropertyGet::set_property(const StringName& p_type){ if (property==p_type) return; property=p_type; _update_cache(); _change_notify(); ports_changed_notify(); } StringName VisualScriptPropertyGet::get_property() const { return property; } void VisualScriptPropertyGet::set_base_path(const NodePath& p_type) { if (base_path==p_type) return; base_path=p_type; _change_notify(); _update_base_type(); ports_changed_notify(); } NodePath VisualScriptPropertyGet::get_base_path() const { return base_path; } void VisualScriptPropertyGet::set_call_mode(CallMode p_mode) { if (call_mode==p_mode) return; call_mode=p_mode; _change_notify(); _update_base_type(); ports_changed_notify(); } VisualScriptPropertyGet::CallMode VisualScriptPropertyGet::get_call_mode() const { return call_mode; } void VisualScriptPropertyGet::set_basic_type(Variant::Type p_type) { if (basic_type==p_type) return; basic_type=p_type; _change_notify(); ports_changed_notify(); } Variant::Type VisualScriptPropertyGet::get_basic_type() const{ return basic_type; } void VisualScriptPropertyGet::set_event_type(InputEvent::Type p_type) { if (event_type==p_type) return; event_type=p_type; if(call_mode==CALL_MODE_BASIC_TYPE) { _update_cache(); } _change_notify(); _update_base_type(); ports_changed_notify(); } InputEvent::Type VisualScriptPropertyGet::get_event_type() const{ return event_type; } void VisualScriptPropertyGet::_set_type_cache(Variant::Type p_type) { type_cache=p_type; } Variant::Type VisualScriptPropertyGet::_get_type_cache() const { return type_cache; } void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { if (property.name=="property/base_type") { if (call_mode!=CALL_MODE_INSTANCE) { property.usage=PROPERTY_USAGE_NOEDITOR; } } if (property.name=="property/base_script") { if (call_mode!=CALL_MODE_INSTANCE) { property.usage=0; } } if (property.name=="property/basic_type") { if (call_mode!=CALL_MODE_BASIC_TYPE) { property.usage=0; } } if (property.name=="property/event_type") { if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) { property.usage=0; } } if (property.name=="property/node_path") { if (call_mode!=CALL_MODE_NODE_PATH) { property.usage=0; } else { Node *bnode = _get_base_node(); if (bnode) { property.hint_string=bnode->get_path(); //convert to loong string } else { } } } if (property.name=="property/property") { if (call_mode==CALL_MODE_BASIC_TYPE) { property.hint=PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; property.hint_string=Variant::get_type_name(basic_type); } else if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) { property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint_string=itos(get_visual_script()->get_instance_ID()); } else if (call_mode==CALL_MODE_INSTANCE) { property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; property.hint_string=base_type; if (base_script!=String()) { if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { ScriptServer::edit_request_func(base_script); //make sure it's loaded } if (ResourceCache::has(base_script)) { Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) ); if (script.is_valid()) { property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint_string=itos(script->get_instance_ID()); } } } } else if (call_mode==CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { property.hint=PROPERTY_HINT_PROPERTY_OF_INSTANCE; property.hint_string=itos(node->get_instance_ID()); } else { property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; property.hint_string=get_base_type(); } } } } void VisualScriptPropertyGet::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertyGet::set_base_type); ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertyGet::get_base_type); ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertyGet::set_base_script); ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertyGet::get_base_script); ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertyGet::set_basic_type); ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertyGet::get_basic_type); ObjectTypeDB::bind_method(_MD("_set_type_cache","type_cache"),&VisualScriptPropertyGet::_set_type_cache); ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertyGet::_get_type_cache); ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertyGet::set_event_type); ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertyGet::get_event_type); ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertyGet::set_property); ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertyGet::get_property); ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertyGet::set_call_mode); ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertyGet::get_call_mode); ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertyGet::set_base_path); ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertyGet::get_base_path); String bt; for(int i=0;i<Variant::VARIANT_MAX;i++) { if (i>0) bt+=","; bt+=Variant::get_type_name(Variant::Type(i)); } String et; for(int i=0;i<InputEvent::TYPE_MAX;i++) { if (i>0) et+=","; et+=event_type_names[i]; } List<String> script_extensions; for(int i=0;i<ScriptServer::get_language_count();i++) { ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); } String script_ext_hint; for (List<String>::Element *E=script_extensions.front();E;E=E->next()) { if (script_ext_hint!=String()) script_ext_hint+=","; script_ext_hint+="."+E->get(); } ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); BIND_CONSTANT( CALL_MODE_INSTANCE); } class VisualScriptNodeInstancePropertyGet : public VisualScriptNodeInstance { public: VisualScriptPropertyGet::CallMode call_mode; NodePath node_path; StringName property; VisualScriptPropertyGet *node; VisualScriptInstance *instance; virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { switch(call_mode) { case VisualScriptPropertyGet::CALL_MODE_SELF: { Object *object=instance->get_owner_ptr(); bool valid; *p_outputs[0] = object->get(property,&valid); if (!valid) { 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_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_str=RTR("Path does not lead Node!"); return 0; } bool valid; *p_outputs[0] = another->get(property,&valid); if (!valid) { 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: { bool valid; Variant v = *p_inputs[0]; *p_outputs[0] = v.get(property,&valid); if (!valid) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str=RTR("Invalid index property name."); } }; } return 0; } }; VisualScriptNodeInstance* VisualScriptPropertyGet::instance(VisualScriptInstance* p_instance) { VisualScriptNodeInstancePropertyGet * instance = memnew(VisualScriptNodeInstancePropertyGet ); instance->node=this; instance->instance=p_instance; instance->property=property; instance->call_mode=call_mode; instance->node_path=base_path; return instance; } VisualScriptPropertyGet::VisualScriptPropertyGet() { call_mode=CALL_MODE_SELF; base_type="Object"; basic_type=Variant::NIL; event_type=InputEvent::NONE; type_cache=Variant::NIL; } template<VisualScriptPropertyGet::CallMode cmode> static Ref<VisualScriptNode> create_property_get_node(const String& p_name) { Ref<VisualScriptPropertyGet> node; node.instance(); node->set_call_mode(cmode); return node; } ////////////////////////////////////////// ////////////////EMIT////////////////////// ////////////////////////////////////////// int VisualScriptEmitSignal::get_output_sequence_port_count() const { return 1; } bool VisualScriptEmitSignal::has_input_sequence_port() const{ return true; } int VisualScriptEmitSignal::get_input_value_port_count() const{ Ref<VisualScript> vs = get_visual_script(); if (vs.is_valid()) { if (!vs->has_custom_signal(name)) return 0; return vs->custom_signal_get_argument_count(name); } return 0; } int VisualScriptEmitSignal::get_output_value_port_count() const{ return 0; } String VisualScriptEmitSignal::get_output_sequence_port_text(int p_port) const { return String(); } PropertyInfo VisualScriptEmitSignal::get_input_value_port_info(int p_idx) const{ Ref<VisualScript> vs = get_visual_script(); if (vs.is_valid()) { if (!vs->has_custom_signal(name)) return PropertyInfo(); return PropertyInfo(vs->custom_signal_get_argument_type(name,p_idx),vs->custom_signal_get_argument_name(name,p_idx)); } return PropertyInfo(); } PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const{ return PropertyInfo(); } String VisualScriptEmitSignal::get_caption() const { return "EmitSignal"; } String VisualScriptEmitSignal::get_text() const { return "emit "+String(name); } void VisualScriptEmitSignal::set_signal(const StringName& p_type){ if (name==p_type) return; name=p_type; _change_notify(); ports_changed_notify(); } StringName VisualScriptEmitSignal::get_signal() const { return name; } void VisualScriptEmitSignal::_validate_property(PropertyInfo& property) const { if (property.name=="signal/signal") { property.hint=PROPERTY_HINT_ENUM; List<StringName> sigs; Ref<VisualScript> vs = get_visual_script(); if (vs.is_valid()) { vs->get_custom_signal_list(&sigs); } String ml; for (List<StringName>::Element *E=sigs.front();E;E=E->next()) { if (ml!=String()) ml+=","; ml+=E->get(); } property.hint_string=ml; } } void VisualScriptEmitSignal::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_signal","name"),&VisualScriptEmitSignal::set_signal); ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptEmitSignal::get_signal); ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal")); } class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance { public: VisualScriptEmitSignal *node; VisualScriptInstance *instance; int argcount; StringName name; //virtual int get_working_memory_size() const { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { Object *obj = instance->get_owner_ptr(); obj->emit_signal(name,p_inputs,argcount); return 0; } }; VisualScriptNodeInstance* VisualScriptEmitSignal::instance(VisualScriptInstance* p_instance) { VisualScriptNodeInstanceEmitSignal * instance = memnew(VisualScriptNodeInstanceEmitSignal ); instance->node=this; instance->instance=p_instance; instance->name=name; instance->argcount=get_input_value_port_count(); return instance; } VisualScriptEmitSignal::VisualScriptEmitSignal() { } static Ref<VisualScriptNode> create_basic_type_call_node(const String& p_name) { Vector<String> path = p_name.split("/"); ERR_FAIL_COND_V(path.size()<4,Ref<VisualScriptNode>()); String base_type = path[2]; String method = path[3]; Ref<VisualScriptFunctionCall> node; node.instance(); Variant::Type type=Variant::VARIANT_MAX; for(int i=0;i<Variant::VARIANT_MAX;i++) { if (Variant::get_type_name(Variant::Type(i))==base_type) { type=Variant::Type(i); break; } } ERR_FAIL_COND_V(type==Variant::VARIANT_MAX,Ref<VisualScriptNode>()); node->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); node->set_basic_type(type); node->set_function(method); return node; } void register_visual_script_func_nodes() { VisualScriptLanguage::singleton->add_register_func("functions/call",create_node_generic<VisualScriptFunctionCall>); VisualScriptLanguage::singleton->add_register_func("functions/set",create_node_generic<VisualScriptPropertySet>); VisualScriptLanguage::singleton->add_register_func("functions/get",create_node_generic<VisualScriptPropertyGet>); //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_self",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>); // VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>); VisualScriptLanguage::singleton->add_register_func("functions/emit_signal",create_node_generic<VisualScriptEmitSignal>); for(int i=0;i<Variant::VARIANT_MAX;i++) { Variant::Type t = Variant::Type(i); String type_name = Variant::get_type_name(t); Variant::CallError ce; Variant vt = Variant::construct(t,NULL,0,ce); List<MethodInfo> ml; vt.get_method_list(&ml); for (List<MethodInfo>::Element *E=ml.front();E;E=E->next()) { VisualScriptLanguage::singleton->add_register_func("functions/by_type/"+type_name+"/"+E->get().name,create_basic_type_call_node); } } }