diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp
index 2a79e6647d..75384d4ab6 100644
--- a/core/io/resource_format_xml.cpp
+++ b/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);
}
diff --git a/core/variant.h b/core/variant.h
index f651e38352..9109f4ad08 100644
--- a/core/variant.h
+++ b/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;
diff --git a/demos/3d/navmesh/navmesh.gd b/demos/3d/navmesh/navmesh.gd
index a81a5e90d6..b5dc488ec3 100644
--- a/demos/3d/navmesh/navmesh.gd
+++ b/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)
diff --git a/demos/3d/truck_town/crane.scn b/demos/3d/truck_town/crane.scn
index 080bd8ea17..2c4645af69 100644
Binary files a/demos/3d/truck_town/crane.scn and b/demos/3d/truck_town/crane.scn differ
diff --git a/demos/misc/tween/icon.png b/demos/misc/tween/icon.png
new file mode 100644
index 0000000000..3e991fcc29
Binary files /dev/null and b/demos/misc/tween/icon.png differ
diff --git a/doc/base/classes.xml b/doc/base/classes.xml
index 2c49926d66..35de0106b5 100644
--- a/doc/base/classes.xml
+++ b/doc/base/classes.xml
@@ -3281,6 +3281,12 @@
+
+
+
+
+
+
@@ -3418,6 +3424,12 @@
+
+
+
+
+
+
@@ -4828,6 +4840,10 @@
+
+
+
+
@@ -11647,6 +11663,14 @@
+
+
+
+
+
+
+
+
@@ -15474,14 +15498,12 @@
Finally, when a node is freed, it will free all its children nodes too.
-
+
- Called when entered the scene.
-
+
- Called when being removed from the scene.
@@ -15634,11 +15656,10 @@
-
+
- Return wether the node is inside a scene tree (a tree where the topmost node is a [RootNode])
@@ -15882,11 +15903,10 @@
-
-
+
+
- Get the current SceneMainLoop. Only returned if the node is inside the scene, else returns null.
@@ -15917,28 +15937,24 @@
-
-
- Emitted when the node enters the scene.
-
-
Emitted when the node is renamed.
-
+
+
+
+
+
- Emitted when the node exits the scene.
-
- 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.
+
-
- 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.
+
@@ -16554,6 +16570,10 @@
+
+
+
+
@@ -17334,7 +17354,7 @@
-
+
@@ -17368,6 +17388,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Provides an opaque background for [Control] children.
@@ -18039,6 +18123,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -18173,7 +18281,7 @@
-
+
@@ -19534,7 +19642,7 @@
-
+
@@ -20994,7 +21102,7 @@
-
+
@@ -24091,6 +24199,12 @@
+
+
+
+
+
+
@@ -24364,6 +24478,12 @@
Return true if the body has the ability to fall asleep when not moving. See [set_can_sleep].
+
+
+
+
+
+
@@ -25275,13 +25395,10 @@
-
+
- Scene-Based implementation of the MainLoop.
- 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.
@@ -25292,7 +25409,6 @@
- Call a notification in all the nodes belonging to a given group. See GROUP_CALL_* enum for options.
@@ -25305,7 +25421,6 @@
- Set a property in all the nodes belonging to a given group. See GROUP_CALL_* enum for options.
@@ -25314,7 +25429,6 @@
- Get all the nods belonging to a given group.
@@ -25327,21 +25441,18 @@
- Set to true if the application will quit automatically when quit is requested (Alt-f4 or ctrl-c).
- Set to true to tell nodes and the scene that it is being edited. This is used by editors, not release.
- Return true if the scene is being run inside an editor.
@@ -25360,19 +25471,16 @@
- Set pause. The built-in pause system is very basic and only meant to avoid processing nodes not allowed to work in pause mode.
- Return true if the scene is paused.
- Handle a current input event (avoid further processing of it).
@@ -25385,12 +25493,10 @@
- Return the frame index (how many frames were drawn).
- Quit the application.
@@ -25407,7 +25513,6 @@
- Queue an object for deletion next time the loop goes idle.
@@ -25428,41 +25533,33 @@
- Call a function for all the nodes in a given group.
- Emitted when the screen changes size.
- Emitted when a node is removed from the scene.
- Emitted when the scene tree changed (nodes added/removed/moved/etc)
- Regular group call flag (no flags).
- Call a group in inverse-scene order.
- Call a group immediately (usually calls are delivered on idle).
- Call a group only once, even if call is performed many times.
@@ -32543,7 +32640,7 @@
-
+
@@ -32601,6 +32698,12 @@
+
+
+
+
+
+
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 057de329df..9f2fd032fa 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/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)));
diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl
index 7d9aca4b4d..f2d9eaf1e5 100644
--- a/drivers/gles2/shaders/material.glsl
+++ b/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
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index b1db087fb3..546fed4e8a 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/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* r_optio
}
+struct GDCompletionIdentifier {
-static void _parse_expression_node(const GDParser::Node *p_node,List* r_options,List::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(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(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(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(p_node);
+ if (op->op==GDParser::OperatorNode::OP_CALL) {
+
+ if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
+
+ const GDParser::TypeNode *tn = static_cast(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(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(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 mi;
+ v.get_method_list(&mi);
+ for (List::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;isub_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;istatements.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(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(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(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* r_options,List::Element *p_indices) {
@@ -433,7 +665,7 @@ static void _parse_expression_node(const GDParser::Node *p_node,List* r_
} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {
const GDParser::DictionaryNode *dn=static_cast(p_node);
- for(int i=0;ielements.size();i++) {
+ for (int i=0;ielements.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* 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* r_
}
}
}
+ } else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+
+ MethodInfo mi = GDFunctions::get_info(static_cast(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(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* r_options,List::Element *p_indices) {
+static bool _parse_completion_block(const GDParser::ClassNode *p_class,const GDParser::BlockNode *p_block,int p_line,List* r_options,List::Element *p_indices) {
+
+ print_line("COMPLETION BLOCK "+itos(p_block->line)+" -> "+itos(p_block->end_line));
for(int i=0;isub_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;istatements.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(p_block->statements[i]);
+ const GDParser::LocalVarNode *lv=static_cast(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;ivariables.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& 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* r_options,List::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;iget()==_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;isubclasses.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* 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(root);
List indices;
Vector spl = p_base.split(".");
for(int i=0;i::Element *E=globals.front();E;E=E->next()) {
if (!indices.empty()) {
if (String(E->key())==indices.front()->get()) {
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index de2b5219a9..904b6ba52f 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/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 res;
if (!validating) {
@@ -2616,8 +2623,9 @@ Error GDParser::_parse(const String& p_base_path) {
return OK;
}
-Error GDParser::parse_bytecode(const Vector &p_bytecode,const String& p_base_path) {
+Error GDParser::parse_bytecode(const Vector &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 &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);
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index 5fac34396c..3f82cafc61 100644
--- a/modules/gdscript/gd_parser.h
+++ b/modules/gdscript/gd_parser.h
@@ -373,6 +373,7 @@ private:
List 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 &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 &p_bytecode,const String& p_base_path="",const String& p_self_path="");
const Node *get_parse_tree() const;
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index 7085ae6a56..982584c75c 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/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