Browse Source

More improvements to visual script..
fixed a bug of not saving when sub-nodes changed.

Juan Linietsky 9 years ago
parent
commit
fc70824f7c

+ 3 - 0
core/io/resource_format_binary.cpp

@@ -2175,6 +2175,9 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
 			if (takeover_paths) {
 			if (takeover_paths) {
 				r->set_path(p_path+"::"+itos(r->get_subindex()),true);
 				r->set_path(p_path+"::"+itos(r->get_subindex()),true);
 			}
 			}
+#ifdef TOOLS_ENABLED
+			r->set_edited(false);
+#endif
 		} else {
 		} else {
 			save_unicode_string(r->get_path()); //actual external
 			save_unicode_string(r->get_path()); //actual external
 		}
 		}

+ 4 - 0
core/io/resource_format_xml.cpp

@@ -2800,6 +2800,10 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
 			if (takeover_paths) {
 			if (takeover_paths) {
 				res->set_path(p_path+"::"+itos(idx),true);
 				res->set_path(p_path+"::"+itos(idx),true);
 			}
 			}
+#ifdef TOOLS_ENABLED
+			res->set_edited(false);
+#endif
+
 
 
 		}
 		}
 		write_string("\n",false);
 		write_string("\n",false);

+ 3 - 0
modules/visual_script/register_types.cpp

@@ -117,6 +117,9 @@ void unregister_visual_script_types() {
 
 
 	ScriptServer::unregister_language(visual_script_language);
 	ScriptServer::unregister_language(visual_script_language);
 
 
+#ifdef TOOLS_ENABLED
+	VisualScriptEditor::free_clipboard();
+#endif
 	if (visual_script_language)
 	if (visual_script_language)
 		memdelete( visual_script_language );
 		memdelete( visual_script_language );
 
 

+ 20 - 0
modules/visual_script/visual_script.cpp

@@ -907,6 +907,9 @@ void VisualScript::_update_placeholders() {
 
 
 	for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
 	for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
 
 
+		if (!E->get()._export)
+			continue;
+
 		PropertyInfo p = E->get().info;
 		PropertyInfo p = E->get().info;
 		p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
 		p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
 		pinfo.push_back(p);
 		pinfo.push_back(p);
@@ -940,6 +943,9 @@ ScriptInstance* VisualScript::instance_create(Object *p_this) {
 
 
 		for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
 		for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
 
 
+			if (!E->get()._export)
+				continue;
+
 			PropertyInfo p = E->get().info;
 			PropertyInfo p = E->get().info;
 			p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
 			p.name=SCRIPT_VARIABLES_PREFIX+String(E->key());
 			pinfo.push_back(p);
 			pinfo.push_back(p);
@@ -1110,6 +1116,20 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const {
 	}
 	}
 }
 }
 
 
