X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=d78432d1ebb372df5ca77f21b97809554666b177;hb=5bed0c59a91d32e2e82def3a95625b26bb8610a4;hp=8e51f5ad801cd1edd8bfe89bb42de8bc8d71dbcd;hpb=224535bfe9ef9bfae63168c8ed99c2b70d2f44b1;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index 8e51f5ad..d78432d1 100644 --- a/src/files.c +++ b/src/files.c @@ -2814,8 +2814,9 @@ static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level) for (x = 0; x < 3; x++) ei->content.e[x][y] = getMappedElement(getFile16BitBE(file)); + // bits 0 - 31 of "has_event[]" event_bits = getFile32BitBE(file); - for (j = 0; j < NUM_CHANGE_EVENTS; j++) + for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++) if (event_bits & (1 << j)) ei->change->has_event[j] = TRUE; @@ -7763,6 +7764,7 @@ static void setTapeInfoToDefaults(void) tape.scr_fieldx = SCR_FIELDX_DEFAULT; tape.scr_fieldy = SCR_FIELDY_DEFAULT; + tape.no_info_chunk = TRUE; tape.no_valid_file = FALSE; } @@ -7867,6 +7869,8 @@ static int LoadTape_INFO(File *file, int chunk_size, struct TapeInfo *tape) int level_identifier_size; int i; + tape->no_info_chunk = FALSE; + level_identifier_size = getFile16BitBE(file); level_identifier = checked_malloc(level_identifier_size); @@ -8473,8 +8477,17 @@ void DumpTape(struct TapeInfo *tape) Print("[tas_keys]"); if (tape->property_bits & TAPE_PROPERTY_SMALL_GRAPHICS) Print("[small_graphics]"); - Print("\n"); + + int year2 = tape->date / 10000; + int year4 = (year2 < 70 ? 2000 + year2 : 1900 + year2); + int month_index_raw = (tape->date / 100) % 100; + int month_index = month_index_raw % 12; // prevent invalid index + int month = month_index + 1; + int day = tape->date % 100; + + Print("Tape date: %04d-%02d-%02d\n", year4, month, day); + PrintLine("-", 79); tape_frame_counter = 0; @@ -9026,9 +9039,13 @@ void SaveScore(int nr) SaveScoreToFilename(filename); } -static void ExecuteAsThread(SDL_ThreadFunction function, char *name, void *data, - char *error) +void ExecuteAsThread(SDL_ThreadFunction function, char *name, void *data, + char *error) { +#if defined(PLATFORM_EMSCRIPTEN) + // threads currently not fully supported by Emscripten/SDL and some browsers + function(data); +#else SDL_Thread *thread = SDL_CreateThread(function, name, data); if (thread != NULL) @@ -9038,9 +9055,10 @@ static void ExecuteAsThread(SDL_ThreadFunction function, char *name, void *data, // nasty kludge to lower probability of intermingled thread error messages Delay(1); +#endif } -static char *getPasswordJSON(char *password) +char *getPasswordJSON(char *password) { static char password_json[MAX_FILENAME_LEN] = ""; static boolean initialized = FALSE; @@ -9060,42 +9078,74 @@ static char *getPasswordJSON(char *password) return password_json; } -static void DownloadServerScoreToCacheExt(struct HttpRequest *request, - struct HttpResponse *response, - int level_nr, - char *score_cache_filename) +struct ApiGetScoreThreadData +{ + int level_nr; + char *score_cache_filename; +}; + +static void *CreateThreadData_ApiGetScore(int nr) +{ + struct ApiGetScoreThreadData *data = + checked_malloc(sizeof(struct ApiGetScoreThreadData)); + char *score_cache_filename = getScoreCacheFilename(nr); + + data->level_nr = nr; + data->score_cache_filename = getStringCopy(score_cache_filename); + + return data; +} + +static void FreeThreadData_ApiGetScore(void *data_raw) { + struct ApiGetScoreThreadData *data = data_raw; + + checked_free(data->score_cache_filename); + checked_free(data); +} + +static boolean SetRequest_ApiGetScore(struct HttpRequest *request, + void *data_raw) +{ + struct ApiGetScoreThreadData *data = data_raw; + int level_nr = data->level_nr; + request->hostname = setup.api_server_hostname; request->port = API_SERVER_PORT; request->method = API_SERVER_METHOD; request->uri = API_SERVER_URI_GET; + char *levelset_identifier = getEscapedJSON(leveldir_current->identifier); + char *levelset_name = getEscapedJSON(leveldir_current->name); + snprintf(request->body, MAX_HTTP_BODY_SIZE, "{\n" "%s" + " \"game_version\": \"%s\",\n" + " \"game_platform\": \"%s\",\n" " \"levelset_identifier\": \"%s\",\n" + " \"levelset_name\": \"%s\",\n" " \"level_nr\": \"%d\"\n" "}\n", getPasswordJSON(setup.api_server_password), - levelset.identifier, level_nr); - - ConvertHttpRequestBodyToServerEncoding(request); + getProgramRealVersionString(), + getProgramPlatformString(), + levelset_identifier, + levelset_name, + level_nr); - if (!DoHttpRequest(request, response)) - { - Error("HTTP request failed: %s", GetHttpError()); + checked_free(levelset_identifier); + checked_free(levelset_name); - return; - } + ConvertHttpRequestBodyToServerEncoding(request); - if (!HTTP_SUCCESS(response->status_code)) - { - Error("server failed to handle request: %d %s", - response->status_code, - response->status_text); + return TRUE; +} - return; - } +static void HandleResponse_ApiGetScore(struct HttpResponse *response, + void *data_raw) +{ + struct ApiGetScoreThreadData *data = data_raw; if (response->body_size == 0) { @@ -9106,7 +9156,7 @@ static void DownloadServerScoreToCacheExt(struct HttpRequest *request, ConvertHttpResponseBodyToClientEncoding(response); - char *filename = score_cache_filename; + char *filename = data->score_cache_filename; FILE *file; int i; @@ -9130,48 +9180,129 @@ static void DownloadServerScoreToCacheExt(struct HttpRequest *request, server_scores.updated = TRUE; } -static void DownloadServerScoreToCache(int level_nr, char *score_cache_filename) +#if defined(PLATFORM_EMSCRIPTEN) +static void Emscripten_ApiGetScore_Loaded(unsigned handle, void *data_raw, + void *buffer, unsigned int size) { - struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest)); - struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse)); + struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size); - DownloadServerScoreToCacheExt(request, response, - level_nr, score_cache_filename); + if (response != NULL) + { + HandleResponse_ApiGetScore(response, data_raw); - checked_free(request); - checked_free(response); + checked_free(response); + } + else + { + Error("server response too large to handle (%d bytes)", size); + } + + FreeThreadData_ApiGetScore(data_raw); } -struct DownloadServerScoreToCacheThreadData +static void Emscripten_ApiGetScore_Failed(unsigned handle, void *data_raw, + int code, const char *status) { - int level_nr; - char *score_cache_filename; -}; + Error("server failed to handle request: %d %s", code, status); + + FreeThreadData_ApiGetScore(data_raw); +} -static int DownloadServerScoreToCacheThread(void *data_raw) +static void Emscripten_ApiGetScore_Progress(unsigned handle, void *data_raw, + int bytes, int size) { - struct DownloadServerScoreToCacheThreadData *data = data_raw; + // nothing to do here +} - DownloadServerScoreToCache(data->level_nr, - data->score_cache_filename); +static void Emscripten_ApiGetScore_HttpRequest(struct HttpRequest *request, + void *data_raw) +{ + if (!SetRequest_ApiGetScore(request, data_raw)) + { + FreeThreadData_ApiGetScore(data_raw); - checked_free(data->score_cache_filename); - checked_free(data); + return; + } - return 0; + emscripten_async_wget2_data(request->uri, + request->method, + request->body, + data_raw, + TRUE, + Emscripten_ApiGetScore_Loaded, + Emscripten_ApiGetScore_Failed, + Emscripten_ApiGetScore_Progress); } -static void DownloadServerScoreToCacheAsThread(int nr) +#else + +static void ApiGetScore_HttpRequestExt(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) { - struct DownloadServerScoreToCacheThreadData *data = - checked_malloc(sizeof(struct DownloadServerScoreToCacheThreadData)); - char *score_cache_filename = getScoreCacheFilename(nr); + if (!SetRequest_ApiGetScore(request, data_raw)) + return; - data->level_nr = nr; - data->score_cache_filename = getStringCopy(score_cache_filename); + if (!DoHttpRequest(request, response)) + { + Error("HTTP request failed: %s", GetHttpError()); + + return; + } - ExecuteAsThread(DownloadServerScoreToCacheThread, - "DownloadServerScoreToCache", data, + if (!HTTP_SUCCESS(response->status_code)) + { + // do not show error message if no scores found for this level set + if (response->status_code == 404) + return; + + Error("server failed to handle request: %d %s", + response->status_code, + response->status_text); + + return; + } + + HandleResponse_ApiGetScore(response, data_raw); +} + +static void ApiGetScore_HttpRequest(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) +{ + ApiGetScore_HttpRequestExt(request, response, data_raw); + + FreeThreadData_ApiGetScore(data_raw); +} +#endif + +static int ApiGetScoreThread(void *data_raw) +{ + struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest)); + struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse)); + + program.api_thread_count++; + +#if defined(PLATFORM_EMSCRIPTEN) + Emscripten_ApiGetScore_HttpRequest(request, data_raw); +#else + ApiGetScore_HttpRequest(request, response, data_raw); +#endif + + program.api_thread_count--; + + checked_free(request); + checked_free(response); + + return 0; +} + +static void ApiGetScoreAsThread(int nr) +{ + struct ApiGetScoreThreadData *data = CreateThreadData_ApiGetScore(nr); + + ExecuteAsThread(ApiGetScoreThread, + "ApiGetScore", data, "download scores from server"); } @@ -9243,7 +9374,7 @@ static void LoadServerScoreFromCache(int nr) void LoadServerScore(int nr, boolean download_score) { - if (!setup.api_server) + if (!setup.use_api_server) return; // always start with reliable default values @@ -9253,11 +9384,11 @@ void LoadServerScore(int nr, boolean download_score) // (this should prevent reading it while the thread is writing to it) LoadServerScoreFromCache(nr); - if (download_score && runtime.api_server) + if (download_score && runtime.use_api_server) { // 2nd step: download server scores from score server to cache file // (as thread, as it might time out if the server is not reachable) - DownloadServerScoreToCacheAsThread(nr); + ApiGetScoreAsThread(nr); } } @@ -9315,12 +9446,66 @@ static char *get_file_base64(char *filename) return buffer_encoded; } -static void UploadScoreToServerExt(struct HttpRequest *request, - struct HttpResponse *response, - int level_nr, - char *score_tape_filename, - struct ScoreEntry *score_entry) +static void PrepareScoreTapesForUpload(char *leveldir_subdir) +{ + MarkTapeDirectoryUploadsAsIncomplete(leveldir_subdir); + + // if score tape not uploaded, ask for uploading missing tapes later + if (!setup.has_remaining_tapes) + setup.ask_for_remaining_tapes = TRUE; + + setup.provide_uploading_tapes = TRUE; + setup.has_remaining_tapes = TRUE; + + SaveSetup_ServerSetup(); +} + +struct ApiAddScoreThreadData { + int level_nr; + boolean tape_saved; + char *leveldir_subdir; + char *score_tape_filename; + struct ScoreEntry score_entry; +}; + +static void *CreateThreadData_ApiAddScore(int nr, boolean tape_saved, + char *score_tape_filename) +{ + struct ApiAddScoreThreadData *data = + checked_malloc(sizeof(struct ApiAddScoreThreadData)); + struct ScoreEntry *score_entry = &scores.entry[scores.last_added]; + + if (score_tape_filename == NULL) + score_tape_filename = getScoreTapeFilename(score_entry->tape_basename, nr); + + data->level_nr = nr; + data->tape_saved = tape_saved; + data->leveldir_subdir = getStringCopy(leveldir_current->subdir); + data->score_tape_filename = getStringCopy(score_tape_filename); + data->score_entry = *score_entry; + + return data; +} + +static void FreeThreadData_ApiAddScore(void *data_raw) +{ + struct ApiAddScoreThreadData *data = data_raw; + + checked_free(data->leveldir_subdir); + checked_free(data->score_tape_filename); + checked_free(data); +} + +static boolean SetRequest_ApiAddScore(struct HttpRequest *request, + void *data_raw) +{ + struct ApiAddScoreThreadData *data = data_raw; + struct ScoreEntry *score_entry = &data->score_entry; + char *score_tape_filename = data->score_tape_filename; + boolean tape_saved = data->tape_saved; + int level_nr = data->level_nr; + request->hostname = setup.api_server_hostname; request->port = API_SERVER_PORT; request->method = API_SERVER_METHOD; @@ -9332,7 +9517,16 @@ static void UploadScoreToServerExt(struct HttpRequest *request, { Error("loading and base64 encoding score tape file failed"); - return; + return FALSE; + } + + char *player_name_raw = score_entry->name; + char *player_uuid_raw = setup.player_uuid; + + if (options.player_name != NULL && global.autoplay_leveldir != NULL) + { + player_name_raw = options.player_name; + player_uuid_raw = ""; } char *levelset_identifier = getEscapedJSON(leveldir_current->identifier); @@ -9340,12 +9534,15 @@ static void UploadScoreToServerExt(struct HttpRequest *request, char *levelset_author = getEscapedJSON(leveldir_current->author); char *level_name = getEscapedJSON(level.name); char *level_author = getEscapedJSON(level.author); - char *player_name = getEscapedJSON(score_entry->name); + char *player_name = getEscapedJSON(player_name_raw); + char *player_uuid = getEscapedJSON(player_uuid_raw); snprintf(request->body, MAX_HTTP_BODY_SIZE, "{\n" "%s" " \"game_version\": \"%s\",\n" + " \"game_platform\": \"%s\",\n" + " \"batch_time\": \"%d\",\n" " \"levelset_identifier\": \"%s\",\n" " \"levelset_name\": \"%s\",\n" " \"levelset_author\": \"%s\",\n" @@ -9354,15 +9551,20 @@ static void UploadScoreToServerExt(struct HttpRequest *request, " \"level_nr\": \"%d\",\n" " \"level_name\": \"%s\",\n" " \"level_author\": \"%s\",\n" + " \"use_step_counter\": \"%d\",\n" " \"rate_time_over_score\": \"%d\",\n" " \"player_name\": \"%s\",\n" + " \"player_uuid\": \"%s\",\n" " \"score\": \"%d\",\n" " \"time\": \"%d\",\n" " \"tape_basename\": \"%s\",\n" + " \"tape_saved\": \"%d\",\n" " \"tape\": \"%s\"\n" "}\n", getPasswordJSON(setup.api_server_password), getProgramRealVersionString(), + getProgramPlatformString(), + (int)global.autoplay_time, levelset_identifier, levelset_name, levelset_author, @@ -9371,11 +9573,14 @@ static void UploadScoreToServerExt(struct HttpRequest *request, level_nr, level_name, level_author, + level.use_step_counter, level.rate_time_over_score, player_name, + player_uuid, score_entry->score, score_entry->time, score_entry->tape_basename, + tape_saved, tape_base64); checked_free(tape_base64); @@ -9386,13 +9591,99 @@ static void UploadScoreToServerExt(struct HttpRequest *request, checked_free(level_name); checked_free(level_author); checked_free(player_name); + checked_free(player_uuid); ConvertHttpRequestBodyToServerEncoding(request); + return TRUE; +} + +static void HandleResponse_ApiAddScore(struct HttpResponse *response, + void *data_raw) +{ + server_scores.uploaded = TRUE; +} + +static void HandleFailure_ApiAddScore(void *data_raw) +{ + struct ApiAddScoreThreadData *data = data_raw; + + PrepareScoreTapesForUpload(data->leveldir_subdir); +} + +#if defined(PLATFORM_EMSCRIPTEN) +static void Emscripten_ApiAddScore_Loaded(unsigned handle, void *data_raw, + void *buffer, unsigned int size) +{ + struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size); + + if (response != NULL) + { + HandleResponse_ApiAddScore(response, data_raw); + + checked_free(response); + } + else + { + Error("server response too large to handle (%d bytes)", size); + + HandleFailure_ApiAddScore(data_raw); + } + + FreeThreadData_ApiAddScore(data_raw); +} + +static void Emscripten_ApiAddScore_Failed(unsigned handle, void *data_raw, + int code, const char *status) +{ + Error("server failed to handle request: %d %s", code, status); + + HandleFailure_ApiAddScore(data_raw); + + FreeThreadData_ApiAddScore(data_raw); +} + +static void Emscripten_ApiAddScore_Progress(unsigned handle, void *data_raw, + int bytes, int size) +{ + // nothing to do here +} + +static void Emscripten_ApiAddScore_HttpRequest(struct HttpRequest *request, + void *data_raw) +{ + if (!SetRequest_ApiAddScore(request, data_raw)) + { + FreeThreadData_ApiAddScore(data_raw); + + return; + } + + emscripten_async_wget2_data(request->uri, + request->method, + request->body, + data_raw, + TRUE, + Emscripten_ApiAddScore_Loaded, + Emscripten_ApiAddScore_Failed, + Emscripten_ApiAddScore_Progress); +} + +#else + +static void ApiAddScore_HttpRequestExt(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) +{ + if (!SetRequest_ApiAddScore(request, data_raw)) + return; + if (!DoHttpRequest(request, response)) { Error("HTTP request failed: %s", GetHttpError()); + HandleFailure_ApiAddScore(data_raw); + return; } @@ -9402,90 +9693,92 @@ static void UploadScoreToServerExt(struct HttpRequest *request, response->status_code, response->status_text); + HandleFailure_ApiAddScore(data_raw); + return; } - server_scores.uploaded = TRUE; + HandleResponse_ApiAddScore(response, data_raw); } -static void UploadScoreToServer(int level_nr, char *score_tape_filename, - struct ScoreEntry *score_entry) +static void ApiAddScore_HttpRequest(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) { - struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest)); - struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse)); - - UploadScoreToServerExt(request, response, - level_nr, score_tape_filename, score_entry); + ApiAddScore_HttpRequestExt(request, response, data_raw); - checked_free(request); - checked_free(response); + FreeThreadData_ApiAddScore(data_raw); } +#endif -struct UploadScoreToServerThreadData +static int ApiAddScoreThread(void *data_raw) { - int level_nr; - char *score_tape_filename; - struct ScoreEntry score_entry; -}; + struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest)); + struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse)); -static int UploadScoreToServerThread(void *data_raw) -{ - struct UploadScoreToServerThreadData *data = data_raw; + program.api_thread_count++; - UploadScoreToServer(data->level_nr, - data->score_tape_filename, - &data->score_entry); +#if defined(PLATFORM_EMSCRIPTEN) + Emscripten_ApiAddScore_HttpRequest(request, data_raw); +#else + ApiAddScore_HttpRequest(request, response, data_raw); +#endif - checked_free(data->score_tape_filename); - checked_free(data); + program.api_thread_count--; + + checked_free(request); + checked_free(response); return 0; } -static void UploadScoreToServerAsThread(int nr, char *score_tape_filename) +static void ApiAddScoreAsThread(int nr, boolean tape_saved, + char *score_tape_filename) { - struct UploadScoreToServerThreadData *data = - checked_malloc(sizeof(struct UploadScoreToServerThreadData)); - struct ScoreEntry *score_entry = &scores.entry[scores.last_added]; - - if (score_tape_filename == NULL) - score_tape_filename = getScoreTapeFilename(score_entry->tape_basename, nr); + struct ApiAddScoreThreadData *data = + CreateThreadData_ApiAddScore(nr, tape_saved, score_tape_filename); - data->level_nr = nr; - data->score_entry = *score_entry; - data->score_tape_filename = getStringCopy(score_tape_filename); - - ExecuteAsThread(UploadScoreToServerThread, - "UploadScoreToServer", data, + ExecuteAsThread(ApiAddScoreThread, + "ApiAddScore", data, "upload score to server"); } -void SaveServerScore(int nr) +void SaveServerScore(int nr, boolean tape_saved) { - if (!runtime.api_server) + if (!runtime.use_api_server) + { + PrepareScoreTapesForUpload(leveldir_current->subdir); + return; + } - UploadScoreToServerAsThread(nr, NULL); + ApiAddScoreAsThread(nr, tape_saved, NULL); } -void SaveServerScoreFromFile(int nr, char *score_tape_filename) +void SaveServerScoreFromFile(int nr, boolean tape_saved, + char *score_tape_filename) { - if (!runtime.api_server) + if (!runtime.use_api_server) return; - UploadScoreToServerAsThread(nr, score_tape_filename); + ApiAddScoreAsThread(nr, tape_saved, score_tape_filename); } void LoadLocalAndServerScore(int nr, boolean download_score) { int last_added_local = scores.last_added_local; - LoadScore(nr); + // needed if only showing server scores + setScoreInfoToDefaults(); + + if (!strEqual(setup.scores_in_highscore_list, STR_SCORES_TYPE_SERVER_ONLY)) + LoadScore(nr); // restore last added local score entry (before merging server scores) scores.last_added = scores.last_added_local = last_added_local; - if (setup.api_server && !setup.only_show_local_scores) + if (setup.use_api_server && + !strEqual(setup.scores_in_highscore_list, STR_SCORES_TYPE_LOCAL_ONLY)) { // load server scores from cache file and trigger update from server LoadServerScore(nr, download_score); @@ -9509,14 +9802,6 @@ static struct TokenInfo global_setup_tokens[] = TYPE_STRING, &setup.player_name, "player_name" }, - { - TYPE_STRING, - &setup.player_uuid, "player_uuid" - }, - { - TYPE_STRING, - &setup.system_uuid, "system_uuid" - }, { TYPE_SWITCH, &setup.multiple_users, "multiple_users" @@ -9694,8 +9979,8 @@ static struct TokenInfo global_setup_tokens[] = &setup.show_undo_redo_buttons, "show_undo_redo_buttons" }, { - TYPE_SWITCH, - &setup.only_show_local_scores, "only_show_local_scores" + TYPE_STRING, + &setup.scores_in_highscore_list, "scores_in_highscore_list" }, { TYPE_STRING, @@ -9745,18 +10030,6 @@ static struct TokenInfo global_setup_tokens[] = TYPE_STRING, &setup.network_server_hostname, "network_server_hostname" }, - { - TYPE_SWITCH, - &setup.api_server, "api_server" - }, - { - TYPE_STRING, - &setup.api_server_hostname, "api_server_hostname" - }, - { - TYPE_STRING, - &setup.api_server_password, "api_server_password" - }, { TYPE_STRING, &setup.touch.control_type, "touch.control_type" @@ -9807,6 +10080,50 @@ static struct TokenInfo auto_setup_tokens[] = }, }; +static struct TokenInfo server_setup_tokens[] = +{ + { + TYPE_STRING, + &setup.player_uuid, "player_uuid" + }, + { + TYPE_INTEGER, + &setup.player_version, "player_version" + }, + { + TYPE_SWITCH, + &setup.use_api_server, TEST_PREFIX "use_api_server" + }, + { + TYPE_STRING, + &setup.api_server_hostname, TEST_PREFIX "api_server_hostname" + }, + { + TYPE_STRING, + &setup.api_server_password, TEST_PREFIX "api_server_password" + }, + { + TYPE_SWITCH, + &setup.ask_for_uploading_tapes, TEST_PREFIX "ask_for_uploading_tapes" + }, + { + TYPE_SWITCH, + &setup.ask_for_remaining_tapes, TEST_PREFIX "ask_for_remaining_tapes" + }, + { + TYPE_SWITCH, + &setup.provide_uploading_tapes, TEST_PREFIX "provide_uploading_tapes" + }, + { + TYPE_SWITCH, + &setup.ask_for_using_api_server,TEST_PREFIX "ask_for_using_api_server" + }, + { + TYPE_SWITCH, + &setup.has_remaining_tapes, TEST_PREFIX "has_remaining_tapes" + }, +}; + static struct TokenInfo editor_setup_tokens[] = { { @@ -10329,9 +10646,6 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->player_name = getStringCopy(getDefaultUserName(user.nr)); - si->player_uuid = NULL; // (will be set later) - si->system_uuid = NULL; // (will be set later) - si->multiple_users = TRUE; si->sound = TRUE; @@ -10377,7 +10691,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->small_game_graphics = FALSE; si->show_load_save_buttons = FALSE; si->show_undo_redo_buttons = FALSE; - si->only_show_local_scores = FALSE; + si->scores_in_highscore_list = getStringCopy(STR_SCORES_TYPE_DEFAULT); si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR); si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR); @@ -10395,10 +10709,6 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->network_player_nr = 0; // first player si->network_server_hostname = getStringCopy(STR_NETWORK_AUTO_DETECT); - si->api_server = TRUE; - si->api_server_hostname = getStringCopy(API_SERVER_HOSTNAME); - si->api_server_password = getStringCopy(UNDEFINED_PASSWORD); - si->touch.control_type = getStringCopy(TOUCH_CONTROL_DEFAULT); si->touch.move_distance = TOUCH_MOVE_DISTANCE_DEFAULT; // percent si->touch.drop_distance = TOUCH_DROP_DISTANCE_DEFAULT; // percent @@ -10605,6 +10915,21 @@ static void setSetupInfoToDefaults_AutoSetup(struct SetupInfo *si) si->auto_setup.editor_zoom_tilesize = MINI_TILESIZE; } +static void setSetupInfoToDefaults_ServerSetup(struct SetupInfo *si) +{ + si->player_uuid = NULL; // (will be set later) + si->player_version = 1; // (will be set later) + + si->use_api_server = TRUE; + si->api_server_hostname = getStringCopy(API_SERVER_HOSTNAME); + si->api_server_password = getStringCopy(UNDEFINED_PASSWORD); + si->ask_for_uploading_tapes = TRUE; + si->ask_for_remaining_tapes = FALSE; + si->provide_uploading_tapes = TRUE; + si->ask_for_using_api_server = TRUE; + si->has_remaining_tapes = FALSE; +} + static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si) { si->editor_cascade.el_bd = TRUE; @@ -10692,7 +11017,7 @@ static void setSetupInfoFromTokenInfo(SetupFileHash *setup_file_hash, token_info[token_nr].text); } -static void decodeSetupFileHash(SetupFileHash *setup_file_hash) +static void decodeSetupFileHash_Default(SetupFileHash *setup_file_hash) { int i, pnr; @@ -10792,6 +11117,19 @@ static void decodeSetupFileHash_AutoSetup(SetupFileHash *setup_file_hash) auto_setup_tokens[i].text)); } +static void decodeSetupFileHash_ServerSetup(SetupFileHash *setup_file_hash) +{ + int i; + + if (!setup_file_hash) + return; + + for (i = 0; i < ARRAY_SIZE(server_setup_tokens); i++) + setSetupInfo(server_setup_tokens, i, + getHashEntry(setup_file_hash, + server_setup_tokens[i].text)); +} + static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash) { int i; @@ -10848,7 +11186,7 @@ void LoadSetupFromFilename(char *filename) if (setup_file_hash) { - decodeSetupFileHash(setup_file_hash); + decodeSetupFileHash_Default(setup_file_hash); freeSetupFileHash(setup_file_hash); } @@ -10877,23 +11215,9 @@ static void LoadSetup_SpecialPostProcessing(void) // make sure that scroll delay value stays inside valid range setup.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY); - - if (setup.player_uuid == NULL || - setup.system_uuid == NULL) - { - if (setup.player_uuid == NULL) - setup.player_uuid = getStringCopy(GetPlayerUUID()); - - if (setup.system_uuid == NULL) - setup.system_uuid = getStringCopy(GetSystemUUID()); - - SaveSetup(); - } - - SetSystemUUID(setup.system_uuid); } -void LoadSetup(void) +void LoadSetup_Default(void) { char *filename; @@ -10934,6 +11258,35 @@ void LoadSetup_AutoSetup(void) free(filename); } +void LoadSetup_ServerSetup(void) +{ + char *filename = getPath2(getSetupDir(), SERVERSETUP_FILENAME); + SetupFileHash *setup_file_hash = NULL; + + // always start with reliable default values + setSetupInfoToDefaults_ServerSetup(&setup); + + setup_file_hash = loadSetupFileHash(filename); + + if (setup_file_hash) + { + decodeSetupFileHash_ServerSetup(setup_file_hash); + + freeSetupFileHash(setup_file_hash); + } + + free(filename); + + if (setup.player_uuid == NULL) + { + // player UUID does not yet exist in setup file + setup.player_uuid = getStringCopy(getUUID()); + setup.player_version = 2; + + SaveSetup_ServerSetup(); + } +} + void LoadSetup_EditorCascade(void) { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); @@ -10954,6 +11307,14 @@ void LoadSetup_EditorCascade(void) free(filename); } +void LoadSetup(void) +{ + LoadSetup_Default(); + LoadSetup_AutoSetup(); + LoadSetup_ServerSetup(); + LoadSetup_EditorCascade(); +} + static void addGameControllerMappingToHash(SetupFileHash *mappings_hash, char *mapping_line) { @@ -11003,7 +11364,7 @@ static void LoadSetup_ReadGameControllerMappings(SetupFileHash *mappings_hash, fclose(file); } -void SaveSetup(void) +void SaveSetup_Default(void) { char *filename = getSetupFilename(); FILE *file; @@ -11023,13 +11384,11 @@ void SaveSetup(void) for (i = 0; i < ARRAY_SIZE(global_setup_tokens); i++) { // just to make things nicer :) - if (global_setup_tokens[i].value == &setup.player_uuid || - global_setup_tokens[i].value == &setup.multiple_users || + if (global_setup_tokens[i].value == &setup.multiple_users || global_setup_tokens[i].value == &setup.sound || global_setup_tokens[i].value == &setup.graphics_set || global_setup_tokens[i].value == &setup.volume_simple || global_setup_tokens[i].value == &setup.network_mode || - global_setup_tokens[i].value == &setup.api_server || global_setup_tokens[i].value == &setup.touch.control_type || global_setup_tokens[i].value == &setup.touch.grid_xsize[0] || global_setup_tokens[i].value == &setup.touch.grid_xsize[1]) @@ -11136,6 +11495,41 @@ void SaveSetup_AutoSetup(void) free(filename); } +void SaveSetup_ServerSetup(void) +{ + char *filename = getPath2(getSetupDir(), SERVERSETUP_FILENAME); + FILE *file; + int i; + + InitUserDataDirectory(); + + if (!(file = fopen(filename, MODE_WRITE))) + { + Warn("cannot write server setup file '%s'", filename); + + free(filename); + + return; + } + + fprintFileHeader(file, SERVERSETUP_FILENAME); + + for (i = 0; i < ARRAY_SIZE(server_setup_tokens); i++) + { + // just to make things nicer :) + if (server_setup_tokens[i].value == &setup.use_api_server) + fprintf(file, "\n"); + + fprintf(file, "%s\n", getSetupLine(server_setup_tokens, "", i)); + } + + fclose(file); + + SetFilePermissions(filename, PERMS_PRIVATE); + + free(filename); +} + void SaveSetup_EditorCascade(void) { char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME); @@ -11165,6 +11559,14 @@ void SaveSetup_EditorCascade(void) free(filename); } +void SaveSetup(void) +{ + SaveSetup_Default(); + SaveSetup_AutoSetup(); + SaveSetup_ServerSetup(); + SaveSetup_EditorCascade(); +} + static void SaveSetup_WriteGameControllerMappings(SetupFileHash *mappings_hash, char *filename) { @@ -11577,6 +11979,7 @@ int get_parameter_value(char *value_raw, char *suffix, int type) string_has_parameter(value, "pingpong") ? ANIM_PINGPONG : string_has_parameter(value, "pingpong2") ? ANIM_PINGPONG2 : string_has_parameter(value, "random") ? ANIM_RANDOM : + string_has_parameter(value, "random_static") ? ANIM_RANDOM_STATIC : string_has_parameter(value, "ce_value") ? ANIM_CE_VALUE : string_has_parameter(value, "ce_score") ? ANIM_CE_SCORE : string_has_parameter(value, "ce_delay") ? ANIM_CE_DELAY : @@ -11584,6 +11987,7 @@ int get_parameter_value(char *value_raw, char *suffix, int type) string_has_parameter(value, "vertical") ? ANIM_VERTICAL : string_has_parameter(value, "centered") ? ANIM_CENTERED : string_has_parameter(value, "all") ? ANIM_ALL : + string_has_parameter(value, "tiled") ? ANIM_TILED : ANIM_DEFAULT); if (string_has_parameter(value, "once"))