fixed bug with undefined behaviour when shifting left by 32 or more
[rocksndiamonds.git] / src / files.c
index 535b1d520ff0ae0f49e6bbaec4fc66f9fe0b5b90..d78432d1ebb372df5ca77f21b97809554666b177 100644 (file)
@@ -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;
 
@@ -9280,12 +9281,16 @@ 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);
 
@@ -9441,10 +9446,25 @@ static char *get_file_base64(char *filename)
   return buffer_encoded;
 }
 
+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;
 };
@@ -9461,8 +9481,9 @@ static void *CreateThreadData_ApiAddScore(int nr, boolean tape_saved,
 
   data->level_nr = nr;
   data->tape_saved = tape_saved;
-  data->score_entry = *score_entry;
+  data->leveldir_subdir = getStringCopy(leveldir_current->subdir);
   data->score_tape_filename = getStringCopy(score_tape_filename);
+  data->score_entry = *score_entry;
 
   return data;
 }
@@ -9471,6 +9492,7 @@ 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);
 }
@@ -9582,6 +9604,13 @@ static void HandleResponse_ApiAddScore(struct HttpResponse *response,
   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)
@@ -9597,6 +9626,8 @@ static void Emscripten_ApiAddScore_Loaded(unsigned handle, void *data_raw,
   else
   {
     Error("server response too large to handle (%d bytes)", size);
+
+    HandleFailure_ApiAddScore(data_raw);
   }
 
   FreeThreadData_ApiAddScore(data_raw);
@@ -9607,6 +9638,8 @@ static void Emscripten_ApiAddScore_Failed(unsigned handle, void *data_raw,
 {
   Error("server failed to handle request: %d %s", code, status);
 
+  HandleFailure_ApiAddScore(data_raw);
+
   FreeThreadData_ApiAddScore(data_raw);
 }
 
@@ -9649,6 +9682,8 @@ static void ApiAddScore_HttpRequestExt(struct HttpRequest *request,
   {
     Error("HTTP request failed: %s", GetHttpError());
 
+    HandleFailure_ApiAddScore(data_raw);
+
     return;
   }
 
@@ -9658,6 +9693,8 @@ static void ApiAddScore_HttpRequestExt(struct HttpRequest *request,
          response->status_code,
          response->status_text);
 
+    HandleFailure_ApiAddScore(data_raw);
+
     return;
   }
 
@@ -9679,12 +9716,16 @@ static int ApiAddScoreThread(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_ApiAddScore_HttpRequest(request, data_raw);
 #else
   ApiAddScore_HttpRequest(request, response, data_raw);
 #endif
 
+  program.api_thread_count--;
+
   checked_free(request);
   checked_free(response);
 
@@ -9705,7 +9746,11 @@ static void ApiAddScoreAsThread(int nr, boolean tape_saved,
 void SaveServerScore(int nr, boolean tape_saved)
 {
   if (!runtime.use_api_server)
+  {
+    PrepareScoreTapesForUpload(leveldir_current->subdir);
+
     return;
+  }
 
   ApiAddScoreAsThread(nr, tape_saved, NULL);
 }
@@ -10041,6 +10086,10 @@ 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"
@@ -10057,10 +10106,22 @@ static struct TokenInfo server_setup_tokens[] =
     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[] =
@@ -10857,12 +10918,16 @@ static void setSetupInfoToDefaults_AutoSetup(struct SetupInfo *si)
 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)
@@ -11216,6 +11281,7 @@ void LoadSetup_ServerSetup(void)
   {
     // player UUID does not yet exist in setup file
     setup.player_uuid = getStringCopy(getUUID());
+    setup.player_version = 2;
 
     SaveSetup_ServerSetup();
   }
@@ -11913,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 :
@@ -11920,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"))