Explorar o código

update pvp position parsing

websocket data is only fetched once, then the rest of the components will parse the game's ws_info string
jblanked hai 8 meses
pai
achega
af0c15303d
Modificáronse 4 ficheiros con 163 adicións e 90 borrados
  1. 126 89
      game/enemy.c
  2. 8 0
      game/game.c
  3. 24 1
      game/player.c
  4. 5 0
      game/player.h

+ 126 - 89
game/enemy.c

@@ -433,111 +433,148 @@ static void enemy_collision(Entity *self, Entity *other, GameManager *manager, v
     }
 }
 
-static void enemy_pvp_position(GameContext *game_context, EntityContext *enemy, Entity *self)
+static void enemy_pvp_position(GameManager *manager, EntityContext *enemy, Entity *self)
 {
-    if (!game_context || !enemy || !self)
+    if (!manager || !enemy || !self)
     {
-        FURI_LOG_E("Game", "PVP position: Invalid parameters");
+        FURI_LOG_E("Game", "enemy_pvp_position: Invalid parameters");
         return;
     }
 
-    if (game_context->fhttp->last_response != NULL && strlen(game_context->fhttp->last_response) > 0)
+    GameContext *game_context = game_manager_game_context_get(manager);
+    if (!game_context)
     {
-        // for debugging
-        // save_char("received_pvp_position", game_context->fhttp->last_response);
-        // parse the response and set the enemy position
-        /* expected response:
-        {
-            "u": "JBlanked",
-            "xp": 37743,
-            "h": 207,
-            "ehr": 0.7,
-            "eat": 127.5,
-            "d": 2,
-            "s": 1,
-            "sp": {
-                "x": 381.0,
-                "y": 192.0
-            }
-        }
-        */
+        FURI_LOG_E("Game", "enemy_pvp_position: Failed to get GameContext");
+        return;
+    }
 
-        // FuriStrings are probably safer but we already last_response as a char*
+    if (!game_context->ws_info || furi_string_size(game_context->ws_info) == 0)
+    {
+        return;
+    }
 
-        // match username
-        char *u = get_json_value("u", game_context->fhttp->last_response);
-        if (!u || !is_str(u, enemy->username))
-        {
-            if (u)
-                free(u);
-            return;
+    // parse the response and set the enemy position
+    /* expected response:
+    {
+        "u": "JBlanked",
+        "xp": 37743,
+        "h": 207,
+        "ehr": 0.7,
+        "eat": 127.5,
+        "d": 2,
+        "s": 1,
+        "sp": {
+            "x": 381.0,
+            "y": 192.0
         }
+    }
+    */
 
-        // we need the health, elapsed attack timer, direction, and position
-        char *h = get_json_value("h", game_context->fhttp->last_response);
-        char *eat = get_json_value("eat", game_context->fhttp->last_response);
-        char *d = get_json_value("d", game_context->fhttp->last_response);
-        char *sp = get_json_value("sp", game_context->fhttp->last_response);
-        char *x = get_json_value("x", sp);
-        char *y = get_json_value("y", sp);
+    // match username
+    FuriString *u = get_json_value_furi("u", game_context->ws_info);
+    if (!u)
+    {
+        FURI_LOG_E("Game", "enemy_pvp_position: Failed to get username");
+        return;
+    }
+    // check if the username matches
+    if (!is_str(furi_string_get_cstr(u), enemy->username))
+    {
+        furi_string_free(u);
+        return;
+    }
+    furi_string_free(u);
+
+    // we need the health, elapsed attack timer, direction, xp, and position
+    FuriString *h = get_json_value_furi("h", game_context->ws_info);
+    FuriString *eat = get_json_value_furi("eat", game_context->ws_info);
+    FuriString *d = get_json_value_furi("d", game_context->ws_info);
+    FuriString *xp = get_json_value_furi("xp", game_context->ws_info);
+    FuriString *sp = get_json_value_furi("sp", game_context->ws_info);
+    FuriString *x = get_json_value_furi("x", sp);
+    FuriString *y = get_json_value_furi("y", sp);
+
+    if (!h || !eat || !d || !sp || !x || !y || !xp)
+    {
+        if (h)
+            furi_string_free(h);
+        if (eat)
+            furi_string_free(eat);
+        if (d)
+            furi_string_free(d);
+        if (sp)
+            furi_string_free(sp);
+        if (x)
+            furi_string_free(x);
+        if (y)
+            furi_string_free(y);
+        if (xp)
+            furi_string_free(xp);
+        return;
+    }
 
-        if (!h || !eat || !d || !sp || !x || !y)
+    // set enemy info
+    enemy->health = (float)atoi(furi_string_get_cstr(h)); // h is an int
+    if (enemy->health <= 0)
+    {
+        enemy->health = 0;
+        enemy->state = ENTITY_DEAD;
+        entity_pos_set(self, (Vector){-100, -100});
+        furi_string_free(h);
+        furi_string_free(eat);
+        furi_string_free(d);
+        furi_string_free(sp);
+        furi_string_free(x);
+        furi_string_free(y);
+        PlayerContext *player_context = entity_context_get(game_context->player);
+        if (player_context)
         {
-            if (h)
-                free(h);
-            if (eat)
-                free(eat);
-            if (d)
-                free(d);
-            if (sp)
-                free(sp);
-            if (x)
-                free(x);
-            if (y)
-                free(y);
-            free(u);
-            return;
+            save_player_context(player_context);
+            furi_delay_ms(100);
+            game_manager_game_stop(manager);
         }
+        return;
+    }
 
-        // set enemy info
-        enemy->health = (float)atoi(h);
-        enemy->elapsed_attack_timer = (float)atof_(eat);
-        switch (atoi(d))
-        {
-        case 0:
-            enemy->direction = ENTITY_LEFT;
-            break;
-        case 1:
-            enemy->direction = ENTITY_RIGHT;
-            break;
-        case 2:
-            enemy->direction = ENTITY_UP;
-            break;
-        case 3:
-            enemy->direction = ENTITY_DOWN;
-            break;
-        default:
-            enemy->direction = ENTITY_RIGHT;
-            break;
-        }
+    enemy->elapsed_attack_timer = atof_furi(eat);
 
-        Vector new_pos = (Vector){
-            .x = (float)atof_(x),
-            .y = (float)atof_(y),
-        };
+    switch (atoi(furi_string_get_cstr(d)))
+    {
+    case 0:
+        enemy->direction = ENTITY_LEFT;
+        break;
+    case 1:
+        enemy->direction = ENTITY_RIGHT;
+        break;
+    case 2:
+        enemy->direction = ENTITY_UP;
+        break;
+    case 3:
+        enemy->direction = ENTITY_DOWN;
+        break;
+    default:
+        enemy->direction = ENTITY_RIGHT;
+        break;
+    }
 
-        // set enemy position
-        entity_pos_set(self, new_pos);
+    enemy->xp = (atoi)(furi_string_get_cstr(xp)); // xp is an int
+    enemy->level = player_level_iterative_get(enemy->xp);
 
-        // free the strings
-        free(h);
-        free(eat);
-        free(d);
-        free(sp);
-        free(x);
-        free(y);
-        free(u);
-    }
+    Vector new_pos = (Vector){
+        .x = atof_furi(x),
+        .y = atof_furi(y),
+    };
+
+    // set enemy position
+    entity_pos_set(self, new_pos);
+
+    // free the strings
+    furi_string_free(h);
+    furi_string_free(eat);
+    furi_string_free(d);
+    furi_string_free(sp);
+    furi_string_free(x);
+    furi_string_free(y);
 }
 
 // Enemy update function