+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;
+}
+
 
 
 void VisualScript::_set_data(const Dictionary& p_data) {
 void VisualScript::_set_data(const Dictionary& p_data) {
 
 

+ 1 - 0
modules/visual_script/visual_script.h

@@ -342,6 +342,7 @@ public:
 
 
 	virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
 	virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
 
 
+	virtual bool are_subnodes_edited() const;
 
 
 	VisualScript();
 	VisualScript();
 	~VisualScript();
 	~VisualScript();

+ 28 - 16
modules/visual_script/visual_script_editor.cpp

@@ -2127,7 +2127,8 @@ Ref<Texture> VisualScriptEditor::get_icon(){
 
 
 bool VisualScriptEditor::is_unsaved(){
 bool VisualScriptEditor::is_unsaved(){
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
-	return script->is_edited();
+
+	return script->is_edited() || script->are_subnodes_edited();
 #else
 #else
 	return false;
 	return false;
 #endif
 #endif
@@ -2722,9 +2723,9 @@ void VisualScriptEditor::_menu_option(int p_what) {
 			if (!script->has_function(edited_func))
 			if (!script->has_function(edited_func))
 				break;
 				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++) {
 			for(int i=0;i<graph->get_child_count();i++) {
 				GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
 				GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
@@ -2738,15 +2739,15 @@ void VisualScriptEditor::_menu_option(int p_what) {
 							return;
 							return;
 						}
 						}
 						if (node.is_valid()) {
 						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;
 				break;
 
 
 			List<VisualScript::SequenceConnection> sequence_connections;
 			List<VisualScript::SequenceConnection> sequence_connections;
@@ -2755,9 +2756,9 @@ void VisualScriptEditor::_menu_option(int p_what) {
 
 
 			for (List<VisualScript::SequenceConnection>::Element *E=sequence_connections.front();E;E=E->next()) {
 			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());
 				}
 				}
 			}
 			}
 
 
@@ -2767,9 +2768,9 @@ void VisualScriptEditor::_menu_option(int p_what) {
 
 
 			for (List<VisualScript::DataConnection>::Element *E=data_connections.front();E;E=E->next()) {
 			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());
 				}
 				}
 			}
 			}
 
 
@@ -2783,7 +2784,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
 			if (!script->has_function(edited_func))
 			if (!script->has_function(edited_func))
 				break;
 				break;
 
 
-			if (clipboard.nodes.empty()) {
+			if (clipboard->nodes.empty()) {
 				EditorNode::get_singleton()->show_warning("Clipboard is empty!");
 				EditorNode::get_singleton()->show_warning("Clipboard is empty!");
 				break;
 				break;
 			}
 			}
@@ -2806,7 +2807,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();
 				Ref<VisualScriptNode> node = E->get()->duplicate();
@@ -2816,7 +2817,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
 
 
 				remap[E->key()]=new_id;
 				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)))) {
 				while(existing_positions.has(paste_pos.snapped(Vector2(2,2)))) {
 					paste_pos+=Vector2(20,20)*EDSCALE;
 					paste_pos+=Vector2(20,20)*EDSCALE;
@@ -2828,7 +2829,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]);
 				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]);
@@ -2836,7 +2837,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);
 				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);
