Moud

Player data and erasure#

Players can download what Moud keeps about them and delete their account from the website. Both reach into your game: the download includes what your game saved under the player, and deleting the account wipes it. This page says what Moud does on its own and what is left to your scripts.

Key saves by player.id#

Moud finds a player's data in your stores by their id. Any key that contains player.id, in any store or ordered store and on every leaderboard, counts as theirs:

luau
local saves = store("players")
saves:set(player.id, { coins = 10 })              -- found
saves:set("inventory:" .. player.id, { "sword" })  -- found
saves:set(player.name, { coins = 10 })            -- not found, a name is not an id
  • Use player.id, not the name. A name changes and is not unique over time, and Moud cannot tell that a key holding a name belongs to anyone.
  • The id can sit anywhere in the key, so prefixes and suffixes such as inventory:<id> or <id>:pets work.
  • A value that mentions the player, such as a guild's member list saved under the guild's name, is not found. Clean those up in dataErased, below.

What happens when an account is deleted#

Under a fleet, when a player deletes their Moud account:

  1. Every store row and leaderboard score whose key contains their id is deleted, in every game, along with any session lock on those keys. Their badges are removed and each badge's count goes down by one.
  2. Each fleet of a game they played is told, and every running server of it fires game.players.dataErased with the player's id.
  3. An open store:session on one of their keys is let go without saving, so the server does not write the save back when the session ends.

Moud keeps a record that an erasure ran and when, without the account or the player id.

game.players.dataErased#

Fires on the server with the id of a player whose account was deleted. Use it for data Moud cannot find on its own: values that mention the player, memory stores, and anything you sent to your own website with http.

luau
-- server
local guilds = store("guilds")

game.players.dataErased:connect(function(playerId)
    for _, name in guilds:keys("", 1000) do
        guilds:update(name, function(guild)
            if guild and guild.members then
                guild.members[playerId] = nil
            end
            return guild
        end)
    end
end)
  • The id is the same text player.id gives, so compare it the same way.
  • The signal only fires on servers running at the time. A server that starts later never hears about it, which is why the rows themselves are deleted by Moud rather than left to the script.
  • It does not fire in the editor or on a server without a fleet, because there is no account to delete there.

What a player's download holds#

The JSON a player downloads from their account page has a games section with, for every game:

  • each store row whose key contains their id, with the store name, key and value
  • each leaderboard score, with the board name and its window (all, day:<date> or week:<date>)
  • each badge they earned, with its name and when

So anything you save under player.id is something the player can read. Keep secrets such as anti-cheat notes out of keys that hold the player's id, or expect them to be read.