2
0
Эх сурвалжийг харах

Merge branch 'master' of http://github.com/okamstudio/godot

Anton Yabchinskiy 10 жил өмнө
parent
commit
ff755f93eb
48 өөрчлөгдсөн 935 нэмэгдсэн , 198 устгасан
  1. 5 1
      core/io/resource_format_xml.cpp
  2. 1 1
      core/variant.h
  3. 1 1
      demos/3d/navmesh/navmesh.gd
  4. BIN
      demos/3d/truck_town/crane.scn
  5. BIN
      demos/misc/tween/icon.png
  6. 151 48
      doc/base/classes.xml
  7. 3 1
      drivers/gles2/rasterizer_gles2.cpp
  8. 1 1
      drivers/gles2/shaders/material.glsl
  9. 285 22
      modules/gdscript/gd_editor.cpp
  10. 12 4
      modules/gdscript/gd_parser.cpp
  11. 3 2
      modules/gdscript/gd_parser.h
  12. 131 35
      modules/gdscript/gd_script.cpp
  13. 11 2
      modules/gdscript/gd_script.h
  14. 1 1
      platform/android/export/export.cpp
  15. 8 4
      platform/isim/detect.py
  16. 5 2
      scene/2d/animated_sprite.cpp
  17. 15 0
      scene/2d/area_2d.cpp
  18. 1 0
      scene/2d/area_2d.h
  19. 1 0
      scene/2d/polygon_2d.cpp
  20. 6 0
      scene/2d/sprite.cpp
  21. 18 0
      scene/3d/area.cpp
  22. 1 0
      scene/3d/area.h
  23. 2 0
      scene/3d/camera.cpp
  24. 2 2
      scene/3d/light.cpp
  25. 10 0
      scene/3d/sprite_3d.cpp
  26. 4 4
      scene/3d/visual_instance.cpp
  27. 11 8
      scene/gui/text_edit.cpp
  28. 7 0
      scene/gui/tree.cpp
  29. 6 0
      scene/main/node.cpp
  30. 1 0
      scene/main/node.h
  31. 3 0
      scene/main/scene_main_loop.cpp
  32. 2 1
      scene/main/timer.cpp
  33. 2 0
      scene/scene_string_names.cpp
  34. 1 0
      scene/scene_string_names.h
  35. 1 1
      servers/physics/body_pair_sw.cpp
  36. 43 1
      servers/physics/collision_solver_sw.cpp
  37. 1 0
      servers/physics/collision_solver_sw.h
  38. 1 1
      servers/visual/rasterizer.cpp
  39. 14 2
      servers/visual/shader_language.cpp
  40. 22 13
      tools/editor/animation_editor.cpp
  41. 2 0
      tools/editor/editor_node.cpp
  42. 1 0
      tools/editor/editor_settings.cpp
  43. 9 0
      tools/editor/plugins/polygon_2d_editor_plugin.cpp
  44. 98 28
      tools/editor/plugins/script_editor_plugin.cpp
  45. 1 1
      tools/editor/plugins/script_editor_plugin.h
  46. 4 1
      tools/editor/plugins/shader_editor_plugin.cpp
  47. 26 9
      tools/export/blender25/io_scene_dae/export_dae.py
  48. 1 1
      version.py

+ 5 - 1
core/io/resource_format_xml.cpp