@@ -2921,6 +2922,9 @@ void VisualScriptEditor::_bind_methods() {
 
 
 VisualScriptEditor::VisualScriptEditor() {
 VisualScriptEditor::VisualScriptEditor() {
 
 
+	if (!clipboard) {
+		clipboard = memnew( Clipboard );
+	}
 	updating_graph=false;
 	updating_graph=false;
 
 
 	edit_menu = memnew( MenuButton );
 	edit_menu = memnew( MenuButton );
@@ -3107,6 +3111,14 @@ static ScriptEditorBase * create_editor(const Ref<Script>& p_script) {
 	return NULL;
 	return NULL;
 }
 }
 
 
+
+VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard=NULL;
+
+void VisualScriptEditor::free_clipboard() {
+	if (clipboard)
+		memdelete(clipboard);
+}
+
 static void register_editor_callback() {
 static void register_editor_callback() {
 
 
 	ScriptEditor::register_create_script_editor_function(create_editor);
 	ScriptEditor::register_create_script_editor_function(create_editor);

+ 6 - 1
modules/visual_script/visual_script_editor.h

@@ -13,6 +13,7 @@ class VisualScriptEditorVariableEdit;
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 
 
+
 class VisualScriptEditor : public ScriptEditorBase {
 class VisualScriptEditor : public ScriptEditorBase {
 	OBJ_TYPE(VisualScriptEditor,ScriptEditorBase)
 	OBJ_TYPE(VisualScriptEditor,ScriptEditorBase)
 
 
@@ -109,7 +110,9 @@ class VisualScriptEditor : public ScriptEditorBase {
 
 
 		Set<VisualScript::SequenceConnection> sequence_connections;
 		Set<VisualScript::SequenceConnection> sequence_connections;
 		Set<VisualScript::DataConnection> data_connections;
 		Set<VisualScript::DataConnection> data_connections;
-	} clipboard;
+	};
+
+	static Clipboard *clipboard;
 
 
 
 
 	int error_line;
 	int error_line;
@@ -203,6 +206,8 @@ public:
 
 
 	static void register_editor();
 	static void register_editor();
 
 
+	static void free_clipboard();
+
 	VisualScriptEditor();
 	VisualScriptEditor();
 	~VisualScriptEditor();
 	~VisualScriptEditor();
 };
 };

+ 8 - 7
modules/visual_script/visual_script_flow_control.cpp

@@ -605,7 +605,7 @@ VisualScriptSequence::VisualScriptSequence() {
 
 
 int VisualScriptSwitch::get_output_sequence_port_count() const {
 int VisualScriptSwitch::get_output_sequence_port_count() const {
 
 
-	return case_values.size();
+	return case_values.size()+1;
 }
 }
 
 
 bool VisualScriptSwitch::has_input_sequence_port() const{
 bool VisualScriptSwitch::has_input_sequence_port() const{
@@ -625,6 +625,9 @@ int VisualScriptSwitch::get_output_value_port_count() const{
 
 
 String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const {
 String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const {
 
 
+	if (p_port==case_values.size())
+		return "done";
+
 	if (case_values[p_port].value.get_type()==Variant::NIL)
 	if (case_values[p_port].value.get_type()==Variant::NIL)
 		return "null";
 		return "null";
 	return case_values[p_port].value;
 	return case_values[p_port].value;
@@ -664,20 +667,18 @@ 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) {
 	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_values.size(); //exit
 		}
 		}
 
 
 		for(int i=0;i<case_values.size();i++) {
 		for(int i=0;i<case_values.size();i++) {
 
 
 			if (*p_inputs[0]==case_values[i]) {
 			if (*p_inputs[0]==case_values[i]) {
-				return i;
+				return i|STEP_FLAG_PUSH_STACK_BIT;
 			}
 			}
 		}
 		}
 
 
-		return STEP_NO_ADVANCE_BIT;
+		return case_values.size();
 	}
 	}
 
 
 
 

+ 25 - 0
modules/visual_script/visual_script_func_nodes.cpp

@@ -513,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) {
 void VisualScriptFunctionCall::_set_argument_cache(const Dictionary& p_cache) {
@@ -700,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("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("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;
 	String bt;
 	for(int i=0;i<Variant::VARIANT_MAX;i++) {
 	for(int i=0;i<Variant::VARIANT_MAX;i++) {
 		if (i>0)
 		if (i>0)
@@ -732,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::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::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); //when set, if loaded properly, will override argument count.
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),_SCS("set_use_default_args"),_SCS("get_use_default_args"));
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"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.
 	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_SELF );
@@ -747,6 +760,7 @@ public:
 	VisualScriptFunctionCall::CallMode call_mode;
 	VisualScriptFunctionCall::CallMode call_mode;
 	NodePath node_path;
 	NodePath node_path;
 	int input_args;
 	int input_args;
+	bool validate;
 	bool returns;
 	bool returns;
 	VisualScriptFunctionCall::RPCCallMode rpc_mode;
 	VisualScriptFunctionCall::RPCCallMode rpc_mode;
 	StringName function;
 	StringName function;
@@ -874,7 +888,16 @@ public:
 					object->call(function,p_inputs,input_args,r_error);
 					object->call(function,p_inputs,input_args,r_error);
 				}
 				}
 			} break;
 			} break;
+
 		}
 		}
+
+		if (!validate) {
+
+			//ignore call errors if validation is disabled
+			r_error.error=Variant::CallError::CALL_OK;
+			r_error_str=String();
+		}
+
 		return 0;
 		return 0;
 
 
 	}
 	}
@@ -894,10 +917,12 @@ VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstanc
 	instance->node_path=base_path;
 	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->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->rpc_mode=rpc_call_mode;
