bool Main::start() { ERR_FAIL_COND_V(!_start_success,false); bool editor=false; String doc_tool; bool doc_base=true; String game_path; String script; String test; String screen; String optimize; String optimize_preset; String _export_platform; String _import; String _import_script; String dumpstrings; bool noquit=false; bool convert_old=false; bool export_debug=false; bool project_manager_request = false; List<String> args = OS::get_singleton()->get_cmdline_args(); for (int i=0;i<args.size();i++) { //parameters that do not have an argument to the right if (args[i]=="-nodocbase") { doc_base=false; } else if (args[i]=="-noquit") { noquit=true; } else if (args[i]=="-convert_old") { convert_old=true; } else if (args[i]=="-editor" || args[i]=="-e") { editor=true; } else if (args[i] == "-pm" || args[i] == "-project_manager") { project_manager_request = true; } else if (args[i].length() && args[i][0] != '-' && game_path == "") { game_path=args[i]; } //parameters that have an argument to the right else if (i < (args.size()-1)) { bool parsed_pair=true; if (args[i]=="-doctool") { doc_tool=args[i+1]; } else if (args[i]=="-script" || args[i]=="-s") { script=args[i+1]; } else if (args[i]=="-level" || args[i]=="-l") { OS::get_singleton()->_custom_level=args[i+1]; } else if (args[i]=="-test") { test=args[i+1]; } else if (args[i]=="-optimize") { optimize=args[i+1]; } else if (args[i]=="-optimize_preset") { optimize_preset=args[i+1]; } else if (args[i]=="-export") { editor=true; //needs editor _export_platform=args[i+1]; } else if (args[i]=="-export_debug") { editor=true; //needs editor _export_platform=args[i+1]; export_debug=true; } else if (args[i]=="-import") { editor=true; //needs editor _import=args[i+1]; } else if (args[i]=="-import_script") { editor=true; //needs editor _import_script=args[i+1]; } else if (args[i]=="-dumpstrings") { editor=true; //needs editor dumpstrings=args[i+1]; } else { // The parameter does not match anything known, don't skip the next argument parsed_pair=false; } if (parsed_pair) { i++; } } } if (editor) Globals::get_singleton()->set("editor_active",true); String main_loop_type; #ifdef TOOLS_ENABLED if(doc_tool!="") { DocData doc; doc.generate(doc_base); DocData docsrc; if (docsrc.load(doc_tool)==OK) { print_line("Doc exists. Merging.."); doc.merge_from(docsrc); } else { print_line("No Doc exists. Generating empty."); } doc.save(doc_tool); return false; } if (optimize!="") editor=true; //need editor #endif if (_export_platform!="") { if (game_path=="") { String err="Command line param "; err+=export_debug?"-export_debug":"-export"; err+=" passed but no destination path given.\n"; err+="Please specify the binary's file path to export to. Aborting export."; ERR_PRINT(err.utf8().get_data()); return false; } } if(script=="" && game_path=="" && String(GLOBAL_DEF("application/main_scene",""))!="") { game_path=GLOBAL_DEF("application/main_scene",""); } MainLoop *main_loop=NULL; if (editor) { main_loop = memnew(SceneTree); }; if (test!="") { #ifdef DEBUG_ENABLED main_loop = test_main(test,args); if (!main_loop) return false; #endif } else if (script!="") { Ref<Script> script_res = ResourceLoader::load(script); ERR_EXPLAIN("Can't load script: "+script); ERR_FAIL_COND_V(script_res.is_null(),false); if( script_res->can_instance() /*&& script_res->inherits_from("SceneTreeScripted")*/) { StringName instance_type=script_res->get_instance_base_type(); Object *obj = ObjectTypeDB::instance(instance_type); MainLoop *script_loop = obj?obj->cast_to<MainLoop>():NULL; if (!script_loop) { if (obj) memdelete(obj); ERR_EXPLAIN("Can't load script '"+script+"', it does not inherit from a MainLoop type"); ERR_FAIL_COND_V(!script_loop,false); } script_loop->set_init_script(script_res); main_loop=script_loop; } else { return false; } } else { main_loop_type=GLOBAL_DEF("application/main_loop_type",""); } if (!main_loop && main_loop_type=="") main_loop_type="SceneTree"; if (!main_loop) { if (!ObjectTypeDB::type_exists(main_loop_type)) { OS::get_singleton()->alert("godot: error: MainLoop type doesn't exist: "+main_loop_type); return false; } else { Object *ml = ObjectTypeDB::instance(main_loop_type); if (!ml) { ERR_EXPLAIN("Can't instance MainLoop type"); ERR_FAIL_V(false); } main_loop=ml->cast_to<MainLoop>(); if (!main_loop) { memdelete(ml); ERR_EXPLAIN("Invalid MainLoop type"); ERR_FAIL_V(false); } } } if (main_loop->is_type("SceneTree")) { SceneTree *sml = main_loop->cast_to<SceneTree>(); if (debug_collisions) { sml->set_debug_collisions_hint(true); } if (debug_navigation) { sml->set_debug_navigation_hint(true); } #ifdef TOOLS_ENABLED EditorNode *editor_node=NULL; if (editor) { editor_node = memnew( EditorNode ); sml->get_root()->add_child(editor_node); //root_node->set_editor(editor); //startup editor if (_export_platform!="") { editor_node->export_platform(_export_platform,game_path,export_debug,"",true); game_path=""; //no load anything } } #endif if (!editor) { //standard helpers that can be changed from main config String stretch_mode = GLOBAL_DEF("display/stretch_mode","disabled"); String stretch_aspect = GLOBAL_DEF("display/stretch_aspect","ignore"); Size2i stretch_size = Size2(GLOBAL_DEF("display/width",0),GLOBAL_DEF("display/height",0)); SceneTree::StretchMode sml_sm=SceneTree::STRETCH_MODE_DISABLED; if (stretch_mode=="2d") sml_sm=SceneTree::STRETCH_MODE_2D; else if (stretch_mode=="viewport") sml_sm=SceneTree::STRETCH_MODE_VIEWPORT; SceneTree::StretchAspect sml_aspect=SceneTree::STRETCH_ASPECT_IGNORE; if (stretch_aspect=="keep") sml_aspect=SceneTree::STRETCH_ASPECT_KEEP; else if (stretch_aspect=="keep_width") sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_WIDTH; else if (stretch_aspect=="keep_height") sml_aspect=SceneTree::STRETCH_ASPECT_KEEP_HEIGHT; sml->set_screen_stretch(sml_sm,sml_aspect,stretch_size); sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true)); String appname = Globals::get_singleton()->get("application/name"); appname = TranslationServer::get_singleton()->translate(appname); OS::get_singleton()->set_window_title(appname); } else { GLOBAL_DEF("display/stretch_mode","disabled"); Globals::get_singleton()->set_custom_property_info("display/stretch_mode",PropertyInfo(Variant::STRING,"display/stretch_mode",PROPERTY_HINT_ENUM,"disabled,2d,viewport")); GLOBAL_DEF("display/stretch_aspect","ignore"); Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height")); sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true)); } if (game_path!="" && !project_manager_request) { String local_game_path=game_path.replace("\\","/"); if (!local_game_path.begins_with("res://")) { bool absolute=(local_game_path.size()>1) && (local_game_path[0]=='/' || local_game_path[1]==':'); if (!absolute) { if (Globals::get_singleton()->is_using_datapack()) { local_game_path="res://"+local_game_path; } else { int sep=local_game_path.find_last("/"); if (sep==-1) { DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); local_game_path=da->get_current_dir()+"/"+local_game_path; memdelete(da) ; } else { DirAccess *da = DirAccess::open(local_game_path.substr(0,sep)); if (da) { local_game_path=da->get_current_dir()+"/"+local_game_path.substr(sep+1,local_game_path.length());; memdelete(da); } } } } } local_game_path=Globals::get_singleton()->localize_path(local_game_path); #ifdef TOOLS_ENABLED if (editor) { if (_import!="") { //editor_node->import_scene(_import,local_game_path,_import_script); if (!noquit) sml->quit(); game_path=""; //no load anything } else { Error serr = editor_node->load_scene(local_game_path); if (serr==OK) { if (optimize!="") { editor_node->save_optimized_copy(optimize,optimize_preset); if (!noquit) sml->quit(); } if (dumpstrings!="") { editor_node->save_translatable_strings(dumpstrings); if (!noquit) sml->quit(); } } } OS::get_singleton()->set_context(OS::CONTEXT_EDITOR); //editor_node->set_edited_scene(game); } else { #endif { //autoload List<PropertyInfo> props; Globals::get_singleton()->get_property_list(&props); //first pass, add the constants so they exist before any script is loaded for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { String s = E->get().name; if (!s.begins_with("autoload/")) continue; String name = s.get_slicec('/',1); String path = Globals::get_singleton()->get(s); bool global_var=false; if (path.begins_with("*")) { global_var=true; } if (global_var) { for(int i=0;i<ScriptServer::get_language_count();i++) { ScriptServer::get_language(i)->add_global_constant(name,Variant()); } } } //second pass, load into global constants List<Node*> to_add; for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { String s = E->get().name; if (!s.begins_with("autoload/")) continue; String name = s.get_slicec('/',1); String path = Globals::get_singleton()->get(s); bool global_var=false; if (path.begins_with("*")) { global_var=true; path=path.substr(1,path.length()-1); } RES res = ResourceLoader::load(path); ERR_EXPLAIN("Can't autoload: "+path); ERR_CONTINUE(res.is_null()); Node *n=NULL; if (res->is_type("PackedScene")) { Ref<PackedScene> ps = res; n=ps->instance(); } else if (res->is_type("Script")) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ObjectTypeDB::is_type(ibt,"Node"); ERR_EXPLAIN("Script does not inherit a Node: "+path); ERR_CONTINUE( !valid_type ); Object *obj = ObjectTypeDB::instance(ibt); ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: "+String(ibt)); ERR_CONTINUE( obj==NULL ); n = obj->cast_to<Node>(); n->set_script(s.get_ref_ptr()); } ERR_EXPLAIN("Path in autoload not a node or script: "+path); ERR_CONTINUE(!n); n->set_name(name); //defer so references are all valid on _ready() //sml->get_root()->add_child(n); to_add.push_back(n); if (global_var) { for(int i=0;i<ScriptServer::get_language_count();i++) { ScriptServer::get_language(i)->add_global_constant(name,n); } } } for(List<Node*>::Element *E=to_add.front();E;E=E->next()) { sml->get_root()->add_child(E->get()); } } Node *scene=NULL; Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path); if (scenedata.is_valid()) scene=scenedata->instance(); ERR_EXPLAIN("Failed loading scene: "+local_game_path); ERR_FAIL_COND_V(!scene,false) //sml->get_root()->add_child(scene); sml->add_current_scene(scene); String iconpath = GLOBAL_DEF("application/icon","Variant()"""); if (iconpath!="") { Image icon; if (icon.load(iconpath)==OK) OS::get_singleton()->set_icon(icon); } //singletons #ifdef TOOLS_ENABLED } #endif } #ifdef TOOLS_ENABLED /*if (_export_platform!="") { sml->quit(); }*/ /* if (sml->get_root_node()) { Console *console = memnew( Console ); sml->get_root_node()->cast_to<RootNode>()->set_console(console); if (GLOBAL_DEF("console/visible_default",false).operator bool()) { console->show(); } else {P console->hide(); }; } */ if (project_manager_request || (script=="" && test=="" && game_path=="" && !editor)) { ProjectManager *pmanager = memnew( ProjectManager ); sml->get_root()->add_child(pmanager); OS::get_singleton()->set_context(OS::CONTEXT_PROJECTMAN); } #endif } OS::get_singleton()->set_main_loop( main_loop ); return true; }
void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,bool p_main) { switch(p_variant.get_type()) { case Variant::OBJECT: { RES res = p_variant.operator RefPtr(); if (res.is_null() || external_resources.has(res)) return; if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) { int index = external_resources.size(); external_resources[res]=index; return; } if (resource_set.has(res)) return; List<PropertyInfo> property_list; res->get_property_list( &property_list ); property_list.sort(); List<PropertyInfo>::Element *I=property_list.front(); while(I) { PropertyInfo pi=I->get(); if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) { Variant v=res->get(I->get().name); _find_resources(v); } I=I->next(); } resource_set.insert( res ); //saved after, so the childs it needs are available when loaded saved_resources.push_back(res); } break; case Variant::ARRAY: { Array varray=p_variant; int len=varray.size(); for(int i=0;i<len;i++) { Variant v=varray.get(i); _find_resources(v); } } break; case Variant::DICTIONARY: { Dictionary d=p_variant; List<Variant> keys; d.get_key_list(&keys); for(List<Variant>::Element *E=keys.front();E;E=E->next()) { Variant v = d[E->get()]; _find_resources(v); } } break; default: {} } }
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) { if (r_error) *r_error = ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) local_path = "res://" + p_path; else local_path = ProjectSettings::get_singleton()->localize_path(p_path); if (!p_no_cache) { //lock first if possible if (ResourceCache::lock) { ResourceCache::lock->read_lock(); } //get ptr Resource **rptr = ResourceCache::resources.getptr(local_path); if (rptr) { RES res(*rptr); //it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached if (res.is_valid()) { //referencing is fine if (r_error) *r_error = OK; if (ResourceCache::lock) { ResourceCache::lock->read_unlock(); } print_verbose("Loading resource: " + local_path + " (cached)"); return res; } } if (ResourceCache::lock) { ResourceCache::lock->read_unlock(); } } bool xl_remapped = false; String path = _path_remap(local_path, &xl_remapped); ERR_FAIL_COND_V(path == "", RES()); print_verbose("Loading resource: " + path); RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error); if (res.is_null()) { return RES(); } if (!p_no_cache) res->set_path(local_path); if (xl_remapped) res->set_as_translation_remapped(true); #ifdef TOOLS_ENABLED res->set_edited(false); if (timestamp_on_load) { uint64_t mt = FileAccess::get_modified_time(path); //printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt); res->set_last_modified_time(mt); } #endif return res; }
void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); if (!obj) return; typedef Pair<PropertyInfo, Variant> PropertyDesc; List<PropertyDesc> properties; if (ScriptInstance *si = obj->get_script_instance()) { if (!si->get_script().is_null()) { Set<StringName> members; si->get_script()->get_members(&members); for (Set<StringName>::Element *E = members.front(); E; E = E->next()) { Variant m; if (si->get(E->get(), m)) { PropertyInfo pi(m.get_type(), String("Members/") + E->get()); properties.push_back(PropertyDesc(pi, m)); } } Map<StringName, Variant> constants; si->get_script()->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { PropertyInfo pi(E->value().get_type(), (String("Constants/") + E->key())); properties.push_back(PropertyDesc(pi, E->value())); } } } if (Node *node = Object::cast_to<Node>(obj)) { PropertyInfo pi(Variant::NODE_PATH, String("Node/path")); properties.push_front(PropertyDesc(pi, node->get_path())); } else if (Resource *res = Object::cast_to<Resource>(obj)) { if (Script *s = Object::cast_to<Script>(res)) { Map<StringName, Variant> constants; s->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key()); properties.push_front(PropertyDesc(pi, E->value())); } } } List<PropertyInfo> pinfo; obj->get_property_list(&pinfo, true); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name))); } } Array send_props; for (int i = 0; i < properties.size(); i++) { const PropertyInfo &pi = properties[i].first; Variant &var = properties[i].second; WeakRef *ref = Object::cast_to<WeakRef>(var); if (ref) { var = ref->get_ref(); } RES res = var; Array prop; prop.push_back(pi.name); prop.push_back(pi.type); //only send information that can be sent.. int len = 0; //test how big is this to encode encode_variant(var, NULL, len); if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG); prop.push_back(""); prop.push_back(pi.usage); prop.push_back(Variant()); } else { prop.push_back(pi.hint); if (res.is_null()) prop.push_back(pi.hint_string); else prop.push_back(String("RES:") + res->get_path()); prop.push_back(pi.usage); prop.push_back(var); } send_props.push_back(prop); } packet_peer_stream->put_var("message:inspect_object"); packet_peer_stream->put_var(3); packet_peer_stream->put_var(p_id); packet_peer_stream->put_var(obj->get_class()); packet_peer_stream->put_var(send_props); }
Error _ResourceSaver::save(const String &p_path,const RES& p_resource, uint32_t p_flags) { ERR_FAIL_COND_V(p_resource.is_null(),ERR_INVALID_PARAMETER); return ResourceSaver::save(p_path,p_resource, p_flags); }
void PhysicsShapeQueryParameters::set_shape(const RES &p_shape) { ERR_FAIL_COND(p_shape.is_null()); shape=p_shape->get_rid(); }
Error ResourceInteractiveLoaderBinary::poll(){ if (error!=OK) return error; int s = stage; if (s<external_resources.size()) { RES res = ResourceLoader::load(external_resources[s].path,external_resources[s].type); if (res.is_null()) { if (!ResourceLoader::get_abort_on_missing_resources()) { ResourceLoader::notify_load_error("Resource Not Found: "+external_resources[s].path); } else { error=ERR_FILE_CORRUPT; ERR_EXPLAIN("Can't load dependency: "+external_resources[s].path); ERR_FAIL_V(error); } } else { resource_cache.push_back(res); } stage++; return OK; } s-=external_resources.size(); if (s>=internal_resources.size()) { error=ERR_BUG; ERR_FAIL_COND_V(s>=internal_resources.size(),error); } bool main = s==(internal_resources.size()-1); //maybe it is loaded already String path; if (!main) { path=internal_resources[s].path; if (path.begins_with("local://")) path=path.replace("local://",res_path+"::"); if (ResourceCache::has(path)) { //already loaded, don't do anything stage++; error=OK; return error; } } else { path=res_path; } uint64_t offset = internal_resources[s].offset; f->seek(offset); String t = get_unicode_string(); Object *obj = ObjectTypeDB::instance(t); if (!obj) { error=ERR_FILE_CORRUPT; ERR_EXPLAIN(local_path+":Resource of unrecognized type in file: "+t); } ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT); Resource *r = obj->cast_to<Resource>(); if (!r) { error=ERR_FILE_CORRUPT; memdelete(obj); //bye ERR_EXPLAIN(local_path+":Resoucre type in resource field not a resource, type is: "+obj->get_type()); ERR_FAIL_COND_V(!r,ERR_FILE_CORRUPT); } RES res = RES( r ); r->set_path(path); int pc = f->get_32(); //set properties for(int i=0;i<pc;i++) { uint32_t name_idx = f->get_32(); if (name_idx>=(uint32_t)string_map.size()) { error=ERR_FILE_CORRUPT; ERR_FAIL_V(ERR_FILE_CORRUPT); } Variant value; error = parse_variant(value); if (error) return error; res->set(string_map[name_idx],value); } #ifdef TOOLS_ENABLED res->set_edited(false); #endif stage++; resource_cache.push_back(res); if (main) { if (importmd_ofs) { f->seek(importmd_ofs); Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata ); imd->set_editor(get_unicode_string()); int sc = f->get_32(); for(int i=0;i<sc;i++) { String src = get_unicode_string(); String md5 = get_unicode_string(); imd->add_source(src,md5); } int pc = f->get_32(); for(int i=0;i<pc;i++) { String name = get_unicode_string(); Variant val; parse_variant(val); imd->set_option(name,val); } res->set_import_metadata(imd); } f->close(); resource=res; error=ERR_FILE_EOF; } else { error=OK; } return OK; }
RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p_no_cache, Error *r_error) { if (r_error) *r_error=ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) local_path="res://"+p_path; else local_path = GlobalConfig::get_singleton()->localize_path(p_path); local_path=find_complete_path(local_path,p_type_hint); ERR_FAIL_COND_V(local_path=="",RES()); if (!p_no_cache && ResourceCache::has(local_path)) { if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: "+local_path+" (cached)"); return RES( ResourceCache::get(local_path ) ); } String remapped_path = PathRemap::get_singleton()->get_remap(local_path); if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: "+remapped_path); String extension=remapped_path.extension(); bool found=false; for (int i=0;i<loader_count;i++) { if (!loader[i]->recognize(extension)) continue; if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) continue; found=true; RES res = loader[i]->load(remapped_path,local_path,r_error); if (res.is_null()) continue; if (!p_no_cache) res->set_path(local_path); #ifdef TOOLS_ENABLED res->set_edited(false); if (timestamp_on_load) { uint64_t mt = FileAccess::get_modified_time(remapped_path); //printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt); res->set_last_modified_time(mt); } #endif return res; } if (found) { ERR_EXPLAIN("Failed loading resource: "+p_path); } else { ERR_EXPLAIN("No loader found for resource: "+p_path); } ERR_FAIL_V(RES()); return RES(); }
Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { uint32_t type = f->get_32(); print_bl("find property of type: "+itos(type)); switch(type) { case VARIANT_NIL: { r_v=Variant(); } break; case VARIANT_BOOL: { r_v=bool(f->get_32()); } break; case VARIANT_INT: { r_v=int(f->get_32()); } break; case VARIANT_REAL: { r_v=f->get_real(); } break; case VARIANT_STRING: { r_v=get_unicode_string(); } break; case VARIANT_VECTOR2: { Vector2 v; v.x=f->get_real(); v.y=f->get_real(); r_v=v; } break; case VARIANT_RECT2: { Rect2 v; v.pos.x=f->get_real(); v.pos.y=f->get_real(); v.size.x=f->get_real(); v.size.y=f->get_real(); r_v=v; } break; case VARIANT_VECTOR3: { Vector3 v; v.x=f->get_real(); v.y=f->get_real(); v.z=f->get_real(); r_v=v; } break; case VARIANT_PLANE: { Plane v; v.normal.x=f->get_real(); v.normal.y=f->get_real(); v.normal.z=f->get_real(); v.d=f->get_real(); r_v=v; } break; case VARIANT_QUAT: { Quat v; v.x=f->get_real(); v.y=f->get_real(); v.z=f->get_real(); v.w=f->get_real(); r_v=v; } break; case VARIANT_AABB: { AABB v; v.pos.x=f->get_real(); v.pos.y=f->get_real(); v.pos.z=f->get_real(); v.size.x=f->get_real(); v.size.y=f->get_real(); v.size.z=f->get_real(); r_v=v; } break; case VARIANT_MATRIX32: { Matrix32 v; v.elements[0].x=f->get_real(); v.elements[0].y=f->get_real(); v.elements[1].x=f->get_real(); v.elements[1].y=f->get_real(); v.elements[2].x=f->get_real(); v.elements[2].y=f->get_real(); r_v=v; } break; case VARIANT_MATRIX3: { Matrix3 v; v.elements[0].x=f->get_real(); v.elements[0].y=f->get_real(); v.elements[0].z=f->get_real(); v.elements[1].x=f->get_real(); v.elements[1].y=f->get_real(); v.elements[1].z=f->get_real(); v.elements[2].x=f->get_real(); v.elements[2].y=f->get_real(); v.elements[2].z=f->get_real(); r_v=v; } break; case VARIANT_TRANSFORM: { Transform v; v.basis.elements[0].x=f->get_real(); v.basis.elements[0].y=f->get_real(); v.basis.elements[0].z=f->get_real(); v.basis.elements[1].x=f->get_real(); v.basis.elements[1].y=f->get_real(); v.basis.elements[1].z=f->get_real(); v.basis.elements[2].x=f->get_real(); v.basis.elements[2].y=f->get_real(); v.basis.elements[2].z=f->get_real(); v.origin.x=f->get_real(); v.origin.y=f->get_real(); v.origin.z=f->get_real(); r_v=v; } break; case VARIANT_COLOR: { Color v; v.r=f->get_real(); v.g=f->get_real(); v.b=f->get_real(); v.a=f->get_real(); r_v=v; } break; case VARIANT_IMAGE: { uint32_t encoding = f->get_32(); if (encoding==IMAGE_ENCODING_EMPTY) { r_v=Variant(); break; } else if (encoding==IMAGE_ENCODING_RAW) { uint32_t width = f->get_32(); uint32_t height = f->get_32(); uint32_t mipmaps = f->get_32(); uint32_t format = f->get_32(); Image::Format fmt; switch(format) { case IMAGE_FORMAT_GRAYSCALE: { fmt=Image::FORMAT_GRAYSCALE; } break; case IMAGE_FORMAT_INTENSITY: { fmt=Image::FORMAT_INTENSITY; } break; case IMAGE_FORMAT_GRAYSCALE_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; } break; case IMAGE_FORMAT_RGB: { fmt=Image::FORMAT_RGB; } break; case IMAGE_FORMAT_RGBA: { fmt=Image::FORMAT_RGBA; } break; case IMAGE_FORMAT_INDEXED: { fmt=Image::FORMAT_INDEXED; } break; case IMAGE_FORMAT_INDEXED_ALPHA: { fmt=Image::FORMAT_INDEXED_ALPHA; } break; case IMAGE_FORMAT_BC1: { fmt=Image::FORMAT_BC1; } break; case IMAGE_FORMAT_BC2: { fmt=Image::FORMAT_BC2; } break; case IMAGE_FORMAT_BC3: { fmt=Image::FORMAT_BC3; } break; case IMAGE_FORMAT_BC4: { fmt=Image::FORMAT_BC4; } break; case IMAGE_FORMAT_BC5: { fmt=Image::FORMAT_BC5; } break; case IMAGE_FORMAT_PVRTC2: { fmt=Image::FORMAT_PVRTC2; } break; case IMAGE_FORMAT_PVRTC2_ALPHA: { fmt=Image::FORMAT_PVRTC2_ALPHA; } break; case IMAGE_FORMAT_PVRTC4: { fmt=Image::FORMAT_PVRTC4; } break; case IMAGE_FORMAT_PVRTC4_ALPHA: { fmt=Image::FORMAT_PVRTC4_ALPHA; } break; case IMAGE_FORMAT_ETC: { fmt=Image::FORMAT_ETC; } break; case IMAGE_FORMAT_CUSTOM: { fmt=Image::FORMAT_CUSTOM; } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } } uint32_t datalen = f->get_32(); DVector<uint8_t> imgdata; imgdata.resize(datalen); DVector<uint8_t>::Write w = imgdata.write(); f->get_buffer(w.ptr(),datalen); _advance_padding(datalen); w=DVector<uint8_t>::Write(); r_v=Image(width,height,mipmaps,fmt,imgdata); } else { //compressed DVector<uint8_t> data; data.resize(f->get_32()); DVector<uint8_t>::Write w = data.write(); f->get_buffer(w.ptr(),data.size()); w = DVector<uint8_t>::Write(); Image img; if (encoding==IMAGE_ENCODING_LOSSY && Image::lossy_unpacker) { img = Image::lossy_unpacker(data); } else if (encoding==IMAGE_ENCODING_LOSSLESS && Image::lossless_unpacker) { img = Image::lossless_unpacker(data); } _advance_padding(data.size()); r_v=img; } } break; case VARIANT_NODE_PATH: { Vector<StringName> names; Vector<StringName> subnames; StringName property; bool absolute; int name_count = f->get_16(); uint32_t subname_count = f->get_16(); absolute=subname_count&0x8000; subname_count&=0x7FFF; for(int i=0;i<name_count;i++) names.push_back(string_map[f->get_32()]); for(uint32_t i=0;i<subname_count;i++) subnames.push_back(string_map[f->get_32()]); property=string_map[f->get_32()]; NodePath np = NodePath(names,subnames,absolute,property); //print_line("got path: "+String(np)); r_v=np; } break; case VARIANT_RID: { r_v=f->get_32(); } break; case VARIANT_OBJECT: { uint32_t type=f->get_32(); switch(type) { case OBJECT_EMPTY: { //do none } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index=f->get_32(); String path = res_path+"::"+itos(index); RES res = ResourceLoader::load(path); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); } r_v=res; } break; case OBJECT_EXTERNAL_RESOURCE: { String type = get_unicode_string(); String path = get_unicode_string(); if (path.find("://")==-1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path path=Globals::get_singleton()->localize_path(res_path.get_base_dir()+"/"+path); } RES res=ResourceLoader::load(path,type); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); } r_v=res; } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } } break; case VARIANT_INPUT_EVENT: { } break; case VARIANT_DICTIONARY: { uint32_t len=f->get_32(); Dictionary d(len&0x80000000); //last bit means shared len&=0x7FFFFFFF; for(uint32_t i=0;i<len;i++) { Variant key; Error err = parse_variant(key); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); Variant value; err = parse_variant(value); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); d[key]=value; } r_v=d; } break; case VARIANT_ARRAY: { uint32_t len=f->get_32(); Array a(len&0x80000000); //last bit means shared len&=0x7FFFFFFF; a.resize(len); for(uint32_t i=0;i<len;i++) { Variant val; Error err = parse_variant(val); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); a[i]=val; } r_v=a; } break; case VARIANT_RAW_ARRAY: { uint32_t len = f->get_32(); DVector<uint8_t> array; array.resize(len); DVector<uint8_t>::Write w = array.write(); f->get_buffer(w.ptr(),len); _advance_padding(len); w=DVector<uint8_t>::Write(); r_v=array; } break; case VARIANT_INT_ARRAY: { uint32_t len = f->get_32(); DVector<int> array; array.resize(len); DVector<int>::Write w = array.write(); f->get_buffer((uint8_t*)w.ptr(),len*4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif w=DVector<int>::Write(); r_v=array; } break; case VARIANT_REAL_ARRAY: { uint32_t len = f->get_32(); DVector<real_t> array; array.resize(len); DVector<real_t>::Write w = array.write(); f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif w=DVector<real_t>::Write(); r_v=array; } break; case VARIANT_STRING_ARRAY: { uint32_t len = f->get_32(); DVector<String> array; array.resize(len); DVector<String>::Write w = array.write(); for(uint32_t i=0;i<len;i++) w[i]=get_unicode_string(); w=DVector<String>::Write(); r_v=array; } break; case VARIANT_VECTOR2_ARRAY: { uint32_t len = f->get_32(); DVector<Vector2> array; array.resize(len); DVector<Vector2>::Write w = array.write(); if (sizeof(Vector2)==8) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*2); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len*2;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector2 size is NOT 8!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector<Vector2>::Write(); r_v=array; } break; case VARIANT_VECTOR3_ARRAY: { uint32_t len = f->get_32(); DVector<Vector3> array; array.resize(len); DVector<Vector3>::Write w = array.write(); if (sizeof(Vector3)==12) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*3); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len*3;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector3 size is NOT 12!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector<Vector3>::Write(); r_v=array; } break; case VARIANT_COLOR_ARRAY: { uint32_t len = f->get_32(); DVector<Color> array; array.resize(len); DVector<Color>::Write w = array.write(); if (sizeof(Color)==16) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr=(uint32_t*)w.ptr(); for(int i=0;i<len*4;i++) { ptr[i]=BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Color size is NOT 16!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector<Color>::Write(); r_v=array; } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } return OK; //never reach anyway }
void ResourceFormatSaverBinaryInstance::_find_resources(const Variant& p_variant,bool p_main) { switch(p_variant.get_type()) { case Variant::OBJECT: { RES res = p_variant.operator RefPtr(); if (res.is_null()) return; if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) { external_resources.insert(res); return; } if (resource_map.has(res)) return; List<PropertyInfo> property_list; res->get_property_list(&property_list); for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) { if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) { _find_resources(res->get(E->get().name)); } } resource_map[ res ] = saved_resources.size(); saved_resources.push_back(res); } break; case Variant::ARRAY: { Array varray=p_variant; int len=varray.size(); for(int i=0;i<len;i++) { Variant v=varray.get(i); _find_resources(v); } } break; case Variant::DICTIONARY: { Dictionary d=p_variant; List<Variant> keys; d.get_key_list(&keys); for(List<Variant>::Element *E=keys.front();E;E=E->next()) { _find_resources(E->get()); Variant v = d[E->get()]; _find_resources(v); } } break; case Variant::NODE_PATH: { //take the chance and save node path strings NodePath np = p_variant; for(int i=0;i<np.get_name_count();i++) get_string_index(np.get_name(i)); for(int i=0;i<np.get_subname_count();i++) get_string_index(np.get_subname(i)); get_string_index(np.get_property()); } break; default: {} } }
void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property,const PropertyInfo& p_hint) { switch(p_property.get_type()) { case Variant::NIL: { f->store_32(VARIANT_NIL); // don't store anything } break; case Variant::BOOL: { f->store_32(VARIANT_BOOL); bool val=p_property; f->store_32(val); } break; case Variant::INT: { f->store_32(VARIANT_INT); int val=p_property; f->store_32(val); } break; case Variant::REAL: { f->store_32(VARIANT_REAL); real_t val=p_property; f->store_real(val); } break; case Variant::STRING: { f->store_32(VARIANT_STRING); String val=p_property; save_unicode_string(val); } break; case Variant::VECTOR2: { f->store_32(VARIANT_VECTOR2); Vector2 val=p_property; f->store_real(val.x); f->store_real(val.y); } break; case Variant::RECT2: { f->store_32(VARIANT_RECT2); Rect2 val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.size.x); f->store_real(val.size.y); } break; case Variant::VECTOR3: { f->store_32(VARIANT_VECTOR3); Vector3 val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); } break; case Variant::PLANE: { f->store_32(VARIANT_PLANE); Plane val=p_property; f->store_real(val.normal.x); f->store_real(val.normal.y); f->store_real(val.normal.z); f->store_real(val.d); } break; case Variant::QUAT: { f->store_32(VARIANT_QUAT); Quat val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); f->store_real(val.w); } break; case Variant::_AABB: { f->store_32(VARIANT_AABB); AABB val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.pos.z); f->store_real(val.size.x); f->store_real(val.size.y); f->store_real(val.size.z); } break; case Variant::MATRIX32: { f->store_32(VARIANT_MATRIX32); Matrix32 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); } break; case Variant::MATRIX3: { f->store_32(VARIANT_MATRIX3); Matrix3 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[0].z); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[1].z); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); f->store_real(val.elements[2].z); } break; case Variant::TRANSFORM: { f->store_32(VARIANT_TRANSFORM); Transform val=p_property; f->store_real(val.basis.elements[0].x); f->store_real(val.basis.elements[0].y); f->store_real(val.basis.elements[0].z); f->store_real(val.basis.elements[1].x); f->store_real(val.basis.elements[1].y); f->store_real(val.basis.elements[1].z); f->store_real(val.basis.elements[2].x); f->store_real(val.basis.elements[2].y); f->store_real(val.basis.elements[2].z); f->store_real(val.origin.x); f->store_real(val.origin.y); f->store_real(val.origin.z); } break; case Variant::COLOR: { f->store_32(VARIANT_COLOR); Color val=p_property; f->store_real(val.r); f->store_real(val.g); f->store_real(val.b); f->store_real(val.a); } break; case Variant::IMAGE: { f->store_32(VARIANT_IMAGE); Image val =p_property; if (val.empty()) { f->store_32(IMAGE_ENCODING_EMPTY); break; } int encoding=IMAGE_ENCODING_RAW; float quality=0.7; if (val.get_format() <= Image::FORMAT_INDEXED_ALPHA) { //can only compress uncompressed stuff if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSY && Image::lossy_packer) { encoding=IMAGE_ENCODING_LOSSY; float qs=p_hint.hint_string.to_double(); if (qs!=0.0) quality=qs; } else if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS && Image::lossless_packer) { encoding=IMAGE_ENCODING_LOSSLESS; } } f->store_32(encoding); //raw encoding if (encoding==IMAGE_ENCODING_RAW) { f->store_32(val.get_width()); f->store_32(val.get_height()); f->store_32(val.get_mipmaps()); switch(val.get_format()) { case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255 case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha) case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1 case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3 case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5 case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1 case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2 case Image::FORMAT_PVRTC2: f->store_32(IMAGE_FORMAT_PVRTC2 ); break; case Image::FORMAT_PVRTC2_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC2_ALPHA ); break; case Image::FORMAT_PVRTC4: f->store_32(IMAGE_FORMAT_PVRTC4 ); break; case Image::FORMAT_PVRTC4_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC4_ALPHA ); break; case Image::FORMAT_ETC: f->store_32(IMAGE_FORMAT_ETC); break; case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break; default: {} } int dlen = val.get_data().size(); f->store_32(dlen); DVector<uint8_t>::Read r = val.get_data().read(); f->store_buffer(r.ptr(),dlen); _pad_buffer(dlen); } else { DVector<uint8_t> data; if (encoding==IMAGE_ENCODING_LOSSY) { data=Image::lossy_packer(val,quality); } else if (encoding==IMAGE_ENCODING_LOSSLESS) { data=Image::lossless_packer(val); } int ds=data.size(); f->store_32(ds); if (ds>0) { DVector<uint8_t>::Read r = data.read(); f->store_buffer(r.ptr(),ds); _pad_buffer(ds); } } } break; case Variant::NODE_PATH: { f->store_32(VARIANT_NODE_PATH); NodePath np=p_property; f->store_16(np.get_name_count()); uint16_t snc = np.get_subname_count(); if (np.is_absolute()) snc|=0x8000; f->store_16(snc); for(int i=0;i<np.get_name_count();i++) f->store_32(get_string_index(np.get_name(i))); for(int i=0;i<np.get_subname_count();i++) f->store_32(get_string_index(np.get_subname(i))); f->store_32(get_string_index(np.get_property())); } break; case Variant::_RID: { f->store_32(VARIANT_RID); WARN_PRINT("Can't save RIDs"); RID val = p_property; f->store_32(val.get_id()); } break; case Variant::OBJECT: { f->store_32(VARIANT_OBJECT); RES res = p_property; if (res.is_null()) { f->store_32(OBJECT_EMPTY); return; // don't save it } if (res->get_path().length() && res->get_path().find("::")==-1) { f->store_32(OBJECT_EXTERNAL_RESOURCE); save_unicode_string(res->get_save_type()); String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); if (no_extensions) path=path.basename()+".*"; save_unicode_string(path); } else { if (!resource_map.has(res)) { f->store_32(OBJECT_EMPTY); ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); ERR_FAIL(); } f->store_32(OBJECT_INTERNAL_RESOURCE); f->store_32(resource_map[res]); //internal resource } } break; case Variant::INPUT_EVENT: { f->store_32(VARIANT_INPUT_EVENT); WARN_PRINT("Can't save InputEvent (maybe it could..)"); } break; case Variant::DICTIONARY: { f->store_32(VARIANT_DICTIONARY); Dictionary d = p_property; f->store_32(uint32_t(d.size())|(d.is_shared()?0x80000000:0)); List<Variant> keys; d.get_key_list(&keys); for(List<Variant>::Element *E=keys.front();E;E=E->next()) { //if (!_check_type(dict[E->get()])) // continue; write_variant(E->get()); write_variant(d[E->get()]); } } break; case Variant::ARRAY: { f->store_32(VARIANT_ARRAY); Array a=p_property; f->store_32(uint32_t(a.size())|(a.is_shared()?0x80000000:0)); for(int i=0;i<a.size();i++) { write_variant(a[i]); } } break; case Variant::RAW_ARRAY: { f->store_32(VARIANT_RAW_ARRAY); DVector<uint8_t> arr = p_property; int len=arr.size(); f->store_32(len); DVector<uint8_t>::Read r = arr.read(); f->store_buffer(r.ptr(),len); _pad_buffer(len); } break; case Variant::INT_ARRAY: { f->store_32(VARIANT_INT_ARRAY); DVector<int> arr = p_property; int len=arr.size(); f->store_32(len); DVector<int>::Read r = arr.read(); for(int i=0;i<len;i++) f->store_32(r[i]); } break; case Variant::REAL_ARRAY: { f->store_32(VARIANT_REAL_ARRAY); DVector<real_t> arr = p_property; int len=arr.size(); f->store_32(len); DVector<real_t>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i]); } } break; case Variant::STRING_ARRAY: { f->store_32(VARIANT_STRING_ARRAY); DVector<String> arr = p_property; int len=arr.size(); f->store_32(len); DVector<String>::Read r = arr.read(); for(int i=0;i<len;i++) { save_unicode_string(r[i]); } } break; case Variant::VECTOR3_ARRAY: { f->store_32(VARIANT_VECTOR3_ARRAY); DVector<Vector3> arr = p_property; int len=arr.size(); f->store_32(len); DVector<Vector3>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i].x); f->store_real(r[i].y); f->store_real(r[i].z); } } break; case Variant::VECTOR2_ARRAY: { f->store_32(VARIANT_VECTOR2_ARRAY); DVector<Vector2> arr = p_property; int len=arr.size(); f->store_32(len); DVector<Vector2>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i].x); f->store_real(r[i].y); } } break; case Variant::COLOR_ARRAY: { f->store_32(VARIANT_COLOR_ARRAY); DVector<Color> arr = p_property; int len=arr.size(); f->store_32(len); DVector<Color>::Read r = arr.read(); for(int i=0;i<len;i++) { f->store_real(r[i].r); f->store_real(r[i].g); f->store_real(r[i].b); f->store_real(r[i].a); } } break; default: { ERR_EXPLAIN("Invalid variant"); ERR_FAIL(); } } }
RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) { if (r_error) *r_error = ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) local_path = "res://" + p_path; else local_path = ProjectSettings::get_singleton()->localize_path(p_path); bool xl_remapped = false; String path = _path_remap(local_path, &xl_remapped); ERR_FAIL_COND_V(path == "", RES()); if (!p_no_cache && ResourceCache::has(path)) { if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: " + path + " (cached)"); return RES(ResourceCache::get(path)); } if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: " + path); bool found = false; // Try all loaders and pick the first match for the type hint for (int i = 0; i < loader_count; i++) { if (!loader[i]->recognize_path(path, p_type_hint)) { continue; } found = true; RES res = loader[i]->load(path, path, r_error); if (res.is_null()) { continue; } if (!p_no_cache) res->set_path(local_path); if (xl_remapped) res->set_as_translation_remapped(true); #ifdef TOOLS_ENABLED res->set_edited(false); if (timestamp_on_load) { uint64_t mt = FileAccess::get_modified_time(path); //printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt); res->set_last_modified_time(mt); } #endif return res; } if (found) { ERR_EXPLAIN("Failed loading resource: " + path); } else { ERR_EXPLAIN("No loader found for resource: " + path); } ERR_FAIL_V(RES()); return RES(); }
Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { uint32_t type = f->get_32(); print_bl("find property of type: " + itos(type)); switch (type) { case VARIANT_NIL: { r_v = Variant(); } break; case VARIANT_BOOL: { r_v = bool(f->get_32()); } break; case VARIANT_INT: { r_v = int(f->get_32()); } break; case VARIANT_INT64: { r_v = int64_t(f->get_64()); } break; case VARIANT_REAL: { r_v = f->get_real(); } break; case VARIANT_DOUBLE: { r_v = f->get_double(); } break; case VARIANT_STRING: { r_v = get_unicode_string(); } break; case VARIANT_VECTOR2: { Vector2 v; v.x = f->get_real(); v.y = f->get_real(); r_v = v; } break; case VARIANT_RECT2: { Rect2 v; v.position.x = f->get_real(); v.position.y = f->get_real(); v.size.x = f->get_real(); v.size.y = f->get_real(); r_v = v; } break; case VARIANT_VECTOR3: { Vector3 v; v.x = f->get_real(); v.y = f->get_real(); v.z = f->get_real(); r_v = v; } break; case VARIANT_PLANE: { Plane v; v.normal.x = f->get_real(); v.normal.y = f->get_real(); v.normal.z = f->get_real(); v.d = f->get_real(); r_v = v; } break; case VARIANT_QUAT: { Quat v; v.x = f->get_real(); v.y = f->get_real(); v.z = f->get_real(); v.w = f->get_real(); r_v = v; } break; case VARIANT_AABB: { AABB v; v.position.x = f->get_real(); v.position.y = f->get_real(); v.position.z = f->get_real(); v.size.x = f->get_real(); v.size.y = f->get_real(); v.size.z = f->get_real(); r_v = v; } break; case VARIANT_MATRIX32: { Transform2D v; v.elements[0].x = f->get_real(); v.elements[0].y = f->get_real(); v.elements[1].x = f->get_real(); v.elements[1].y = f->get_real(); v.elements[2].x = f->get_real(); v.elements[2].y = f->get_real(); r_v = v; } break; case VARIANT_MATRIX3: { Basis v; v.elements[0].x = f->get_real(); v.elements[0].y = f->get_real(); v.elements[0].z = f->get_real(); v.elements[1].x = f->get_real(); v.elements[1].y = f->get_real(); v.elements[1].z = f->get_real(); v.elements[2].x = f->get_real(); v.elements[2].y = f->get_real(); v.elements[2].z = f->get_real(); r_v = v; } break; case VARIANT_TRANSFORM: { Transform v; v.basis.elements[0].x = f->get_real(); v.basis.elements[0].y = f->get_real(); v.basis.elements[0].z = f->get_real(); v.basis.elements[1].x = f->get_real(); v.basis.elements[1].y = f->get_real(); v.basis.elements[1].z = f->get_real(); v.basis.elements[2].x = f->get_real(); v.basis.elements[2].y = f->get_real(); v.basis.elements[2].z = f->get_real(); v.origin.x = f->get_real(); v.origin.y = f->get_real(); v.origin.z = f->get_real(); r_v = v; } break; case VARIANT_COLOR: { Color v; v.r = f->get_real(); v.g = f->get_real(); v.b = f->get_real(); v.a = f->get_real(); r_v = v; } break; case VARIANT_NODE_PATH: { Vector<StringName> names; Vector<StringName> subnames; bool absolute; int name_count = f->get_16(); uint32_t subname_count = f->get_16(); absolute = subname_count & 0x8000; subname_count &= 0x7FFF; if (ver_format < FORMAT_VERSION_NO_NODEPATH_PROPERTY) { subname_count += 1; // has a property field, so we should count it as well } for (int i = 0; i < name_count; i++) names.push_back(_get_string()); for (uint32_t i = 0; i < subname_count; i++) subnames.push_back(_get_string()); NodePath np = NodePath(names, subnames, absolute); r_v = np; } break; case VARIANT_RID: { r_v = f->get_32(); } break; case VARIANT_OBJECT: { uint32_t type = f->get_32(); switch (type) { case OBJECT_EMPTY: { //do none } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index = f->get_32(); String path = res_path + "::" + itos(index); RES res = ResourceLoader::load(path); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); } r_v = res; } break; case OBJECT_EXTERNAL_RESOURCE: { //old file format, still around for compatibility String type = get_unicode_string(); String path = get_unicode_string(); if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } if (remaps.find(path)) { path = remaps[path]; } RES res = ResourceLoader::load(path, type); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); } r_v = res; } break; case OBJECT_EXTERNAL_RESOURCE_INDEX: { //new file format, just refers to an index in the external list int erindex = f->get_32(); if (erindex < 0 || erindex >= external_resources.size()) { WARN_PRINT("Broken external resource! (index out of size"); r_v = Variant(); } else { String type = external_resources[erindex].type; String path = external_resources[erindex].path; if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } RES res = ResourceLoader::load(path, type); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); } r_v = res; } } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } } break; case VARIANT_DICTIONARY: { uint32_t len = f->get_32(); Dictionary d; //last bit means shared len &= 0x7FFFFFFF; for (uint32_t i = 0; i < len; i++) { Variant key; Error err = parse_variant(key); ERR_FAIL_COND_V(err, ERR_FILE_CORRUPT); Variant value; err = parse_variant(value); ERR_FAIL_COND_V(err, ERR_FILE_CORRUPT); d[key] = value; } r_v = d; } break; case VARIANT_ARRAY: { uint32_t len = f->get_32(); Array a; //last bit means shared len &= 0x7FFFFFFF; a.resize(len); for (uint32_t i = 0; i < len; i++) { Variant val; Error err = parse_variant(val); ERR_FAIL_COND_V(err, ERR_FILE_CORRUPT); a[i] = val; } r_v = a; } break; case VARIANT_RAW_ARRAY: { uint32_t len = f->get_32(); PoolVector<uint8_t> array; array.resize(len); PoolVector<uint8_t>::Write w = array.write(); f->get_buffer(w.ptr(), len); _advance_padding(len); w = PoolVector<uint8_t>::Write(); r_v = array; } break; case VARIANT_INT_ARRAY: { uint32_t len = f->get_32(); PoolVector<int> array; array.resize(len); PoolVector<int>::Write w = array.write(); f->get_buffer((uint8_t *)w.ptr(), len * 4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif w = PoolVector<int>::Write(); r_v = array; } break; case VARIANT_REAL_ARRAY: { uint32_t len = f->get_32(); PoolVector<real_t> array; array.resize(len); PoolVector<real_t>::Write w = array.write(); f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t)); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif w = PoolVector<real_t>::Write(); r_v = array; } break; case VARIANT_STRING_ARRAY: { uint32_t len = f->get_32(); PoolVector<String> array; array.resize(len); PoolVector<String>::Write w = array.write(); for (uint32_t i = 0; i < len; i++) w[i] = get_unicode_string(); w = PoolVector<String>::Write(); r_v = array; } break; case VARIANT_VECTOR2_ARRAY: { uint32_t len = f->get_32(); PoolVector<Vector2> array; array.resize(len); PoolVector<Vector2>::Write w = array.write(); if (sizeof(Vector2) == 8) { f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t) * 2); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len * 2; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector2 size is NOT 8!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w = PoolVector<Vector2>::Write(); r_v = array; } break; case VARIANT_VECTOR3_ARRAY: { uint32_t len = f->get_32(); PoolVector<Vector3> array; array.resize(len); PoolVector<Vector3>::Write w = array.write(); if (sizeof(Vector3) == 12) { f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t) * 3); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len * 3; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Vector3 size is NOT 12!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w = PoolVector<Vector3>::Write(); r_v = array; } break; case VARIANT_COLOR_ARRAY: { uint32_t len = f->get_32(); PoolVector<Color> array; array.resize(len); PoolVector<Color>::Write w = array.write(); if (sizeof(Color) == 16) { f->get_buffer((uint8_t *)w.ptr(), len * sizeof(real_t) * 4); #ifdef BIG_ENDIAN_ENABLED { uint32_t *ptr = (uint32_t *)w.ptr(); for (int i = 0; i < len * 4; i++) { ptr[i] = BSWAP32(ptr[i]); } } #endif } else { ERR_EXPLAIN("Color size is NOT 16!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w = PoolVector<Color>::Write(); r_v = array; } break; #ifndef DISABLE_DEPRECATED case VARIANT_IMAGE: { uint32_t encoding = f->get_32(); if (encoding == IMAGE_ENCODING_EMPTY) { r_v = Ref<Image>(); break; } else if (encoding == IMAGE_ENCODING_RAW) { uint32_t width = f->get_32(); uint32_t height = f->get_32(); uint32_t mipmaps = f->get_32(); uint32_t format = f->get_32(); const uint32_t format_version_shift = 24; const uint32_t format_version_mask = format_version_shift - 1; uint32_t format_version = format >> format_version_shift; const uint32_t current_version = 0; if (format_version > current_version) { ERR_PRINT("Format version for encoded binary image is too new"); return ERR_PARSE_ERROR; } Image::Format fmt = Image::Format(format & format_version_mask); //if format changes, we can add a compatibility bit on top uint32_t datalen = f->get_32(); PoolVector<uint8_t> imgdata; imgdata.resize(datalen); PoolVector<uint8_t>::Write w = imgdata.write(); f->get_buffer(w.ptr(), datalen); _advance_padding(datalen); w = PoolVector<uint8_t>::Write(); Ref<Image> image; image.instance(); image->create(width, height, mipmaps, fmt, imgdata); r_v = image; } else { //compressed PoolVector<uint8_t> data; data.resize(f->get_32()); PoolVector<uint8_t>::Write w = data.write(); f->get_buffer(w.ptr(), data.size()); w = PoolVector<uint8_t>::Write(); Ref<Image> image; if (encoding == IMAGE_ENCODING_LOSSY && Image::lossy_unpacker) { image = Image::lossy_unpacker(data); } else if (encoding == IMAGE_ENCODING_LOSSLESS && Image::lossless_unpacker) { image = Image::lossless_unpacker(data); } _advance_padding(data.size()); r_v = image; } } break;
Error ResourceInteractiveLoaderText::poll() { if (error!=OK) return error; if (next_tag.name=="ext_resource") { if (!next_tag.fields.has("path")) { error=ERR_FILE_CORRUPT; error_text="Missing 'path' in external resource tag"; _printerr(); return error; } if (!next_tag.fields.has("type")) { error=ERR_FILE_CORRUPT; error_text="Missing 'type' in external resource tag"; _printerr(); return error; } if (!next_tag.fields.has("id")) { error=ERR_FILE_CORRUPT; error_text="Missing 'id' in external resource tag"; _printerr(); return error; } String path=next_tag.fields["path"]; String type=next_tag.fields["type"]; int index=next_tag.fields["id"]; if (path.find("://")==-1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); } if (remaps.has(path)) { path=remaps[path]; } RES res = ResourceLoader::load(path,type); if (res.is_null()) { if (ResourceLoader::get_abort_on_missing_resources()) { error=ERR_FILE_CORRUPT; error_text="[ext_resource] referenced nonexistent resource at: "+path; _printerr(); return error; } else { ResourceLoader::notify_dependency_error(local_path,path,type); } } else { resource_cache.push_back(res); } ExtResource er; er.path=path; er.type=type; ext_resources[index]=er; error = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp); if (error) { _printerr(); } resource_current++; return error; } else if (next_tag.name=="sub_resource") { if (!next_tag.fields.has("type")) { error=ERR_FILE_CORRUPT; error_text="Missing 'type' in external resource tag"; _printerr(); return error; } if (!next_tag.fields.has("id")) { error=ERR_FILE_CORRUPT; error_text="Missing 'index' in external resource tag"; _printerr(); return error; } String type=next_tag.fields["type"]; int id=next_tag.fields["id"]; String path = local_path+"::"+itos(id); //bool exists=ResourceCache::has(path); Ref<Resource> res; if ( !ResourceCache::has(path)) { //only if it doesn't exist Object *obj = ObjectTypeDB::instance(type); if (!obj) { error_text+="Can't create sub resource of type: "+type; _printerr(); error=ERR_FILE_CORRUPT; return error; } Resource *r = obj->cast_to<Resource>(); if (!r) { error_text+="Can't create sub resource of type, because not a resource: "+type; _printerr(); error=ERR_FILE_CORRUPT; return error; } res=Ref<Resource>(r); resource_cache.push_back(res); res->set_path(path); } resource_current++; while(true) { String assign; Variant value; error = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,&rp); if (error) { _printerr(); return error; } if (assign!=String()) { if (res.is_valid()) { res->set(assign,value); } //it's assignment } else if (next_tag.name!=String()) { error=OK; break; } else { error=ERR_FILE_CORRUPT; error_text="Premature end of file while parsing [sub_resource]"; _printerr(); return error; } } return OK; } else if (next_tag.name=="resource") { if (is_scene) { error_text+="found the 'resource' tag on a scene file!"; _printerr(); error=ERR_FILE_CORRUPT; return error; } Object *obj = ObjectTypeDB::instance(res_type); if (!obj) { error_text+="Can't create sub resource of type: "+res_type; _printerr(); error=ERR_FILE_CORRUPT; return error; } Resource *r = obj->cast_to<Resource>(); if (!r) { error_text+="Can't create sub resource of type, because not a resource: "+res_type; _printerr(); error=ERR_FILE_CORRUPT; return error; } resource=Ref<Resource>(r); resource_current++; while(true) { String assign; Variant value; error = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,&rp); if (error) { if (error!=ERR_FILE_EOF) { _printerr(); } else { if (!ResourceCache::has(res_path)) { resource->set_path(res_path); } } return error; } if (assign!=String()) { resource->set(assign,value); //it's assignment } else if (next_tag.name!=String()) { error=ERR_FILE_CORRUPT; error_text="Extra tag found when parsing main resource file"; _printerr(); return error; } else { error=ERR_FILE_EOF; return error; } } return OK; } else if (next_tag.name=="node") { if (!is_scene) { error_text+="found the 'node' tag on a resource file!"; _printerr(); error=ERR_FILE_CORRUPT; return error; } /* int add_name(const StringName& p_name); int add_value(const Variant& p_value); int add_node_path(const NodePath& p_path); int add_node(int p_parent,int p_owner,int p_type,int p_name, int p_instance); void add_node_property(int p_node,int p_name,int p_value); void add_node_group(int p_node,int p_group); void set_base_scene(int p_idx); void add_connection(int p_from,int p_to, int p_signal, int p_method, int p_flags,const Vector<int>& p_binds); void add_editable_instance(const NodePath& p_path); */ int parent=-1; int owner=-1; int type=-1; int name=-1; int instance=-1; // int base_scene=-1; if (next_tag.fields.has("name")) { name=packed_scene->get_state()->add_name(next_tag.fields["name"]); } if (next_tag.fields.has("parent")) { NodePath np = next_tag.fields["parent"]; np.prepend_period(); //compatible to how it manages paths internally parent=packed_scene->get_state()->add_node_path(np); } if (next_tag.fields.has("type")) { type=packed_scene->get_state()->add_name(next_tag.fields["type"]); } else { type=SceneState::TYPE_INSTANCED; //no type? assume this was instanced } if (next_tag.fields.has("instance")) { instance=packed_scene->get_state()->add_value(next_tag.fields["instance"]); if (packed_scene->get_state()->get_node_count()==0 && parent==-1) { packed_scene->get_state()->set_base_scene(instance); instance=-1; } } if (next_tag.fields.has("instance_placeholder")) { String path=next_tag.fields["instance_placeholder"]; int path_v = packed_scene->get_state()->add_value(path); if (packed_scene->get_state()->get_node_count()==0) { error=ERR_FILE_CORRUPT; error_text="Instance Placeholder can't be used for inheritance."; _printerr(); return error; } instance=path_v|SceneState::FLAG_INSTANCE_IS_PLACEHOLDER; } if (next_tag.fields.has("owner")) { owner=packed_scene->get_state()->add_node_path(next_tag.fields["owner"]); } else { if (parent!=-1 && !(type==SceneState::TYPE_INSTANCED && instance==-1)) owner=0; //if no owner, owner is root } int node_id = packed_scene->get_state()->add_node(parent,owner,type,name,instance); if (next_tag.fields.has("groups")) { Array groups = next_tag.fields["groups"]; for (int i=0;i<groups.size();i++) { packed_scene->get_state()->add_node_group(node_id,packed_scene->get_state()->add_name(groups[i])); } } while(true) { String assign; Variant value; error = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,&rp); if (error) { if (error!=ERR_FILE_EOF) { _printerr(); } else { resource=packed_scene; if (!ResourceCache::has(res_path)) { packed_scene->set_path(res_path); } } return error; } if (assign!=String()) { int nameidx = packed_scene->get_state()->add_name(assign); int valueidx = packed_scene->get_state()->add_value(value); packed_scene->get_state()->add_node_property(node_id,nameidx,valueidx); //it's assignment } else if (next_tag.name!=String()) { error=OK; return error; } else { resource=packed_scene; error=ERR_FILE_EOF; return error; } } return OK; } else if (next_tag.name=="connection") { if (!is_scene) { error_text+="found the 'connection' tag on a resource file!"; _printerr(); error=ERR_FILE_CORRUPT; return error; } if (!next_tag.fields.has("from")) { error=ERR_FILE_CORRUPT; error_text="missing 'from' field fron connection tag"; return error; } if (!next_tag.fields.has("to")) { error=ERR_FILE_CORRUPT; error_text="missing 'to' field fron connection tag"; return error; } if (!next_tag.fields.has("signal")) { error=ERR_FILE_CORRUPT; error_text="missing 'signal' field fron connection tag"; return error; } if (!next_tag.fields.has("method")) { error=ERR_FILE_CORRUPT; error_text="missing 'method' field fron connection tag"; return error; } NodePath from = next_tag.fields["from"]; NodePath to = next_tag.fields["to"]; StringName method = next_tag.fields["method"]; StringName signal = next_tag.fields["signal"]; int flags=CONNECT_PERSIST; Array binds; if (next_tag.fields.has("flags")) { flags=next_tag.fields["flags"]; } if (next_tag.fields.has("binds")) { binds=next_tag.fields["binds"]; } Vector<int> bind_ints; for(int i=0;i<binds.size();i++) { bind_ints.push_back( packed_scene->get_state()->add_value( binds[i] ) ); } packed_scene->get_state()->add_connection( packed_scene->get_state()->add_node_path(from.simplified()), packed_scene->get_state()->add_node_path(to.simplified()), packed_scene->get_state()->add_name(signal), packed_scene->get_state()->add_name(method), flags, bind_ints ); error = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp); if (error) { if (error!=ERR_FILE_EOF) { _printerr(); } else { resource=packed_scene; } } return error; } else if (next_tag.name=="editable") { if (!is_scene) { error_text+="found the 'editable' tag on a resource file!"; _printerr(); error=ERR_FILE_CORRUPT; return error; } if (!next_tag.fields.has("path")) { error=ERR_FILE_CORRUPT; error_text="missing 'path' field fron connection tag"; _printerr(); return error; } NodePath path = next_tag.fields["path"]; packed_scene->get_state()->add_editable_instance(path.simplified()); error = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp); if (error) { if (error!=ERR_FILE_EOF) { _printerr(); } else { resource=packed_scene; } } return error; } else { error_text+="Unknown tag in file: "+next_tag.name; _printerr(); error=ERR_FILE_CORRUPT; return error; } return OK; }
MainLoop* test() { print_line("this is test io"); DirAccess* da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); da->change_dir("."); print_line("Opening current dir "+ da->get_current_dir()); String entry; da->list_dir_begin(); while ( (entry = da->get_next()) != "") { print_line("entry "+entry+" is dir: " + Variant(da->current_is_dir())); }; da->list_dir_end(); RES texture = ResourceLoader::load("test_data/rock.png"); ERR_FAIL_COND_V(texture.is_null(), NULL); ResourceSaver::save("test_data/rock.xml",texture); print_line("localize paths"); print_line(Globals::get_singleton()->localize_path("algo.xml")); print_line(Globals::get_singleton()->localize_path("c:\\windows\\algo.xml")); print_line(Globals::get_singleton()->localize_path(Globals::get_singleton()->get_resource_path()+"/something/something.xml")); print_line(Globals::get_singleton()->localize_path("somedir/algo.xml")); { FileAccess* z = FileAccess::open("test_data/archive.zip", FileAccess::READ); int len = z->get_len(); Vector<uint8_t> zip; zip.resize(len); z->get_buffer(&zip[0], len); z->close(); memdelete(z); FileAccessMemory::register_file("a_package", zip); FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_FILESYSTEM); FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_USERDATA); print_line("archive test"); #if 0 Archive arch; Archive::get_singleton()->add_package("a_package"); FileAccessArchive f; print_line("opening for read"); f._open("file.txt", FileAccess::READ); int pos = f.get_pos(); printf("file has %i bytes, initial pos %i\n", (int)f.get_len(), pos); do { printf("%c", f.get_8()); } while (!f.eof_reached()); print_line("opening for stored seek"); f.open("seek.bin", FileAccess::READ); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); f.seek(128); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); print_line("opening for deflated seek"); f.open("seek_deflated.bin", FileAccess::READ); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); f.seek(128); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); f.seek(256); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); f.seek(4); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); pos = f.get_pos(); printf("byte at pos %i is %i\n", pos, (int)f.get_8()); f.close(); DirAccessArchive d; String dir = "../blah1/blah2/blahask/../blah3/.//blah4/"; printf("changing dir to %s\n", dir.utf8().get_data()); d.change_dir(dir); printf("current dir is %s\n", d.get_current_dir().utf8().get_data()); FileAccessMemory::cleanup(); #endif }; print_line("test done"); return memnew( TestMainLoop ); }
void AnimationCache::_update_cache() { cache_valid=false; ERR_FAIL_COND(!root); ERR_FAIL_COND(!root->is_inside_tree()); ERR_FAIL_COND(animation.is_null()); for(int i=0;i<animation->get_track_count();i++) { NodePath np = animation->track_get_path(i); Node *node = root->get_node(np); if (!node) { path_cache.push_back(Path()); ERR_EXPLAIN("Invalid Track Path in Animation: "+np); ERR_CONTINUE(!node); } Path path; Ref<Resource> res; if (np.get_subname_count()) { if (animation->track_get_type(i)==Animation::TYPE_TRANSFORM) { path_cache.push_back(Path()); ERR_EXPLAIN("Transform tracks can't have a subpath: "+np); ERR_CONTINUE(animation->track_get_type(i)==Animation::TYPE_TRANSFORM); } RES res; for(int j=0;j<np.get_subname_count();j++) { res = j==0 ? node->get(np.get_subname(j)) : res->get(np.get_subname(j)); if (res.is_null()) break; } if (res.is_null()) { path_cache.push_back(Path()); ERR_EXPLAIN("Invalid Track SubPath in Animation: "+np); ERR_CONTINUE(res.is_null()); } path.resource=res; path.object=res.ptr(); } else { if (animation->track_get_type(i)==Animation::TYPE_TRANSFORM) { StringName property = np.get_property(); String ps = property; Spatial *sp = node->cast_to<Spatial>(); if (!sp) { path_cache.push_back(Path()); ERR_EXPLAIN("Transform track not of type Spatial: "+np); ERR_CONTINUE(!sp); } if (ps!="") { Skeleton *sk = node->cast_to<Skeleton>(); if (!sk) { path_cache.push_back(Path()); ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton!: "+np); ERR_CONTINUE(!sk); } int idx = sk->find_bone(ps); if (idx==-1) { path_cache.push_back(Path()); ERR_EXPLAIN("Property defined in Transform track, but not a Skeleton Bone!: "+np); ERR_CONTINUE(idx==-1); } path.bone_idx=idx; path.skeleton=sk; } path.spatial=sp; } path.node=node; path.object=node; } if (animation->track_get_type(i)==Animation::TYPE_VALUE) { if (np.get_property().operator String()=="") { path_cache.push_back(Path()); ERR_EXPLAIN("Value Track lacks property: "+np); ERR_CONTINUE(np.get_property().operator String()==""); } path.property=np.get_property(); } else if (animation->track_get_type(i)==Animation::TYPE_METHOD) { if (np.get_property().operator String()!="") { path_cache.push_back(Path()); ERR_EXPLAIN("Method Track has property: "+np); ERR_CONTINUE(np.get_property().operator String()!=""); } } path.valid=true; path_cache.push_back(path); if (!connected_nodes.has(path.node)) { connected_nodes.insert(path.node); path.node->connect("exit_tree",this,"_node_exit_tree",Node::make_binds(path.node),CONNECT_ONESHOT); } } cache_dirty=false; cache_valid=true; }
Error VariantParser::parse_value(Token& token,Variant &value,Stream *p_stream,int &line,String &r_err_str,ResourceParser *p_res_parser) { /* { Error err = get_token(p_stream,token,line,r_err_str); if (err) return err; }*/ if (token.type==TK_CURLY_BRACKET_OPEN) { Dictionary d; Error err = _parse_dictionary(d,p_stream,line,r_err_str,p_res_parser); if (err) return err; value=d; return OK; } else if (token.type==TK_BRACKET_OPEN) { Array a; Error err = _parse_array(a,p_stream,line,r_err_str,p_res_parser); if (err) return err; value=a; return OK; } else if (token.type==TK_IDENTIFIER) { /* VECTOR2, // 5 RECT2, VECTOR3, MATRIX32, PLANE, QUAT, // 10 _AABB, //sorry naming convention fail :( not like it's used often MATRIX3, TRANSFORM, // misc types COLOR, IMAGE, // 15 NODE_PATH, _RID, OBJECT, INPUT_EVENT, DICTIONARY, // 20 ARRAY, // arrays RAW_ARRAY, INT_ARRAY, REAL_ARRAY, STRING_ARRAY, // 25 VECTOR2_ARRAY, VECTOR3_ARRAY, COLOR_ARRAY, VARIANT_MAX */ String id = token.value; if (id=="true") value=true; else if (id=="false") value=false; else if (id=="null") value=Variant(); else if (id=="Vector2"){ Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=2) { r_err_str="Expected 2 arguments for constructor"; } value=Vector2(args[0],args[1]); return OK; } else if (id=="Rect2"){ Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=4) { r_err_str="Expected 4 arguments for constructor"; } value=Rect2(args[0],args[1],args[2],args[3]); return OK; } else if (id=="Vector3"){ Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=3) { r_err_str="Expected 3 arguments for constructor"; } value=Vector3(args[0],args[1],args[2]); return OK; } else if (id=="Matrix32"){ Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=6) { r_err_str="Expected 6 arguments for constructor"; } Matrix32 m; m[0]=Vector2(args[0],args[1]); m[1]=Vector2(args[2],args[3]); m[2]=Vector2(args[4],args[5]); value=m; return OK; } else if (id=="Plane") { Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=4) { r_err_str="Expected 4 arguments for constructor"; } value=Plane(args[0],args[1],args[2],args[3]); return OK; } else if (id=="Quat") { Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=4) { r_err_str="Expected 4 arguments for constructor"; } value=Quat(args[0],args[1],args[2],args[3]); return OK; } else if (id=="AABB"){ Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=6) { r_err_str="Expected 6 arguments for constructor"; } value=AABB(Vector3(args[0],args[1],args[2]),Vector3(args[3],args[4],args[5])); return OK; } else if (id=="Matrix3"){ Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=9) { r_err_str="Expected 9 arguments for constructor"; } value=Matrix3(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]); return OK; } else if (id=="Transform"){ Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=12) { r_err_str="Expected 12 arguments for constructor"; } value=Transform(Matrix3(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]),Vector3(args[9],args[10],args[11])); return OK; } else if (id=="Color") { Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; if (args.size()!=4) { r_err_str="Expected 4 arguments for constructor"; } value=Color(args[0],args[1],args[2],args[3]); return OK; } else if (id=="Image") { //:| get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_OPEN) { r_err_str="Expected '('"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type==TK_PARENTHESIS_CLOSE) { value=Image(); // just an Image() return OK; } else if (token.type!=TK_NUMBER) { r_err_str="Expected number (width)"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); int width=token.value; if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected number (height)"; return ERR_PARSE_ERROR; } int height=token.value; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected number (mipmaps)"; return ERR_PARSE_ERROR; } int mipmaps=token.value; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_IDENTIFIER) { r_err_str="Expected identifier (format)"; return ERR_PARSE_ERROR; } String sformat=token.value; Image::Format format; if (sformat=="GRAYSCALE") format=Image::FORMAT_GRAYSCALE; else if (sformat=="INTENSITY") format=Image::FORMAT_INTENSITY; else if (sformat=="GRAYSCALE_ALPHA") format=Image::FORMAT_GRAYSCALE_ALPHA; else if (sformat=="RGB") format=Image::FORMAT_RGB; else if (sformat=="RGBA") format=Image::FORMAT_RGBA; else if (sformat=="INDEXED") format=Image::FORMAT_INDEXED; else if (sformat=="INDEXED_ALPHA") format=Image::FORMAT_INDEXED_ALPHA; else if (sformat=="BC1") format=Image::FORMAT_BC1; else if (sformat=="BC2") format=Image::FORMAT_BC2; else if (sformat=="BC3") format=Image::FORMAT_BC3; else if (sformat=="BC4") format=Image::FORMAT_BC4; else if (sformat=="BC5") format=Image::FORMAT_BC5; else if (sformat=="PVRTC2") format=Image::FORMAT_PVRTC2; else if (sformat=="PVRTC2_ALPHA") format=Image::FORMAT_PVRTC2_ALPHA; else if (sformat=="PVRTC4") format=Image::FORMAT_PVRTC4; else if (sformat=="PVRTC4_ALPHA") format=Image::FORMAT_PVRTC4_ALPHA; else if (sformat=="ATC") format=Image::FORMAT_ATC; else if (sformat=="ATC_ALPHA_EXPLICIT") format=Image::FORMAT_ATC_ALPHA_EXPLICIT; else if (sformat=="ATC_ALPHA_INTERPOLATED") format=Image::FORMAT_ATC_ALPHA_INTERPOLATED; else if (sformat=="CUSTOM") format=Image::FORMAT_CUSTOM; else { r_err_str="Invalid image format: '"+sformat+"'"; return ERR_PARSE_ERROR; }; int len = Image::get_image_data_size(width,height,format,mipmaps); DVector<uint8_t> buffer; buffer.resize(len); if (buffer.size()!=len) { r_err_str="Couldn't allocate image buffer of size: "+itos(len); } { DVector<uint8_t>::Write w=buffer.write(); for(int i=0;i<len;i++) { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected number"; return ERR_PARSE_ERROR; } w[i]=int(token.value); } } Image img(width,height,mipmaps,format,buffer); value=img; return OK; } else if (id=="NodePath") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_OPEN) { r_err_str="Expected '('"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_STRING) { r_err_str="Expected string as argument for NodePath()"; return ERR_PARSE_ERROR; } value=NodePath(String(token.value)); get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')'"; return ERR_PARSE_ERROR; } } else if (id=="RID") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_OPEN) { r_err_str="Expected '('"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected number as argument"; return ERR_PARSE_ERROR; } value=token.value; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')'"; return ERR_PARSE_ERROR; } return OK; } else if (id=="Resource" || id=="SubResource" || id=="ExtResource") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_OPEN) { r_err_str="Expected '('"; return ERR_PARSE_ERROR; } if (p_res_parser && id=="Resource" && p_res_parser->func){ RES res; Error err = p_res_parser->func(p_res_parser->userdata,p_stream,res,line,r_err_str); if (err) return err; value=res; return OK; } else if (p_res_parser && id=="ExtResource" && p_res_parser->ext_func){ RES res; Error err = p_res_parser->ext_func(p_res_parser->userdata,p_stream,res,line,r_err_str); if (err) return err; value=res; return OK; } else if (p_res_parser && id=="SubResource" && p_res_parser->sub_func){ RES res; Error err = p_res_parser->sub_func(p_res_parser->userdata,p_stream,res,line,r_err_str); if (err) return err; value=res; return OK; } else { get_token(p_stream,token,line,r_err_str); if (token.type==TK_STRING) { String path=token.value; RES res = ResourceLoader::load(path); if (res.is_null()) { r_err_str="Can't load resource at path: '"+path+"'."; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')'"; return ERR_PARSE_ERROR; } value=res; return OK; } else { r_err_str="Expected string as argument for Resource()."; return ERR_PARSE_ERROR; } } return OK; } else if (id=="InputEvent") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_OPEN) { r_err_str="Expected '('"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_IDENTIFIER) { r_err_str="Expected identifier"; return ERR_PARSE_ERROR; } String id = token.value; InputEvent ie; if (id=="KEY") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } ie.type=InputEvent::KEY; get_token(p_stream,token,line,r_err_str); if (token.type==TK_IDENTIFIER) { String name=token.value; ie.key.scancode=find_keycode(name); } else if (token.type==TK_NUMBER) { ie.key.scancode=token.value; } else { r_err_str="Expected string or integer for keycode"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type==TK_COMMA) { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_IDENTIFIER) { r_err_str="Expected identifier with modifier flas"; return ERR_PARSE_ERROR; } String mods=token.value; if (mods.findn("C")!=-1) ie.key.mod.control=true; if (mods.findn("A")!=-1) ie.key.mod.alt=true; if (mods.findn("S")!=-1) ie.key.mod.shift=true; if (mods.findn("M")!=-1) ie.key.mod.meta=true; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')'"; return ERR_PARSE_ERROR; } } else if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')' or modifier flags."; return ERR_PARSE_ERROR; } } else if (id=="MBUTTON") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } ie.type=InputEvent::MOUSE_BUTTON; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected button index"; return ERR_PARSE_ERROR; } ie.mouse_button.button_index = token.value; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')'"; return ERR_PARSE_ERROR; } } else if (id=="JBUTTON") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } ie.type=InputEvent::JOYSTICK_BUTTON; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected button index"; return ERR_PARSE_ERROR; } ie.joy_button.button_index = token.value; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')'"; return ERR_PARSE_ERROR; } } else if (id=="JAXIS") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ','"; return ERR_PARSE_ERROR; } ie.type=InputEvent::JOYSTICK_MOTION; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected axis index"; return ERR_PARSE_ERROR; } ie.joy_motion.axis = token.value; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_COMMA) { r_err_str="Expected ',' after axis index"; return ERR_PARSE_ERROR; } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_NUMBER) { r_err_str="Expected axis sign"; return ERR_PARSE_ERROR; } ie.joy_motion.axis_value = token.value; get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_CLOSE) { r_err_str="Expected ')' for jaxis"; return ERR_PARSE_ERROR; } } else { r_err_str="Invalid input event type."; return ERR_PARSE_ERROR; } value=ie; return OK; } else if (id=="ByteArray") { Vector<uint8_t> args; Error err = _parse_construct<uint8_t>(p_stream,args,line,r_err_str); if (err) return err; DVector<uint8_t> arr; { int len=args.size(); arr.resize(len); DVector<uint8_t>::Write w = arr.write(); for(int i=0;i<len;i++) { w[i]=args[i]; } } value=arr; return OK; } else if (id=="IntArray") { Vector<int32_t> args; Error err = _parse_construct<int32_t>(p_stream,args,line,r_err_str); if (err) return err; DVector<int32_t> arr; { int len=args.size(); arr.resize(len); DVector<int32_t>::Write w = arr.write(); for(int i=0;i<len;i++) { w[i]=int(args[i]); } } value=arr; return OK; } else if (id=="FloatArray") { Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; DVector<float> arr; { int len=args.size(); arr.resize(len); DVector<float>::Write w = arr.write(); for(int i=0;i<len;i++) { w[i]=args[i]; } } value=arr; return OK; } else if (id=="StringArray") { get_token(p_stream,token,line,r_err_str); if (token.type!=TK_PARENTHESIS_OPEN) { r_err_str="Expected '('"; return ERR_PARSE_ERROR; } Vector<String> cs; bool first=true; while(true) { if (!first) { get_token(p_stream,token,line,r_err_str); if (token.type==TK_COMMA) { //do none } else if (token.type==TK_PARENTHESIS_CLOSE) { break; } else { r_err_str="Expected ',' or ')'"; return ERR_PARSE_ERROR; } } get_token(p_stream,token,line,r_err_str); if (token.type!=TK_STRING) { r_err_str="Expected string"; return ERR_PARSE_ERROR; } first=false; cs.push_back(token.value); } DVector<String> arr; { int len=cs.size(); arr.resize(len); DVector<String>::Write w = arr.write(); for(int i=0;i<len;i++) { w[i]=cs[i]; } } value=arr; return OK; } else if (id=="Vector2Array") { Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; DVector<Vector2> arr; { int len=args.size()/2; arr.resize(len); DVector<Vector2>::Write w = arr.write(); for(int i=0;i<len;i++) { w[i]=Vector2(args[i*2+0],args[i*2+1]); } } value=arr; return OK; } else if (id=="Vector3Array") { Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; DVector<Vector3> arr; { int len=args.size()/3; arr.resize(len); DVector<Vector3>::Write w = arr.write(); for(int i=0;i<len;i++) { w[i]=Vector3(args[i*3+0],args[i*3+1],args[i*3+2]); } } value=arr; return OK; } else if (id=="ColorArray") { Vector<float> args; Error err = _parse_construct<float>(p_stream,args,line,r_err_str); if (err) return err; DVector<Color> arr; { int len=args.size()/4; arr.resize(len); DVector<Color>::Write w = arr.write(); for(int i=0;i<len;i++) { w[i]=Color(args[i*4+0],args[i*4+1],args[i*4+2],args[i*4+3]); } } value=arr; return OK; } else if (id=="key") { // compatibility with engine.cfg Vector<String> params; Error err = _parse_enginecfg(p_stream,params,line,r_err_str); if (err) return err; ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,ERR_PARSE_ERROR); int scode=0; if (params[0].is_numeric()) { scode=params[0].to_int(); if (scode < 10) { scode=KEY_0+scode; } } else scode=find_keycode(params[0]); InputEvent ie; ie.type=InputEvent::KEY; ie.key.scancode=scode; if (params.size()==2) { String mods=params[1]; if (mods.findn("C")!=-1) ie.key.mod.control=true; if (mods.findn("A")!=-1) ie.key.mod.alt=true; if (mods.findn("S")!=-1) ie.key.mod.shift=true; if (mods.findn("M")!=-1) ie.key.mod.meta=true; } value=ie; return OK; } else if (id=="mbutton") { // compatibility with engine.cfg Vector<String> params; Error err = _parse_enginecfg(p_stream,params,line,r_err_str); if (err) return err; ERR_FAIL_COND_V(params.size()!=2,ERR_PARSE_ERROR); InputEvent ie; ie.type=InputEvent::MOUSE_BUTTON; ie.device=params[0].to_int(); ie.mouse_button.button_index=params[1].to_int(); value=ie; return OK; } else if (id=="jbutton") { // compatibility with engine.cfg Vector<String> params; Error err = _parse_enginecfg(p_stream,params,line,r_err_str); if (err) return err; ERR_FAIL_COND_V(params.size()!=2,ERR_PARSE_ERROR); InputEvent ie; ie.type=InputEvent::JOYSTICK_BUTTON; ie.device=params[0].to_int(); ie.joy_button.button_index=params[1].to_int(); value=ie; return OK; } else if (id=="jaxis") { // compatibility with engine.cfg Vector<String> params; Error err = _parse_enginecfg(p_stream,params,line,r_err_str); if (err) return err; ERR_FAIL_COND_V(params.size()!=2,ERR_PARSE_ERROR); InputEvent ie; ie.type=InputEvent::JOYSTICK_MOTION; ie.device=params[0].to_int(); int axis=params[1].to_int(); ie.joy_motion.axis=axis>>1; ie.joy_motion.axis_value=axis&1?1:-1; value= ie; return OK; } else if (id=="img") { // compatibility with engine.cfg