@@ -193,6 +193,7 @@ Error ResourceInteractiveLoaderXML::close_tag(const String& p_name) {
 
 void ResourceInteractiveLoaderXML::unquote(String& p_str) {
 
+
 	p_str=p_str.strip_edges().replace("\"","").xml_unescape();
 
 	/*p_str=p_str.strip_edges();
@@ -1851,7 +1852,10 @@ void ResourceFormatSaverXMLInstance::escape(String& p_str) {
 	for (int i=1;i<32;i++) {
 
 		char chr[2]={i,0};
-		p_str=p_str.replace(chr,"&#"+String::num(i)+";");
+		const char hexn[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+		const char hex[8]={'&','#','0','0',hexn[i>>4],hexn[i&0xf],';',0};
+
+		p_str=p_str.replace(chr,hex);
 	}
 
 

+ 1 - 1
core/variant.h

@@ -358,7 +358,7 @@ public:
 
 	static String get_operator_name(Operator p_op);
 	static void evaluate(const Operator& p_op,const Variant& p_a, const Variant& p_b,Variant &r_ret,bool &r_valid);
-	static _FORCE_INLINE_ Variant evaluate(Operator& p_op,const Variant& p_a, const Variant& p_b) {
+	static _FORCE_INLINE_ Variant evaluate(const Operator& p_op,const Variant& p_a, const Variant& p_b) {
 
 		bool valid=true;
 		Variant res;

+ 1 - 1
demos/3d/navmesh/navmesh.gd

@@ -76,7 +76,7 @@ func _input(ev):
 
 	if (ev.type==InputEvent.MOUSE_BUTTON and ev.button_index==BUTTON_LEFT and ev.pressed):
                 
-		var from = get_node("cambase/Camera").project_position(ev.pos)
+		var from = get_node("cambase/Camera").project_ray_origin(ev.pos)
 		var to = from+get_node("cambase/Camera").project_ray_normal(ev.pos)*100
 		var p = get_closest_point_to_segment(from,to)
 	

BIN
demos/3d/truck_town/crane.scn


BIN
demos/misc/tween/icon.png


+ 151 - 48
doc/base/classes.xml

@@ -3281,6 +3281,12 @@
 			<description>
 			</description>
 		</method>
+		<method name="get_overlapping_bodies" qualifiers="const" >
+			<return type="Array">
+			</return>
+			<description>
+			</description>
+		</method>
 	</methods>
 	<signals>
 		<signal name="body_enter">
@@ -3418,6 +3424,12 @@
 			<description>
 			</description>
 		</method>
+		<method name="get_overlapping_bodies" qualifiers="const" >
+			<return type="Array">
+			</return>
+			<description>
+			</description>
+		</method>
 	</methods>
 	<signals>
 		<signal name="body_enter">
@@ -4828,6 +4840,10 @@
 		</method>
 	</methods>
 	<signals>
+		<signal name="released">
+			<description>
+			</description>
+		</signal>
 		<signal name="toggled">
 			<argument index="0" name="pressed" type="bool">
 			</argument>
@@ -11647,6 +11663,14 @@
 			<description>
 			</description>
 		</method>
+		<method name="save_png"  >
+			<return type="int">
+			</return>
+			<argument index="0" name="path" type="String" default="0">
+			</argument>
+			<description>
+			</description>
+		</method>
 	</methods>
 	<constants>
 		<constant name="COMPRESS_BC" value="0">
@@ -15474,14 +15498,12 @@
         Finally, when a node is freed, it will free all its children nodes too.
 	</description>
 	<methods>
-		<method name="_enter_scene" qualifiers="virtual" >
+		<method name="_enter_tree" qualifiers="virtual" >
 			<description>
-			Called when entered the scene.
 			</description>
 		</method>
-		<method name="_exit_scene" qualifiers="virtual" >
+		<method name="_exit_tree" qualifiers="virtual" >
 			<description>
-			Called when being removed from the scene.
 			</description>
 		</method>
 		<method name="_fixed_process" qualifiers="virtual" >
@@ -15634,11 +15656,10 @@
 			<description>
 			</description>
 		</method>
-		<method name="is_inside_scene" qualifiers="const" >
+		<method name="is_inside_tree" qualifiers="const" >
 			<return type="bool">
 			</return>
 			<description>
-			Return wether the node is inside a scene tree (a tree where the topmost node is a [RootNode])
 			</description>
 		</method>
 		<method name="is_a_parent_of" qualifiers="const" >
@@ -15882,11 +15903,10 @@
 			<description>
 			</description>
 		</method>
-		<method name="get_scene" qualifiers="const" >
-			<return type="SceneMainLoop">
+		<method name="get_tree" qualifiers="const" >
+			<return type="SceneTree">
 			</return>
 			<description>
-			Get the current SceneMainLoop. Only returned if the node is inside the scene, else returns null.
 			</description>
 		</method>
 		<method name="duplicate" qualifiers="const" >
@@ -15917,28 +15937,24 @@
 		</method>
 	</methods>
 	<signals>
-		<signal name="enter_scene">
+		<signal name="renamed">
 			<description>
-			Emitted when the node enters the scene.
+			Emitted when the node is renamed.
 			</description>
 		</signal>
-		<signal name="renamed">
+		<signal name="enter_tree">
 			<description>
-			Emitted when the node is renamed.
 			</description>
 		</signal>
-		<signal name="exit_scene">
+		<signal name="exit_tree">
 			<description>
-			Emitted when the node exits the scene.
 			</description>
 		</signal>
 	</signals>
 	<constants>
-		<constant name="NOTIFICATION_ENTER_SCENE" value="10">
-			Notification received when the node enters the Scene Tree and gains access to the [RootNode]. Note that children nodes will not have received the notification at that time yet.
+		<constant name="NOTIFICATION_ENTER_TREE" value="10">
 		</constant>
-		<constant name="NOTIFICATION_EXIT_SCENE" value="11">
-			Notification received when the node exits the Scene Tree and loses access to the [RootNode]. Note that parent nodes will not have received the notification at that time yet.
+		<constant name="NOTIFICATION_EXIT_TREE" value="11">
 		</constant>
 		<constant name="NOTIFICATION_MOVED_IN_PARENT" value="12">
 		</constant>
@@ -16554,6 +16570,10 @@
 			</argument>
 			<argument index="1" name="arg1" type="float">
 			</argument>
+			<argument index="2" name="arg2" type="int">
+			</argument>
+			<argument index="3" name="arg3" type="int">
+			</argument>
 			<description>
 			</description>
 		</method>
@@ -17334,7 +17354,7 @@
 		<method name="put_var"  >
 			<return type="int">
 			</return>
-			<argument index="0" name="var" type="Variant">
+			<argument index="0" name="var" type="var">
 			</argument>
 			<description>
 			</description>
@@ -17368,6 +17388,70 @@
 	<constants>
 	</constants>
 </class>
+<class name="PacketPeerUDP" inherits="PacketPeer" category="Core">
+	<brief_description>
+	</brief_description>
+	<description>
+	</description>
+	<methods>
+		<method name="listen"  >
+			<return type="int">
+			</return>
+			<argument index="0" name="port" type="int">
+			</argument>
+			<argument index="1" name="recv_buf_size" type="int" default="65536">
+			</argument>
+			<description>
+			</description>
+		</method>
+		<method name="close"  >
+			<description>
+			</description>
+		</method>
+		<method name="wait"  >
+			<return type="int">
+			</return>
+			<description>
+			</description>
+		</method>
+		<method name="is_listening" qualifiers="const" >
+			<return type="bool">
+			</return>
+			<description>
+			</description>
+		</method>
+		<method name="get_packet_ip" qualifiers="const" >
+			<return type="String">
+			</return>
+			<description>
+			</description>
+		</method>
+		<method name="get_packet_address" qualifiers="const" >
+			<return type="int">
+			</return>
+			<description>
+			</description>
+		</method>
+		<method name="get_packet_port" qualifiers="const" >
+			<return type="int">
+			</return>
+			<description>
+			</description>
+		</method>
+		<method name="set_send_address"  >
+			<return type="int">
+			</return>
+			<argument index="0" name="host" type="String">
+			</argument>
+			<argument index="1" name="port" type="int">
+			</argument>
+			<description>
+			</description>
+		</method>
+	</methods>
+	<constants>
+	</constants>
+</class>
 <class name="Panel" inherits="Control" category="Core">
 	<brief_description>
 	Provides an opaque background for [Control] children.
@@ -18039,6 +18123,30 @@
 			<description>
 			</description>
 		</method>
+		<method name="set_h_frames"  >
+			<argument index="0" name="enable" type="int">
+			</argument>
+			<description>
+			</description>
+		</method>
+		<method name="get_h_frames" qualifiers="const" >
+			<return type="int">
+			</return>
+			<description>
+			</description>
+		</method>
+		<method name="set_v_frames"  >
+			<argument index="0" name="enable" type="int">
+			</argument>
+			<description>
+			</description>
+		</method>
+		<method name="get_v_frames" qualifiers="const" >
+			<return type="int">
+			</return>
+			<description>
+			</description>
+		</method>
 		<method name="set_emission_half_extents"  >
 			<argument index="0" name="extents" type="Vector2">
 			</argument>
@@ -18173,7 +18281,7 @@
 		</constant>
 		<constant name="PARAM_HUE_VARIATION" value="13">
 		</constant>
-		<constant name="PARAM_MAX" value="14">
+		<constant name="PARAM_MAX" value="16">
 		</constant>
 		<constant name="MAX_COLOR_PHASES" value="4">
 		</constant>
@@ -19534,7 +19642,7 @@
 			<description>
 			</description>
 		</method>
-		<method name="free"  >
+		<method name="free_rid"  >
 			<argument index="0" name="rid" type="RID">
 			</argument>
 			<description>
@@ -20994,7 +21102,7 @@
 			<description>
 			</description>
 		</method>
-		<method name="free"  >
+		<method name="free_rid"  >
 			<argument index="0" name="rid" type="RID">
 			</argument>
 			<description>
@@ -24091,6 +24199,12 @@
 			<description>
 			</description>
 		</method>
+		<method name="get_colliding_bodies" qualifiers="const" >
+			<return type="Array">
+			</return>
+			<description>
+			</description>
+		</method>
 	</methods>
 	<signals>
 		<signal name="body_enter">
@@ -24364,6 +24478,12 @@
 			Return true if the body has the ability to fall asleep when not moving. See [set_can_sleep].
 			</description>
 		</method>
+		<method name="get_colliding_bodies" qualifiers="const" >
+			<return type="Array">
+			</return>
+			<description>
+			</description>
+		</method>
 	</methods>
 	<signals>
 		<signal name="body_enter">
@@ -25275,13 +25395,10 @@
 		</constant>
 	</constants>
 </class>
-<class name="SceneMainLoop" inherits="MainLoop" category="Core">
+<class name="SceneTree" inherits="MainLoop" category="Core">
 	<brief_description>
-	Scene-Based implementation of the MainLoop.
 	</brief_description>
 	<description>
-	Scene implementation of the MainLoop. All scenes edited using the editor are loaded with this main loop, which provides the base for the scene system.[br]
-	All group operations (get nodes, call, etc) is performed here. All nodes in a group can be called a specific functions, set a property or notified. This happens in scene-order.
 	</description>
 	<methods>
 		<method name="notify_group"  >
@@ -25292,7 +25409,6 @@
 			<argument index="2" name="notification" type="int">
 			</argument>
 			<description>
-			Call a notification in all the nodes belonging to a given group. See GROUP_CALL_* enum for options.
 			</description>
 		</method>
 		<method name="set_group"  >
@@ -25305,7 +25421,6 @@
 			<argument index="3" name="value" type="var">
 			</argument>
 			<description>
-			Set a property in all the nodes belonging to a given group. See GROUP_CALL_* enum for options.
 			</description>
 		</method>
 		<method name="get_nodes_in_group"  >
@@ -25314,7 +25429,6 @@
 			<argument index="0" name="arg0" type="String">
 			</argument>
 			<description>
-			Get all the nods belonging to a given group.
 			</description>
 		</method>
 		<method name="get_root" qualifiers="const" >
@@ -25327,21 +25441,18 @@
 			<argument index="0" name="enabled" type="bool">
 			</argument>
 			<description>
-			Set to true if the application will quit automatically when quit is requested (Alt-f4 or ctrl-c).
 			</description>
 		</method>
 		<method name="set_editor_hint"  >
 			<argument index="0" name="enable" type="bool">
 			</argument>
 			<description>
-			Set to true to tell nodes and the scene that it is being edited. This is used by editors, not release.
 			</description>
 		</method>
 		<method name="is_editor_hint" qualifiers="const" >
 			<return type="bool">
 			</return>
 			<description>
-			Return true if the scene is being run inside an editor.
 			</description>
 		</method>
 		<method name="set_edited_scene_root"  >
@@ -25360,19 +25471,16 @@
 			<argument index="0" name="enable" type="bool">
 			</argument>
 			<description>
-			Set pause. The built-in pause system is very basic and only meant to avoid processing nodes not allowed to work in pause mode.
 			</description>
 		</method>
 		<method name="is_paused" qualifiers="const" >
 			<return type="bool">
 			</return>
 			<description>
-			Return true if the scene is paused.
 			</description>
 		</method>
 		<method name="set_input_as_handled"  >
 			<description>
-			Handle a current input event (avoid further processing of it).
 			</description>
 		</method>
 		<method name="get_node_count" qualifiers="const" >
@@ -25385,12 +25493,10 @@
 			<return type="int">
 			</return>
 			<description>
-			Return the frame index (how many frames were drawn).
 			</description>
 		</method>
 		<method name="quit"  >
 			<description>
-			Quit the application.
 			</description>
 		</method>
 		<method name="set_screen_stretch"  >
@@ -25407,7 +25513,6 @@
 			<argument index="0" name="obj" type="Object">
 			</argument>
 			<description>
-			Queue an object for deletion next time the loop goes idle.
 			</description>
 		</method>
 		<method name="call_group"  >
@@ -25428,41 +25533,33 @@
 			<argument index="7" name="arg4" type="var" default="NULL">
 			</argument>
 			<description>
-			Call a function for all the nodes in a given group.
 			</description>
 		</method>
 	</methods>
 	<signals>
 		<signal name="screen_resized">
 			<description>
-			Emitted when the screen changes size.
 			</description>
 		</signal>
 		<signal name="node_removed">
 			<argument index="0" name="node" type="Object">
 			</argument>
 			<description>
-			Emitted when a node is removed from the scene.
 			</description>
 		</signal>
 		<signal name="tree_changed">
 			<description>
-			Emitted when the scene tree changed (nodes added/removed/moved/etc)
 			</description>
 		</signal>
 	</signals>
 	<constants>
 		<constant name="GROUP_CALL_DEFAULT" value="0">
-			Regular group call flag (no flags).
 		</constant>
 		<constant name="GROUP_CALL_REVERSE" value="1">
-			Call a group in inverse-scene order.
 		</constant>
 		<constant name="GROUP_CALL_REALTIME" value="2">
-			Call a group immediately (usually calls are delivered on idle).
 		</constant>
 		<constant name="GROUP_CALL_UNIQUE" value="4">
-			Call a group only once, even if call is performed many times.
 		</constant>
 		<constant name="STRETCH_MODE_DISABLED" value="0">
 		</constant>
@@ -32543,7 +32640,7 @@
 			<description>
 			</description>
 		</method>
-		<method name="get_pos" qualifiers="const" >
+		<method name="get_stream_pos" qualifiers="const" >
 			<return type="float">
 			</return>
 			<description>
@@ -32601,6 +32698,12 @@
 			<description>
 			</description>
 		</method>
+		<method name="set_audio_track"  >
+			<argument index="0" name="idx" type="int">
+			</argument>
+			<description>
+			</description>
+		</method>
 	</methods>
 	<constants>
 	</constants>

+ 3 - 1
drivers/gles2/rasterizer_gles2.cpp

@@ -4648,7 +4648,8 @@ void RasterizerGLES2::_add_geometry( const Geometry* p_geometry, const InstanceD
 	if (m->flags[VS::MATERIAL_FLAG_INVERT_FACES])
 		e->mirror=!e->mirror;
 
-	e->light_type=0xFF; // no lights!
+	//e->light_type=0xFF; // no lights!
+	e->light_type=3; //light type 3 is no light?
 	e->light=0xFFFF;
 
 	if (!shadow && !has_blend_alpha && has_alpha && m->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA) {
@@ -9122,6 +9123,7 @@ void RasterizerGLES2::init() {
 	use_anisotropic_filter=true;
 	float_linear_supported=true;
 	float_supported=true;
+	use_rgba_shadowmaps=false;
 
 	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&anisotropic_level);
 	anisotropic_level=MIN(anisotropic_level,float(GLOBAL_DEF("rasterizer/anisotropic_filter_level",4.0)));

+ 1 - 1
drivers/gles2/shaders/material.glsl

@@ -1214,7 +1214,7 @@ LIGHT_SHADER_CODE
 # if !defined(LIGHT_TYPE_DIRECTIONAL) && !defined(LIGHT_TYPE_OMNI) && !defined (LIGHT_TYPE_SPOT)
 //none
 #ifndef SHADELESS
-	diffuse.rgb=vec3(0.0,0.0,0.0);
+	diffuse.rgb=ambient_light *diffuse.rgb;
 #endif
 
 # endif

+ 285 - 22
modules/gdscript/gd_editor.cpp

@@ -66,7 +66,7 @@ bool GDScriptLanguage::validate(const String& p_script, int &r_line_error,int &r
 
 	GDParser parser;
 
-	Error err = parser.parse(p_script,p_path.get_base_dir(),true);
+	Error err = parser.parse(p_script,p_path.get_base_dir(),true,p_path);
 	if (err) {
 		r_line_error=parser.get_error_line();
 		r_col_error=parser.get_error_column();
@@ -421,8 +421,240 @@ static bool _parse_completion_variant(const Variant& p_var,List<String>* r_optio
 
 }
 
+struct GDCompletionIdentifier {
 
-static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_options,List<String>::Element *p_indices) {
+	StringName obj_type;
+	Variant::Type type;
+};
+
+
+static GDCompletionIdentifier _guess_identifier_type(const GDParser::ClassNode *p_class,int p_line,const StringName& p_identifier);
+
+
+static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_class,const GDParser::Node *p_node,int p_line,GDCompletionIdentifier &r_type) {
+
+
+	if (p_node->type==GDParser::Node::TYPE_CONSTANT) {
+
+		const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(p_node);
+
+		r_type.type=cn->value.get_type();
+		if (r_type.type==Variant::OBJECT) {
+			Object *obj = cn->value;
+			if (obj) {
+				r_type.obj_type=obj->get_type();
+			}
+		}
+
+		return true;
+	} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {
+
+		r_type.type=Variant::DICTIONARY;
+		return true;
+	} else if (p_node->type==GDParser::Node::TYPE_ARRAY) {
+
+		r_type.type=Variant::ARRAY;
+		return true;
+
+	} else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+
+		MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function);
+		r_type.type=mi.return_val.type;
+		if (mi.return_val.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+			r_type.obj_type=mi.return_val.hint_string;
+		}
+		return true;
+	} else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+
+		r_type=_guess_identifier_type(p_class,p_line,static_cast<const GDParser::IdentifierNode *>(p_node)->name);
+		return true;
+	} else if (p_node->type==GDParser::Node::TYPE_SELF) {
+		//eeh...
+		return false;
+
+	} else if (p_node->type==GDParser::Node::TYPE_OPERATOR) {
+		const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_node);
+		if (op->op==GDParser::OperatorNode::OP_CALL) {
+
+			if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
+
+				const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode *>(op->arguments[0]);
+				r_type.type=tn->vtype;
+				return true;
+			} else if (op->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+
+
+				const GDParser::BuiltInFunctionNode *bin = static_cast<const GDParser::BuiltInFunctionNode *>(op->arguments[0]);
+				return _guess_identifier_type_in_expression(p_class,bin,p_line,r_type);
+
+			} else if (op->arguments.size()>1 && op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+				GDCompletionIdentifier base;
+				if (!_guess_identifier_type_in_expression(p_class,op->arguments[0],p_line,base))
+					return false;
+				StringName id = static_cast<const GDParser::IdentifierNode *>(p_node)->name;
+				if (base.type==Variant::OBJECT) {
+
+					if (ObjectTypeDB::has_method(base.obj_type,id)) {
+#ifdef TOOLS_ENABLED
+						MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id);
+						PropertyInfo pi = mb->get_argument_info(-1);
+
+						r_type.type=pi.type;
+						if (pi.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+							r_type.obj_type=pi.hint_string;
+						}
+#else
+						return false;
+#endif
+					} else {
+						return false;
+					}
+				} else {
+					//method for some variant..
+					Variant::CallError ce;
+					Variant v = Variant::construct(base.type,NULL,0,ce);
+					List<MethodInfo> mi;
+					v.get_method_list(&mi);
+					for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+
+						if (E->get().name==id.operator String()) {
+
+							MethodInfo mi = E->get();
+							r_type.type=mi.return_val.type;
+							if (mi.return_val.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+								r_type.obj_type=mi.return_val.hint_string;
+							}
+							return true;
+						}
+					}
+
+				}
+
+
+			}
+		} else {
+
+			Variant::Operator vop = Variant::OP_MAX;
+			switch(op->op) {
+				case GDParser::OperatorNode::OP_ASSIGN_ADD: vop=Variant::OP_ADD; break;
+				case GDParser::OperatorNode::OP_ASSIGN_SUB: vop=Variant::OP_SUBSTRACT; break;
+				case GDParser::OperatorNode::OP_ASSIGN_MUL: vop=Variant::OP_MULTIPLY; break;
+				case GDParser::OperatorNode::OP_ASSIGN_DIV: vop=Variant::OP_DIVIDE; break;
+				case GDParser::OperatorNode::OP_ASSIGN_MOD: vop=Variant::OP_MODULE; break;
+				case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: vop=Variant::OP_SHIFT_LEFT; break;
+				case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: vop=Variant::OP_SHIFT_RIGHT; break;
+				case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: vop=Variant::OP_BIT_AND; break;
+				case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: vop=Variant::OP_BIT_OR; break;
+				case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: vop=Variant::OP_BIT_XOR; break;
+				default:{}
+
+			}
+
+			if (vop==Variant::OP_MAX)
+				return false;
+
+			GDCompletionIdentifier p1;
+			GDCompletionIdentifier p2;
+
+			if (op->arguments[0]) {
+				if (!_guess_identifier_type_in_expression(p_class,op->arguments[0],p_line,p1))
+					return false;
+			}
+
+			if (op->arguments.size()>1) {
+				if (!_guess_identifier_type_in_expression(p_class,op->arguments[1],p_line,p2))
+					return false;
+			}
+
+			Variant::CallError ce;
+			Variant v1 = Variant::construct(p1.type,NULL,0,ce);
+			Variant v2 = Variant::construct(p2.type,NULL,0,ce);
+			// avoid potential invalid ops
+			if ((vop==Variant::OP_DIVIDE || vop==Variant::OP_MODULE) && v2.get_type()==Variant::INT) {
+				v2=1;
+			}
+			if (vop==Variant::OP_DIVIDE && v2.get_type()==Variant::REAL) {
+				v2=1.0;
+			}
+
+			Variant r;
+			bool valid;
+			Variant::evaluate(vop,v1,v2,r,valid);
+			if (!valid)
+				return false;
+			r_type.type=r.get_type();
+			return true;
+
+		}
+
+	}
+
+	return false;
+}
+
+static bool _guess_identifier_type_in_block(const GDParser::ClassNode *p_class,const GDParser::BlockNode *p_block,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
+
+
+	for(int i=0;i<p_block->sub_blocks.size();i++) {
+		//parse inner first
+		if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) {
+			if (_guess_identifier_type_in_block(p_class,p_block->sub_blocks[i],p_line,p_identifier,r_type))
+				return true;
+		}
+	}
+
+
+
+	const GDParser::Node *last_assign=NULL;
+	int last_assign_line=-1;
+
+	for (int i=0;i<p_block->statements.size();i++) {
+
+		if (p_block->statements[i]->line>p_line)
+			break;
+
+
+		if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+
+			const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]);
+			if (lv->assign && lv->name==p_identifier) {
+				last_assign=lv->assign;
+				last_assign_line=p_block->statements[i]->line;
+			}
+		}
+
+		if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) {
+			const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_block->statements[i]);
+			if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
+
+				if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) {
+					const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[0]);
+					if (id->name==p_identifier) {
+						last_assign=op->arguments[1];
+						last_assign_line=p_block->statements[i]->line;
+					}
+				}
+			}
+		}
+	}
+
+	//use the last assignment, (then backwards?)
+	if (last_assign) {
+		return _guess_identifier_type_in_expression(p_class,last_assign,last_assign_line-1,r_type);
+	}
+
+	return false;
+}
+
+static GDCompletionIdentifier _guess_identifier_type(const GDParser::ClassNode *p_class,int p_line,const StringName& p_identifier) {
+
+
+	return GDCompletionIdentifier();
+}
+
+static void _parse_expression_node(const GDParser::ClassNode *p_class,const GDParser::Node *p_node,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
 
 
 
@@ -433,7 +665,7 @@ static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_
 	} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {
 
 		const GDParser::DictionaryNode *dn=static_cast<const GDParser::DictionaryNode*>(p_node);
-		for(int i=0;i<dn->elements.size();i++) {
+		for (int i=0;i<dn->elements.size();i++) {
 
 			if (dn->elements[i].key->type==GDParser::Node::TYPE_CONSTANT) {
 
@@ -444,7 +676,7 @@ static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_
 					if (p_indices) {
 
 						if (str==p_indices->get()) {
-							_parse_expression_node(dn->elements[i].value,r_options,p_indices->next());
+							_parse_expression_node(p_class,dn->elements[i].value,p_line,r_options,p_indices->next());
 							return;
 						}
 
@@ -454,15 +686,28 @@ static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_
 				}
 			}
 		}
+	} else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+
+		MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function);
+
+		Variant::CallError ce;
+		_parse_completion_variant(Variant::construct(mi.return_val.type,NULL,0,ce),r_options,p_indices?p_indices->next():NULL);
+	} else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+		//GDCompletionIdentifier idt = _guess_identifier_type(p_class,p_line-1,static_cast<const GDParser::IdentifierNode *>(p_node)->name);
+		//Variant::CallError ce;
+		//_parse_completion_variant(Variant::construct(mi.return_val.type,NULL,0,ce),r_options,p_indices?p_indices->next():NULL);
 	}
 }
 
-static bool _parse_completion_block(const GDParser::BlockNode *p_block,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
+static bool _parse_completion_block(const GDParser::ClassNode *p_class,const GDParser::BlockNode *p_block,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
+
+	print_line("COMPLETION BLOCK "+itos(p_block->line)+" -> "+itos(p_block->end_line));
 
 	for(int i=0;i<p_block->sub_blocks.size();i++) {
 		//parse inner first
 		if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) {
-			if (_parse_completion_block(p_block->sub_blocks[i],p_line,r_options,p_indices))
+			if (_parse_completion_block(p_class,p_block->sub_blocks[i],p_line,r_options,p_indices))
 				return true;
 		}
 	}
@@ -470,29 +715,39 @@ static bool _parse_completion_block(const GDParser::BlockNode *p_block,int p_lin
 	if (p_indices) {
 
 		//parse indices in expressions :|
+
+		const GDParser::Node *last_assign=NULL;
+		int last_assign_line=-1;
+
 		for (int i=0;i<p_block->statements.size();i++) {
 
 			if (p_block->statements[i]->line>p_line)
 				break;
 
+
 			if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
 
-				const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]);
+				const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]);				
 				if (lv->assign && String(lv->name)==p_indices->get()) {
-
-					_parse_expression_node(lv->assign,r_options,p_indices->next());
-					return true;
+					last_assign=lv->assign;
+					last_assign_line=p_block->statements[i]->line;
 				}
 			}
 		}
 
+		//use the last assignment, (then backwards?)
+		if (last_assign) {
+			_parse_expression_node(p_class,last_assign,last_assign_line,r_options,p_indices->next());
+			return true;
+		}
+
 	} else {
+		//no indices, just add all variables and continue
 		for(int i=0;i<p_block->variables.size();i++) {
 			//parse variables second
 			if (p_line>=p_block->variable_lines[i]) {
 				r_options->push_back(p_block->variables[i]);
-			}
-			else break;
+			} else break;
 
 		}
 	}
@@ -545,13 +800,15 @@ static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,Li
 
 static bool _parse_completion_class(const String& p_base_path,const GDParser::ClassNode *p_class,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
 
-
-	static const char*_type_names[Variant::VARIANT_MAX]={
-		"null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform",
-		"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
-		"Vector2Array","Vector3Array","ColorArray"};
+	//checks known classes or built-in types for completion
 
 	if (p_indices && !p_indices->next()) {
+		//built-in types do not have sub-classes, try these first if no sub-indices exist.
+		static const char*_type_names[Variant::VARIANT_MAX]={
+			"null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform",
+			"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
+			"Vector2Array","Vector3Array","ColorArray"};
+
 		for(int i=0;i<Variant::VARIANT_MAX;i++) {
 
 			if (p_indices->get()==_type_names[i]) {
@@ -567,12 +824,12 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl
 		}
 	}
 
-
+	// check the sub-classes of current class
 
 	for(int i=0;i<p_class->subclasses.size();i++) {
 
 		if (p_line>=p_class->subclasses[i]->line && (p_line<=p_class->subclasses[i]->end_line || p_class->subclasses[i]->end_line==-1)) {
-
+			// if OK in sub-classes, try completing the sub-class
 			if (_parse_completion_class(p_base_path,p_class->subclasses[i],p_line,r_options,p_indices))
 				return true;
 		}
@@ -586,7 +843,7 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl
 
 		if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
 			//if in function, first block stuff from outer to inner
-			if (_parse_completion_block(fu->body,p_line,r_options,p_indices))
+			if (_parse_completion_block(p_class,fu->body,p_line,r_options,p_indices))
 				return true;
 			//then function arguments
 			if (!p_indices) {
@@ -606,7 +863,7 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl
 		if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
 
 			//if in function, first block stuff from outer to inne
-			if (_parse_completion_block(fu->body,p_line,r_options,p_indices))
+			if (_parse_completion_block(p_class,fu->body,p_line,r_options,p_indices))
 				return true;
 			//then function arguments
 			if (!p_indices) {
@@ -757,24 +1014,30 @@ static bool _parse_completion_class(const String& p_base_path,const GDParser::Cl
 
 Error GDScriptLanguage::complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_base, List<String>* r_options) {
 
+
+
 	GDParser p;
 	Error err = p.parse(p_code,p_base_path);
 	// don't care much about error I guess
 	const GDParser::Node* root = p.get_parse_tree();
 	ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_INVALID_DATA);
 
+	print_line("BASE: "+p_base);
 	const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
 
 	List<String> indices;
 	Vector<String> spl = p_base.split(".");
 
 	for(int i=0;i<spl.size()-1;i++) {
+		print_line("INDEX "+itos(i)+":  "+spl[i]);
 		indices.push_back(spl[i]);
 	}
 
+	//parse completion inside of the class first
 	if (_parse_completion_class(p_base,cl,p_line,r_options,indices.front()))
 		return OK;
-	//and the globals x_x?
+
+	//if parsing completion inside of the class fails (none found), try using globals for completion
 	for(Map<StringName,int>::Element *E=globals.front();E;E=E->next()) {
 		if (!indices.empty()) {
 			if (String(E->key())==indices.front()->get()) {

+ 12 - 4
modules/gdscript/gd_parser.cpp

@@ -225,7 +225,14 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 			String path = tokenizer->get_token_constant();
 			if (!path.is_abs_path() && base_path!="")
 				path=base_path+"/"+path;
-			path = path.replace("///","//");
+			path = path.replace("///","//").simplify_path();
+			if (path==self_path) {
+
+				_set_error("Can't preload itself (use 'get_script()').");
+				return NULL;
+
+			}
+
 
 			Ref<Resource> res;
 			if (!validating) {
@@ -2616,8 +2623,9 @@ Error GDParser::_parse(const String& p_base_path) {
 	return OK;
 }
 
-Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path) {
+Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) {
 
+	self_path=p_self_path;
 	GDTokenizerBuffer *tb = memnew( GDTokenizerBuffer );
 	tb->set_code_buffer(p_bytecode);
 	tokenizer=tb;
@@ -2628,9 +2636,9 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p
 }
 
 
-Error GDParser::parse(const String& p_code,const String& p_base_path,bool p_just_validate) {
-
+Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) {
 
+	self_path=p_self_path;
 	GDTokenizerText *tt = memnew( GDTokenizerText );
 	tt->set_code(p_code);
 

+ 3 - 2
modules/gdscript/gd_parser.h

@@ -373,6 +373,7 @@ private:
 	List<int> tab_level;
 
 	String base_path;
+	String self_path;
 
 	PropertyInfo current_export;
 
@@ -398,8 +399,8 @@ public:
 	String get_error() const;
 	int get_error_line() const;
 	int get_error_column() const;
-	Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false);
-	Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path="");
+	Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="");
+	Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path="",const String& p_self_path="");
 
 	const Node *get_parse_tree() const;
 

+ 131 - 35
modules/gdscript/gd_script.cpp

@@ -1523,6 +1523,7 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
 	placeholders.erase(p_placeholder);
 }
 
+/*
 void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
 
 
@@ -1563,7 +1564,7 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
 
 	p_placeholder->update(plist,default_values);
 
-}
+}*/
 #endif
 ScriptInstance* GDScript::instance_create(Object *p_this) {
 
@@ -1582,7 +1583,8 @@ ScriptInstance* GDScript::instance_create(Object *p_this) {
 		}*/
 		PlaceHolderScriptInstance *si = memnew( PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(),Ref<Script>(this),p_this) );
 		placeholders.insert(si);
-		_update_placeholder(si);
+		//_update_placeholder(si);
+		_update_exports();
 		return si;
 #else
 		return NULL;
@@ -1623,61 +1625,136 @@ String GDScript::get_source_code() const {
 }
 void GDScript::set_source_code(const String& p_code) {
 
+	if (source==p_code)
+		return;
 	source=p_code;
+#ifdef TOOLS_ENABLED
+	source_changed_cache=true;
+	//print_line("SC CHANGED "+get_path());
+#endif
+
 }
 
+#ifdef TOOLS_ENABLED
+void GDScript::_update_exports_values(Map<StringName,Variant>& values, List<PropertyInfo> &propnames) {
+
+	if (base_cache.is_valid()) {
+		base_cache->_update_exports_values(values,propnames);
+	}
+
+	for(Map<StringName,Variant>::Element *E=member_default_values_cache.front();E;E=E->next()) {
+		values[E->key()]=E->get();
+	}
+
+	for (List<PropertyInfo>::Element *E=members_cache.front();E;E=E->next()) {
+		propnames.push_back(E->get());
+	}
+
+}
+#endif
 
-void GDScript::_update_exports(Set<PlaceHolderScriptInstance*> *p_instances) {
+bool GDScript::_update_exports() {
 
 #ifdef TOOLS_ENABLED
 
-	String basedir=path;
+	bool changed=false;
 
-	if (basedir=="")
-		basedir=get_path();
+	if (source_changed_cache) {
+		//print_line("updating source for "+get_path());
+		source_changed_cache=false;
+		changed=true;
 
-	if (basedir!="")
-		basedir=basedir.get_base_dir();
+		String basedir=path;
 
-	GDParser parser;
-	Error err = parser.parse(source,basedir,true);
-	if (err)
-		return; //do none
+		if (basedir=="")
+			basedir=get_path();
 
-	const GDParser::Node* root = parser.get_parse_tree();
-	ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS);
+		if (basedir!="")
+			basedir=basedir.get_base_dir();
 
+		GDParser parser;
+		Error err = parser.parse(source,basedir,true,path);
 
+		if (err==OK) {
 
-	const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode*>(root);
+			const GDParser::Node* root = parser.get_parse_tree();
+			ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,false);
 
-	if (c->extends_used && String(c->extends_file)!="") {
+			const GDParser::ClassNode *c = static_cast<const GDParser::ClassNode*>(root);
 
-		Ref<GDScript> bf = ResourceLoader::load(c->extends_file);
-		if (bf.is_valid()) {
+			if (base_cache.is_valid()) {
+				base_cache->inheriters_cache.erase(get_instance_ID());
+				base_cache=Ref<GDScript>();
+			}
 
-			bf->_update_exports(p_instances);
 
-		}
-	}
+			if (c->extends_used && String(c->extends_file)!="") {
 
-	List<PropertyInfo> plist;
+				String path = c->extends_file;
+				if (path.is_rel_path()) {
 
-	Map<StringName,Variant> default_values;
+					String base = get_path();
+					if (base=="" || base.is_rel_path()) {
 
-	for(int i=0;i<c->variables.size();i++) {
-		if (c->variables[i]._export.type==Variant::NIL)
-			continue;
+						ERR_PRINT(("Could not resolve relative path for parent class: "+path).utf8().get_data());
+					} else {
+						path=base.get_base_dir().plus_file(path);
+					}
+				}
+
+				Ref<GDScript> bf = ResourceLoader::load(path);
+
+				if (bf.is_valid()) {
+
+					//print_line("parent is: "+bf->get_path());
+					base_cache=bf;
+					bf->inheriters_cache.insert(get_instance_ID());
+
+					//bf->_update_exports(p_instances,true,false);
+
+				}
+			}
+
+			members_cache.clear();;
+			member_default_values_cache.clear();
+
+			for(int i=0;i<c->variables.size();i++) {
+				if (c->variables[i]._export.type==Variant::NIL)
+					continue;
+
+				members_cache.push_back(c->variables[i]._export);
+				//print_line("found "+c->variables[i]._export.name);
+				member_default_values_cache[c->variables[i].identifier]=c->variables[i].default_value;
+			}
+		}
+	} else {
+		//print_line("unchaged is "+get_path());
 
-		plist.push_back(c->variables[i]._export);
-		default_values[c->variables[i].identifier]=c->variables[i].default_value;
 	}
 
+	if (base_cache.is_valid()) {
+		if (base_cache->_update_exports()) {
+			changed = true;
+		}
+	}
 
-	for (Set<PlaceHolderScriptInstance*>::Element *E=p_instances->front();E;E=E->next()) {
+	if (/*changed &&*/ placeholders.size()) { //hm :(
 
-		E->get()->update(plist,default_values);
+		//print_line("updating placeholders for "+get_path());
+
+		//update placeholders if any
+		Map<StringName,Variant> values;
+		List<PropertyInfo> propnames;
+		_update_exports_values(values,propnames);
+
+		for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
+
+			E->get()->update(propnames,values);
+		}
 	}
+
+	return changed;
+
 #endif
 }
 
@@ -1685,8 +1762,20 @@ void GDScript::update_exports() {
 
 #ifdef TOOLS_ENABLED
 
-	_update_exports(&placeholders);
+	_update_exports();
 
+	Set<ObjectID> copy=inheriters_cache; //might get modified
+
+	//print_line("update exports for "+get_path()+" ic: "+itos(copy.size()));
+	for(Set<ObjectID>::Element *E=copy.front();E;E=E->next()) {
+		Object *id=ObjectDB::get_instance(E->get());
+		if (!id)
+			continue;
+		GDScript *s=id->cast_to<GDScript>();
+		if (!s)
+			continue;
+		s->update_exports();
+	}
 
 #endif
 }
@@ -1718,7 +1807,7 @@ Error GDScript::reload() {
 
 	valid=false;
 	GDParser parser;
-	Error err = parser.parse(source,basedir);
+	Error err = parser.parse(source,basedir,false,path);
 	if (err) {
 		if (ScriptDebugger::get_singleton()) {
 			GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),parser.get_error_line(),"Parser Error: "+parser.get_error());
@@ -1746,10 +1835,10 @@ Error GDScript::reload() {
 	}
 
 #ifdef TOOLS_ENABLED
-	for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
+	/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
 
 		_update_placeholder(E->get());
-	}
+	}*/
 #endif
 	return OK;
 }
