diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/SCsub | 2 | ||||
| -rw-r--r-- | modules/gdscript/SCsub | 2 | ||||
| -rw-r--r-- | modules/gdscript/gd_compiler.cpp | 128 | ||||
| -rw-r--r-- | modules/gdscript/gd_compiler.h | 124 | ||||
| -rw-r--r-- | modules/gdscript/gd_editor.cpp | 829 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.cpp | 109 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.h | 7 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.cpp | 243 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.h | 16 | ||||
| -rw-r--r-- | modules/gdscript/gd_pretty_print.cpp | 2 | ||||
| -rw-r--r-- | modules/gdscript/gd_pretty_print.h | 2 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.cpp | 120 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.h | 23 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 51 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.h | 3 | ||||
| -rw-r--r-- | modules/gdscript/register_types.h | 2 | ||||
| -rw-r--r-- | modules/gridmap/SCsub | 3 | ||||
| -rw-r--r-- | modules/gridmap/grid_map.cpp | 84 | ||||
| -rw-r--r-- | modules/gridmap/grid_map.h | 4 | ||||
| -rw-r--r-- | modules/gridmap/grid_map_editor_plugin.cpp | 198 | ||||
| -rw-r--r-- | modules/gridmap/grid_map_editor_plugin.h | 30 | ||||
| -rw-r--r-- | modules/gridmap/register_types.cpp | 6 | ||||
| -rw-r--r-- | modules/gridmap/register_types.h | 2 |
23 files changed, 1612 insertions, 378 deletions
diff --git a/modules/SCsub b/modules/SCsub index d215f72c08..9215bfd48f 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -19,5 +19,3 @@ for x in env.module_list: lib = env_modules.Library("modules",env.modules_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub index d20da72b72..403fe68f66 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.modules_sources,"*.cpp") Export('env') - - diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index d4fe8b626b..a62225f663 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,15 +28,6 @@ /*************************************************************************/ #include "gd_compiler.h" #include "gd_script.h" -/* TODO: - - *AND and OR need early abort - -Inheritance properly process (done?) - *create built in initializer and constructor - *assign operators - *build arrays and dictionaries - *call parent constructor - */ void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) { @@ -45,8 +36,13 @@ void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) return; error=p_error; - err_line=p_node->line; - err_column=p_node->column; + if (p_node) { + err_line=p_node->line; + err_column=p_node->column; + } else { + err_line=0; + err_column=0; + } } bool GDCompiler::_create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) { @@ -523,7 +519,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre int ret = _parse_expression(codegen,on->arguments[i],slevel); if (ret<0) return ret; - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { + if (ret&(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)) { slevel++; codegen.alloc_stack(slevel); } @@ -554,7 +550,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre int index; if (named) { +#ifdef DEBUG_ENABLED + if (on->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) { + const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name); + if (MI && MI->get().getter==codegen.function_node->name) { + String n = static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name; + _set_error("Must use '"+n+"' instead of 'self."+n+"' in getter.",on); + return -1; + } + } +#endif index=codegen.get_name_map_pos(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name); } else { @@ -698,6 +704,25 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre if (on->arguments[0]->type==GDParser::Node::TYPE_OPERATOR && (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX || static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED)) { //SET (chained) MODE!! + +#ifdef DEBUG_ENABLED + if (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED) { + const GDParser::OperatorNode* inon = static_cast<GDParser::OperatorNode*>(on->arguments[0]); + + + if (inon->arguments[0]->type==GDParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) { + + const Map<StringName,GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name); + if (MI && MI->get().setter==codegen.function_node->name) { + String n = static_cast<GDParser::IdentifierNode*>(inon->arguments[1])->name; + _set_error("Must use '"+n+"' instead of 'self."+n+"' in setter.",inon); + return -1; + } + } + } +#endif + + int slevel=p_stack_level; GDParser::OperatorNode* op = static_cast<GDParser::OperatorNode*>(on->arguments[0]); @@ -1363,13 +1388,14 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars int index_from=0; + Ref<GDNativeClass> native; if (p_class->extends_used) { //do inheritance String path = p_class->extends_file; Ref<GDScript> script; - Ref<GDNativeClass> native; + if (path!="") { //path (and optionally subclasses) @@ -1381,7 +1407,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars _set_error("Could not resolve relative path for parent class: "+path,p_class); return ERR_FILE_NOT_FOUND; } - path=base.get_base_dir().plus_file(path); + path=base.get_base_dir().plus_file(path).simplify_path(); } script = ResourceLoader::load(path); if (script.is_null()) { @@ -1522,7 +1548,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars GDScript::MemberInfo minfo; minfo.index = p_script->member_indices.size(); minfo.setter = p_class->variables[i].setter; - minfo.getter = p_class->variables[i].getter; + minfo.getter = p_class->variables[i].getter; p_script->member_indices[name]=minfo; p_script->members.insert(name); @@ -1539,7 +1565,35 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars //p_script->constants[constant->value].make_const(); } + for(int i=0;i<p_class->_signals.size();i++) { + + StringName name = p_class->_signals[i].name; + + GDScript *c = p_script; + + while(c) { + + if (c->_signals.has(name)) { + _set_error("Signal '"+name+"' redefined (in current or parent class)",p_class); + return ERR_ALREADY_EXISTS; + } + if (c->base.is_valid()) { + c=c->base.ptr(); + } else { + c=NULL; + } + } + + if (native.is_valid()) { + if (ObjectTypeDB::has_signal(native->get_name(),name)) { + _set_error("Signal '"+name+"' redefined (original in native class '"+String(native->get_name())+"')",p_class); + return ERR_ALREADY_EXISTS; + } + } + + p_script->_signals[name]=p_class->_signals[i].arguments; + } //parse sub-classes for(int i=0;i<p_class->subclasses.size();i++) { @@ -1586,6 +1640,48 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars return err; } +#ifdef DEBUG_ENABLED + //validate setters/getters if debug is enabled + for(int i=0;i<p_class->variables.size();i++) { + + if (p_class->variables[i].setter) { + const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().find(p_class->variables[i].setter); + if (!E) { + _set_error("Setter function '"+String(p_class->variables[i].setter)+"' not found in class.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + if (E->get().is_static()) { + + _set_error("Setter function '"+String(p_class->variables[i].setter)+"' is static.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + } + if (p_class->variables[i].getter) { + const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().find(p_class->variables[i].getter); + if (!E) { + _set_error("Getter function '"+String(p_class->variables[i].getter)+"' not found in class.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + if (E->get().is_static()) { + + _set_error("Getter function '"+String(p_class->variables[i].getter)+"' is static.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + } + } +#endif return OK; } diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h index b83d0ded4b..bdf4e9816a 100644 --- a/modules/gdscript/gd_compiler.h +++ b/modules/gdscript/gd_compiler.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,77 +37,65 @@ class GDCompiler { const GDParser *parser; struct CodeGen { - - GDScript *script; const GDParser::ClassNode *class_node; const GDParser::FunctionNode *function_node; - - - bool debug_stack; - - - List< Map<StringName,int> > stack_id_stack; - Map<StringName,int> stack_identifiers; - - List<GDFunction::StackDebug> stack_debug; - List< Map<StringName,int> > block_identifier_stack; - Map<StringName,int> block_identifiers; - - - void add_stack_identifier(const StringName& p_id,int p_stackpos) { - - stack_identifiers[p_id]=p_stackpos; - if (debug_stack) { - - block_identifiers[p_id]=p_stackpos; - GDFunction::StackDebug sd; - sd.added=true; - sd.line=current_line; - sd.identifier=p_id; - sd.pos=p_stackpos; - stack_debug.push_back(sd); - } - } - - void push_stack_identifiers() { - - stack_id_stack.push_back( stack_identifiers ); - if (debug_stack) { - - block_identifier_stack.push_back(block_identifiers); - block_identifiers.clear(); - } - } - - void pop_stack_identifiers() { - - stack_identifiers = stack_id_stack.back()->get(); - stack_id_stack.pop_back(); - - if (debug_stack) { - for (Map<StringName,int>::Element *E=block_identifiers.front();E;E=E->next()) { - - GDFunction::StackDebug sd; - sd.added=false; - sd.identifier=E->key(); - sd.line=current_line; - sd.pos=E->get(); - stack_debug.push_back(sd); - } - block_identifiers=block_identifier_stack.back()->get(); - block_identifier_stack.pop_back(); - } - - } - - - // int get_identifier_pos(const StringName& p_dentifier) const; + bool debug_stack; + + List< Map<StringName,int> > stack_id_stack; + Map<StringName,int> stack_identifiers; + + List<GDFunction::StackDebug> stack_debug; + List< Map<StringName,int> > block_identifier_stack; + Map<StringName,int> block_identifiers; + + void add_stack_identifier(const StringName& p_id,int p_stackpos) { + stack_identifiers[p_id]=p_stackpos; + if (debug_stack) { + block_identifiers[p_id]=p_stackpos; + GDFunction::StackDebug sd; + sd.added=true; + sd.line=current_line; + sd.identifier=p_id; + sd.pos=p_stackpos; + stack_debug.push_back(sd); + } + } + + void push_stack_identifiers() { + stack_id_stack.push_back( stack_identifiers ); + if (debug_stack) { + + block_identifier_stack.push_back(block_identifiers); + block_identifiers.clear(); + } + } + + void pop_stack_identifiers() { + stack_identifiers = stack_id_stack.back()->get(); + stack_id_stack.pop_back(); + + if (debug_stack) { + for (Map<StringName,int>::Element *E=block_identifiers.front();E;E=E->next()) { + + GDFunction::StackDebug sd; + sd.added=false; + sd.identifier=E->key(); + sd.line=current_line; + sd.pos=E->get(); + stack_debug.push_back(sd); + } + block_identifiers=block_identifier_stack.back()->get(); + block_identifier_stack.pop_back(); + } + } + + + //int get_identifier_pos(const StringName& p_dentifier) const; HashMap<Variant,int,VariantHasher> constant_map; Map<StringName,int> name_map; int get_name_map_pos(const StringName& p_identifier) { - int ret; if (!name_map.has(p_identifier)) { ret=name_map.size(); @@ -118,11 +106,7 @@ class GDCompiler { return ret; } - - int get_constant_pos(const Variant& p_constant) { - - if (constant_map.has(p_constant)) return constant_map[p_constant]; int pos = constant_map.size(); @@ -134,7 +118,7 @@ class GDCompiler { void alloc_stack(int p_level) { if (p_level >= stack_max) stack_max=p_level+1; } void alloc_call(int p_params) { if (p_params >= call_max) call_max=p_params; } - int current_line; + int current_line; int stack_max; int call_max; }; diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 09f193706c..0d986e92a2 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,12 +28,13 @@ /*************************************************************************/ #include "gd_script.h" #include "gd_compiler.h" - +#include "globals.h" +#include "os/file_access.h" void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("#"); - p_delimiters->push_back("\"\"\""); + p_delimiters->push_back("\"\"\" \"\"\""); } void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { @@ -51,7 +52,7 @@ String GDScriptLanguage::get_template(const String& p_class_name, const String& "# var a=2\n"+ "# var b=\"textvar\"\n\n"+ "func _ready():\n"+ - "\t# Initalization here\n"+ + "\t# Initialization here\n"+ "\tpass\n"+ "\n"+ "\n"; @@ -238,26 +239,26 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p if (_debug_parse_err_line>=0) return; - ERR_FAIL_INDEX(p_level,_debug_call_stack_pos); - int l = _debug_call_stack_pos - p_level -1; + ERR_FAIL_INDEX(p_level,_debug_call_stack_pos); + int l = _debug_call_stack_pos - p_level -1; - GDInstance *instance = _call_stack[l].instance; + GDInstance *instance = _call_stack[l].instance; - if (!instance) - return; + if (!instance) + return; - Ref<GDScript> script = instance->get_script(); - ERR_FAIL_COND( script.is_null() ); + Ref<GDScript> script = instance->get_script(); + ERR_FAIL_COND( script.is_null() ); - const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices(); + const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices(); - for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) { + for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) { - p_members->push_back(E->key()); - p_values->push_back( instance->debug_get_member_by_index(E->get().index)); - } + p_members->push_back(E->key()); + p_values->push_back( instance->debug_get_member_by_index(E->get().index)); + } } void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) { @@ -317,6 +318,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam struct GDCompletionIdentifier { StringName obj_type; + Ref<GDScript> script; Variant::Type type; Variant value; //im case there is a value, also return it }; @@ -381,7 +383,12 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) { path=context.base_path.plus_file(path); } - script = ResourceLoader::load(path); + + if (ScriptCodeCompletionCache::get_sigleton()) + script = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path); + else + script = ResourceLoader::load(path); + if (script.is_null()) { return REF(); } @@ -441,7 +448,7 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) { base_class=base_class->subclasses[subclass]; } else { - print_line("Could not find subclass: "+subclass); + //print_line("Could not find subclass: "+subclass); return _get_type_from_class(context); //fail please } } @@ -606,6 +613,16 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: if (base.type==Variant::OBJECT) { + if (id.operator String()=="new" && base.value.get_type()==Variant::OBJECT) { + Object *obj = base.value; + if (obj && obj->cast_to<GDNativeClass>()) { + GDNativeClass *gdnc = obj->cast_to<GDNativeClass>(); + r_type.type=Variant::OBJECT; + r_type.value=Variant(); + r_type.obj_type=gdnc->get_name(); + return true; + } + } if (ObjectTypeDB::has_method(base.obj_type,id)) { @@ -616,7 +633,9 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: //try calling the function if constant and all args are constant, should not crash.. Object *baseptr = base.value; - if (baseptr && mb->is_const() && pi.type==Variant::OBJECT) { + + if (mb->is_const() && pi.type==Variant::OBJECT) { + bool all_valid=true; Vector<Variant> args; for(int i=2;i<op->arguments.size();i++) { @@ -633,25 +652,88 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: all_valid=false; } } - if (all_valid) { - Vector<const Variant*> argptr; - for(int i=0;i<args.size();i++) { - argptr.push_back(&args[i]); - } - Variant::CallError ce; - Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce); + if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) { + + String arg1=args[0]; + if (arg1.begins_with("/root/")) { + String which = arg1.get_slice("/",2); + if (which!="") { + List<PropertyInfo> props; + Globals::get_singleton()->get_property_list(&props); + //print_line("find singleton"); + + for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + //print_line("found "+s); + String name = s.get_slice("/",1); + //print_line("name: "+name+", which: "+which); + if (name==which) { + String script = Globals::get_singleton()->get(s); - if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) { + if (!script.begins_with("res://")) { + script="res://"+script; + } - if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) { + if (!script.ends_with(".gd")) { + //not a script, try find the script anyway, + //may have some success + script=script.basename()+".gd"; + } - r_type=_get_type_from_variant(ret); - return true; + if (FileAccess::exists(script)) { + + //print_line("is a script"); + + + Ref<Script> scr; + if (ScriptCodeCompletionCache::get_sigleton()) + scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script); + else + scr = ResourceLoader::load(script); + + + r_type.obj_type="Node"; + r_type.type=Variant::OBJECT; + r_type.script=scr; + r_type.value=Variant(); + + return true; + + } + } + } } } + } + + + if (baseptr) { + + if (all_valid) { + Vector<const Variant*> argptr; + for(int i=0;i<args.size();i++) { + argptr.push_back(&args[i]); + } + + Variant::CallError ce; + Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce); + + + if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) { + + if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) { + + r_type=_get_type_from_variant(ret); + return true; + } + } + + } } } @@ -677,7 +759,8 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser:: v.get_method_list(&mi); for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { - if (E->get().name==id.operator String()) { + if (!E->get().name.begins_with("_") && E->get().name==id.operator String()) { + MethodInfo mi = E->get(); r_type.type=mi.return_val.type; @@ -915,6 +998,44 @@ static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_l return false; } + +static bool _guess_identifier_from_assignment_in_function(GDCompletionContext& context,const StringName& p_identifier, const StringName& p_function,GDCompletionIdentifier &r_type) { + + const GDParser::FunctionNode* func=NULL; + for(int i=0;i<context._class->functions.size();i++) { + if (context._class->functions[i]->name==p_function) { + func=context._class->functions[i]; + break; + } + } + + if (!func) + return false; + + for(int i=0;i<func->body->statements.size();i++) { + + + + if (func->body->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) { + const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(func->body->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) { + + return _guess_expression_type(context,op->arguments[1],func->body->statements[i]->line,r_type); + } + } + } + } + } + + return false; +} + static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) { //go to block first @@ -934,7 +1055,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const block=block->parent_block; } - //TODO guess identifier type of arguments (ONLY if this is a virtual function) + //guess from argument if virtual if (context.function && context.function->name!=StringName()) { int argindex = -1; @@ -995,7 +1116,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const } } - if (context.function && !context.function->_static) { + if (!(context.function && context.function->_static)) { for(int i=0;i<context._class->variables.size();i++) { @@ -1006,8 +1127,22 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const r_type=_get_type_from_pinfo(context._class->variables[i]._export); return true; } else if (context._class->variables[i].expression) { - return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); + + bool rtype = _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); + if (rtype && r_type.type!=Variant::NIL) + return true; + //return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); } + + //try to guess from assignment in construtor or _ready + if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_ready",r_type)) + return true; + if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_enter_tree",r_type)) + return true; + if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_init",r_type)) + return true; + + return false; } } } @@ -1136,6 +1271,8 @@ static void _find_identifiers_in_class(GDCompletionContext& context,bool p_stati List<MethodInfo> methods; ObjectTypeDB::get_method_list(type,&methods); for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { + if (E->get().name.begins_with("_")) + continue; if (E->get().arguments.size()) result.insert(E->get().name+"("); else @@ -1182,7 +1319,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl } static const char*_type_names[Variant::VARIANT_MAX]={ - "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform", + "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Transform", "Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray", "Vector2Array","Vector3Array","ColorArray"}; @@ -1196,7 +1333,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl } -static String _get_visual_datatype(const PropertyInfo& p_info) { +static String _get_visual_datatype(const PropertyInfo& p_info,bool p_isarg=true) { String n = p_info.name; int idx = n.find(":"); @@ -1206,8 +1343,12 @@ static String _get_visual_datatype(const PropertyInfo& p_info) { if (p_info.type==Variant::OBJECT && p_info.hint==PROPERTY_HINT_RESOURCE_TYPE) return p_info.hint_string; - if (p_info.type==Variant::NIL) - return "void"; + if (p_info.type==Variant::NIL) { + if (p_isarg) + return "var"; + else + return "void"; + } return Variant::get_type_name(p_info.type); } @@ -1259,82 +1400,321 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const StringName& p_method,const GDCompletionIdentifier& id, int p_argidx, Set<String>& result, String& arghint) { - if (id.type==Variant::OBJECT && id.obj_type!=StringName()) { + //print_line("find type arguments?"); + if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) { + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + String name = pi.name.substr(pi.name.find("/")+1,pi.name.length()); + result.insert("\""+name+"\""); + } + + + } else if (id.type==Variant::OBJECT && id.obj_type!=StringName()) { MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method); - if (!m) - return; + if (!m) { + //not in static method, see script + + //print_line("not in static: "+String(p_method)); + Ref<GDScript> on_script; + + if (id.value.get_type()) { + Object *obj=id.value; + + + if (obj) { + + + GDScript *scr = obj->cast_to<GDScript>(); + if (scr) { + while (scr) { + + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (E->get().is_static() && p_method==E->get().get_name()) { + arghint="static func "+String(p_method)+"("; + for(int i=0;i<E->get().get_argument_count();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + arghint+="var "+E->get().get_argument_name(i); + int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count(); + if (i>=deffrom) { + int defidx = deffrom-i; + if (defidx>=0 && defidx<E->get().get_default_argument_count()) { + arghint+="="+E->get().get_default_argument(defidx).get_construct_string(); + } + } + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + } + arghint+=")"; + return; //found + } + } + + if (scr->get_base().is_valid()) + scr=scr->get_base().ptr(); + else + scr=NULL; + } + } else { + on_script=obj->get_script(); + } + } + } + + //print_line("but it has a script?"); + if (!on_script.is_valid() && id.script.is_valid()) { + //print_line("yes"); + on_script=id.script; + } + + if (on_script.is_valid()) { + + GDScript *scr = on_script.ptr(); + if (scr) { + while (scr) { + + String code = scr->get_source_code(); + //print_line("has source code!"); + + if (code!="") { + //if there is code, parse it. This way is slower but updates in real-time + GDParser p; + //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); + + Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false); + + if (err==OK) { + //print_line("checking the functions..."); + //only if ok, otherwise use what is cached on the script + //GDParser::ClassNode *base = p. + const GDParser::Node *root = p.get_parse_tree(); + ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS); + + const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root); + + const GDParser::FunctionNode* func=NULL; + bool st=false; + + for(int i=0;i<cl->functions.size();i++) { + //print_line(String(cl->functions[i]->name)+" vs "+String(p_method)); + if (cl->functions[i]->name==p_method) { + func=cl->functions[i]; + } + } + + for(int i=0;i<cl->static_functions.size();i++) { - if (p_method.operator String()=="connect") { + //print_line(String(cl->static_functions[i]->name)+" vs "+String(p_method)); + if (cl->static_functions[i]->name==p_method) { + func=cl->static_functions[i]; + st=true; + } + + } + + if (func) { + + arghint="func "+String(p_method)+"("; + if (st) + arghint="static "+arghint; + for(int i=0;i<func->arguments.size();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + arghint+="var "+String(func->arguments[i]); + int deffrom = func->arguments.size()-func->default_values.size(); + if (i>=deffrom) { + + int defidx = deffrom-i; + + if (defidx>=0 && defidx<func->default_values.size() && func->default_values[defidx]->type==GDParser::Node::TYPE_OPERATOR) { + const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(func->default_values[defidx]); + if (op->op==GDParser::OperatorNode::OP_ASSIGN) { + const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(op->arguments[1]); + arghint+="="+cn->value.get_construct_string(); + } + } + } + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + } + + arghint+=" )"; + return; + } + } else { + //print_line("failed parsing?"); + code=""; + } + } - if (p_argidx==0) { - List<MethodInfo> sigs; - ObjectTypeDB::get_signal_list(id.obj_type,&sigs); - for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) { - result.insert("\""+E->get().name+"\""); + if (code=="") { + + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (p_method==E->get().get_name()) { + arghint="func "+String(p_method)+"("; + for(int i=0;i<E->get().get_argument_count();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + arghint+="var "+E->get().get_argument_name(i); + int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count(); + if (i>=deffrom) { + int defidx = deffrom-i; + if (defidx>=0 && defidx<E->get().get_default_argument_count()) { + arghint+="="+E->get().get_default_argument(defidx).get_construct_string(); + } + } + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + } + arghint+=")"; + return; //found + } + } +#if 0 + //use class directly, no code was found + if (!isfunction) { + for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { + options.insert(E->key()); + } + } + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + options.insert(String(E->key())+"("); + } + + for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) { + options.insert(E->get()); + } +#endif + } + + if (scr->get_base().is_valid()) + scr=scr->get_base().ptr(); + else + scr=NULL; + } } } - /*if (p_argidx==2) { - ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR); - const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node); - if (op->arguments.size()>) - }*/ } else { + //regular method - Object *obj=id.value; - if (obj) { - List<String> options; - obj->get_argument_options(p_method,p_argidx,&options); - for(List<String>::Element *E=options.front();E;E=E->next()) { + if (p_method.operator String()=="connect") { - result.insert(E->get()); + + if (p_argidx==0) { + List<MethodInfo> sigs; + ObjectTypeDB::get_signal_list(id.obj_type,&sigs); + for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) { + result.insert("\""+E->get().name+"\""); + } } - } + /*if (p_argidx==2) { - } + ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR); + const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node); + if (op->arguments.size()>) - arghint = _get_visual_datatype(m->get_argument_info(-1))+" "+p_method.operator String()+String("("); + }*/ + } else { - for(int i=0;i<m->get_argument_count();i++) { - if (i>0) - arghint+=", "; - else - arghint+=" "; + if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) { - if (i==p_argidx) { - arghint+=String::chr(0xFFFF); - } - String n = m->get_argument_info(i).name; - int dp = n.find(":"); - if (dp!=-1) - n=n.substr(0,dp); - arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n; - int deffrom = m->get_argument_count()-m->get_default_argument_count(); + List<PropertyInfo> props; + Globals::get_singleton()->get_property_list(&props); + for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { - if (i>=deffrom) { - int defidx = i-deffrom; + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + // print_line("found "+s); + String name = s.get_slice("/",1); + result.insert("\"/root/"+name+"\""); + } + } - if (defidx>=0 && defidx<m->get_default_argument_count()) { - Variant v= m->get_default_argument(i); - arghint+="="+v.get_construct_string(); + Object *obj=id.value; + if (obj) { + List<String> options; + obj->get_argument_options(p_method,p_argidx,&options); + + for(List<String>::Element *E=options.front();E;E=E->next()) { + + result.insert(E->get()); + } } - } - if (i==p_argidx) { - arghint+=String::chr(0xFFFF); } - } - if (m->get_argument_count()>0) - arghint+=" "; + arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("("); + for(int i=0;i<m->get_argument_count();i++) { + if (i>0) + arghint+=", "; + else + arghint+=" "; - arghint+=")"; + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + String n = m->get_argument_info(i).name; + int dp = n.find(":"); + if (dp!=-1) + n=n.substr(0,dp); + arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n; + int deffrom = m->get_argument_count()-m->get_default_argument_count(); + + + if (i>=deffrom) { + int defidx = i-deffrom; + + if (defidx>=0 && defidx<m->get_default_argument_count()) { + Variant v= m->get_default_argument(i); + arghint+="="+v.get_construct_string(); + } + } + + if (i==p_argidx) { + arghint+=String::chr(0xFFFF); + } + + } + if (m->get_argument_count()>0) + arghint+=" "; + + + arghint+=")"; + } } } @@ -1361,7 +1741,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No const GDParser::BuiltInFunctionNode *fn = static_cast<const GDParser::BuiltInFunctionNode*>(op->arguments[0]); MethodInfo mi = GDFunctions::get_info(fn->function); - arghint = _get_visual_datatype(mi.return_val)+" "+GDFunctions::get_func_name(fn->function)+String("("); + arghint = _get_visual_datatype(mi.return_val,false)+" "+GDFunctions::get_func_name(fn->function)+String("("); for(int i=0;i<mi.arguments.size();i++) { if (i>0) arghint+=", "; @@ -1381,7 +1761,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No arghint+=")"; } else if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) { - //complete built-in function + //complete constructor const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode*>(op->arguments[0]); List<MethodInfo> mil; @@ -1516,7 +1896,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No } } else { - + //indexed lookup GDCompletionIdentifier ci; if (_guess_expression_type(context,op->arguments[0],p_line,ci)) { @@ -1625,16 +2005,12 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No } Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base_path, Object*p_owner, List<String>* r_options, String &r_call_hint) { -/* bugs: - a[0].<complete> does not work - functions should end in ( - when completing virtuals, ask for full back - - */ //print_line( p_code.replace(String::chr(0xFFFF),"<cursor>")); GDParser p; - Error err = p.parse(p_code,p_base_path); + //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); + + Error err = p.parse(p_code,p_base_path,false,"",true); bool isfunction=false; Set<String> options; @@ -1674,7 +2050,6 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base isfunction=true; case GDParser::COMPLETION_INDEX: { - print_line("index"); const GDParser::Node *node = p.get_completion_node(); if (node->type!=GDParser::Node::TYPE_OPERATOR) break; @@ -1686,6 +2061,139 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) { if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { + + Ref<GDScript> on_script; + + if (t.value.get_type()) { + Object *obj=t.value; + + + if (obj) { + + + GDScript *scr = obj->cast_to<GDScript>(); + if (scr) { + while (scr) { + + if (!isfunction) { + for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { + options.insert(E->key()); + } + } + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (E->get().is_static()) + options.insert(E->key()); + } + + if (scr->get_base().is_valid()) + scr=scr->get_base().ptr(); + else + scr=NULL; + } + } else { + on_script=obj->get_script(); + } + } + } + + + if (!on_script.is_valid() && t.script.is_valid()) { + on_script=t.script; + } + + if (on_script.is_valid()) { + + GDScript *scr = on_script.ptr(); + if (scr) { + while (scr) { + + String code = scr->get_source_code(); + + if (code!="") { + //if there is code, parse it. This way is slower but updates in real-time + GDParser p; + //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); + + Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false); + + if (err==OK) { + //only if ok, otherwise use what is cached on the script + //GDParser::ClassNode *base = p. + const GDParser::Node *root = p.get_parse_tree(); + ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_PARSE_ERROR); + + const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root); + + for(int i=0;i<cl->functions.size();i++) { + + if (cl->functions[i]->arguments.size()) + options.insert(String(cl->functions[i]->name)+"("); + else + options.insert(String(cl->functions[i]->name)+"()"); + } + + for(int i=0;i<cl->static_functions.size();i++) { + + if (cl->static_functions[i]->arguments.size()) + options.insert(String(cl->static_functions[i]->name)+"("); + else + options.insert(String(cl->static_functions[i]->name)+"()"); + + } + + if (!isfunction) { + for(int i=0;i<cl->variables.size();i++) { + + options.insert(String(cl->variables[i].identifier)); + } + + for(int i=0;i<cl->constant_expressions.size();i++) { + + options.insert(String(cl->constant_expressions[i].identifier)); + } + + } + + + } else { + code=""; //well, then no code + } + + } + + if (code=="") { + //use class directly, no code was found + if (!isfunction) { + for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { + options.insert(E->key()); + } + } + for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { + if (E->get().get_argument_count()) + options.insert(String(E->key())+"()"); + else + options.insert(String(E->key())+"("); + + } + + for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) { + options.insert(E->get()); + } + } + + if (scr->get_base().is_valid()) + scr=scr->get_base().ptr(); + else + scr=NULL; + } + } + } + + + + + + if (!isfunction) { ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options); } @@ -1693,6 +2201,9 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base ObjectTypeDB::get_method_list(t.obj_type,&mi); for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { + if (E->get().name.begins_with("_")) + continue; + if (E->get().arguments.size()) options.insert(E->get().name+"("); else @@ -1700,40 +2211,124 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base } } else { - if (t.value.get_type()==Variant::NIL) { - Variant::CallError ce; - t.value=Variant::construct(t.type,NULL,0,ce); - } - if (!isfunction) { - List<PropertyInfo> pl; - t.value.get_property_list(&pl); - for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { - if (E->get().name.find("/")==-1) - options.insert(E->get().name); + if (t.type==Variant::INPUT_EVENT) { + + //this is hardcoded otherwise it's not obvious + Set<String> exclude; + + for(int i=0;i<InputEvent::TYPE_MAX;i++) { + + InputEvent ie; + ie.type=InputEvent::Type(i); + static const char*evnames[]={ + "# Common", + "# Key", + "# MouseMotion", + "# MouseButton", + "# JoyMotion", + "# JoyButton", + "# ScreenTouch", + "# ScreenDrag", + "# Action" + }; + + r_options->push_back(evnames[i]); + + Variant v = ie; + + if (i==0) { + List<MethodInfo> mi; + v.get_method_list(&mi); + for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { + r_options->push_back(E->get().name+"("); + + } + + } + + List<PropertyInfo> pi; + v.get_property_list(&pi); + + for (List<PropertyInfo>::Element *E=pi.front();E;E=E->next()) { + + if (i==0) + exclude.insert(E->get().name); + else if (exclude.has(E->get().name)) + continue; + + r_options->push_back(E->get().name); + } + } + return OK; + } else { + if (t.value.get_type()==Variant::NIL) { + Variant::CallError ce; + t.value=Variant::construct(t.type,NULL,0,ce); } - } - List<MethodInfo> mi; - t.value.get_method_list(&mi); - for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { - if (E->get().arguments.size()) - options.insert(E->get().name+"("); - else - options.insert(E->get().name+"()"); + if (!isfunction) { + List<PropertyInfo> pl; + t.value.get_property_list(&pl); + for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { + + if (E->get().name.find("/")==-1) + options.insert(E->get().name); + } + } + + List<MethodInfo> mi; + t.value.get_method_list(&mi); + for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { + if (E->get().arguments.size()) + options.insert(E->get().name+"("); + else + options.insert(E->get().name+"()"); + + } } } } - } break; case GDParser::COMPLETION_CALL_ARGUMENTS: { _find_call_arguments(context,p.get_completion_node(),p.get_completion_line(),p.get_completion_argument_index(),options,r_call_hint); } break; + case GDParser::COMPLETION_VIRTUAL_FUNC: { + + GDCompletionIdentifier cid = _get_native_class(context); + + if (cid.obj_type!=StringName()) { + List<MethodInfo> vm; + ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm); + for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) { + + MethodInfo &mi=E->get(); + String m = mi.name; + if (m.find(":")!=-1) + m=m.substr(0,m.find(":")); + m+="("; + + if (mi.arguments.size()) { + for(int i=0;i<mi.arguments.size();i++) { + if (i>0) + m+=", "; + String n =mi.arguments[i].name; + if (n.find(":")!=-1) + n=n.substr(0,n.find(":")); + m+=n; + } + } + m+="):"; + + options.insert(m); + } + } + } break; } diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index 0d11734bbd..6f51ac5312 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -71,6 +71,7 @@ const char *GDFunctions::get_func_name(Function p_func) { "randi", "randf", "rand_range", + "seed", "rand_seed", "deg2rad", "rad2deg", @@ -87,14 +88,18 @@ const char *GDFunctions::get_func_name(Function p_func) { "str", "print", "printt", + "prints", "printerr", "printraw", + "var2str", + "str2var", "range", "load", "inst2dict", "dict2inst", "hash", "print_stack", + "instance_from_id", }; return _names[p_func]; @@ -326,6 +331,13 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va VALIDATE_ARG_NUM(1); r_ret=Math::random(*p_args[0],*p_args[1]); } break; + case MATH_SEED: { + VALIDATE_ARG_COUNT(1); + VALIDATE_ARG_NUM(0); + uint32_t seed=*p_args[0]; + Math::seed(seed); + r_ret=Variant(); + } break; case MATH_RANDSEED: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); @@ -551,6 +563,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } break; + case TEXT_PRINT_SPACED: { + + String str; + for(int i=0;i<p_arg_count;i++) { + + if (i) + str+=" "; + str+=p_args[i]->operator String(); + } + + //str+="\n"; + print_line(str); + r_ret=Variant(); + + + } break; case TEXT_PRINTERR: { @@ -573,14 +601,27 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } //str+="\n"; - OS::get_singleton()->print("%s\n",str.utf8().get_data()); + OS::get_singleton()->print("%s",str.utf8().get_data()); r_ret=Variant(); } break; + case VAR_TO_STR: { + VALIDATE_ARG_COUNT(1); + r_ret=p_args[0]->get_construct_string(); + } break; + case STR_TO_VAR: { + VALIDATE_ARG_COUNT(1); + if (p_args[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + r_ret=Variant(); + return; + } + Variant::construct_from_string(*p_args[0],r_ret); + } break; case GEN_RANGE: { - - switch(p_arg_count) { case 0: { @@ -861,9 +902,17 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } } - r_ret = gdscr->_new(NULL,0,r_error); + GDInstance *ins = static_cast<GDInstance*>(static_cast<Object*>(r_ret)->get_script_instance()); + Ref<GDScript> gd_ref = ins->get_script(); + + for(Map<StringName,GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) { + if(d.has(E->key())) { + ins->members[E->get().index] = d[E->key()]; + } + } + } break; case HASH: { @@ -881,6 +930,20 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va }; } break; + case INSTANCE_FROM_ID: { + + VALIDATE_ARG_COUNT(1); + if (p_args[0]->get_type()!=Variant::INT && p_args[0]->get_type()!=Variant::REAL) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_ret=Variant(); + break; + } + + uint32_t id=*p_args[0]; + r_ret=ObjectDB::get_instance(id); + + } break; case FUNC_MAX: { ERR_FAIL_V(); @@ -1087,7 +1150,7 @@ MethodInfo GDFunctions::get_info(Function p_func) { return mi; } break; case MATH_LERP: { - MethodInfo mi("lerp",PropertyInfo(Variant::REAL,"a"),PropertyInfo(Variant::REAL,"b"), PropertyInfo(Variant::REAL,"c")); + MethodInfo mi("lerp",PropertyInfo(Variant::REAL,"from"),PropertyInfo(Variant::REAL,"to"), PropertyInfo(Variant::REAL,"weight")); mi.return_val.type=Variant::REAL; return mi; } break; @@ -1116,6 +1179,11 @@ MethodInfo GDFunctions::get_info(Function p_func) { mi.return_val.type=Variant::REAL; return mi; } break; + case MATH_SEED: { + MethodInfo mi("seed",PropertyInfo(Variant::REAL,"seed")); + mi.return_val.type=Variant::NIL; + return mi; + } break; case MATH_RANDSEED: { MethodInfo mi("rand_seed",PropertyInfo(Variant::REAL,"seed")); mi.return_val.type=Variant::ARRAY; @@ -1166,6 +1234,8 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("weakref",PropertyInfo(Variant::OBJECT,"obj")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="WeakRef"; + return mi; } break; @@ -1173,6 +1243,7 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("funcref",PropertyInfo(Variant::OBJECT,"instance"),PropertyInfo(Variant::STRING,"funcname")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="FuncRef"; return mi; } break; @@ -1207,6 +1278,13 @@ MethodInfo GDFunctions::get_info(Function p_func) { return mi; } break; + case TEXT_PRINT_SPACED: { + + MethodInfo mi("prints",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); + mi.return_val.type=Variant::NIL; + return mi; + + } break; case TEXT_PRINTERR: { MethodInfo mi("printerr",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); @@ -1221,6 +1299,18 @@ MethodInfo GDFunctions::get_info(Function p_func) { return mi; } break; + case VAR_TO_STR: { + MethodInfo mi("var2str",PropertyInfo(Variant::NIL,"var")); + mi.return_val.type=Variant::STRING; + return mi; + + } break; + case STR_TO_VAR: { + + MethodInfo mi("str2var:var",PropertyInfo(Variant::STRING,"string")); + mi.return_val.type=Variant::NIL; + return mi; + } break; case GEN_RANGE: { MethodInfo mi("range",PropertyInfo(Variant::NIL,"...")); @@ -1231,6 +1321,7 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("load",PropertyInfo(Variant::STRING,"path")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="Resource"; return mi; } break; case INST2DICT: { @@ -1258,6 +1349,12 @@ MethodInfo GDFunctions::get_info(Function p_func) { return mi; } break; + case INSTANCE_FROM_ID: { + MethodInfo mi("instance_from_id",PropertyInfo(Variant::INT,"instance_id")); + mi.return_val.type=Variant::OBJECT; + return mi; + } break; + case FUNC_MAX: { ERR_FAIL_V(MethodInfo()); diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index 340763fb8c..ad35a628d5 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -67,6 +67,7 @@ public: MATH_RAND, MATH_RANDF, MATH_RANDOM, + MATH_SEED, MATH_RANDSEED, MATH_DEG2RAD, MATH_RAD2DEG, @@ -83,14 +84,18 @@ public: TEXT_STR, TEXT_PRINT, TEXT_PRINT_TABBED, + TEXT_PRINT_SPACED, TEXT_PRINTERR, TEXT_PRINTRAW, + VAR_TO_STR, + STR_TO_VAR, GEN_RANGE, RESOURCE_LOAD, INST2DICT, DICT2INST, HASH, PRINT_STACK, + INSTANCE_FROM_ID, FUNC_MAX }; diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index f79f3ee44a..202ab76da0 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,6 +30,7 @@ #include "print_string.h" #include "io/resource_loader.h" #include "os/file_access.h" +#include "script_language.h" template<class T> T* GDParser::alloc_node() { @@ -116,6 +117,14 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) { _make_completable_call(argidx); completion_node=p_parent; + } else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING && tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) { + //completing a string argument.. + completion_cursor=tokenizer->get_token_constant(); + + _make_completable_call(argidx); + completion_node=p_parent; + tokenizer->advance(1); + return false; } Node*arg = _parse_expression(p_parent,p_static); @@ -161,6 +170,7 @@ void GDParser::_make_completable_call(int p_arg) { completion_line=tokenizer->get_token_line(); completion_argument=p_arg; completion_block=current_block; + completion_found=true; tokenizer->advance(); } @@ -181,6 +191,7 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide completion_function=current_function; completion_line=tokenizer->get_token_line(); completion_block=current_block; + completion_found=true; tokenizer->advance(); if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { @@ -277,7 +288,11 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ if (!validating) { //this can be too slow for just validating code - res = ResourceLoader::load(path); + if (for_completion && ScriptCodeCompletionCache::get_sigleton()) { + res = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path); + } else { + res = ResourceLoader::load(path); + } if (!res.is_valid()) { _set_error("Can't preload resource at path: "+path); return NULL; @@ -1075,6 +1090,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { ConstantNode *cn = alloc_node<ConstantNode>(); Array arr(!p_to_const); + //print_line("mk array "+itos(!p_to_const)); arr.resize(an->elements.size()); for(int i=0;i<an->elements.size();i++) { ConstantNode *acn = static_cast<ConstantNode*>(an->elements[i]); @@ -1400,6 +1416,24 @@ GDParser::Node* GDParser::_parse_and_reduce_expression(Node *p_parent,bool p_sta return expr; } +bool GDParser::_recover_from_completion() { + + if (!completion_found) { + return false; //can't recover if no completion + } + //skip stuff until newline + while(tokenizer->get_token()!=GDTokenizer::TK_NEWLINE && tokenizer->get_token()!=GDTokenizer::TK_EOF && tokenizer->get_token()!=GDTokenizer::TK_ERROR) { + tokenizer->advance(); + } + completion_found=false; + error_set=false; + if(tokenizer->get_token() == GDTokenizer::TK_ERROR){ + error_set = true; + } + + return true; +} + void GDParser::_parse_block(BlockNode *p_block,bool p_static) { int indent_level = tab_level.back()->get(); @@ -1461,7 +1495,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; case GDTokenizer::TK_CF_PASS: { - if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE ) { + if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE && tokenizer->get_token(1)!=GDTokenizer::TK_EOF) { _set_error("Expected ';' or <NewLine>."); return; @@ -1497,8 +1531,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { Node *subexpr=NULL; subexpr = _parse_and_reduce_expression(p_block,p_static); - if (!subexpr) + if (!subexpr) { + if (_recover_from_completion()) { + break; + } return; + } + + lv->assign=subexpr; assigned=subexpr; @@ -1519,16 +1559,22 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { op->arguments.push_back(assigned); p_block->statements.push_back(op); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (var)"); + return; + } } break; case GDTokenizer::TK_CF_IF: { tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } ControlFlowNode *cf_if = alloc_node<ControlFlowNode>(); @@ -1582,8 +1628,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { //condition Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } cf_else->arguments.push_back(condition); cf_else->cf_type=ControlFlowNode::CF_IF; @@ -1644,8 +1694,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } ControlFlowNode *cf_while = alloc_node<ControlFlowNode>(); @@ -1690,8 +1744,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { tokenizer->advance(); Node *container = _parse_and_reduce_expression(p_block,p_static); - if (!container) + if (!container) { + if (_recover_from_completion()) { + break; + } return; + } ControlFlowNode *cf_for = alloc_node<ControlFlowNode>(); @@ -1755,8 +1813,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } else { //expect expression Node *retexpr = _parse_and_reduce_expression(p_block,p_static); - if (!retexpr) + if (!retexpr) { + if (_recover_from_completion()) { + break; + } return; + } cf_return->arguments.push_back(retexpr); p_block->statements.push_back(cf_return); if (!_end_statement()) { @@ -1771,8 +1833,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } AssertNode *an = alloc_node<AssertNode>(); an->condition=condition; p_block->statements.push_back(an); @@ -1785,8 +1851,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { default: { Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true); - if (!expression) + if (!expression) { + if (_recover_from_completion()) { + break; + } return; + } p_block->statements.push_back(expression); if (!_end_statement()) { _set_error("Expected end of statement after expression."); @@ -1870,9 +1940,15 @@ void GDParser::_parse_extends(ClassNode *p_class) { p_class->extends_used=true; - //see if inheritance happens from a file tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE && tokenizer->get_token_type()==Variant::OBJECT) { + p_class->extends_class.push_back(Variant::get_type_name(Variant::OBJECT)); + tokenizer->advance(); + return; + } + + // see if inheritance happens from a file if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) { Variant constant = tokenizer->get_token_constant(); @@ -1945,8 +2021,10 @@ void GDParser::_parse_class(ClassNode *p_class) { _parse_extends(p_class); if (error_set) return; - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement after extends"); + return; + } } break; case GDTokenizer::TK_PR_TOOL: { @@ -2027,14 +2105,20 @@ void GDParser::_parse_class(ClassNode *p_class) { } - if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER) { + tokenizer->advance(); + StringName name; + + if (_get_completable_identifier(COMPLETION_VIRTUAL_FUNC,name)) { + + } + + + if (name==StringName()) { _set_error("Expected identifier after 'func' (syntax: 'func <identifier>([arguments]):' )."); return; } - StringName name = tokenizer->get_token_identifier(1); - for(int i=0;i<p_class->functions.size();i++) { if (p_class->functions[i]->name==name) { _set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->functions[i]->line)+")."); @@ -2045,7 +2129,7 @@ void GDParser::_parse_class(ClassNode *p_class) { _set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->static_functions[i]->line)+")."); } } - tokenizer->advance(2); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { @@ -2220,6 +2304,53 @@ void GDParser::_parse_class(ClassNode *p_class) { //arguments } break; + case GDTokenizer::TK_PR_SIGNAL: { + tokenizer->advance(); + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier after 'signal'."); + return; + } + + ClassNode::Signal sig; + sig.name = tokenizer->get_token_identifier(); + tokenizer->advance(); + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { + tokenizer->advance(); + while(true) { + + + if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { + tokenizer->advance(); + break; + } + + if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) { + _set_error("Expected identifier in signal argument."); + return; + } + + sig.arguments.push_back(tokenizer->get_token_identifier()); + tokenizer->advance(); + + if (tokenizer->get_token()==GDTokenizer::TK_COMMA) { + tokenizer->advance(); + } else if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ',' or ')' after signal parameter identifier."); + return; + } + } + } + + p_class->_signals.push_back(sig); + + if (!_end_statement()) { + _set_error("Expected end of statement (signal)"); + return; + } + } break; case GDTokenizer::TK_PR_EXPORT: { tokenizer->advance(); @@ -2244,6 +2375,17 @@ void GDParser::_parse_class(ClassNode *p_class) { case Variant::INT: { + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="FLAGS") { + + current_export.hint=PROPERTY_HINT_ALL_FLAGS; + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' in hint."); + return; + } + break; + } + if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING) { //enumeration current_export.hint=PROPERTY_HINT_ENUM; @@ -2285,6 +2427,16 @@ void GDParser::_parse_class(ClassNode *p_class) { }; //fallthrough to use the same case Variant::REAL: { + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="EASE") { + current_export.hint=PROPERTY_HINT_EXP_EASING; + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' in hint."); + return; + } + break; + } + float sign=1.0; if (tokenizer->get_token()==GDTokenizer::TK_OP_SUB) { @@ -2435,6 +2587,17 @@ void GDParser::_parse_class(ClassNode *p_class) { } break; } + + if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="MULTILINE") { + + current_export.hint=PROPERTY_HINT_MULTILINE_TEXT; + tokenizer->advance(); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')' in hint."); + return; + } + break; + } } break; case Variant::COLOR: { @@ -2536,14 +2699,18 @@ void GDParser::_parse_class(ClassNode *p_class) { Node *subexpr=NULL; - subexpr = _parse_and_reduce_expression(p_class,false); - if (!subexpr) + subexpr = _parse_and_reduce_expression(p_class,false,autoexport); + if (!subexpr) { + if (_recover_from_completion()) { + break; + } return; + } member.expression=subexpr; if (autoexport) { - if (subexpr->type==Node::TYPE_ARRAY) { + if (1)/*(subexpr->type==Node::TYPE_ARRAY) { member._export.type=Variant::ARRAY; @@ -2551,7 +2718,7 @@ void GDParser::_parse_class(ClassNode *p_class) { member._export.type=Variant::DICTIONARY; - } else { + } else*/ { if (subexpr->type!=Node::TYPE_CONSTANT) { @@ -2637,8 +2804,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->variables.push_back(member); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (continue)"); + return; + } } break; case GDTokenizer::TK_PR_CONST: { //variale declaration and (eventual) initialization @@ -2665,8 +2834,12 @@ void GDParser::_parse_class(ClassNode *p_class) { Node *subexpr=NULL; subexpr = _parse_and_reduce_expression(p_class,true,true); - if (!subexpr) + if (!subexpr) { + if (_recover_from_completion()) { + break; + } return; + } if (subexpr->type!=Node::TYPE_CONSTANT) { _set_error("Expected constant expression"); @@ -2675,8 +2848,10 @@ void GDParser::_parse_class(ClassNode *p_class) { p_class->constant_expressions.push_back(constant); - _end_statement(); - + if (!_end_statement()) { + _set_error("Expected end of statement (constant)"); + return; + } } break; @@ -2752,11 +2927,14 @@ Error GDParser::_parse(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) { + for_completion=false; + validating=false; completion_type=COMPLETION_NONE; completion_node=NULL; completion_class=NULL; completion_function=NULL; completion_block=NULL; + completion_found=false; current_block=NULL; current_class=NULL; current_function=NULL; @@ -2772,13 +2950,14 @@ 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, const String &p_self_path) { +Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path,bool p_for_completion) { completion_type=COMPLETION_NONE; completion_node=NULL; completion_class=NULL; completion_function=NULL; completion_block=NULL; + completion_found=false; current_block=NULL; current_class=NULL; @@ -2789,6 +2968,7 @@ Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_ju tt->set_code(p_code); validating=p_just_validate; + for_completion=p_for_completion; tokenizer=tt; Error ret = _parse(p_base_path); memdelete(tt); @@ -2821,9 +3001,12 @@ void GDParser::clear() { current_block=NULL; current_class=NULL; + completion_found=false; + current_function=NULL; validating=false; + for_completion=false; error_set=false; tab_level.clear(); tab_level.push_back(0); diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 26955d2b7a..04f3dff3de 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -76,6 +76,7 @@ public: StringName extends_file; Vector<StringName> extends_class; + struct Member { PropertyInfo _export; #ifdef TOOLS_ENABLED @@ -92,11 +93,17 @@ public: Node *expression; }; + struct Signal { + StringName name; + Vector<StringName> arguments; + }; + Vector<ClassNode*> subclasses; Vector<Member> variables; Vector<Constant> constant_expressions; Vector<FunctionNode*> functions; Vector<FunctionNode*> static_functions; + Vector<Signal> _signals; BlockNode *initializer; ClassNode *owner; //Vector<Node*> initializers; @@ -269,7 +276,6 @@ public: }; struct NewLineNode : public Node { - int line; NewLineNode() { type=TYPE_NEWLINE; } }; @@ -363,6 +369,7 @@ public: COMPLETION_METHOD, COMPLETION_CALL_ARGUMENTS, COMPLETION_INDEX, + COMPLETION_VIRTUAL_FUNC }; @@ -379,6 +386,7 @@ private: T* alloc_node(); bool validating; + bool for_completion; int parenthesis; bool error_set; String error; @@ -410,10 +418,12 @@ private: BlockNode *completion_block; int completion_line; int completion_argument; + bool completion_found; PropertyInfo current_export; void _set_error(const String& p_error, int p_line=-1, int p_column=-1); + bool _recover_from_completion(); bool _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false); @@ -435,7 +445,7 @@ 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,const String& p_self_path=""); + Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); 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; diff --git a/modules/gdscript/gd_pretty_print.cpp b/modules/gdscript/gd_pretty_print.cpp index a5a993bb3a..9c290eac4a 100644 --- a/modules/gdscript/gd_pretty_print.cpp +++ b/modules/gdscript/gd_pretty_print.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gdscript/gd_pretty_print.h b/modules/gdscript/gd_pretty_print.h index fbf002295b..998fdc53ab 100644 --- a/modules/gdscript/gd_pretty_print.h +++ b/modules/gdscript/gd_pretty_print.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 97d97f1ef4..99ddc74bb4 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -140,7 +140,7 @@ String GDFunction::_get_call_error(const Variant::CallError& p_err, const String } else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments."; } else if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) { - err_text="Invalid call. Unexisting "+p_where+"."; + err_text="Invalid call. Nonexistent "+p_where+"."; } else if (p_err.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { err_text="Attempt to call "+p_where+" on a null instance."; } else { @@ -335,16 +335,30 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GET_VARIANT_PTR(b,3); GET_VARIANT_PTR(dst,4); +#ifdef DEBUG_ENABLED + Variant ret; + Variant::evaluate(op,*a,*b,ret,valid); +#else Variant::evaluate(op,*a,*b,*dst,valid); +#endif + if (!valid) { - if (false && dst->get_type()==Variant::STRING) { +#ifdef DEBUG_ENABLED + + if (ret.get_type()==Variant::STRING) { //return a string when invalid with the error - err_text=*dst; + err_text=ret; + err_text += " in operator '"+Variant::get_operator_name(op)+"'."; } else { err_text="Invalid operands '"+Variant::get_type_name(a->get_type())+"' and '"+Variant::get_type_name(b->get_type())+"' in operator '"+Variant::get_operator_name(op)+"'."; } +#endif break; + } +#ifdef DEBUG_ENABLED + *dst=ret; +#endif ip+=5; @@ -456,8 +470,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a GET_VARIANT_PTR(dst,3); bool valid; +#ifdef DEBUG_ENABLED +//allow better error message in cases where src and dst are the same stack position + Variant ret = src->get(*index,&valid); +#else *dst = src->get(*index,&valid); +#endif if (!valid) { String v = index->operator String(); if (v!="") { @@ -468,6 +487,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err_text="Invalid get index "+v+" (on base: '"+_get_var_type(src)+"')."; break; } +#ifdef DEBUG_ENABLED + *dst=ret; +#endif ip+=4; } continue; case OPCODE_SET_NAMED: { @@ -507,7 +529,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a const StringName *index = &_global_names_ptr[indexname]; bool valid; +#ifdef DEBUG_ENABLED +//allow better error message in cases where src and dst are the same stack position + Variant ret = src->get_named(*index,&valid); + +#else *dst = src->get_named(*index,&valid); +#endif if (!valid) { if (src->has_method(*index)) { @@ -517,7 +545,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } break; } - +#ifdef DEBUG_ENABLED + *dst=ret; +#endif ip+=4; } continue; case OPCODE_ASSIGN: { @@ -820,7 +850,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a gdfs->state.stack.resize(alloca_size); //copy variant stack for(int i=0;i<_stack_size;i++) { - memnew_placement(&stack[sizeof(Variant)*i],Variant(stack[i])); + memnew_placement(&gdfs->state.stack[sizeof(Variant)*i],Variant(stack[i])); } gdfs->state.stack_size=_stack_size; gdfs->state.self=self; @@ -1688,7 +1718,7 @@ bool GDScript::_update_exports() { } - if (c->extends_used && String(c->extends_file)!="") { + if (c->extends_used && String(c->extends_file)!="" && String(c->extends_file) != get_path()) { String path = c->extends_file; if (path.is_rel_path()) { @@ -1726,6 +1756,12 @@ bool GDScript::_update_exports() { //print_line("found "+c->variables[i]._export.name); member_default_values_cache[c->variables[i].identifier]=c->variables[i].default_value; } + + _signals.clear(); + + for(int i=0;i<c->_signals.size();i++) { + _signals[c->_signals[i].name]=c->_signals[i].arguments; + } } } else { //print_line("unchaged is "+get_path()); @@ -1756,6 +1792,7 @@ bool GDScript::_update_exports() { return changed; #endif + return false; } void GDScript::update_exports() { @@ -1940,9 +1977,17 @@ void GDScript::_bind_methods() { ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo("new")); + ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code); + } +Vector<uint8_t> GDScript::get_as_byte_code() const { + + GDTokenizerBuffer tokenizer; + return tokenizer.parse_code_string(source); +}; + Error GDScript::load_byte_code(const String& p_path) { @@ -2069,6 +2114,47 @@ Ref<GDScript> GDScript::get_base() const { return base; } +bool GDScript::has_script_signal(const StringName& p_signal) const { + if (_signals.has(p_signal)) + return true; + if (base.is_valid()) { + return base->has_script_signal(p_signal); + } +#ifdef TOOLS_ENABLED + else if (base_cache.is_valid()){ + return base_cache->has_script_signal(p_signal); + } + +#endif + return false; +} +void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + + for(const Map<StringName,Vector<StringName> >::Element *E=_signals.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + for(int i=0;i<E->get().size();i++) { + PropertyInfo arg; + arg.name=E->get()[i]; + mi.arguments.push_back(arg); + } + r_signals->push_back(mi); + } + + if (base.is_valid()) { + base->get_script_signal_list(r_signals); + } +#ifdef TOOLS_ENABLED + else if (base_cache.is_valid()){ + base_cache->get_script_signal_list(r_signals); + } + +#endif + +} + + GDScript::GDScript() { @@ -2100,7 +2186,6 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) { { const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); if (E) { - members[E->get().index]=p_value; if (E->get().setter) { const Variant *val=&p_value; Variant::CallError err; @@ -2109,6 +2194,8 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) { return true; //function exists, call was successful } } + else + members[E->get().index] = p_value; return true; } } @@ -2477,9 +2564,9 @@ void GDScriptLanguage::init() { //populate native classes - List<String> class_list; + List<StringName> class_list; ObjectTypeDB::get_type_list(&class_list); - for(List<String>::Element *E=class_list.front();E;E=E->next()) { + for(List<StringName>::Element *E=class_list.front();E;E=E->next()) { StringName n = E->get(); String s = String(n); @@ -2562,6 +2649,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "static", "float", "int", + "signal", 0}; @@ -2622,7 +2710,10 @@ GDScriptLanguage::~GDScriptLanguage() { /*************** RESOURCE ***************/ -RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderGDScript::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; GDScript *script = memnew( GDScript ); @@ -2654,6 +2745,8 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig script->reload(); } + if (r_error) + *r_error=OK; return scriptres; } @@ -2695,7 +2788,10 @@ Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resour } file->store_string(source); - + if (file->get_error()!=OK && file->get_error()!=ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; + } file->close(); memdelete(file); return OK; diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 5574b30d44..37ef47af6c 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -260,6 +260,7 @@ friend class GDScriptLanguage; Map<StringName,GDFunction> member_functions; Map<StringName,MemberInfo> member_indices; //members are just indices to the instanced script. Map<StringName,Ref<GDScript> > subclasses; + Map<StringName,Vector<StringName> > _signals; #ifdef TOOLS_ENABLED @@ -318,6 +319,9 @@ public: const Map<StringName,GDFunction>& get_member_functions() const { return member_functions; } const Ref<GDNativeClass>& get_native() const { return native; } + virtual bool has_script_signal(const StringName& p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + bool is_tool() const { return tool; } Ref<GDScript> get_base() const; @@ -345,6 +349,8 @@ public: Error load_source_code(const String& p_path); Error load_byte_code(const String& p_path); + Vector<uint8_t> get_as_byte_code() const; + virtual ScriptLanguage *get_language() const; GDScript(); @@ -469,6 +475,19 @@ public: } + virtual Vector<StackInfo> debug_get_current_stack_info() { + if (Thread::get_main_ID()!=Thread::get_caller_ID()) + return Vector<StackInfo>(); + + Vector<StackInfo> csi; + csi.resize(_debug_call_stack_pos); + for(int i=0;i<_debug_call_stack_pos;i++) { + csi[_debug_call_stack_pos-i-1].line=_call_stack[i].line?*_call_stack[i].line:0; + csi[_debug_call_stack_pos-i-1].script=Ref<GDScript>(_call_stack[i].function->get_script()); + } + return csi; + } + struct { StringName _init; @@ -538,7 +557,7 @@ public: class ResourceFormatLoaderGDScript : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 6f968f2080..b591ed3b4b 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -97,6 +97,7 @@ const char* GDTokenizer::token_names[TK_MAX]={ "preload", "assert", "yield", +"signal", "'['", "']'", "'{'", @@ -538,9 +539,12 @@ void GDTokenizerText::_advance() { is_node_path=true; case '\'': - string_mode=STRING_SINGLE_QUOTE; case '"': { - + + if (GETCHAR(0)=='\'') + string_mode=STRING_SINGLE_QUOTE; + + int i=1; if (string_mode==STRING_DOUBLE_QUOTE && GETCHAR(i)=='"' && GETCHAR(i+1)=='"') { i+=2; @@ -565,7 +569,10 @@ void GDTokenizerText::_advance() { } else if( string_mode!=STRING_MULTILINE && CharType(GETCHAR(i))=='\n') { _make_error("Unexpected EOL at String."); return; - + } else if( CharType(GETCHAR(i))==0xFFFF) { + //string ends here, next will be TK + i--; + break; } else if (CharType(GETCHAR(i))=='\\') { //escaped characters... i++; @@ -636,6 +643,11 @@ void GDTokenizerText::_advance() { str+=res; } else { + if (CharType(GETCHAR(i))=='\n') { + line++; + column=0; + } + str+=CharType(GETCHAR(i)); } i++; @@ -667,19 +679,19 @@ void GDTokenizerText::_advance() { while(true) { if (GETCHAR(i)=='.') { if (period_found || exponent_found) { - _make_error("Invalid numeric constant at '.'"); + _make_error("Invalid numeric constant at '.'"); return; } period_found=true; } else if (GETCHAR(i)=='x') { - if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) { - _make_error("Invalid numeric constant at 'x'"); + if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) { + _make_error("Invalid numeric constant at 'x'"); return; } hexa_found=true; - } else if (!hexa_found && GETCHAR(i)=='e') { + } else if (!hexa_found && GETCHAR(i)=='e') { if (hexa_found || exponent_found) { - _make_error("Invalid numeric constant at 'e'"); + _make_error("Invalid numeric constant at 'e'"); return; } exponent_found=true; @@ -689,7 +701,7 @@ void GDTokenizerText::_advance() { } else if ((GETCHAR(i)=='-' || GETCHAR(i)=='+') && exponent_found) { if (sign_found) { - _make_error("Invalid numeric constant at '-'"); + _make_error("Invalid numeric constant at '-'"); return; } sign_found=true; @@ -700,20 +712,20 @@ void GDTokenizerText::_advance() { i++; } - if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) { - _make_error("Invalid numeric constant: "+str); + if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) { + _make_error("Invalid numeric constant: "+str); return; } INCPOS(str.length()); - if (hexa_found) { - int val = str.hex_to_int(); - _make_constant(val); - } else if (period_found) { + if (hexa_found) { + int val = str.hex_to_int(); + _make_constant(val); + } else if (period_found) { real_t val = str.to_double(); //print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val)); _make_constant(val); - } else { + } else { int val = str.to_int(); _make_constant(val); @@ -822,7 +834,7 @@ void GDTokenizerText::_advance() { _make_built_in_func(GDFunctions::Function(i)); found=true; - break; + break; } } @@ -853,6 +865,7 @@ void GDTokenizerText::_advance() { {TK_PR_PRELOAD,"preload"}, {TK_PR_ASSERT,"assert"}, {TK_PR_YIELD,"yield"}, + {TK_PR_SIGNAL,"signal"}, {TK_PR_CONST,"const"}, //controlflow {TK_CF_IF,"if"}, @@ -1033,7 +1046,7 @@ void GDTokenizerText::advance(int p_amount) { ////////////////////////////////////////////////////////////////////////////////////////////////////// -#define BYTECODE_VERSION 3 +#define BYTECODE_VERSION 5 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) { diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index ff59c249a7..d6bd63c5b8 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -104,6 +104,7 @@ public: TK_PR_PRELOAD, TK_PR_ASSERT, TK_PR_YIELD, + TK_PR_SIGNAL, TK_BRACKET_OPEN, TK_BRACKET_CLOSE, TK_CURLY_BRACKET_OPEN, diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h index ff7c2734df..9eb5d1846b 100644 --- a/modules/gdscript/register_types.h +++ b/modules/gdscript/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub index 4cb47e7e67..211a043468 100644 --- a/modules/gridmap/SCsub +++ b/modules/gridmap/SCsub @@ -1,6 +1,3 @@ Import('env') env.add_source_files(env.modules_sources,"*.cpp") - - - diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 7c344e1e90..ad7c392cd0 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,7 +34,7 @@ #include "scene/3d/baked_light_instance.h" #include "io/marshalls.h" #include "scene/scene_string_names.h" - +#include "os/os.h" bool GridMap::_set(const StringName& p_name, const Variant& p_value) { @@ -122,7 +122,7 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { Octant &g = *octant_map[ok]; g.baked=b; - g.bake_instance=VS::get_singleton()->instance_create();; + g.bake_instance=VS::get_singleton()->instance_create();; VS::get_singleton()->instance_set_base(g.bake_instance,g.baked->get_rid()); VS::get_singleton()->instance_geometry_set_baked_light(g.bake_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID()); } @@ -130,8 +130,8 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) { } else if (name.begins_with("areas/")) { - int which = name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int which = name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (what=="bounds") { ERR_FAIL_COND_V(area_map.has(which),false); create_area(which,p_value); @@ -215,8 +215,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const { r_ret= d; } else if (name.begins_with("areas/")) { - int which = name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int which = name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (what=="bounds") r_ret= area_get_bounds(which); else if (what=="name") @@ -393,8 +393,12 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){ if (g.items.empty()) { PhysicsServer::get_singleton()->free(g.static_body); + if (g.collision_debug.is_valid()) { + PhysicsServer::get_singleton()->free(g.collision_debug); + PhysicsServer::get_singleton()->free(g.collision_debug_instance); + } - memdelete(&g); + memdelete(&g); octant_map.erase(octantkey); } else { @@ -418,9 +422,24 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){ Octant *g = memnew( Octant ); g->dirty=true; g->static_body = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC); + PhysicsServer::get_singleton()->body_attach_object_instance_ID(g->static_body,get_instance_ID()); if (is_inside_world()) PhysicsServer::get_singleton()->body_set_space(g->static_body,get_world()->get_space()); + SceneTree *st=SceneTree::get_singleton(); + + if (st && st->is_debugging_collisions_hint()) { + + g->collision_debug=VisualServer::get_singleton()->mesh_create(); + g->collision_debug_instance=VisualServer::get_singleton()->instance_create(); + VisualServer::get_singleton()->instance_set_base(g->collision_debug_instance,g->collision_debug); + if (is_inside_world()) { + VisualServer::get_singleton()->instance_set_scenario(g->collision_debug_instance,get_world()->get_scenario()); + VisualServer::get_singleton()->instance_set_transform(g->collision_debug_instance,get_global_transform()); + } + + } + octant_map[octantkey]=g; } @@ -511,6 +530,13 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) { //print_line("BODYPOS: "+get_global_transform()); + if (g.collision_debug_instance.is_valid()) { + VS::get_singleton()->instance_set_scenario(g.collision_debug_instance,get_world()->get_scenario()); + VS::get_singleton()->instance_set_transform(g.collision_debug_instance,get_global_transform()); + if (area_map.has(p_key.area)) { + VS::get_singleton()->instance_set_room(g.collision_debug_instance,area_map[p_key.area]->instance); + } + } if (g.baked.is_valid()) { Transform xf = get_global_transform(); @@ -544,6 +570,10 @@ void GridMap::_octant_transform(const OctantKey &p_key) { Octant&g = *octant_map[p_key]; PhysicsServer::get_singleton()->body_set_state(g.static_body,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); + if (g.collision_debug_instance.is_valid()) { + VS::get_singleton()->instance_set_transform(g.collision_debug_instance,get_global_transform()); + } + if (g.baked.is_valid()) { Transform xf = get_global_transform(); @@ -571,6 +601,13 @@ void GridMap::_octant_update(const OctantKey &p_key) { PhysicsServer::get_singleton()->body_clear_shapes(g.static_body); + if (g.collision_debug.is_valid()) { + + VS::get_singleton()->mesh_clear(g.collision_debug); + } + + DVector<Vector3> col_debug; + for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { Octant::ItemInstances &ii=E->get(); @@ -608,6 +645,7 @@ void GridMap::_octant_update(const OctantKey &p_key) { xform.basis.scale(Vector3(cell_scale,cell_scale,cell_scale)); ii.multimesh->set_instance_transform(idx,xform); + //ii.multimesh->set_instance_transform(idx,Transform() ); ii.multimesh->set_instance_color(idx,Color(1,1,1,1)); //print_line("MMINST: "+xform); @@ -623,8 +661,11 @@ void GridMap::_octant_update(const OctantKey &p_key) { if (ii.shape.is_valid()) { PhysicsServer::get_singleton()->body_add_shape(g.static_body,ii.shape->get_rid(),xform); - // print_line("PHIS x: "+xform); + if (g.collision_debug.is_valid()) { + ii.shape->add_vertices_to_array(col_debug,xform); + } + // print_line("PHIS x: "+xform); } idx++; @@ -635,6 +676,20 @@ void GridMap::_octant_update(const OctantKey &p_key) { } + if (col_debug.size()) { + + + Array arr; + arr.resize(VS::ARRAY_MAX); + arr[VS::ARRAY_VERTEX]=col_debug; + + VS::get_singleton()->mesh_add_surface(g.collision_debug,VS::PRIMITIVE_LINES,arr); + SceneTree *st=SceneTree::get_singleton(); + if (st) { + VS::get_singleton()->mesh_surface_set_material( g.collision_debug, 0,st->get_debug_collision_material()->get_rid() ); + } + } + g.dirty=false; } @@ -655,6 +710,12 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) { } + if (g.collision_debug_instance.is_valid()) { + + VS::get_singleton()->instance_set_room(g.collision_debug_instance,RID()); + VS::get_singleton()->instance_set_scenario(g.collision_debug_instance,RID()); + } + for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) { VS::get_singleton()->instance_set_scenario(E->get().multimesh_instance,RID()); @@ -958,6 +1019,11 @@ void GridMap::_clear_internal(bool p_keep_areas) { if (E->get()->bake_instance.is_valid()) VS::get_singleton()->free(E->get()->bake_instance); + if (E->get()->collision_debug.is_valid()) + VS::get_singleton()->free(E->get()->collision_debug); + if (E->get()->collision_debug_instance.is_valid()) + VS::get_singleton()->free(E->get()->collision_debug_instance); + PhysicsServer::get_singleton()->free(E->get()->static_body); memdelete(E->get()); diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index df805d99fa..9d3b1dcf95 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -93,6 +93,8 @@ class GridMap : public Spatial { Ref<Mesh> baked; RID bake_instance; + RID collision_debug; + RID collision_debug_instance; bool dirty; RID static_body; diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 140718a91a..e4559ca100 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -61,7 +61,7 @@ void GridMapEditor::_menu_option(int p_option) { case MENU_OPTION_CONFIGURE: { - + } break; case MENU_OPTION_LOCK_VIEW: { @@ -220,7 +220,9 @@ void GridMapEditor::_menu_option(int p_option) { } break; - + case MENU_OPTION_GRIDMAP_SETTINGS: { + settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50)); + } break; } } @@ -304,7 +306,7 @@ bool GridMapEditor::do_input_action(Camera* p_camera,const Point2& p_point,bool p.d=edit_floor[edit_axis]*node->get_cell_size(); Vector3 inters; - if (!p.intersects_segment(from,from+normal*500,&inters)) + if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_val(), &inters)) return false; @@ -522,7 +524,9 @@ void GridMapEditor::_duplicate_paste() { } bool GridMapEditor::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) { - + if (!node) { + return false; + } if (edit_mode->get_selected()==0) { // regular click switch (p_event.type) { @@ -706,9 +710,40 @@ struct _CGMEItemSort { }; +void GridMapEditor::_set_display_mode(int p_mode) { + if (display_mode==p_mode) { + return; + } + + if (p_mode == DISPLAY_LIST) { + mode_list->set_pressed(true); + mode_thumbnail->set_pressed(false); + } else if (p_mode == DISPLAY_THUMBNAIL) { + mode_list->set_pressed(false); + mode_thumbnail->set_pressed(true); + } + + display_mode=p_mode; + + update_pallete(); +} + void GridMapEditor::update_pallete() { + int selected = theme_pallete->get_current(); theme_pallete->clear(); + if (display_mode == DISPLAY_THUMBNAIL) { + theme_pallete->set_max_columns(0); + theme_pallete->set_icon_mode(ItemList::ICON_MODE_TOP); + } else if (display_mode == DISPLAY_LIST){ + theme_pallete->set_max_columns(1); + theme_pallete->set_icon_mode(ItemList::ICON_MODE_LEFT); + } + + float min_size = EDITOR_DEF("grid_map/preview_size",64); + theme_pallete->set_min_icon_size(Size2(min_size, min_size)); + theme_pallete->set_fixed_column_width(min_size*3/2); + theme_pallete->set_max_text_lines(2); Ref<MeshLibrary> theme = node->get_theme(); @@ -720,10 +755,6 @@ void GridMapEditor::update_pallete() { Vector<int> ids; ids = theme->get_item_list(); - TreeItem *root = theme_pallete->create_item(NULL); - theme_pallete->set_hide_root(true); - TreeItem *selected=NULL; - List<_CGMEItemSort> il; for(int i=0;i<ids.size();i++) { @@ -734,45 +765,31 @@ void GridMapEditor::update_pallete() { } il.sort(); - int col=0; - TreeItem *ti=NULL; - int selected_col=0; + int item = 0; for(List<_CGMEItemSort>::Element *E=il.front();E;E=E->next()) { - int id = E->get().id; - if (col==0) { - ti = theme_pallete->create_item(root); - } + theme_pallete->add_item(""); String name=theme->get_item_name(id); Ref<Texture> preview = theme->get_item_preview(id); if (!preview.is_null()) { - - ti->set_cell_mode(col,TreeItem::CELL_MODE_ICON); - ti->set_icon(col,preview); - ti->set_tooltip(col,name); - } else { - - ti->set_text(col,name); + theme_pallete->set_item_icon(item, preview); + theme_pallete->set_item_tooltip(item, name); } - ti->set_metadata(col,id); - - if (selected_pallete==id) { - selected=ti; - selected_col=col; + if (name!="") { + theme_pallete->set_item_text(item,name); } + theme_pallete->set_item_metadata(item, id); - col++; - if (col==theme_pallete->get_columns()) - col=0; - + item++; } - if (selected) - selected->select(selected_col); + if (selected!=-1) { + theme_pallete->select(selected); + } last_theme=theme.operator->(); } @@ -842,6 +859,9 @@ void GridMapEditor::edit(GridMap *p_gridmap) { VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i],VS::INSTANCE_FLAG_VISIBLE,false); } + + VisualServer::get_singleton()->instance_geometry_set_flag(cursor_instance, VS::INSTANCE_FLAG_VISIBLE,false); + _clear_areas(); return; @@ -868,7 +888,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { { //update grids - RID indicator_mat = VisualServer::get_singleton()->fixed_material_create(); + indicator_mat = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true ); VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false ); @@ -922,7 +942,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { d[VS::ARRAY_VERTEX]=grid_points[i]; d[VS::ARRAY_COLOR]=grid_colors[i]; VisualServer::get_singleton()->mesh_add_surface(grid[i],VisualServer::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat,true); + VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat); } @@ -951,7 +971,7 @@ void GridMapEditor::update_grid() { grid_xform.origin.x-=1; //force update in hackish way.. what do i care - VS *vs = VS::get_singleton(); + //VS *vs = VS::get_singleton(); grid_ofs[edit_axis]=edit_floor[edit_axis]*node->get_cell_size(); @@ -976,7 +996,7 @@ void GridMapEditor::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { - theme_pallete->connect("cell_selected", this,"_item_selected_cbk"); + theme_pallete->connect("item_selected", this,"_item_selected_cbk"); edit_mode->connect("item_selected", this,"_edit_mode_changed"); area_list->connect("item_edited", this,"_area_renamed"); area_list->connect("item_selected", this,"_area_selected"); @@ -1014,7 +1034,7 @@ void GridMapEditor::_notification(int p_what) { if (xf!=grid_xform) { for(int i=0;i<3;i++) { - + VS::get_singleton()->instance_set_transform(grid_instance[i],xf * edit_grid_xform); } grid_xform=xf; @@ -1043,7 +1063,9 @@ void GridMapEditor::_notification(int p_what) { } void GridMapEditor::_update_cursor_instance() { - + if (!node) { + return; + } if (cursor_instance.is_valid()) VisualServer::get_singleton()->free(cursor_instance); @@ -1063,18 +1085,8 @@ void GridMapEditor::_update_cursor_instance() { } -void GridMapEditor::_item_selected_cbk() { - - TreeItem *it = theme_pallete->get_selected(); - if (it) { - - selected_pallete=it->get_metadata(theme_pallete->get_selected_column()); - - } else { - - selected_pallete=-1; - - } +void GridMapEditor::_item_selected_cbk(int idx) { + selected_pallete=theme_pallete->get_item_metadata(idx); _update_cursor_instance(); @@ -1092,7 +1104,9 @@ void GridMapEditor::_clear_areas() { } void GridMapEditor::_update_areas_display() { - + if (!node) { + return; + } _clear_areas(); List<int> areas; @@ -1179,7 +1193,7 @@ void GridMapEditor::_bind_methods() { ObjectTypeDB::bind_method("_area_selected",&GridMapEditor::_area_selected); ObjectTypeDB::bind_method("_floor_changed",&GridMapEditor::_floor_changed); - + ObjectTypeDB::bind_method(_MD("_set_display_mode","mode"), &GridMapEditor::_set_display_mode); } @@ -1192,8 +1206,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { undo_redo=p_editor->get_undo_redo(); int mw = EDITOR_DEF("grid_map/palette_min_width",230); - EmptyControl *ec = memnew( EmptyControl); - ec->set_minsize(Size2(mw,0)); + Control *ec = memnew( Control); + ec->set_custom_minimum_size(Size2(mw,0)); add_child(ec); @@ -1222,9 +1236,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { options->get_popup()->add_item("Cursor Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_A); options->get_popup()->add_item("Cursor Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_S); options->get_popup()->add_item("Cursor Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_D); - options->get_popup()->add_item("Cursor Back Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_ALT+KEY_A); - options->get_popup()->add_item("Cursor Back Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_ALT+KEY_S); - options->get_popup()->add_item("Cursor Back Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_ALT+KEY_D); + options->get_popup()->add_item("Cursor Back Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_MASK_SHIFT+KEY_A); + options->get_popup()->add_item("Cursor Back Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_MASK_SHIFT+KEY_S); + options->get_popup()->add_item("Cursor Back Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_MASK_SHIFT+KEY_D); options->get_popup()->add_item("Cursor Clear Rotation",MENU_OPTION_CURSOR_CLEAR_ROTATION,KEY_W); options->get_popup()->add_separator(); options->get_popup()->add_check_item("Duplicate Selects",MENU_OPTION_DUPLICATE_SELECTS); @@ -1237,9 +1251,30 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { //options->get_popup()->add_separator(); //options->get_popup()->add_item("Configure",MENU_OPTION_CONFIGURE); + options->get_popup()->add_separator(); + options->get_popup()->add_item("Settings", MENU_OPTION_GRIDMAP_SETTINGS); + + settings_dialog = memnew(ConfirmationDialog); + settings_dialog->set_title("GridMap Settings"); + add_child(settings_dialog); + settings_vbc = memnew(VBoxContainer); + settings_vbc->set_custom_minimum_size(Size2(200, 0)); + settings_dialog->add_child(settings_vbc); + settings_dialog->set_child_rect(settings_vbc); + + settings_pick_distance = memnew(SpinBox); + settings_pick_distance->set_max(10000.0f); + settings_pick_distance->set_min(500.0f); + settings_pick_distance->set_step(1.0f); + settings_pick_distance->set_val(EDITOR_DEF("gridmap_editor/pick_distance", 5000.0)); + settings_vbc->add_margin_child("Pick Distance:", settings_pick_distance); + clip_mode=CLIP_DISABLED; options->get_popup()->connect("item_pressed", this,"_menu_option"); + HBoxContainer *hb = memnew( HBoxContainer ); + add_child(hb); + hb->set_h_size_flags(SIZE_EXPAND_FILL); edit_mode = memnew(OptionButton); edit_mode->set_area_as_parent_rect(); @@ -1247,13 +1282,27 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { edit_mode->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,14);; edit_mode->add_item("Tiles"); edit_mode->add_item("Areas"); - add_child(edit_mode); - + hb->add_child(edit_mode); + edit_mode->set_h_size_flags(SIZE_EXPAND_FILL); + + mode_thumbnail = memnew( ToolButton ); + mode_thumbnail->set_toggle_mode(true); + mode_thumbnail->set_pressed(true); + mode_thumbnail->set_icon(p_editor->get_gui_base()->get_icon("FileThumbnail","EditorIcons")); + hb->add_child(mode_thumbnail); + mode_thumbnail->connect("pressed", this, "_set_display_mode", varray(DISPLAY_THUMBNAIL)); + + mode_list = memnew( ToolButton ); + mode_list->set_toggle_mode(true); + mode_list->set_pressed(false); + mode_list->set_icon(p_editor->get_gui_base()->get_icon("FileList", "EditorIcons")); + hb->add_child(mode_list); + mode_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST)); + + display_mode = DISPLAY_THUMBNAIL; selected_area=-1; - - theme_pallete = memnew( Tree ); - theme_pallete->set_columns(3); + theme_pallete = memnew( ItemList ); add_child(theme_pallete); theme_pallete->set_v_size_flags(SIZE_EXPAND_FILL); @@ -1340,7 +1389,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { Array d; d.resize(VS::ARRAY_MAX); - RID inner_mat = VisualServer::get_singleton()->fixed_material_create(); + inner_mat = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(inner_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.3)); VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_ONTOP,true); VisualServer::get_singleton()->material_set_flag(inner_mat,VS::MATERIAL_FLAG_UNSHADED,true); @@ -1349,9 +1398,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=triangles; VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_TRIANGLES,d); - VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat,true); + VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,0,inner_mat); - RID outer_mat = VisualServer::get_singleton()->fixed_material_create(); + outer_mat = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(outer_mat,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.7,0.7,1.0,0.8)); VisualServer::get_singleton()->material_set_line_width(outer_mat,3.0); VisualServer::get_singleton()->material_set_flag(outer_mat,VS::MATERIAL_FLAG_ONTOP,true); @@ -1361,10 +1410,10 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=lines; VisualServer::get_singleton()->mesh_add_surface(selection_mesh,VS::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat,true); + VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh,1,outer_mat); - RID inner_mat_dup = VisualServer::get_singleton()->fixed_material_create(); + inner_mat_dup = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(inner_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.3)); VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_ONTOP,true); VisualServer::get_singleton()->material_set_flag(inner_mat_dup,VS::MATERIAL_FLAG_UNSHADED,true); @@ -1373,9 +1422,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=triangles; VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_TRIANGLES,d); - VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup,true); + VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,0,inner_mat_dup); - RID outer_mat_dup = VisualServer::get_singleton()->fixed_material_create(); + outer_mat_dup = VisualServer::get_singleton()->fixed_material_create(); VisualServer::get_singleton()->fixed_material_set_param(outer_mat_dup,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(1.0,0.7,0.7,0.8)); VisualServer::get_singleton()->material_set_line_width(outer_mat_dup,3.0); VisualServer::get_singleton()->material_set_flag(outer_mat_dup,VS::MATERIAL_FLAG_ONTOP,true); @@ -1385,7 +1434,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { d[VS::ARRAY_VERTEX]=lines; VisualServer::get_singleton()->mesh_add_surface(duplicate_mesh,VS::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup,true); + VisualServer::get_singleton()->mesh_surface_set_material(duplicate_mesh,1,outer_mat_dup); } @@ -1409,6 +1458,11 @@ GridMapEditor::~GridMapEditor() { VisualServer::get_singleton()->free(cursor_instance); } + VisualServer::get_singleton()->free(inner_mat); + VisualServer::get_singleton()->free(outer_mat); + VisualServer::get_singleton()->free(inner_mat_dup); + VisualServer::get_singleton()->free(outer_mat_dup); + VisualServer::get_singleton()->free(selection_mesh); if (selection_instance.is_valid()) VisualServer::get_singleton()->free(selection_instance); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 1240d78426..03b2d4226e 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -40,10 +40,8 @@ class SpatialEditorPlugin; class GridMapEditor : public VBoxContainer { - OBJ_TYPE(GridMapEditor, VBoxContainer ); - enum { GRID_CURSOR_SIZE=50 @@ -66,6 +64,10 @@ class GridMapEditor : public VBoxContainer { CLIP_BELOW }; + enum DisplayMode { + DISPLAY_THUMBNAIL, + DISPLAY_LIST + }; UndoRedo *undo_redo; InputAction input_action; @@ -73,7 +75,12 @@ class GridMapEditor : public VBoxContainer { MenuButton * options; SpinBox *floor; OptionButton *edit_mode; + ToolButton *mode_thumbnail; + ToolButton *mode_list; HBoxContainer *spatial_editor_hb; + ConfirmationDialog *settings_dialog; + VBoxContainer *settings_vbc; + SpinBox *settings_pick_distance; struct SetItem { @@ -105,6 +112,13 @@ class GridMapEditor : public VBoxContainer { RID duplicate_mesh; RID duplicate_instance; + RID indicator_mat; + + RID inner_mat; + RID outer_mat; + RID inner_mat_dup; + RID outer_mat_dup; + bool updating; @@ -125,6 +139,7 @@ class GridMapEditor : public VBoxContainer { Vector3 cursor_origin; Vector3 last_mouseover; + int display_mode; int selected_pallete; int selected_area; int cursor_rot; @@ -153,8 +168,8 @@ class GridMapEditor : public VBoxContainer { MENU_OPTION_SELECTION_MAKE_AREA, MENU_OPTION_SELECTION_MAKE_EXTERIOR_CONNECTOR, MENU_OPTION_SELECTION_CLEAR, - MENU_OPTION_REMOVE_AREA - + MENU_OPTION_REMOVE_AREA, + MENU_OPTION_GRIDMAP_SETTINGS }; @@ -176,9 +191,10 @@ class GridMapEditor : public VBoxContainer { void _configure(); void _menu_option(int); void update_pallete(); - Tree *theme_pallete; + void _set_display_mode(int p_mode); + ItemList *theme_pallete; Tree *area_list; - void _item_selected_cbk(); + void _item_selected_cbk(int idx); void _update_cursor_transform(); void _update_cursor_instance(); void _update_clip(); diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp index 3c3c8aa98f..2bc440759d 100644 --- a/modules/gridmap/register_types.cpp +++ b/modules/gridmap/register_types.cpp @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -27,16 +27,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "register_types.h" +#ifndef _3D_DISABLED #include "object_type_db.h" #include "grid_map.h" #include "grid_map_editor_plugin.h" +#endif void register_gridmap_types() { +#ifndef _3D_DISABLED ObjectTypeDB::register_type<GridMap>(); #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<GridMapEditorPlugin>(); #endif +#endif } diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h index 5cddb96b70..326d7acf24 100644 --- a/modules/gridmap/register_types.h +++ b/modules/gridmap/register_types.h @@ -5,7 +5,7 @@ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ |