Ver Fonte

-make signals throw an error when target method is not found, fixes #2036
-removed 4 arguments limit for emit_signal() from script
-remvoed 4 arguments limit for call_deferred() from script

Juan Linietsky há 9 anos atrás
pai
commit
3d0bd1a3f3
7 ficheiros alterados com 140 adições e 126 exclusões
  1. 1 1
      core/input_map.cpp
  2. 47 57
      core/message_queue.cpp
  3. 6 1
      core/message_queue.h
  4. 53 67
      core/object.cpp
  5. 1 0
      core/object.h
  6. 29 0
      core/variant.cpp
  7. 3 0
      core/variant.h

+ 1 - 1
core/input_map.cpp

@@ -248,7 +248,7 @@ bool InputMap::event_is_joy_motion_action_pressed(const InputEvent& p_event) con
 					if (e.joy_motion.axis==p_event.joy_motion.axis) {
 						if (
 								(e.joy_motion.axis_value * p_event.joy_motion.axis_value >0) && //same axis
-								ABS(e.joy_motion.axis_value>0.5) && ABS(p_event.joy_motion.axis_value>0.5) )
+								ABS(e.joy_motion.axis_value)>0.5 && ABS(p_event.joy_motion.axis_value)>0.5 )
 							pressed=true;
 					}
 

+ 47 - 57
core/message_queue.cpp

@@ -28,7 +28,7 @@
 /*************************************************************************/
 #include "message_queue.h"
 #include "globals.h"