@@ -1892,7 +1981,7 @@ Error GDScript::load_byte_code(const String& p_path) {
 
 	valid=false;
 	GDParser parser;
-	Error err = parser.parse_bytecode(bytecode,basedir);
+	Error err = parser.parse_bytecode(bytecode,basedir,get_path());
 	if (err) {
 		_err_print_error("GDScript::load_byte_code",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data());
 		ERR_FAIL_V(ERR_PARSE_ERROR);
@@ -1945,6 +2034,10 @@ Error GDScript::load_source_code(const String& p_path) {
 	}
 
 	source=s;
+#ifdef TOOLS_ENABLED
+	source_changed_cache=true;
+#endif
+	//print_line("LSC :"+get_path());
 	path=p_path;
 	return OK;
 
@@ -1986,6 +2079,9 @@ GDScript::GDScript() {
 	_base=NULL;
 	_owner=NULL;
 	tool=false;
+#ifdef TOOLS_ENABLED
+	source_changed_cache=false;
+#endif
 
 }
 

+ 11 - 2
modules/gdscript/gd_script.h

@@ -245,7 +245,16 @@ friend class GDScriptLanguage;
 	Map<StringName,Ref<GDScript> > subclasses;	
 
 #ifdef TOOLS_ENABLED
+
 	Map<StringName,Variant> member_default_values;
+
+	List<PropertyInfo> members_cache;
+	Map<StringName,Variant> member_default_values_cache;
+	Ref<GDScript> base_cache;
+	Set<ObjectID> inheriters_cache;
+	bool source_changed_cache;
+	void _update_exports_values(Map<StringName,Variant>& values, List<PropertyInfo> &propnames);
+
 #endif
 	Map<StringName,PropertyInfo> member_info;
 
@@ -265,13 +274,13 @@ friend class GDScriptLanguage;
 
 #ifdef TOOLS_ENABLED
 	Set<PlaceHolderScriptInstance*> placeholders;
-	void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
+	//void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
 	virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
 #endif
 
 
 
-	void _update_exports(Set<PlaceHolderScriptInstance *> *p_instances);
+	bool _update_exports();
 
 protected:
 	bool _get(const StringName& p_name,Variant &r_ret) const;

+ 1 - 1
platform/android/export/export.cpp

@@ -1229,7 +1229,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
 		}
 
 		if (!FileAccess::exists(keystore)) {
-			EditorNode::add_io_error("Could not find keytore, unable to export.");
+			EditorNode::add_io_error("Could not find keystore, unable to export.");
 			return ERR_FILE_CANT_OPEN;
 		}
 

+ 8 - 4
platform/isim/detect.py

@@ -60,14 +60,18 @@ def configure(env):
 							'-Xlinker',
 							'-objc_abi_version',
 							'-Xlinker', '2',
+							'-framework', 'AudioToolbox',
+							'-framework', 'AVFoundation',
+							'-framework', 'CoreAudio',
+							'-framework', 'CoreGraphics',
+							'-framework', 'CoreMedia',
 							'-framework', 'Foundation',
+							'-framework', 'Security',
 							'-framework', 'UIKit',
-							'-framework', 'IOKit',
-							'-framework', 'CoreGraphics',
+							'-framework', 'MediaPlayer',
 							'-framework', 'OpenGLES',
 							'-framework', 'QuartzCore',
-							'-framework', 'AudioToolbox',
-							'-framework', 'MediaPlayer',
+							'-framework', 'SystemConfiguration',
 							'-F$ISIMSDK',
 							])
 

+ 5 - 2
scene/2d/animated_sprite.cpp

@@ -27,7 +27,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "animated_sprite.h"
-
+#include "scene/scene_string_names.h"
 void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) {
 
 	set_offset(p_pivot);
@@ -207,7 +207,7 @@ void AnimatedSprite::set_frame(int p_frame) {
 	frame=p_frame;
 	update();
 	_change_notify("frame");
-
+	emit_signal(SceneStringNames::get_singleton()->frame_changed);
 
 }
 int AnimatedSprite::get_frame() const {
@@ -233,6 +233,7 @@ void AnimatedSprite::set_offset(const Point2& p_offset) {
 	offset=p_offset;
 	update();
 	item_rect_changed();
+	_change_notify("offset");
 }
 Point2 AnimatedSprite::get_offset() const {
 
@@ -325,6 +326,8 @@ void AnimatedSprite::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_res_changed"),&AnimatedSprite::_res_changed);
 
+	ADD_SIGNAL(MethodInfo("frame_changed"));
+
 	ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames"));
 	ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame"));
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));

+ 15 - 0
scene/2d/area_2d.cpp

@@ -142,6 +142,8 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
 
 	ERR_FAIL_COND(!body_in && !E);
 
+	locked=true;
+
 	if (body_in) {
 		if (!E) {
 
@@ -197,11 +199,18 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b
 
 	}
 
+	locked=false;
+
+
 }
 
 
 void Area2D::_clear_monitoring() {
 
+	if (locked) {
+		ERR_EXPLAIN("This function can't be used during the in/out signal.");
+	}
+	ERR_FAIL_COND(locked);
 
 	Map<ObjectID,BodyState> bmcopy = body_map;
 	body_map.clear();
@@ -243,6 +252,11 @@ void Area2D::_notification(int p_what) {
 
 void Area2D::set_enable_monitoring(bool p_enable) {
 
+	if (locked) {
+		ERR_EXPLAIN("This function can't be used during the in/out signal.");
+	}
+	ERR_FAIL_COND(locked);
+
 	if (p_enable==monitoring)
 		return;
 
@@ -336,6 +350,7 @@ Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_crea
 	set_gravity_vector(Vector2(0,1));
 	gravity_is_point=false;
 	density=0.1;
+	locked=false;
 	priority=0;
 	monitoring=false;
 	set_enable_monitoring(true);

+ 1 - 0
scene/2d/area_2d.h

@@ -52,6 +52,7 @@ private:
 	real_t density;
 	int priority;
 	bool monitoring;
+	bool locked;
 
 	void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape);
 

+ 1 - 0
scene/2d/polygon_2d.cpp

@@ -359,5 +359,6 @@ Polygon2D::Polygon2D() {
 	tex_rot=0;
 	tex_tile=true;
 	tex_scale=Vector2(1,1);
+	color=Color(1,1,1);
 	rect_cache_dirty=true;
 }

+ 6 - 0
scene/2d/sprite.cpp

@@ -34,6 +34,7 @@
 void Sprite::edit_set_pivot(const Point2& p_pivot) {
 
 	set_offset(p_pivot);
+
 }
 
 Point2 Sprite::edit_get_pivot() const {
@@ -136,6 +137,7 @@ void Sprite::set_offset(const Point2& p_offset) {
 	offset=p_offset;
 	update();
 	item_rect_changed();
+	_change_notify("offset");
 }
 Point2 Sprite::get_offset() const {
 
@@ -199,6 +201,8 @@ void Sprite::set_frame(int p_frame) {
 		item_rect_changed();
 
 	frame=p_frame;
+
+	emit_signal(SceneStringNames::get_singleton()->frame_changed);
 }
 
 int Sprite::get_frame() const {
@@ -307,6 +311,8 @@ void Sprite::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&Sprite::set_modulate);
 	ObjectTypeDB::bind_method(_MD("get_modulate"),&Sprite::get_modulate);
 
+	ADD_SIGNAL(MethodInfo("frame_changed"));
+
 	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
 	ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));

+ 18 - 0
scene/3d/area.cpp

@@ -115,6 +115,7 @@ void Area::_body_enter_tree(ObjectID p_id) {
 
 void Area::_body_exit_tree(ObjectID p_id) {
 
+
 	Object *obj = ObjectDB::get_instance(p_id);
 	Node *node = obj ? obj->cast_to<Node>() : NULL;
 	ERR_FAIL_COND(!node);
@@ -132,6 +133,7 @@ void Area::_body_exit_tree(ObjectID p_id) {
 
 void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape) {
 
+
 	bool body_in = p_status==PhysicsServer::AREA_BODY_ADDED;
 	ObjectID objid=p_instance;
 
@@ -142,6 +144,8 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod
 
 	ERR_FAIL_COND(!body_in && !E);
 
+	locked=true;
+
 	if (body_in) {
 		if (!E) {
 
@@ -197,11 +201,19 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod
 
 	}
 
+	locked=false;
+
+
 }
 
 
 void Area::_clear_monitoring() {
 
+	if (locked) {
+		ERR_EXPLAIN("This function can't be used during the in/out signal.");
+	}
+	ERR_FAIL_COND(locked);
+
 	Map<ObjectID,BodyState> bmcopy = body_map;
 	body_map.clear();
 	//disconnect all monitored stuff
@@ -235,6 +247,11 @@ void Area::_notification(int p_what) {
 
 void Area::set_enable_monitoring(bool p_enable) {
 
+	if (locked) {
+		ERR_EXPLAIN("This function can't be used during the in/out signal.");
+	}
+	ERR_FAIL_COND(locked);
+
 	if (p_enable==monitoring)
 		return;
 
@@ -325,6 +342,7 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru
 
 	space_override=SPACE_OVERRIDE_DISABLED;
 	set_gravity(9.8);;
+	locked=false;
 	set_gravity_vector(Vector3(0,-1,0));
 	gravity_is_point=false;
 	density=0.1;

+ 1 - 0
scene/3d/area.h

@@ -52,6 +52,7 @@ private:
 	real_t density;
 	int priority;
 	bool monitoring;
+	bool locked;
 
 
 	void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape);

+ 2 - 0
scene/3d/camera.cpp

@@ -529,6 +529,8 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
 
 		}
 
+
+
 		Vector3 ray;
 		ray.x = pos.x * (hsize) - hsize/2;
 		ray.y = (1.0 - pos.y) * (vsize) - vsize/2;

+ 2 - 2
scene/3d/light.cpp

@@ -415,11 +415,11 @@ void Light::approximate_opengl_attenuation(float p_constant, float p_linear, flo
 
 	float energy=1.0;
 
-	if (p_constant>0)
+	/*if (p_constant>0)
 		energy=1.0/p_constant; //energy is this
 	else
 		energy=8.0; // some high number..
-
+*/
 
 	if (radius==10000)
 		radius=100; //bug?

+ 10 - 0
scene/3d/sprite_3d.cpp

@@ -275,6 +275,9 @@ void SpriteBase3D::_bind_methods() {
 	BIND_CONSTANT( ALPHA_CUT_DISABLED );
 	BIND_CONSTANT( ALPHA_CUT_DISCARD );
 	BIND_CONSTANT( ALPHA_CUT_OPAQUE_PREPASS );
+
+
+
 }
 
 
@@ -494,6 +497,8 @@ void Sprite3D::set_frame(int p_frame) {
 
 	frame=p_frame;
 	_queue_update();
+	ADD_SIGNAL(MethodInfo("frame_changed"));
+
 }
 
 int Sprite3D::get_frame() const {
@@ -579,6 +584,8 @@ void Sprite3D::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
 	ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
 
+	ADD_SIGNAL(MethodInfo("frame_changed"));
+
 }
 
 Sprite3D::Sprite3D() {
@@ -722,6 +729,8 @@ void AnimatedSprite3D::_bind_methods(){
 	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames"));
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame"));
 
+	ADD_SIGNAL(MethodInfo("frame_changed"));
+
 }
 
 
@@ -764,6 +773,7 @@ void AnimatedSprite3D::set_frame(int p_frame){
 
 	frame=p_frame;
 	_queue_update();
+	emit_signal(SceneStringNames::get_singleton()->frame_changed);
 
 }
 int AnimatedSprite3D::get_frame() const{

+ 4 - 4
scene/3d/visual_instance.cpp

@@ -359,13 +359,13 @@ void GeometryInstance::_bind_methods() {
 GeometryInstance::GeometryInstance() {
 	draw_begin=0;
 	draw_end=0;
+	for(int i=0;i<FLAG_MAX;i++) {
+		flags[i]=false;
+	}
+
 	flags[FLAG_VISIBLE]=true;
 	flags[FLAG_CAST_SHADOW]=true;
 	flags[FLAG_RECEIVE_SHADOWS]=true;
-	flags[FLAG_BILLBOARD]=false;
-	flags[FLAG_BILLBOARD_FIX_Y]=false;
-	flags[FLAG_DEPH_SCALE]=false;
-	flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false;
 	baked_light_instance=NULL;
 	baked_light_texture_id=0;
 	VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);

+ 11 - 8
scene/gui/text_edit.cpp

@@ -1747,16 +1747,16 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
                 }
                 break;}
 
-                default: {
+		default: {
 
-                    scancode_handled=false;
-                } break;
+		    scancode_handled=false;
+		} break;
 
             }
 
             if (scancode_handled)
                 accept_event();
-
+/*
             if (!scancode_handled && !k.mod.command && !k.mod.alt) {
 
                 if (k.unicode>=32) {
@@ -1770,8 +1770,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
                     break;
                 }
             }
-
-            if (!scancode_handled && !k.mod.command && !k.mod.alt) {
+*/
+	    if (!scancode_handled && !k.mod.command && !k.mod.alt) { //for german kbds
 
                 if (k.unicode>=32) {
 
@@ -3150,12 +3150,15 @@ void TextEdit::set_line(int line, String new_text)
 {
     if (line < 0 || line > text.size())
         return;
-    text.set(line, new_text);
+    _remove_text(line, 0, line, text[line].length());
+    _insert_text(line, 0, new_text);
 }
 
 void TextEdit::insert_at(const String &p_text, int at)
 {
-    text.insert(at, p_text);
+	cursor_set_column(0);
+	cursor_set_line(at);
+	_insert_text(at, 0, p_text+"\n");
 }
 
 void TextEdit::set_show_line_numbers(bool p_show) {

+ 7 - 0
scene/gui/tree.cpp

@@ -1693,6 +1693,13 @@ void Tree::text_editor_enter(String p_text) {
 		case TreeItem::CELL_MODE_RANGE: {
 
 			c.val=p_text.to_double();
+			if (c.step>0)
+				c.val=Math::stepify(c.val,c.step);
+			if (c.val<c.min)
+				c.val=c.min;
+			else if (c.val>c.max)
+				c.val=c.max;
+
 			//popup_edited_item->edited_signal.call( popup_edited_item_col );
 		} break;
 	default: { ERR_FAIL(); }

+ 6 - 0
scene/main/node.cpp

@@ -271,6 +271,7 @@ void Node::move_child(Node *p_child,int p_pos) {
 		data.children[i]->data.pos=i;
 	}
 	// notification second
+	move_child_notify(p_child);
 	for (int i=0;i<data.children.size();i++) {
 		data.children[i]->notification( NOTIFICATION_MOVED_IN_PARENT );
 
@@ -310,6 +311,11 @@ void Node::remove_child_notify(Node *p_child) {
 	// to be used when not wanted	
 }
 
+void Node::move_child_notify(Node *p_child) {
+
+	// to be used when not wanted	
+}
+
 void Node::set_fixed_process(bool p_process) {
 	
 	if (data.fixed_process==p_process)

+ 1 - 0
scene/main/node.h

@@ -142,6 +142,7 @@ protected:
 	
 	virtual void add_child_notify(Node *p_child);
 	virtual void remove_child_notify(Node *p_child);
+	virtual void move_child_notify(Node *p_child);
 	void remove_and_delete_child(Node *p_child);
 	
 	void _propagate_replace_owner(Node *p_owner,Node* p_by_owner); 

+ 3 - 0
scene/main/scene_main_loop.cpp

@@ -333,6 +333,9 @@ void SceneTree::input_text( const String& p_text ) {
 void SceneTree::input_event( const InputEvent& p_event ) {
 
 
+	if (is_editor_hint() && (p_event.type==InputEvent::JOYSTICK_MOTION || p_event.type==InputEvent::JOYSTICK_BUTTON))
+		return; //avoid joy input on editor
+
 	root_lock++;
 	//last_id=p_event.ID;
 

+ 2 - 1
scene/main/timer.cpp

@@ -40,7 +40,8 @@ void Timer::_notification(int p_what) {
 #ifdef TOOLS_ENABLED
 				if (get_tree()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()==this || get_tree()->get_edited_scene_root()->is_a_parent_of(this)))
 					break;
-#endif				start();
+#endif
+				start();
 			}
 		} break;
 		case NOTIFICATION_PROCESS: {

+ 2 - 0
scene/scene_string_names.cpp

@@ -150,4 +150,6 @@ SceneStringNames::SceneStringNames() {
 	_pressed=StaticCString::create("_pressed");
 	_toggled=StaticCString::create("_toggled");
 
+	frame_changed=StaticCString::create("frame_changed");
+
 }

+ 1 - 0
scene/scene_string_names.h

@@ -158,6 +158,7 @@ public:
 	StringName _mouse_enter;
 	StringName _mouse_exit;
 
+	StringName frame_changed;
 
 
 };

+ 1 - 1
servers/physics/body_pair_sw.cpp

@@ -175,7 +175,7 @@ void BodyPairSW::validate_contacts() {
 bool BodyPairSW::setup(float p_step) {
 
 	//cannot collide
-	if (A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && A->get_max_contacts_reported()==0 && B->get_max_contacts_reported()==0)) {
+	if ((A->get_layer_mask()&B->get_layer_mask())==0 || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC && A->get_max_contacts_reported()==0 && B->get_max_contacts_reported()==0)) {
 		collided=false;
 		return false;
 	}

+ 43 - 1
servers/physics/collision_solver_sw.cpp

@@ -275,6 +275,44 @@ void CollisionSolverSW::concave_distance_callback(void *p_userdata, ShapeSW *p_c
 }
 
 
+
+bool CollisionSolverSW::solve_distance_plane(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,Vector3& r_point_A,Vector3& r_point_B) {
+
+	const PlaneShapeSW *plane = static_cast<const PlaneShapeSW*>(p_shape_A);
+	if (p_shape_B->get_type()==PhysicsServer::SHAPE_PLANE)
+		return false;
+	Plane p = p_transform_A.xform(plane->get_plane());
+
+	static const int max_supports = 16;
+	Vector3 supports[max_supports];
+	int support_count;
+
+	p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(),max_supports,supports,support_count);
+
+	bool collided=false;
+	Vector3 closest;
+	float closest_d;
+
+
+	for(int i=0;i<support_count;i++) {
+
+		supports[i] = p_transform_B.xform( supports[i] );
+		real_t d = p.distance_to(supports[i]);
+		if (i==0 || d<closest_d) {
+			closest=supports[i];
+			closest_d=d;
+			if (d<=0)
+				collided=true;
+		}
+
+	}
+
+	r_point_A=p.project(closest);
+	r_point_B=closest;
+
+	return collided;
+}
+
 bool CollisionSolverSW::solve_distance(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,Vector3& r_point_A,Vector3& r_point_B,const AABB& p_concave_hint,Vector3 *r_sep_axis) {
 
 	if (p_shape_A->is_concave())
@@ -282,7 +320,11 @@ bool CollisionSolverSW::solve_distance(const ShapeSW *p_shape_A,const Transform&
 
 	if (p_shape_B->get_type()==PhysicsServer::SHAPE_PLANE) {
 
-		return false; //unsupported
+		Vector3 a,b;
+		bool col = solve_distance_plane(p_shape_B,p_transform_B,p_shape_A,p_transform_A,a,b);
+		r_point_A=b;
+		r_point_B=a;
+		return !col;
 
 	} else if (p_shape_B->is_concave()) {
 

+ 1 - 0
servers/physics/collision_solver_sw.h

@@ -42,6 +42,7 @@ private:
 	static bool solve_ray(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result);
 	static bool solve_concave(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result,float p_margin_A=0,float p_margin_B=0);
 	static void concave_distance_callback(void *p_userdata, ShapeSW *p_convex);
+	static bool solve_distance_plane(const ShapeSW *p_shape_A,const Transform& p_transform_A,const ShapeSW *p_shape_B,const Transform& p_transform_B,Vector3& r_point_A,Vector3& r_point_B);
 
 public:
 

+ 1 - 1
servers/visual/rasterizer.cpp

@@ -79,7 +79,7 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) {
 	if (texcoords_used&(1<<VS::FIXED_MATERIAL_TEXCOORD_UV_TRANSFORM)) {
 
 		code+="uniform mat4 fmp_uv_xform;\n";
-		code+="vec2 uv_xform = fmp_uv_xform * UV;\n";
+		code+="vec2 uv_xform = (fmp_uv_xform * vec4(UV,0,1)).xy;\n";
 	}
 
 	/* HANDLE NORMAL MAPPING */

+ 14 - 2
servers/visual/shader_language.cpp

@@ -436,7 +436,10 @@ ShaderLanguage::Token ShaderLanguage::read_token(const CharType* p_text,int p_le
 				return Token(TK_INDENTIFIER,str);
 			}
 
-			return Token(TK_ERROR,"Unknown character");
+			if (GETCHAR(0)>32)
+				return Token(TK_ERROR,"Tokenizer: Unknown character #"+itos(GETCHAR(0))+": '"+String::chr(GETCHAR(0))+"'");
+			else
+				return Token(TK_ERROR,"Tokenizer: Unknown character #"+itos(GETCHAR(0)));
 
 		} break;
 	}
@@ -463,9 +466,9 @@ Error ShaderLanguage::tokenize(const String& p_text,Vector<Token> *p_tokens,Stri
 		if (t.type==TK_ERROR) {
 
 			if (r_error) {
-				return ERR_COMPILATION_FAILED;
 				*r_error=t.text;
 				*r_err_line=line;
+				return ERR_COMPILATION_FAILED;
 			}
 		}
 
@@ -952,10 +955,16 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
 	{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}},
 	{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}},
 	{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}},
+	{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}},
+	{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC3,TYPE_FLOAT}},
+	{OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC4,TYPE_FLOAT}},
 	{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}},
 	{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}},
 	{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}},
 	{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}},
+	{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}},
+	{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC3,TYPE_FLOAT}},
+	{OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC4,TYPE_FLOAT}},
 	{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}},
 	{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}},
 	{OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}},