+	instance->validate=validate;
 	return instance;
 	return instance;
 }
 }
 VisualScriptFunctionCall::VisualScriptFunctionCall() {
 VisualScriptFunctionCall::VisualScriptFunctionCall() {
 
 
+	validate=true;
 	call_mode=CALL_MODE_SELF;
 	call_mode=CALL_MODE_SELF;
 	basic_type=Variant::NIL;
 	basic_type=Variant::NIL;
 	use_default_args=0;
 	use_default_args=0;

+ 4 - 0
modules/visual_script/visual_script_func_nodes.h

@@ -35,6 +35,7 @@ private:
 	int use_default_args;
 	int use_default_args;
 	RPCCallMode rpc_call_mode;
 	RPCCallMode rpc_call_mode;
 	StringName singleton;
 	StringName singleton;
+	bool validate;
 
 
 
 
 	Node *_get_base_node() const;
 	Node *_get_base_node() const;
@@ -96,6 +97,9 @@ public:
 	void set_use_default_args(int p_amount);
 	void set_use_default_args(int p_amount);
 	int get_use_default_args() const;
 	int get_use_default_args() const;
 
 
+	void set_validate(bool p_amount);
+	bool get_validate() const;
+
 	void set_rpc_call_mode(RPCCallMode p_mode);
 	void set_rpc_call_mode(RPCCallMode p_mode);
 	RPCCallMode get_rpc_call_mode() const;
 	RPCCallMode get_rpc_call_mode() const;
 
 

+ 1 - 0
modules/visual_script/visual_script_nodes.cpp

@@ -2858,6 +2858,7 @@ Variant::Type VisualScriptConstructor::get_constructor_type() const {
 void VisualScriptConstructor::set_constructor(const Dictionary& p_info) {
 void VisualScriptConstructor::set_constructor(const Dictionary& p_info) {
 
 
 	constructor=MethodInfo::from_dict(p_info);
 	constructor=MethodInfo::from_dict(p_info);
+	ports_changed_notify();
 }
 }
 
 
 Dictionary VisualScriptConstructor::get_constructor() const {
 Dictionary VisualScriptConstructor::get_constructor() const {

+ 12 - 3
scene/2d/physics_body_2d.cpp

@@ -1228,15 +1228,16 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 
 
 
 
 
 
-Vector2 KinematicBody2D::move_and_slide(const Vector2& p_linear_velocity,const Vector2& p_floor_direction,int p_max_bounces) {
+Vector2 KinematicBody2D::move_and_slide(const Vector2& p_linear_velocity,const Vector2& p_floor_direction,float p_slope_stop_min_velocity,int p_max_bounces) {
 
 
-	Vector2 motion = p_linear_velocity*get_fixed_process_delta_time();
+	Vector2 motion = (move_and_slide_floor_velocity+p_linear_velocity)*get_fixed_process_delta_time();
 	Vector2 lv = p_linear_velocity;
 	Vector2 lv = p_linear_velocity;
 
 
 	move_and_slide_on_floor=false;
 	move_and_slide_on_floor=false;
 	move_and_slide_on_ceiling=false;
 	move_and_slide_on_ceiling=false;
 	move_and_slide_on_wall=false;
 	move_and_slide_on_wall=false;
 	move_and_slide_colliders.clear();
 	move_and_slide_colliders.clear();
+	move_and_slide_floor_velocity=Vector2();
 
 
 	while(motion!=Vector2() && p_max_bounces) {
 	while(motion!=Vector2() && p_max_bounces) {
 
 
@@ -1244,13 +1245,21 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2& p_linear_velocity,const V
 
 
 		if (is_colliding()) {
 		if (is_colliding()) {
 
 
+
 			if (p_floor_direction==Vector2()) {
 			if (p_floor_direction==Vector2()) {
 				//all is a wall
 				//all is a wall
 				move_and_slide_on_wall=true;
 				move_and_slide_on_wall=true;
 			} else {
 			} else {
 				if ( get_collision_normal().dot(p_floor_direction) > Math::cos(Math::deg2rad(45))) { //floor
 				if ( get_collision_normal().dot(p_floor_direction) > Math::cos(Math::deg2rad(45))) { //floor
+
+
 					move_and_slide_on_floor=true;
 					move_and_slide_on_floor=true;
 					move_and_slide_floor_velocity=get_collider_velocity();
 					move_and_slide_floor_velocity=get_collider_velocity();
+
+					if (get_travel().length()<1 && ABS((lv.x-move_and_slide_floor_velocity.x))<p_slope_stop_min_velocity) {
+						revert_motion();
+						return Vector2();
+					}
 				} else if ( get_collision_normal().dot(p_floor_direction) < Math::cos(Math::deg2rad(45))) { //ceiling
 				} else if ( get_collision_normal().dot(p_floor_direction) < Math::cos(Math::deg2rad(45))) { //ceiling
 					move_and_slide_on_ceiling=true;
 					move_and_slide_on_ceiling=true;
 				} else {
 				} else {
@@ -1367,7 +1376,7 @@ void KinematicBody2D::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody2D::move);
 	ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody2D::move);
 	ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to);
 	ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to);
-	ObjectTypeDB::bind_method(_MD("move_and_slide","linear_velocity","floor_normal","max_bounces"),&KinematicBody2D::move_and_slide,DEFVAL(Vector2(0,0)),DEFVAL(4));
+	ObjectTypeDB::bind_method(_MD("move_and_slide","linear_velocity","floor_normal","slope_stop_min_velocity","max_bounces"),&KinematicBody2D::move_and_slide,DEFVAL(Vector2(0,0)),DEFVAL(5),DEFVAL(4));
 
 
 	ObjectTypeDB::bind_method(_MD("test_move","rel_vec"),&KinematicBody2D::test_move);
 	ObjectTypeDB::bind_method(_MD("test_move","rel_vec"),&KinematicBody2D::test_move);
 	ObjectTypeDB::bind_method(_MD("get_travel"),&KinematicBody2D::get_travel);
 	ObjectTypeDB::bind_method(_MD("get_travel"),&KinematicBody2D::get_travel);

+ 1 - 1
scene/2d/physics_body_2d.h

@@ -335,7 +335,7 @@ public:
 	void set_collision_margin(float p_margin);
 	void set_collision_margin(float p_margin);
 	float get_collision_margin() const;
 	float get_collision_margin() const;
 
 
-	Vector2 move_and_slide(const Vector2& p_linear_velocity,const Vector2& p_floor_direction=Vector2(0,0),int p_max_bounces=4);
+	Vector2 move_and_slide(const Vector2& p_linear_velocity, const Vector2& p_floor_direction=Vector2(0,0), float p_slope_stop_min_velocity=5, int p_max_bounces=4);
 	bool is_move_and_slide_on_floor() const;
 	bool is_move_and_slide_on_floor() const;
 	bool is_move_and_slide_on_wall() const;
 	bool is_move_and_slide_on_wall() const;
 	bool is_move_and_slide_on_ceiling() const;
 	bool is_move_and_slide_on_ceiling() const;

+ 36 - 0
scene/2d/ray_cast_2d.cpp

@@ -29,6 +29,7 @@
 #include "ray_cast_2d.h"
 #include "ray_cast_2d.h"
 #include "servers/physics_2d_server.h"
 #include "servers/physics_2d_server.h"
 #include "collision_object_2d.h"
 #include "collision_object_2d.h"
+#include "physics_body_2d.h"
 
 
 void RayCast2D::set_cast_to(const Vector2& p_point) {
 void RayCast2D::set_cast_to(const Vector2& p_point) {
 
 
@@ -106,6 +107,30 @@ bool RayCast2D::is_enabled() const {
 	return enabled;
 	return enabled;
 }
 }
 
 
+void RayCast2D::set_exclude_parent_body(bool p_exclude_parent_body) {
+
+	if (exclude_parent_body==p_exclude_parent_body)
+		return;
+
+	exclude_parent_body=p_exclude_parent_body;
+
+	if (!is_inside_tree())
+		return;
+
+
+
+	if (get_parent()->cast_to<PhysicsBody2D>()) {
+		if (exclude_parent_body)
+			exclude.insert( get_parent()->cast_to<PhysicsBody2D>()->get_rid() );
+		else
+			exclude.erase( get_parent()->cast_to<PhysicsBody2D>()->get_rid() );
+	}
+}
+
+bool RayCast2D::get_exclude_parent_body() const{
+
+	return exclude_parent_body;
+}
 
 
 void RayCast2D::_notification(int p_what) {
 void RayCast2D::_notification(int p_what) {
 
 
@@ -118,6 +143,12 @@ void RayCast2D::_notification(int p_what) {
 			else
 			else
 				set_fixed_process(false);
 				set_fixed_process(false);
 
 
+			if (get_parent()->cast_to<PhysicsBody2D>()) {
+				if (exclude_parent_body)
+					exclude.insert( get_parent()->cast_to<PhysicsBody2D>()->get_rid() );
+				else
+					exclude.erase( get_parent()->cast_to<PhysicsBody2D>()->get_rid() );
+			}
 		} break;
 		} break;
 		case NOTIFICATION_EXIT_TREE: {
 		case NOTIFICATION_EXIT_TREE: {
 
 
@@ -254,7 +285,11 @@ void RayCast2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_type_mask","mask"),&RayCast2D::set_type_mask);
 	ObjectTypeDB::bind_method(_MD("set_type_mask","mask"),&RayCast2D::set_type_mask);
 	ObjectTypeDB::bind_method(_MD("get_type_mask"),&RayCast2D::get_type_mask);
 	ObjectTypeDB::bind_method(_MD("get_type_mask"),&RayCast2D::get_type_mask);
 
 
+	ObjectTypeDB::bind_method(_MD("set_exclude_parent_body","mask"),&RayCast2D::set_exclude_parent_body);
+	ObjectTypeDB::bind_method(_MD("get_exclude_parent_body"),&RayCast2D::get_exclude_parent_body);
+
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"exclude_parent"),_SCS("set_exclude_parent_body"),_SCS("get_exclude_parent_body"));
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"layer_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"layer_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"type_mask",PROPERTY_HINT_FLAGS,"Static,Kinematic,Rigid,Character,Area"),_SCS("set_type_mask"),_SCS("get_type_mask"));
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"type_mask",PROPERTY_HINT_FLAGS,"Static,Kinematic,Rigid,Character,Area"),_SCS("set_type_mask"),_SCS("get_type_mask"));
@@ -269,4 +304,5 @@ RayCast2D::RayCast2D() {
 	layer_mask=1;
 	layer_mask=1;
 	type_mask=Physics2DDirectSpaceState::TYPE_MASK_COLLISION;
 	type_mask=Physics2DDirectSpaceState::TYPE_MASK_COLLISION;
 	cast_to=Vector2(0,50);
 	cast_to=Vector2(0,50);
+	exclude_parent_body=true;
 }
 }

+ 4 - 0
scene/2d/ray_cast_2d.h

@@ -45,6 +45,7 @@ class RayCast2D : public Node2D {
 	Set<RID> exclude;
 	Set<RID> exclude;
 	uint32_t layer_mask;
 	uint32_t layer_mask;
 	uint32_t type_mask;
 	uint32_t type_mask;
+	bool exclude_parent_body;
 
 
 
 
 	Vector2 cast_to;
 	Vector2 cast_to;
@@ -66,6 +67,9 @@ public:
 	void set_type_mask(uint32_t p_mask);
 	void set_type_mask(uint32_t p_mask);
 	uint32_t get_type_mask() const;
 	uint32_t get_type_mask() const;
 
 
+	void set_exclude_parent_body(bool p_exclude_parent_body);
+	bool get_exclude_parent_body() const;
+
 	bool is_colliding() const;
 	bool is_colliding() const;
 	Object *get_collider() const;
 	Object *get_collider() const;
 	int get_collider_shape() const;
 	int get_collider_shape() const;

+ 4 - 0
scene/resources/scene_format_text.cpp

@@ -1289,6 +1289,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_re
 			}
 			}
 
 
 			internal_resources[res]=idx;
 			internal_resources[res]=idx;
+#ifdef TOOLS_ENABLED
+			res->set_edited(false);
+#endif
+
 
 
 		}
 		}
 
 

+ 11 - 1
servers/physics_2d/space_2d_sw.cpp

@@ -681,11 +681,21 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p
 				Vector2 a = sr[i*2+0];
 				Vector2 a = sr[i*2+0];
 				Vector2 b = sr[i*2+1];
 				Vector2 b = sr[i*2+1];
 
 
+				Vector2 rel = b-a;
+				float d = rel.length();
+				if (d==0)
+					continue;
+
+				Vector2 n = rel/d;
+				float traveled = n.dot(recover_motion);
+				a+=n*traveled;
+
+
 			//	float d = a.distance_to(b);
 			//	float d = a.distance_to(b);
 
 
 				//if (d<margin)
 				//if (d<margin)
 				///	continue;
 				///	continue;
-				recover_motion+=(b-a)*0.4;
+				recover_motion+=(b-a)*0.2;
 			}
 			}
 
 
 			if (recover_motion==Vector2()) {
 			if (recover_motion==Vector2()) {