Lost Data When Updating PlayerProfileDataMap Multiple Times in One Flow - How to Avoid It

:warning: Lost Data When Updating PlayerProfileDataMap Twice in One Flow

Hey creators! :waving_hand:

I wanted to share a subtle bug I ran into while using persistent weak_map data like PlayerProfileDataMap. If you modify a player’s data and then later update it again using the same base data, you can accidentally overwrite earlier changes, even from other functions. The key point is: only the last update you make will persist; any previous ones will be lost.


:brain: The Problem

Let’s say you have this:

var PlayerProfileDataMap:weak_map(player, player_profile_data) = map{}

And this function to add score:

AddScore(Player:player, Amount:int):void = 
    if (Data := PlayerProfileDataMap[Player]):
        set PlayerProfileDataMap[Player] = player_profile_data:
            MakePlayerProfileData<constructor>(Data)
            Score := Data.Score + Amount

Then in another function:

HandleButtonPress(Player:player):void =
    if (Data := PlayerProfileDataMap[Player]):
        AddScore(Player, 100) # <-- Problem here
        if:
            set PlayerProfileDataMap[Player] = player_profile_data:
                MakePlayerProfileData<constructor>(Data)
                Level := Data.Level + 1

:red_circle: What happens:
AddScore writes an updated score into the map, but immediately after, the second set uses the same original Data, overwriting the map with stale information. This means the score increase is lost, because only the last set call’s data is saved.


:white_check_mark: The Solutions

You don’t need to rewrite or merge the data manually. Just make sure the AddScore call happens after the last overwrite, or outside/before any conditional assignment using Data.

Option 1: Move the call after the set

HandleButtonPress(Player:player):void =
    if (Data := PlayerProfileDataMap[Player]):
        if:
            set PlayerProfileDataMap[Player] = player_profile_data:
                MakePlayerProfileData<constructor>(Data)
                Level := Data.Level + 1
        AddScore(Player, 100) # ✅ Now this change won't be overwritten

Or Option 2: Move the call outside the Data scope

HandleButtonPress(Player:player):void =
    AddScore(Player, 100) # ✅ Now this change won't be overwritten
    if (Data := PlayerProfileDataMap[Player]):
        if:
            set PlayerProfileDataMap[Player] = player_profile_data:
                MakePlayerProfileData<constructor>(Data)
                Level := Data.Level + 1

:light_bulb: Key takeaway

  • When you modify PlayerProfileDataMap multiple times in a single logical flow, only the last update will be saved.
  • Earlier updates done with a stale reference will be overwritten and lost.
  • To prevent losing data, make sure function calls that update persistent data occur after all other writes, or outside the Data conditional block.

I hope this helps someone avoid this tricky problem that took me hours to figure out on my map! :sweat_smile:

2 Likes