@@ -2485,6 +2494,9 @@ Error ShaderLanguage::compile(const String& p_code,ShaderType p_type,CompileFunc
 	uint64_t t = OS::get_singleton()->get_ticks_usec();
 
 	Error err = tokenize(p_code,&tokens,r_error,r_err_line,r_err_column);
+	if (err!=OK) {
+		print_line("tokenizer error!");
+	}
 
 	double tf = (OS::get_singleton()->get_ticks_usec()-t)/1000.0;
 	//print_line("tokenize time: "+rtos(tf));

+ 22 - 13
tools/editor/animation_editor.cpp

@@ -2513,6 +2513,7 @@ void AnimationKeyEditor::_query_insert(const InsertData& p_id) {
 
 
 	if (insert_frame!=OS::get_singleton()->get_frames_drawn()) {
+		//clear insert list for the frame if frame changed
 		if (insert_confirm->is_visible())
 			return; //do nothing
 		insert_data.clear();
@@ -2520,19 +2521,29 @@ void AnimationKeyEditor::_query_insert(const InsertData& p_id) {
 	}
 	insert_frame=OS::get_singleton()->get_frames_drawn();
 
+	for (List<InsertData>::Element *E=insert_data.front();E;E=E->next()) {
+		//prevent insertion of multiple tracks
+		if (E->get().path==p_id.path)
+			return; //already inserted a track for this on this frame
+	}
+
 	insert_data.push_back(p_id);
 
 	if (p_id.track_idx==-1) {
-		//potential new key, does not exist		
-		if (insert_data.size()==1)
-			insert_confirm->set_text("Create NEW track for "+p_id.query+" and insert key?");
-		else
-			insert_confirm->set_text("Create "+itos(insert_data.size())+" NEW tracks and insert keys?");
-
-		insert_confirm->get_ok()->set_text("Create");
-		insert_confirm->popup_centered(Size2(300,100));
-		insert_query=true;
-
+		if (bool(EDITOR_DEF("animation/confirm_insert_track",true))) {
+			//potential new key, does not exist		
+			if (insert_data.size()==1)
+				insert_confirm->set_text("Create NEW track for "+p_id.query+" and insert key?");
+			else
+				insert_confirm->set_text("Create "+itos(insert_data.size())+" NEW tracks and insert keys?");
+
+			insert_confirm->get_ok()->set_text("Create");
+			insert_confirm->popup_centered(Size2(300,100));
+			insert_query=true;
+		} else {
+			call_deferred("_insert_delay");
+			insert_queue=true;
+		}
 
 	} else {
 		if (!insert_query && !insert_queue) {
@@ -3143,7 +3154,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
 	//add_child(menu);
 
 	menu_track = memnew( MenuButton );
-	menu_track->set_text("Tracks..");
+	menu_track->set_text("Tracks");
 	hb->add_child(menu_track);
 	menu_track->get_popup()->connect("item_pressed",this,"_menu_track");
 
@@ -3341,8 +3352,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
 	add_child(insert_confirm);
 	insert_confirm->connect("confirmed",this,"_confirm_insert_list");
 
-	EDITOR_DEF("animation_editor/confirm_insert_key",true);
-
 	click.click=ClickOver::CLICK_NONE;
 
 

+ 2 - 0
tools/editor/editor_node.cpp

@@ -2819,6 +2819,8 @@ void EditorNode::animation_editor_make_visible(bool p_visible) {
 		//pd_anim->hide();
 		animation_editor->hide();
 //		scene_root_parent->set_margin(MARGIN_TOP,0);
+		if (!animation_vb->get_parent_control())
+			return;
 		animation_vb->get_parent_control()->minimum_size_changed();
 		top_split->set_collapsed(true);
 	}

+ 1 - 0
tools/editor/editor_settings.cpp

@@ -440,6 +440,7 @@ void EditorSettings::_load_defaults() {
 
 
 	set("animation/autorename_animation_tracks",true);
+	set("animation/confirm_insert_track",true);
 
 	set("property_editor/texture_preview_width",48);
 	set("help/doc_path","");

+ 9 - 0
tools/editor/plugins/polygon_2d_editor_plugin.cpp

@@ -187,6 +187,8 @@ void Polygon2DEditor::_wip_close() {
 
 bool Polygon2DEditor::forward_input_event(const InputEvent& p_event) {
 
+	if (node==NULL)
+		return false;
 
 	switch(p_event.type) {
 
@@ -701,11 +703,16 @@ void Polygon2DEditor::edit(Node *p_collision_polygon) {
 		node=p_collision_polygon->cast_to<Polygon2D>();
 		if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
 			canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
+		node->connect("exit_tree",this,"_node_removed",varray(),CONNECT_ONESHOT);
 		wip.clear();
 		wip_active=false;
 		edited_point=-1;
 
 	} else {
+
+		if (node)
+			node->disconnect("exit_tree",this,"_node_removed");
+
 		node=NULL;
 
 		if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
@@ -723,12 +730,14 @@ void Polygon2DEditor::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("_uv_draw"),&Polygon2DEditor::_uv_draw);
 	ObjectTypeDB::bind_method(_MD("_uv_input"),&Polygon2DEditor::_uv_input);
 	ObjectTypeDB::bind_method(_MD("_uv_scroll_changed"),&Polygon2DEditor::_uv_scroll_changed);
+	ObjectTypeDB::bind_method(_MD("_node_removed"),&Polygon2DEditor::_node_removed);
 
 
 }
 
 Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) {
 
+	node=NULL;
 	canvas_item_editor=NULL;
 	editor=p_editor;
 	undo_redo = editor->get_undo_redo();

+ 98 - 28
tools/editor/plugins/script_editor_plugin.cpp

@@ -608,6 +608,16 @@ bool ScriptEditor::_test_script_times_on_disk() {
 	return all_ok;
 }
 
+void ScriptEditor::swap_lines(TextEdit *tx, int line1, int line2)
+{
+    String tmp = tx->get_line(line1);
+    String tmp2 = tx->get_line(line2);
+    tx->set_line(line2, tmp);
+    tx->set_line(line1, tmp2);
+
+    tx->cursor_set_line(line2);
+}
+
 void ScriptEditor::_menu_option(int p_option) {
 
 
@@ -690,18 +700,38 @@ void ScriptEditor::_menu_option(int p_option) {
             if (scr.is_null())
                 return;
 
-            int line_id = tx->cursor_get_line();
-            int next_id = line_id - 1;
+            if (tx->is_selection_active())
+            {
+                int from_line = tx->get_selection_from_line();
+                int from_col  = tx->get_selection_from_column();
+                int to_line   = tx->get_selection_to_line();
+                int to_column = tx->get_selection_to_column();
+
+                for (int i = from_line; i <= to_line; i++)
+                {
+                    int line_id = i;
+                    int next_id = i - 1;
 
-            if (line_id == 0 || next_id < 0)
-                return;
+                    if (line_id == 0 || next_id < 0)
+                        return;
 
-            String tmp = tx->get_line(line_id);
-            String tmp2 = tx->get_line(next_id);
-            tx->set_line(next_id, tmp);
-            tx->set_line(line_id, tmp2);
+                    swap_lines(tx, line_id, next_id);
+                }
+                int from_line_up = from_line > 0 ? from_line-1 : from_line;
+                int to_line_up   = to_line   > 0 ? to_line-1   : to_line;
+                tx->select(from_line_up, from_col, to_line_up, to_column);
+            }
+            else
+            {
+                int line_id = tx->cursor_get_line();
+                int next_id = line_id - 1;
+
+                if (line_id == 0 || next_id < 0)
+                    return;
+
+                swap_lines(tx, line_id, next_id);
+            }
             tx->update();
-            tx->cursor_set_line(next_id);
 
         } break;
         case EDIT_MOVE_LINE_DOWN: {
@@ -711,18 +741,38 @@ void ScriptEditor::_menu_option(int p_option) {
             if (scr.is_null())
                 return;
 
-            int line_id = tx->cursor_get_line();
-            int next_id = line_id + 1;
+            if (tx->is_selection_active())
+            {
+                int from_line = tx->get_selection_from_line();
+                int from_col  = tx->get_selection_from_column();
+                int to_line   = tx->get_selection_to_line();
+                int to_column = tx->get_selection_to_column();
 
-            if (line_id == tx->get_line_count() || next_id > tx->get_line_count())
-                return;
+                for (int i = to_line; i >= from_line; i--)
+                {
+                    int line_id = i;
+                    int next_id = i + 1;
+
+                    if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
+                        return;
 
-            String tmp = tx->get_line(line_id);
-            String tmp2 = tx->get_line(next_id);
-            tx->set_line(next_id, tmp);
-            tx->set_line(line_id, tmp2);
+                    swap_lines(tx, line_id, next_id);
+                }
+                int from_line_down = from_line < tx->get_line_count() ? from_line+1 : from_line;
+                int to_line_down   = to_line   < tx->get_line_count() ? to_line+1   : to_line;
+                tx->select(from_line_down, from_col, to_line_down, to_column);
+            }
+            else
+            {
+                int line_id = tx->cursor_get_line();
+                int next_id = line_id + 1;
+
+                if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
+                    return;
+
+                swap_lines(tx, line_id, next_id);
+            }
             tx->update();
-            tx->cursor_set_line(next_id);
 
         } break;
         case EDIT_INDENT_LEFT: {
@@ -740,19 +790,39 @@ void ScriptEditor::_menu_option(int p_option) {
                 for (int i = begin; i <= end; i++)
                 {
                     String line_text = tx->get_line(i);
-                    line_text = line_text.substr(1, line_text.length());
-                    tx->set_line(i, line_text);
+                    // begins with tab
+                    if (line_text.begins_with("\t"))
+                    {
+                        line_text = line_text.substr(1, line_text.length());
+                        tx->set_line(i, line_text);
+                    }
+                    // begins with 4 spaces
+                    else if (line_text.begins_with("    "))
+                    {
+                        line_text = line_text.substr(4, line_text.length());
+                        tx->set_line(i, line_text);
+                    }
                 }
             }
             else
             {
                 begin = tx->cursor_get_line();
                 String line_text = tx->get_line(begin);
-                line_text = line_text.substr(1, line_text.length());
-                tx->set_line(begin, line_text);
+                // begins with tab
+                if (line_text.begins_with("\t"))
+                {
+                    line_text = line_text.substr(1, line_text.length());
+                    tx->set_line(begin, line_text);
+                }
+                // begins with 4 spaces
+                else if (line_text.begins_with("    "))
+                {
+                    line_text = line_text.substr(4, line_text.length());
+                    tx->set_line(begin, line_text);
+                }
             }
             tx->update();
-            tx->deselect();
+            //tx->deselect();
 
         } break;
         case EDIT_INDENT_RIGHT: {
@@ -782,7 +852,7 @@ void ScriptEditor::_menu_option(int p_option) {
                 tx->set_line(begin, line_text);
             }
             tx->update();
-            tx->deselect();
+            //tx->deselect();
 
         } break;
         case EDIT_CLONE_DOWN: {
@@ -837,7 +907,7 @@ void ScriptEditor::_menu_option(int p_option) {
                 tx->set_line(begin, line_text);
             }
             tx->update();
-            tx->deselect();
+            //tx->deselect();
 
         } break;
 		case EDIT_COMPLETE: {
@@ -1443,7 +1513,7 @@ void ScriptEditor::_add_callback(Object *p_obj, const String& p_function, const
 		int pos = script->get_language()->find_function(p_function,code);
 		if (pos==-1) {
 			//does not exist
-
+			ste->get_text_edit()->deselect();
 			pos=ste->get_text_edit()->get_line_count()+2;
 			String func = script->get_language()->make_function("",p_function,p_args);
 			//code=code+func;
@@ -1498,8 +1568,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 	edit_menu->get_popup()->add_separator();
 	edit_menu->get_popup()->add_item("Select All",EDIT_SELECT_ALL,KEY_MASK_CMD|KEY_A);
     edit_menu->get_popup()->add_separator();
-    edit_menu->get_popup()->add_item("Move Line Up",EDIT_MOVE_LINE_UP,KEY_MASK_ALT|KEY_UP);
-    edit_menu->get_popup()->add_item("Move Line Down",EDIT_MOVE_LINE_DOWN,KEY_MASK_ALT|KEY_DOWN);
+    edit_menu->get_popup()->add_item("Move Up",EDIT_MOVE_LINE_UP,KEY_MASK_ALT|KEY_UP);
+    edit_menu->get_popup()->add_item("Move Down",EDIT_MOVE_LINE_DOWN,KEY_MASK_ALT|KEY_DOWN);
     edit_menu->get_popup()->add_item("Indent Left",EDIT_INDENT_LEFT,KEY_MASK_ALT|KEY_LEFT);
     edit_menu->get_popup()->add_item("Indent Right",EDIT_INDENT_RIGHT,KEY_MASK_ALT|KEY_RIGHT);
     edit_menu->get_popup()->add_item("Toggle Comment",EDIT_TOGGLE_COMMENT,KEY_MASK_CMD|KEY_SLASH);

+ 1 - 1
tools/editor/plugins/script_editor_plugin.h

@@ -218,7 +218,7 @@ public:
 
 	void get_breakpoints(List<String> *p_breakpoints);
 
-
+    void swap_lines(TextEdit *tx, int line1, int line2);
 
 	void save_external_data();
 

+ 4 - 1
tools/editor/plugins/shader_editor_plugin.cpp

@@ -144,10 +144,13 @@ void ShaderTextEditor::_validate_script() {
 	Error err = ShaderLanguage::compile(code,type,NULL,NULL,&errortxt,&line,&col);
 
 	if (err!=OK) {
-		String error_text="error("+itos(line)+","+itos(col)+"): "+errortxt;
+		String error_text="error("+itos(line+1)+","+itos(col)+"): "+errortxt;
 		set_error(error_text);
+		get_text_edit()->set_line_as_marked(line,true);
 
 	} else {
+		for(int i=0;i<get_text_edit()->get_line_count();i++)
+			get_text_edit()->set_line_as_marked(i,false);
 		set_error("");
 	}
 

+ 26 - 9
tools/export/blender25/io_scene_dae/export_dae.py

@@ -335,7 +335,7 @@ class DaeExporter:
 		return matid
 
 
-	def export_mesh(self,node,armature=None,skeyindex=-1,skel_source=None):
+	def export_mesh(self,node,armature=None,skeyindex=-1,skel_source=None,custom_name=None):
 
 		mesh = node.data
 
@@ -372,9 +372,9 @@ class DaeExporter:
 #				self.export_node(node,il,shape.name)
 				node.data.update()
 				if (armature and k==0):
-					md=self.export_mesh(node,armature,k,mid)
+					md=self.export_mesh(node,armature,k,mid,shape.name)
 				else:
-					md=self.export_mesh(node,None,k)
+					md=self.export_mesh(node,None,k,None,shape.name)
 
 				node.data = p
 				node.data.update()
@@ -596,7 +596,10 @@ class DaeExporter:
 
 
 		meshid = self.new_id("mesh")
-		self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+mesh.name+'">')
+		if (custom_name!=None):
+			self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+custom_name+'">')
+		else:
+			self.writel(S_GEOM,1,'<geometry id="'+meshid+'" name="'+mesh.name+'">')
 
 		self.writel(S_GEOM,2,'<mesh>')
 
@@ -1438,11 +1441,16 @@ class DaeExporter:
 		return tcn
 
 	def export_animations(self):
-
+		tmp_mat = []												# workaround by ndee					
+		for s in self.skeletons:									# workaround by ndee
+			tmp_bone_mat = []										# workaround by ndee
+			for bone in s.pose.bones:								# workaround by ndee
+				tmp_bone_mat.append(Matrix(bone.matrix_basis))		# workaround by ndee
+			tmp_mat.append([Matrix(s.matrix_local),tmp_bone_mat])	# workaround by ndee -> stores skeleton and bone transformations
+			
 		self.writel(S_ANIM,0,'<library_animations>')
 
 
-
 		if (self.config["use_anim_action_all"] and len(self.skeletons)):
 
 			cached_actions = {}
@@ -1473,13 +1481,18 @@ class DaeExporter:
 								bones.append(dp)
 
 				allowed_skeletons=[]
-				for y in self.skeletons:
+				for i,y in enumerate(self.skeletons):				# workaround by ndee
 					if (y.animation_data):
 						for z in y.pose.bones:
 							if (z.bone.name in bones):
 								if (not y in allowed_skeletons):
 									allowed_skeletons.append(y)
 						y.animation_data.action=x;
+						
+						y.matrix_local = tmp_mat[i][0]				# workaround by ndee -> resets the skeleton transformation. 
+						for j,bone in enumerate(s.pose.bones):		# workaround by ndee
+							bone.matrix_basis = Matrix()			# workaround by ndee -> resets the bone transformations. Important if bones in follwing actions miss keyframes
+							
 
 				print("allowed skeletons "+str(allowed_skeletons))
 
@@ -1498,16 +1511,20 @@ class DaeExporter:
 
 			self.writel(S_ANIM_CLIPS,0,'</library_animation_clips>')
 
-			for s in self.skeletons:
+			for i,s in enumerate(self.skeletons):					# workaround by ndee
 				if (s.animation_data==None):
 					continue
 				if s in cached_actions:
 					s.animation_data.action = bpy.data.actions[cached_actions[s]]
 				else:
 					s.animation_data.action = None
+					for j,bone in enumerate(s.pose.bones):			# workaround by ndee
+						bone.matrix_basis = tmp_mat[i][1][j]		# workaround by ndee  -> resets the bone transformation to what they were before exporting.
 		else:
 			self.export_animation(self.scene.frame_start,self.scene.frame_end)
-
+		
+			
+		
 		self.writel(S_ANIM,0,'</library_animations>')
 
 	def export(self):

+ 1 - 1
version.py

@@ -2,6 +2,6 @@ short_name="godot"
 name="Godot Engine"
 major=1
 minor=0
-status="rc1"
+status="rc2"