-
+#include "script_language.h"
 MessageQueue *MessageQueue::singleton=NULL;
 
 MessageQueue *MessageQueue::get_singleton() {
@@ -36,26 +36,11 @@ MessageQueue *MessageQueue::get_singleton() {
 	return singleton;
 }
 
-Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_DECLARE) {
+Error MessageQueue::push_call(ObjectID p_id,const StringName& p_method,const Variant** p_args,int p_argcount,bool p_show_error) {
 
 	_THREAD_SAFE_METHOD_
 
-	uint8_t room_needed=sizeof(Message);
-	int args=0;
-	if (p_arg5.get_type()!=Variant::NIL)
-		args=5;
-	else if (p_arg4.get_type()!=Variant::NIL)
-		args=4;
-	else if (p_arg3.get_type()!=Variant::NIL)
-		args=3;
-	else if (p_arg2.get_type()!=Variant::NIL)
-		args=2;
-	else if (p_arg1.get_type()!=Variant::NIL)
-		args=1;
-	else
-		args=0;
-
-	room_needed+=sizeof(Variant)*args;
+	int room_needed=sizeof(Message)+sizeof(Variant)*p_argcount;
 
 	if ((buffer_end+room_needed) >= buffer_size) {
 		String type;
@@ -65,53 +50,43 @@ Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT
 		statistics();
 
 	}
+
 	ERR_FAIL_COND_V( (buffer_end+room_needed) >= buffer_size , ERR_OUT_OF_MEMORY );
 	Message * msg = memnew_placement( &buffer[ buffer_end ], Message );
-	msg->args=args;
+	msg->args=p_argcount;
 	msg->instance_ID=p_id;
 	msg->target=p_method;
 	msg->type=TYPE_CALL;
-	buffer_end+=sizeof(Message);
+	if (p_show_error)
+		msg->type|=FLAG_SHOW_ERROR;
 
+	buffer_end+=sizeof(Message);
 
-	if (args>=1) {
+	for(int i=0;i<p_argcount;i++) {
 
 		Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
 		buffer_end+=sizeof(Variant);
-		*v=p_arg1;
-	}
-
-	if (args>=2) {
+		*v=*p_args[i];
 
-		Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
-		buffer_end+=sizeof(Variant);
-		*v=p_arg2;
 	}
 
-	if (args>=3) {
+	return OK;
+}
 
-		Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
-		buffer_end+=sizeof(Variant);
-		*v=p_arg3;
+Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_DECLARE) {
 
-	}
+	VARIANT_ARGPTRS;
 
-	if (args>=4) {
+	int argc=0;
 
-		Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
-		buffer_end+=sizeof(Variant);
-		*v=p_arg4;
+	for(int i=0;i<VARIANT_ARG_MAX;i++) {
+		if (argptr[i]->get_type()==Variant::NIL)
+			break;
+		argc++;
 	}
 
-	if (args>=5) {
+	return push_call(p_id,p_method,argptr,argc,false);
 
-		Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
-		buffer_end+=sizeof(Variant);
-		*v=p_arg5;
-	}
-
-
-	return OK;
 }
 
 Error MessageQueue::push_set(ObjectID p_id, const StringName& p_prop, const Variant& p_value) {
@@ -212,7 +187,7 @@ void MessageQueue::statistics() {
 		if (target!=NULL) {
 
 
-			switch(message->type) {
+			switch(message->type&FLAG_MASK) {
 
 				case TYPE_CALL: {
 
@@ -251,7 +226,7 @@ void MessageQueue::statistics() {
 
 
 		read_pos+=sizeof(Message);
-		if (message->type!=TYPE_NOTIFICATION)
+		if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION)
 			read_pos+=sizeof(Variant)*message->args;
 	}
 
@@ -322,6 +297,26 @@ int MessageQueue::get_max_buffer_usage() const {
 	return buffer_max_used;
 }
 
+
+void MessageQueue::_call_function(Object* p_target, const StringName& p_func, const Variant *p_args, int p_argcount,bool p_show_error) {
+
+	const Variant **argptrs=NULL;
+	if (p_argcount) {
+		argptrs = (const Variant**)alloca(sizeof(Variant*)*p_argcount);
+		for(int i=0;i<p_argcount;i++) {
+			argptrs[i]=&p_args[i];
+		}
+	}
+
+	Variant::CallError ce;
+	p_target->call(p_func,argptrs,p_argcount,ce);
+	if (p_show_error && ce.error!=Variant::CallError::CALL_OK) {
+
+		ERR_PRINTS("Error calling deferred method: "+Variant::get_call_error_text(p_target,p_func,argptrs,p_argcount,ce));
+
+	}
+}
+
 void MessageQueue::flush() {
 
 
@@ -347,7 +342,7 @@ void MessageQueue::flush() {
 
 		if (target!=NULL) {
 
-			switch(message->type) {
+			switch(message->type&FLAG_MASK) {
 				case TYPE_CALL: {
 
 					Variant *args= (Variant*)(message+1);
@@ -355,12 +350,7 @@ void MessageQueue::flush() {
 					// messages don't expect a return value
 
 
-					target->call( message->target,
-						(message->args>=1) ? args[0] : Variant(),
-						(message->args>=2) ? args[1] : Variant(),
-						(message->args>=3) ? args[2] : Variant(),
-						(message->args>=4) ? args[3] : Variant(),
-						(message->args>=5) ? args[4] : Variant() );
+					_call_function(target,message->target,args,message->args,message->type&FLAG_SHOW_ERROR);
 
 					for(int i=0;i<message->args;i++) {
 						args[i].~Variant();
@@ -386,7 +376,7 @@ void MessageQueue::flush() {
 		}
 
 		uint32_t advance = sizeof(Message);
-		if (message->type!=TYPE_NOTIFICATION)
+		if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION)
 			advance+=sizeof(Variant)*message->args;
 		message->~Message();
 
@@ -423,14 +413,14 @@ MessageQueue::~MessageQueue() {
 		Message *message = (Message*)&buffer[ read_pos ];
 		Variant *args= (Variant*)(message+1);
 		int argc = message->args;
-		if (message->type!=TYPE_NOTIFICATION) {
+		if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION) {
 			for (int i=0;i<argc;i++)
 				args[i].~Variant();
 		}
 		message->~Message();
 
 		read_pos+=sizeof(Message);
-		if (message->type!=TYPE_NOTIFICATION)
+		if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION)
 			read_pos+=sizeof(Variant)*message->args;
 	}
 

+ 6 - 1
core/message_queue.h

@@ -46,7 +46,10 @@ class MessageQueue {
 	enum {
 		TYPE_CALL,
 		TYPE_NOTIFICATION,
-		TYPE_SET
+		TYPE_SET,
+		FLAG_SHOW_ERROR=1<<14,
+		FLAG_MASK=FLAG_SHOW_ERROR-1
+
 	};
 
 	struct Message {
@@ -65,12 +68,14 @@ class MessageQueue {
 	uint32_t buffer_max_used;
 	uint32_t buffer_size;
 
+	void _call_function(Object* p_target,const StringName& p_func,const Variant *p_args,int p_argcount,bool p_show_error);
 
 	static MessageQueue *singleton;
 public:
 
 	static MessageQueue *get_singleton();
 
+	Error push_call(ObjectID p_id,const StringName& p_method,const Variant** p_args,int p_argcount,bool p_show_error=false);
 	Error push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_LIST);
 	Error push_notification(ObjectID p_id, int p_notification);
 	Error push_set(ObjectID p_id, const StringName& p_prop, const Variant& p_value);

+ 53 - 67
core/object.cpp

@@ -512,17 +512,10 @@ Variant Object::_call_deferred_bind(const Variant** p_args, int p_argcount, Vari
 
 	r_error.error=Variant::CallError::CALL_OK;
 
-	StringName signal = *p_args[0];
-
-	Variant v[VARIANT_ARG_MAX];
-
-
-	for(int i=0;i<MIN(5,p_argcount-1);i++) {
+	StringName method = *p_args[0];
 
-		v[i]=*p_args[i+1];
-	}
+	MessageQueue::get_singleton()->push_call(get_instance_ID(),method,&p_args[1],p_argcount-1);
 
-	call_deferred(signal,v[0],v[1],v[2],v[3],v[4]);
 	return Variant();
 
 }
@@ -839,6 +832,8 @@ void Object::call_multilevel(const StringName& p_name, VARIANT_ARG_DECLARE) {
 
 Variant Object::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
 
+	r_error.error=Variant::CallError::CALL_OK;
+
 	if (p_method==CoreStringNames::get_singleton()->_free) {
 		//free must be here, before anything, always ready
 #ifdef DEBUG_ENABLED
@@ -1130,21 +1125,22 @@ Variant Object::_emit_signal(const Variant** p_args, int p_argcount, Variant::Ca
 
 	StringName signal = *p_args[0];
 
-	Variant v[VARIANT_ARG_MAX];
-
 
-	for(int i=0;i<MIN(5,p_argcount-1);i++) {
+	const Variant**args=NULL;
 
-		v[i]=*p_args[i+1];
+	int argc=p_argcount-1;
+	if (argc) {
+		args=&p_args[1];
 	}
 
-	emit_signal(signal,v[0],v[1],v[2],v[3],v[4]);
+	emit_signal(signal,args,argc);
+
 	return Variant();
-}
 
+}
 
 
-void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
+void Object::emit_signal(const StringName& p_name,const Variant** p_args,int p_argcount) {
 
 	if (_block_signals)
 		return; //no emit, signals blocked
@@ -1167,10 +1163,12 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
 
 	OBJ_DEBUG_LOCK
 
+	Vector<const Variant*> bind_mem;
+
+
 	for(int i=0;i<ssize;i++) {
 
 		const Connection &c = slot_map.getv(i).conn;
-		VARIANT_ARGPTRS
 
 		Object *target;
 #ifdef DEBUG_ENABLED
@@ -1181,21 +1179,37 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
 #endif
 
 
-		int bind_count=c.binds.size();
-		int bind=0;
+		const Variant **args=p_args;
+		int argc=p_argcount;
 
-		for(int i=0;bind < bind_count && i<VARIANT_ARG_MAX;i++) {
+		if (c.binds.size()) {
+			//handle binds
+			bind_mem.resize(p_argcount+c.binds.size());
 
-			if (argptr[i]->get_type()==Variant::NIL) {
-				argptr[i]=&c.binds[bind];
-				bind++;
+			for(int j=0;j<p_argcount;j++) {
+				bind_mem[j]=p_args[j];
+			}
+			for(int j=0;j<c.binds.size();j++) {
+				bind_mem[p_argcount+j]=&c.binds[j];
 			}
+
+			args=bind_mem.ptr();
+			argc=bind_mem.size();
 		}
 
 		if (c.flags&CONNECT_DEFERRED) {
-			MessageQueue::get_singleton()->push_call(target->get_instance_ID(),c.method,VARIANT_ARGPTRS_PASS);
+			MessageQueue::get_singleton()->push_call(target->get_instance_ID(),c.method,args,argc,true);
 		} else {
-			target->call( c.method, VARIANT_ARGPTRS_PASS );
+			Variant::CallError ce;
+			target->call( c.method, args, argc,ce );
+			if (ce.error!=Variant::CallError::CALL_OK) {
+
+				if (ce.error==Variant::CallError::CALL_ERROR_INVALID_METHOD && !ObjectTypeDB::type_exists( target->get_type_name() ) ) {
+					//most likely object is not initialized yet, do not throw error.
+				} else {
+					ERR_PRINTS("Error calling method from signal '"+String(p_name)+"': "+Variant::get_call_error_text(target,c.method,args,argc,ce));
+				}
+			}
 		}
 
 		if (c.flags&CONNECT_ONESHOT) {
@@ -1208,57 +1222,29 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
 
 	}
 
-#if 0
-
-	//old (deprecated and dangerous code)
-	s->lock++;
-	for( Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.front();E;E=E->next() ) {
-
-		const Signal::Target& t = E->key();
-		const Signal::Slot& s = E->get();
-		const Connection &c = s.cE->get();
 
-		VARIANT_ARGPTRS
+	while (!disconnect_data.empty()) {
 
-		int bind_count=c.binds.size();
-		int bind=0;
+		const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
+		disconnect(dd.signal,dd.target,dd.method);
+		disconnect_data.pop_front();
+	}
 
-		for(int i=0;bind < bind_count && i<VARIANT_ARG_MAX;i++) {
+}
 
-			if (argptr[i]->get_type()==Variant::NIL) {
-				argptr[i]=&c.binds[bind];
-				bind++;
-			}
-		}
+void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
 
-		if (c.flags&CONNECT_DEFERRED) {
-			MessageQueue::get_singleton()->push_call(t._id,t.method,VARIANT_ARGPTRS_PASS);
-		} else {
-			Object *obj = ObjectDB::get_instance(t._id);
-			ERR_CONTINUE(!obj); //yeah this should always be here
-			obj->call( t.method, VARIANT_ARGPTRS_PASS );
-		}
+	VARIANT_ARGPTRS;
 
-		if (c.flags&CONNECT_ONESHOT) {
-			_ObjectSignalDisconnectData dd;
-			dd.signal=p_name;
-			dd.target=ObjectDB::get_instance(t._id);
-			dd.method=t.method;
-			disconnect_data.push_back(dd);
-		}
+	int argc=0;
 
+	for(int i=0;i<VARIANT_ARG_MAX;i++) {
+		if (argptr[i]->get_type()==Variant::NIL)
+			break;
+		argc++;
 	}
 
-
-
-	s->lock--;
-#endif
-	while (!disconnect_data.empty()) {
-
-		const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
-		disconnect(dd.signal,dd.target,dd.method);
-		disconnect_data.pop_front();
-	}
+	emit_signal(p_name,argptr,argc);
 
 }
 

+ 1 - 0
core/object.h

@@ -593,6 +593,7 @@ public:
 
 	void add_user_signal(const MethodInfo& p_signal);
 	void emit_signal(const StringName& p_name,VARIANT_ARG_LIST);
+	void emit_signal(const StringName& p_name, const Variant** p_args, int p_argcount);
 	void get_signal_list(List<MethodInfo> *p_signals ) const;
 	void get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const;
 	void get_all_signal_connections(List<Connection> *p_connections) const;

+ 29 - 0
core/variant.cpp

@@ -2992,3 +2992,32 @@ String Variant::get_construct_string() const {
 	return vars;
 
 }
+
+String Variant::get_call_error_text(Object* p_base, const StringName& p_method,const Variant** p_argptrs,int p_argcount,const Variant::CallError &ce) {
+
+
+	String err_text;
+
+	if (ce.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+		int errorarg=ce.argument;
+		err_text="Cannot convert argument "+itos(errorarg+1)+" from "+Variant::get_type_name(p_argptrs[errorarg]->get_type())+" to "+Variant::get_type_name(ce.expected)+".";
+	} else if (ce.error==Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+		err_text="Expected "+itos(ce.argument)+" arguments.";
+	} else if (ce.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+		err_text="Expected "+itos(ce.argument)+" arguments.";
+	} else if (ce.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) {
+		err_text="Method not found.";
+	} else if (ce.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+		err_text="Instance is null";
+	} else if (ce.error==Variant::CallError::CALL_OK){
+		return "Call OK";
+	}
+
+	String class_name = p_base->get_type();
+	Ref<Script> script = p_base->get_script();
+	if (script.is_valid() && script->get_path().is_resource_file()) {
+
+		class_name+="("+script->get_path().get_file()+")";
+	}
+	return "'"+class_name+"::"+String(p_method)+"': "+err_text;
+}

+ 3 - 0
core/variant.h

@@ -390,6 +390,9 @@ public:
 
 	Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,CallError &r_error);
 	Variant call(const StringName& p_method,const Variant& p_arg1=Variant(),const Variant& p_arg2=Variant(),const Variant& p_arg3=Variant(),const Variant& p_arg4=Variant(),const Variant& p_arg5=Variant());
+
+	static String get_call_error_text(Object* p_base, const StringName& p_method,const Variant** p_argptrs,int p_argcount,const Variant::CallError &ce);
+
 	static Variant construct(const Variant::Type,const Variant** p_args,int p_argcount,CallError &r_error,bool p_strict=true);
 
 	void get_method_list(List<MethodInfo> *p_list) const;