void print_dependencies(char *name) { struct pkglist *p = NULL; p = get_dependencies(name); while (p != NULL) { if (strcmp(p->repo, "not found") == 0) { printf("%s [not found]\n", p->name); p = p->next; continue; } printf("%s [", p->name); if (pkglist_exists(p->name, ilenia_pkgs) != 0) { printf(" ]\n"); p = p->next; continue; } printf("installed]"); struct pkglist *paus = NULL; paus = pkglist_find(p->name, ilenia_pkgs); if (strcmp(paus->version, "alias") == 0) printf(" (%s)\n", paus->repo); else printf("\n"); p = p->next; } }
/** OTFUR algorithm **/ otfur_result* otfur(antichain *safety_game_PO, antichain *safety_game_PI, GNode* cfinfo, alphabet_info *alphabet, char starting_player, int dimension, int* max_credit) { clock_t start_time = clock(); // Structures initialization GHashTable *succ_to_visit = g_hash_table_new_full(hash_key, compare_keys, free, NULL); GHashTable *passed = g_hash_table_new_full(hash_key, compare_keys, (GDestroyNotify)free_hash_table_key, free); GHashTable *depend = g_hash_table_new_full(hash_key, compare_keys, free, NULL); //GList *trash = NULL; GList *waiting = NULL; antichain *losing_PO = new_antichain(); antichain *losing_PI = new_antichain(); // Build initial tuple tuple *s_ini = build_initial_tuple(cfinfo, dimension, max_credit); // if s_ini belongs to the system and all its successors are unsafe, s_ini is losing if((starting_player == P_O && has_successor_in_safety_game(s_ini, alphabet, safety_game_PI) == FALSE)/* || (starting_player == P_I && has_successor_not_in_safety_game(s_ini, alphabet, safety_game_PO) == TRUE)*/) { // To avoid k differences between forward and backward algorithms add_to_losing(s_ini, losing_PO, losing_PI); } // else, explore its successors else { waiting = add_to_waiting(s_ini, alphabet, safety_game_PO, safety_game_PI, losing_PO, losing_PI, waiting, succ_to_visit, passed); add_to_passed(s_ini, passed); } safety_game_edge *cur_edge; char cur_losing; int nb_cf_passed = 1; int nb_iter = 0; antichain* cur_safety_game; while(waiting != NULL && is_losing(s_ini, losing_PO, losing_PI) == FALSE) { nb_iter++; GList *last_link = g_list_last(waiting); cur_edge = (safety_game_edge*)last_link->data; waiting = remove_last(waiting); if(is_losing(cur_edge->from, losing_PO, losing_PI) == FALSE) { // If s is not losing if(is_passed(cur_edge->to, passed) == FALSE) { // If s' is not passed add_to_passed(cur_edge->to, passed); nb_cf_passed++; if(is_losing(cur_edge->to, losing_PO, losing_PI) == TRUE) { // If s' is losing -> add e for reevaluation //waiting = g_list_append(waiting, clone_safety_game_edge(cur_edge)); waiting = g_list_append(waiting, cur_edge); } // Basic case: if s' belongs to P_O and has no successor safe non losing, add it to losing // Put the same test for P_I to avoid k differences between forward and backward algorithms else if(cur_edge->to->cf->player == P_O && has_successor_non_losing_in_safety_game(cur_edge->to, alphabet, losing_PO, losing_PI, safety_game_PI) == FALSE) { //waiting = g_list_append(waiting, clone_safety_game_edge(cur_edge)); waiting = g_list_append(waiting, cur_edge); add_to_losing(cur_edge->to, losing_PO, losing_PI); } else { // else, explore its successors add_to_depend(cur_edge->to, cur_edge, depend); waiting = add_to_waiting(cur_edge->to, alphabet, safety_game_PO, safety_game_PI, losing_PO, losing_PI, waiting, succ_to_visit, passed); } } else { // s' is passed if(cur_edge->from->cf->player == P_O) { // s belongs to P_O if(is_losing(cur_edge->to, losing_PO, losing_PI) == FALSE) { // if s' is not losing, add e to the dependencies of s' add_to_depend(cur_edge->to, cur_edge, depend); } else { // if s' is losing, and if there is no more successor of s non losing to visit, s is losing -> add its dependencies to waiting if(has_one_succ_to_visit_non_losing(cur_edge->from, succ_to_visit, losing_PO, losing_PI) == FALSE) { add_to_losing(cur_edge->from, losing_PO, losing_PI); waiting = g_list_concat(waiting, get_dependencies(cur_edge->from, depend)); } else { // if there is still at least a successor non passed non losing, add it to waiting waiting = g_list_append(waiting, get_first_successor_passed_non_losing(cur_edge->from, succ_to_visit, passed, losing_PO, losing_PI)); } } } else { // s belongs to P_I // reevaluation if(is_losing(cur_edge->to, losing_PO, losing_PI) == TRUE) { cur_losing = TRUE; } else { cur_losing = reevaluation(cur_edge->from, alphabet, losing_PO, losing_PI); } // if s is losing, add its dependencies to waiting if(cur_losing == TRUE) { add_to_losing(cur_edge->from, losing_PO, losing_PI); waiting = g_list_concat(waiting, get_dependencies(cur_edge->from, depend)); } // if s' is not losing, add e to its dependencies list if(is_losing(cur_edge->to, losing_PO, losing_PI) == FALSE) { add_to_depend(cur_edge->to, cur_edge, depend); } } //trash = g_list_append(trash, cur_edge->to); } } else { // if s is losing, add its dependencies to waiting //free_tuple_full(cur_edge->to); waiting = g_list_concat(waiting, get_dependencies(cur_edge->from, depend)); } } float otfur_time = (clock() - start_time) * 1e-6; // Extract the solution from passed and losing start_time = clock(); safety_game* sg = compute_winning_positions(losing_PO, losing_PI, passed, build_initial_tuple(cfinfo, dimension, max_credit), alphabet, nb_cf_passed); float winning_positions_computation_time = (clock() - start_time) * 1e-6; // Free memory GList *curlink = waiting; //while(curlink != NULL) { // free_safety_game_edge(curlink->data); // curlink = curlink->next; //} g_list_free(waiting); /*curlink = trash; while(curlink != NULL) { free_tuple_full(curlink->data); curlink = curlink->next; } g_list_free(trash);*/ //g_hash_table_destroy(passed); // this one is not correct ! g_hash_table_foreach(depend, free_depend, NULL); g_hash_table_destroy(depend); g_hash_table_foreach(succ_to_visit, free_succ_to_visit, NULL); g_hash_table_destroy(succ_to_visit); // Build result otfur_result *res = (otfur_result*)malloc(sizeof(otfur_result)); res->winning_positions = sg; res->otfur_time = otfur_time; res->winning_positions_computation_time = winning_positions_computation_time; res->nb_cf_passed = nb_cf_passed; res->nb_iter = nb_iter; return res; }
Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func, void* p_udata,bool p_make_bundles) { /* ALL FILES AND DEPENDENCIES */ Vector<StringName> files=get_dependencies(p_make_bundles); /* GROUP ATLAS */ List<StringName> groups; EditorImportExport::get_singleton()->image_export_get_groups(&groups); Map<StringName,StringName> remap_files; Set<StringName> saved; int counter=0; for(List<StringName>::Element *E=groups.front();E;E=E->next()) { if (!EditorImportExport::get_singleton()->image_export_group_get_make_atlas(E->get())) continue; //uninterested, only process for atlas! List<StringName> atlas_images; EditorImportExport::get_singleton()->image_export_get_images_in_group(E->get(),&atlas_images); atlas_images.sort_custom<StringName::AlphCompare>(); for (List<StringName>::Element *F=atlas_images.front();F;) { List<StringName>::Element *N=F->next(); if (!FileAccess::exists(F->get())) { atlas_images.erase(F); } F=N; } if (atlas_images.size()<=1) continue; int group_format=0; float group_lossy_quality=EditorImportExport::get_singleton()->image_export_group_get_lossy_quality(E->get()); int group_shrink=EditorImportExport::get_singleton()->image_export_group_get_shrink(E->get()); group_shrink*=EditorImportExport::get_singleton()->get_export_image_shrink(); switch(EditorImportExport::get_singleton()->image_export_group_get_image_action(E->get())) { case EditorImportExport::IMAGE_ACTION_NONE: { switch(EditorImportExport::get_singleton()->get_export_image_action()) { case EditorImportExport::IMAGE_ACTION_NONE: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS; //? } break; //use default case EditorImportExport::IMAGE_ACTION_COMPRESS_DISK: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY; } break; //use default case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM; } break; //use default } group_lossy_quality=EditorImportExport::get_singleton()->get_export_image_quality(); } break; //use default case EditorImportExport::IMAGE_ACTION_COMPRESS_DISK: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY; } break; //use default case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM; } break; //use default } String image_list_md5; { MD5_CTX ctx; MD5Init(&ctx); for (List<StringName>::Element *F=atlas_images.front();F;F=F->next()) { String p = F->get(); MD5Update(&ctx,(unsigned char*)p.utf8().get_data(),p.utf8().length()); } MD5Final(&ctx); image_list_md5=String::md5(ctx.digest); } //ok see if cached String md5; bool atlas_valid=true; String atlas_name; { MD5_CTX ctx; MD5Init(&ctx); String path = Globals::get_singleton()->get_resource_path()+"::"+String(E->get())+"::"+get_name(); MD5Update(&ctx,(unsigned char*)path.utf8().get_data(),path.utf8().length()); MD5Final(&ctx); md5 = String::md5(ctx.digest); } FileAccess *f=NULL; if (!FileAccess::exists(EditorSettings::get_singleton()->get_settings_path()+"/tmp/atlas-"+md5)) { print_line("NO MD5 INVALID"); atlas_valid=false; } if (atlas_valid) f=FileAccess::open(EditorSettings::get_singleton()->get_settings_path()+"/tmp/atlas-"+md5,FileAccess::READ); if (atlas_valid) { //compare options Dictionary options; options.parse_json(f->get_line()); if (!options.has("lossy_quality") || float(options["lossy_quality"])!=group_lossy_quality) atlas_valid=false; else if (!options.has("shrink") || int(options["shrink"])!=group_shrink) atlas_valid=false; else if (!options.has("image_format") || int(options["image_format"])!=group_format) atlas_valid=false; if (!atlas_valid) print_line("JSON INVALID"); } if (atlas_valid) { //check md5 of list of image /names/ if (f->get_line().strip_edges()!=image_list_md5) { atlas_valid=false; print_line("IMAGE MD5 INVALID!"); } } Vector<Rect2> rects; bool resave_deps=false; if (atlas_valid) { //check if images were not modified for (List<StringName>::Element *F=atlas_images.front();F;F=F->next()) { Vector<String> slices = f->get_line().strip_edges().split("::"); if (slices.size()!=10) { atlas_valid=false; print_line("CANT SLICE IN 10"); break; } uint64_t mod_time = slices[0].to_int64(); uint64_t file_mod_time = FileAccess::get_modified_time(F->get()); if (mod_time!=file_mod_time) { String image_md5 = slices[1]; String file_md5 = FileAccess::get_md5(F->get()); if (image_md5!=file_md5) { atlas_valid=false; print_line("IMAGE INVALID "+slices[0]); break; } else { resave_deps=true; } } if (atlas_valid) { //push back region and margin rects.push_back(Rect2(slices[2].to_float(),slices[3].to_float(),slices[4].to_float(),slices[5].to_float())); rects.push_back(Rect2(slices[6].to_float(),slices[7].to_float(),slices[8].to_float(),slices[9].to_float())); } } } if (f) { memdelete(f); f=NULL; } print_line("ATLAS VALID? "+itos(atlas_valid)+" RESAVE DEPS? "+itos(resave_deps)); if (!atlas_valid) { rects.clear(); //oh well, atlas is not valid. need to make new one.... String dst_file = EditorSettings::get_singleton()->get_settings_path()+"/tmp/atlas-"+md5+".tex"; Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata ); //imd->set_editor(); for (List<StringName>::Element *F=atlas_images.front();F;F=F->next()) { imd->add_source(EditorImportPlugin::validate_source_path(F->get())); } imd->set_option("format",group_format); int flags=0; if (Globals::get_singleton()->get("texture_import/filter")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER; if (!Globals::get_singleton()->get("texture_import/gen_mipmaps")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS; if (!Globals::get_singleton()->get("texture_import/repeat")) flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT; flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA; imd->set_option("flags",flags); imd->set_option("quality",group_lossy_quality); imd->set_option("atlas",true); imd->set_option("crop",true); imd->set_option("shrink",group_shrink); Ref<EditorTextureImportPlugin> plugin = EditorImportExport::get_singleton()->get_import_plugin_by_name("texture_atlas"); Error err = plugin->import2(dst_file,imd,get_image_compression(),true); if (err) { EditorNode::add_io_error("Error saving atlas! "+dst_file.get_file()); return ERR_CANT_CREATE; } ERR_FAIL_COND_V(imd->get_option("rects")==Variant(),ERR_BUG); Array r_rects=imd->get_option("rects"); rects.resize(r_rects.size()); for(int i=0;i<r_rects.size();i++) { //get back region and margins rects[i]=r_rects[i]; } resave_deps=true; } //atlas is valid (or it was just saved i guess), create the atex files and save them if (resave_deps) { f=FileAccess::open(EditorSettings::get_singleton()->get_settings_path()+"/tmp/atlas-"+md5,FileAccess::WRITE); Dictionary options; options["lossy_quality"]=group_lossy_quality; options["shrink"]=EditorImportExport::get_singleton()->image_export_group_get_shrink(E->get()); options["image_format"]=group_format; f->store_line(options.to_json()); f->store_line(image_list_md5); } //go through all ATEX files { Ref<ImageTexture> atlas = memnew( ImageTexture ); //fake atlas! String atlas_path="res://atlas-"+md5+".tex"; atlas->set_path(atlas_path); int idx=0; for (List<StringName>::Element *F=atlas_images.front();F;F=F->next()) { String p = F->get(); Ref<AtlasTexture> atex = memnew(AtlasTexture); atex->set_atlas(atlas); Rect2 region=rects[idx++]; Rect2 margin=rects[idx++]; atex->set_region(region); atex->set_margin(margin); String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpatlas.atex"; Error err = ResourceSaver::save(path,atex); if (err!=OK) { EditorNode::add_io_error("Could not save atlas subtexture: "+path); return ERR_CANT_CREATE; } Vector<uint8_t> data = FileAccess::get_file_as_array(path); String dst_path = F->get().operator String().basename()+".atex"; err = p_func(p_udata,dst_path,data,counter++,files.size()); saved.insert(dst_path); if (err) return err; if (f) { //recreating deps.. String depline; // depline=String(F->get())+"::"+itos(FileAccess::get_modified_time(F->get()))+"::"+FileAccess::get_md5(F->get()); name unneccesary by top md5 depline=itos(FileAccess::get_modified_time(F->get()))+"::"+FileAccess::get_md5(F->get()); depline+="::"+itos(region.pos.x)+"::"+itos(region.pos.y)+"::"+itos(region.size.x)+"::"+itos(region.size.y); depline+="::"+itos(margin.pos.x)+"::"+itos(margin.pos.y)+"::"+itos(margin.size.x)+"::"+itos(margin.size.y); f->store_line(depline); } remap_files[F->get()]=dst_path; } Vector<uint8_t> atlas_data = FileAccess::get_file_as_array(EditorSettings::get_singleton()->get_settings_path()+"/tmp/atlas-"+md5+".tex"); Error err = p_func(p_udata,atlas_path,atlas_data,counter,files.size()); saved.insert(atlas_path); if (err) return err; } if (f) { memdelete(f); } } StringName engine_cfg="res://engine.cfg"; for(int i=0;i<files.size();i++) { if (remap_files.has(files[i]) || files[i]==engine_cfg) //gonna be remapped (happened before!) continue; //from atlas? String src=files[i]; Vector<uint8_t> buf = get_exported_file(src); ERR_CONTINUE( saved.has(src) ); Error err = p_func(p_udata,src,buf,counter++,files.size()); if (err) return err; saved.insert(src); if (src!=String(files[i])) remap_files[files[i]]=src; } { //make binary engine.cfg config Map<String,Variant> custom; if (remap_files.size()) { Vector<String> remapsprop; for(Map<StringName,StringName>::Element *E=remap_files.front();E;E=E->next()) { remapsprop.push_back(E->key()); remapsprop.push_back(E->get()); } custom["remap/all"]=remapsprop; } String remap_file="engine.cfb"; String engine_cfb =EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmp"+remap_file; Globals::get_singleton()->save_custom(engine_cfb,custom); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); Error err = p_func(p_udata,"res://"+remap_file,data,counter,files.size()); if (err) return err; } return OK; }