@@ -564,7 +601,7 @@ static void enemy_update(Entity *self, GameManager *manager, void *context)
     if (game_context->game_mode == GAME_MODE_PVP)
     {
         // update enemy position
-        enemy_pvp_position(game_context, enemy_context, self);
+        enemy_pvp_position(manager, enemy_context, self);
     }
     else
     {

+ 8 - 0
game/game.c

@@ -98,6 +98,9 @@ static void game_start(GameManager *game_manager, void *ctx)
             game_manager_game_stop(game_manager); // end game early
             return;
         }
+
+        game_context->ws_info = furi_string_alloc();
+        furi_string_reserve(game_context->ws_info, sizeof(game_context->fhttp->last_response));
     }
 }
 
@@ -138,6 +141,11 @@ static void game_stop(void *ctx)
             remove_player_from_lobby(game_context->fhttp);    // remove player from lobby
             flipper_http_free(game_context->fhttp);
         }
+        if (game_context->ws_info)
+        {
+            furi_string_free(game_context->ws_info);
+            game_context->ws_info = NULL;
+        }
     }
 
     PlayerContext *player_context = malloc(sizeof(PlayerContext));

+ 24 - 1
game/player.c

@@ -56,7 +56,7 @@ static Level *player_next_level(GameManager *manager)
 }
 
 // Update player stats based on XP using iterative method
-static int player_level_iterative_get(uint32_t xp)
+int player_level_iterative_get(uint32_t xp)
 {
     int level = 1;
     uint32_t xp_required = 100; // Base XP for level 2
@@ -70,6 +70,26 @@ static int player_level_iterative_get(uint32_t xp)
     return level;
 }
 
+// Fetch last_response once then store it in ws_info to parse later
+static void player_ws_info_update(GameManager *manager)
+{
+    GameContext *game_context = game_manager_game_context_get(manager);
+    if (!game_context || !game_context->fhttp)
+    {
+        FURI_LOG_E(TAG, "Failed to get game context or FlipperHTTP");
+        return;
+    }
+    if (!game_context->ws_info || !game_context->fhttp->last_response)
+    {
+        return;
+    }
+    // validate response
+    if (strlen(game_context->fhttp->last_response) > 0)
+    {
+        furi_string_set_str(game_context->ws_info, game_context->fhttp->last_response);
+    }
+}
+
 void player_spawn(Level *level, GameManager *manager)
 {
     if (!level || !manager)
@@ -256,6 +276,9 @@ static void player_update(Entity *self, GameManager *manager, void *context)
     // update websocket player context
     if (game_context->game_mode == GAME_MODE_PVP)
     {
+        // load the websocket info
+        player_ws_info_update(manager);
+
         // if pvp, end the game if the player is dead
         if (player->health <= 0)
         {

+ 5 - 0
game/player.h

@@ -43,6 +43,8 @@ typedef struct
     char message[64];           // Message to display when interacting with the entity
     bool is_user;               // Flag to indicate if the entity is a live player or not
     char username[32];          // entity username
+    uint32_t xp;                // experience points
+    uint32_t level;             // entity level
 } EntityContext;
 
 typedef struct
@@ -119,6 +121,8 @@ typedef struct
     uint8_t tutorial_step;
     //
     FlipperHTTP *fhttp;
+    //
+    FuriString *ws_info;
 } GameContext;
 
 typedef struct
@@ -133,3 +137,4 @@ typedef struct
 extern const EntityDescription player_desc;
 void player_spawn(Level *level, GameManager *manager);
 SpriteContext *sprite_context_get(const char *name);
+int player_level_iterative_get(uint32_t xp);