Skip to main content

HasSaveSlotsDataStore

This item only works when running on the server. Server

The save slot system over a DataStore, with no Player attached.

This is the whole slot model -- the roster, the per-slot stores, selection, create/delete/reset, export/import, ephemeral slots and playtime -- expressed against an injected datastore rather than against a bound player. HasSaveSlots is the binder that owns one of these for a live player and supplies the player-shaped parts (replication, remotes, teleport data, summary providers).

Splitting it out is what makes a slot reachable for a player who is not in this server: admin tooling borrows that player's datastore (see PlayerDataStoreHandle) and builds one of these over it, getting the same slot semantics with no Player instance in sight.

The slot roster is still modelled as Folders with attributes, because that representation is what the client reads. Offline, those folders simply live in an unparented container and replicate to nobody.

INFO

Constructed with a promise of a datastore rather than a datastore, so every method can gate on the same load promise the player path always gated on. Callers do not have to wait before using it.

Types

HasSaveSlotsDataStoreOptions

interface HasSaveSlotsDataStoreOptions {
ActiveSlotIdValueObject<SlotId?>
LastActiveSlotIdValueObject<SlotId?>
ActiveTransferableEphemeralKeyValueObject<string?>
MaxSlotCountValueObject<number>
SharedDataStoreServiceany--

SaveSlotSharedDataStoreService

PromisePreSelect((SlotId) → Promise<boolean>)?--

veto hook, defaults to allowing every selection

UserIdnumber?--

identity for generated share codes

UserNamestring?--

identity for generated share codes

TrackPlaytimeboolean?--

accrue play sessions from selection changes, defaults to true

}

The state and collaborators this class cannot derive from a datastore alone.

The four value objects are borrowed, never owned: the player path passes the ones backed by replicated player attributes, so writing them replicates, while offline tooling passes detached ones. Either way this class only reads and writes them, and never destroys them.

Functions

new

HasSaveSlotsDataStore.new(
promiseDataStorePromise<DataStore>,
) → HasSaveSlotsDataStore

Builds the slot system over a datastore that may not have loaded yet.

GetSlotFolder

HasSaveSlotsDataStore.GetSlotFolder(
slotIdSlotId?
) → Folder?

Returns the folder holding the slot's replicated metadata, or nil when there is no such slot. The folder is owned by this object; do not parent or destroy it.

GetActiveSlotId

HasSaveSlotsDataStore.GetActiveSlotId(selfHasSaveSlotsDataStore) → SlotId?

Returns the active slot's id, or nil when nothing is selected.

GetLastActiveSlotId

HasSaveSlotsDataStore.GetLastActiveSlotId(selfHasSaveSlotsDataStore) → SlotId?

Returns the slot the player is on, or would resume on: the active slot when one is selected, and the persisted "Continue" target otherwise. The synchronous twin of HasSaveSlotsDataStore.PromiseLastActiveSlotId.

This is the one to read when acting on "their current slot" without a live session. Freshly opened against a datastore, nothing is selected yet -- the stored pointer loads as the last-active slot, and HasSaveSlotsDataStore.GetActiveSlotId stays nil until something selects.

IsActiveSlotEphemeral

HasSaveSlotsDataStore.IsActiveSlotEphemeral(selfHasSaveSlotsDataStore) → boolean

Returns whether the active slot is an ephemeral (session-only) one. False when nothing is active.

GetSlotMetadata

HasSaveSlotsDataStore.GetSlotMetadata(
slotIdSlotId?
) → SaveSlotMetadata?

Returns the slot's metadata, or nil when there is no such slot.

GetActiveSlotMetadata

HasSaveSlotsDataStore.GetActiveSlotMetadata(selfHasSaveSlotsDataStore) → SaveSlotMetadata?

Returns the active slot's metadata, or nil when nothing is selected. Unlike HasSaveSlotsDataStore.GetSlotList this does see an ephemeral slot, which is the only way to read the metadata of a session in progress.

GetSlotList

HasSaveSlotsDataStore.GetSlotList(selfHasSaveSlotsDataStore) → {SaveSlotMetadata}

Returns the persisted slots, ordered by index. Ephemeral slots are excluded, matching SaveSlotDataService.GetSlotList -- read the active slot directly with HasSaveSlotsDataStore.GetActiveSlotMetadata to see one.

Ordered because the underlying map is not: an unordered listing would shuffle between calls, and the tooling reading this prints it.

GetSlotIdFromIndex

HasSaveSlotsDataStore.GetSlotIdFromIndex(
slotIndexnumber
) → SlotId?

Returns the id of the persisted slot at the given index, or nil when there is none. Ephemeral slots are never addressable by index.

GetSlotStore

HasSaveSlotsDataStore.GetSlotStore(
slotIdSlotId
) → DataStoreStage

Returns the DataStoreStage backing the slot's saved data. For the default slot this is the player's root store; for an ephemeral slot it is an in-memory store.

ObserveActiveSlotStoreBrio

HasSaveSlotsDataStore.ObserveActiveSlotStoreBrio(selfHasSaveSlotsDataStore) → Observable.Observable<Brio.Brio<DataStoreStage.DataStoreStage>>

Observes the DataStoreStage for the active slot as a Brio

PromiseActiveSlotStore

HasSaveSlotsDataStore.PromiseActiveSlotStore(selfHasSaveSlotsDataStore) → Promise.Promise<DataStoreStage.DataStoreStage?>

Returns the DataStoreStage for the active slot

PromiseSlotsLoaded

HasSaveSlotsDataStore.PromiseSlotsLoaded(selfHasSaveSlotsDataStore) → Promise.Promise<any>

Promises that all slots have loaded

PromiseHasSlot

HasSaveSlotsDataStore.PromiseHasSlot(
slotIdSaveSlotData.SlotId?
) → Promise.Promise<boolean>

Returns whether the slot with the given ID exists

PromiseSelectSlot

HasSaveSlotsDataStore.PromiseSelectSlot(
slotIdSaveSlotData.SlotId
) → Promise.Promise<any>

Selects the slot with the given ID

PromiseDeselectSlot

HasSaveSlotsDataStore.PromiseDeselectSlot(selfHasSaveSlotsDataStore) → Promise.Promise<()>

Clears the active slot selection, returning the player to a no-slot state -- the counterpart to HasSaveSlotsDataStore.PromiseSelectSlot, backing a "back to menu" affordance. The active slot's progress is flushed first (mirroring the save PromiseSelectSlot runs when switching away), and the last-active slot is remembered, so HasSaveSlotsDataStore.PromiseSelectLastSaveSlot can resume it later. A no-op when no slot is active.

PromiseCreateSlot

HasSaveSlotsDataStore.PromiseCreateSlot(
slotIndexnumber,
metadataSaveSlotCreateMetadata?
) → Promise.Promise<SaveSlotData.SlotId>

Creates a slot at the given index

PromiseExportSlot

HasSaveSlotsDataStore.PromiseExportSlot(
slotIdSlotId,
allowMainSlotboolean?--

defaults to false

) → Promise<SaveSlotExportUtils.SaveSlotExport>

Exports a slot's saved data into a plain, serializable SaveSlotExportUtils.SaveSlotExport. Rejects the main/default slot by default: its store is the player's shared root datastore, so exporting it would leak the SaveSlots system data and universe-scoped global data living alongside it. Only isolated non-main slot substores are exportable.

allowMainSlot opts out of that refusal for trusted admin tooling (see SaveSlotCmdrService). The SaveSlots system data is always stripped from the result, so the export never carries the slot roster or the other slots' saved data. Universe-scoped global data sharing the root store is indistinguishable from the main slot's own data and is still carried, which is why this is not exposed through SaveSlotService.

PromiseImportSlot

HasSaveSlotsDataStore.PromiseImportSlot(
exportSaveSlotExportUtils.SaveSlotExport,
targetSlotIndexnumber?--

defaults to the lowest free non-main index

) → Promise<SlotId>

Imports an exported slot into a fresh slot, seeding the new slot's store with the exported data. The destination defaults to the lowest free non-main index; passing targetSlotIndex puts the import at that index instead, which must be free (delete or reset what is there first). Never uses the main/default index either way -- importing onto the shared root store would wipe the player's global data. Resolves to the new slot's id. Rejects a malformed export, a taken or main-slot destination, or when no non-main index is free.

PromiseSaveSlotToSharedDataStore

HasSaveSlotsDataStore.PromiseSaveSlotToSharedDataStore(
slotIdSlotId,
keystring,
allowMainSlotboolean?--

defaults to false, see HasSaveSlotsDataStore.PromiseExportSlot

) → Promise<boolean>

Exports a non-main slot (see HasSaveSlotsDataStore.PromiseExportSlot) and writes it to the shared save slot store under the given key, tagged as a share code (see SaveSlotExportUtils.Kind) so the teleport arrival path will not load it.

PromiseImportSlotFromSharedDataStore

HasSaveSlotsDataStore.PromiseImportSlotFromSharedDataStore(
keystring
) → Promise<SlotId>

Reads a share code's export from the shared save slot store and imports it into a fresh non-main slot (see HasSaveSlotsDataStore.PromiseImportSlot). Rejects when no export is stored under the key, or when the entry there is a transfer snapshot rather than a share code -- a transfer key is replicated to every client (see the arrival path in HasSaveSlotsDataStore.PromiseSelectTransferableEphemeralSlot), so redeeming one into a kept slot would turn a public handle into a permanent copy of someone else's save.

PromiseSelectTransferableEphemeralSlot

HasSaveSlotsDataStore.PromiseSelectTransferableEphemeralSlot(
keystring
) → Promise<SlotId>

Resumes a transfer: loads the snapshot stored under the given shared-store key into a fresh ephemeral slot and selects it, keeping the key so the next teleport carries the slot forward again (see the transferable-ephemeral teleport provider in SaveSlotService). Like every ephemeral slot it is never persisted, stays out of the slot list, and is torn down on deselect.

WARNING

The key comes from the arriving client's teleport band, so this loads whatever a client asks for. Only entries written as transfers are accepted -- a share code, which players hand to each other, is refused here and redeemed through HasSaveSlotsDataStore.PromiseImportEphemeralSaveSlotFromCode instead. Entries predating that tag are refused too; see SaveSlotExportUtils.canLoadAs.

PromiseImportEphemeralSaveSlotFromCode

HasSaveSlotsDataStore.PromiseImportEphemeralSaveSlotFromCode(
codestring
) → Promise<SlotId>

Redeems a share code into a fresh transferable ephemeral slot and selects it (see HasSaveSlotsDataStore.PromiseSelectTransferableEphemeralSlot for what that slot is).

The slot transfers onward under a freshly minted key rather than the code it came from: the transfer key is handed to the client to carry across teleports, so reusing the code as that key would publish the code and hand every holder of it a slot the arrival path would load. The code entry is left untouched, so the same code still redeems for whoever else holds it.

PromiseBuildEphemeralTransferSlice

HasSaveSlotsDataStore.PromiseBuildEphemeralTransferSlice(selfHasSaveSlotsDataStore) → Promise<{[string]any}?>

Builds this player's teleport slice for a transferable ephemeral slot: re-saves the active slot's current live data to the shared store under its key and returns a slice carrying that key. Resolves nil when the active slot is not a transferable ephemeral slot. A failed re-save degrades to nil so a teleport is never blocked (the destination then re-loads the last saved state). Asynchronous -- it is consumed through TeleportDataService.PromiseBuildTeleportData.

SetCodeGenerator

HasSaveSlotsDataStore.SetCodeGenerator() → ()

Overrides the share-code generator for this player's exports (see SaveSlotCodeUtils.CodeGenerator). Games inject a custom format; the default is SaveSlotCodeUtils.generateDefaultCode. Usually set game-wide via SaveSlotService.SetCodeGenerator rather than per player.

PromiseExportSaveSlotToCode

HasSaveSlotsDataStore.PromiseExportSaveSlotToCode(
slotIdSlotId?,--

defaults to the active slot

allowMainSlotboolean?--

defaults to false, see HasSaveSlotsDataStore.PromiseExportSlot

) → Promise<string>

Exports a slot to the shared store under a fresh generated code and resolves to that code. The code is a shareable handle other sessions load with HasSaveSlotsDataStore.PromiseImportEphemeralSaveSlotFromCode. Defaults to the active slot. Refuses the main slot unless allowMainSlot is set (see HasSaveSlotsDataStore.PromiseExportSlot). The code format comes from the configured generator (see HasSaveSlotsDataStore.SetCodeGenerator).

PromiseExportSaveSlotToJson

HasSaveSlotsDataStore.PromiseExportSaveSlotToJson(
slotIdSlotId?,--

defaults to the active slot

allowMainSlotboolean?--

defaults to false, see HasSaveSlotsDataStore.PromiseExportSlot

) → Promise<string>

Exports a slot as a raw JSON string (no shared store), for direct inspection or attaching to a bug report. Defaults to the active slot. Refuses the main slot unless allowMainSlot is set (see HasSaveSlotsDataStore.PromiseExportSlot).

PromiseDuplicateSlot

HasSaveSlotsDataStore.PromiseDuplicateSlot(
slotIdSaveSlotData.SlotId
) → Promise.Promise<SaveSlotData.SlotId>

Duplicates the slot with the given ID into a new slot at the lowest free index, copying its saved data and accrued playtime. Resolves to the new slot's id. The copy is not selected, its timestamps and session counters start fresh, and its name is suffixed with " (Copy)". Rejects when the source slot is missing or every index is in use.

An ephemeral slot may be duplicated: the copy is a real, persisted slot seeded with the ephemeral slot's live in-memory data, which is how a throwaway session is turned into a save. It keeps the source's name unsuffixed (the copy is the first real slot for that session, not a second copy of an existing save) and, like any duplicate, is not selected -- see HasSaveSlotsDataStore.PromisePersistEphemeralSlot for the version that continues play on the new slot.

PromisePersistEphemeralSlot

HasSaveSlotsDataStore.PromisePersistEphemeralSlot(
slotIdSlotId?--

defaults to the active slot

) → Promise<SlotId>

Turns an ephemeral slot into a real save: duplicates it into a fresh persisted slot at the lowest free index (see HasSaveSlotsDataStore.PromiseDuplicateSlot) and selects that slot, so play continues on data that is now being written. Defaults to the active slot, which in practice is the only ephemeral slot there is -- one stops existing the moment it stops being active. Resolves to the new slot's id.

The copy is taken from the ephemeral slot's live in-memory data at the moment this runs, and selecting the new slot retires the ephemeral one, so anything written to the old store between the copy and the selection is dropped. Rejects when no slot is active, the slot is missing, the slot is not ephemeral, or every index is in use.

PromiseDeleteSlot

HasSaveSlotsDataStore.PromiseDeleteSlot(
slotIdSaveSlotData.SlotId
) → Promise.Promise<any>

Deletes the slot with the given ID. Deleting an ephemeral slot ends that session -- it is deselected and retired along with its in-memory store -- rather than being refused for being the active slot.

PromiseDeleteAllSlots

HasSaveSlotsDataStore.PromiseDeleteAllSlots(selfHasSaveSlotsDataStore) → Promise.Promise<any>

Deletes every slot for the player and clears the active/last-active selection, resetting the player to a fresh state. Resolves once all slots are gone.

PromiseResetSlot

HasSaveSlotsDataStore.PromiseResetSlot(
slotIdSaveSlotData.SlotId
) → Promise.Promise<SaveSlotData.SlotId>

Resets the slot with the given id to a fresh empty one -- equivalent to deleting the slot and creating a new one at the same index. The slot keeps its index and name; its saved data and metadata (timestamps) start fresh. Resolves to the new slot id.

When the reset slot is the active slot, the selection clears and then reselects the fresh slot: everything bound to HasSaveSlotsDataStore.ObserveActiveSlotStoreBrio tears down as the selection clears and rebuilds against the empty store on reselect, so consumers reset reactively without wiping their own state. A non-active slot is left unselected, and its "Continue" pointer (when it was the last-active slot) is carried across to the fresh id so the reset slot stays resumable. Rejects when the slot is missing.

PromiseResetActiveSlot

HasSaveSlotsDataStore.PromiseResetActiveSlot(selfHasSaveSlotsDataStore) → Promise.Promise<SaveSlotData.SlotId?>

Resets the active slot to a fresh empty one -- see HasSaveSlotsDataStore.PromiseResetSlot. The slot keeps its index and name; its saved data and metadata (timestamps) start fresh, and the fresh slot stays selected. Resolves to the new slot id, or nil when no slot is active.

PromiseSetSlotMetadata

HasSaveSlotsDataStore.PromiseSetSlotMetadata(
slotIdSaveSlotData.SlotId,
dataSaveSlotData.SaveSlotMetadata
) → Promise.Promise<any>

Sets the metadata for the slot with the given ID

PromiseGetSlotMetadata

HasSaveSlotsDataStore.PromiseGetSlotMetadata(
slotIdSaveSlotData.SlotId
) → Promise.Promise<SaveSlotData.SaveSlotMetadata?>

Gets the metadata for the slot with the given ID

PromiseSlotIdFromIndex

HasSaveSlotsDataStore.PromiseSlotIdFromIndex(
slotIndexnumber
) → Promise.Promise<SaveSlotData.SlotId?>

Returns the slot ID from the given index

PromiseLastActiveSlotId

HasSaveSlotsDataStore.PromiseLastActiveSlotId(selfHasSaveSlotsDataStore) → Promise.Promise<SaveSlotData.SlotId?>

Gets the last active slot ID

PromiseSelectLastSaveSlot

HasSaveSlotsDataStore.PromiseSelectLastSaveSlot(selfHasSaveSlotsDataStore) → Promise.Promise<SaveSlotData.SlotId?>

Selects the player's last active slot if one still exists, resolving to the selected slot id -- or nil when there is no slot to continue on. Backs a "Continue" affordance that every save-slot consumer tends to need.

PromiseSelectNewSaveSlot

HasSaveSlotsDataStore.PromiseSelectNewSaveSlot(selfHasSaveSlotsDataStore) → Promise.Promise<SaveSlotData.SlotId?>

Creates a new slot at the lowest free index and selects it, resolving to the new slot id -- or nil when every slot is already in use. Backs a "New Game" affordance.

PromiseSelectEphemeralSlot

HasSaveSlotsDataStore.PromiseSelectEphemeralSlot(
metadataSaveSlotCreateMetadata?--

optional SlotName/Summary for the in-memory slot

) → Promise<SlotId>

Creates a fresh ephemeral slot and selects it, resolving to its id. An ephemeral slot is selectable and active exactly like a real one -- it drives HasSaveSlotsDataStore.ObserveActiveSlotStoreBrio, summaries, and playtime the same way, and its metadata replicates to the client like any other slot's, so UI can render the active session's name and summary -- but it is never persisted: no metadata is written, its data store is in-memory, and it is torn down the moment it stops being the active slot. It is also excluded from the save list (SaveSlotDataService.GetSlotList / SaveSlotDataService.ObserveSlotList), so it never shows up as something the player can return to. Selecting it never disturbs the persisted active-slot pointer or the "Continue" target, so the real slot the player came from resumes untouched afterward. Backs a throwaway session (e.g. exploring a lobby) that must leave no trace on save data.

_setupPlaytimeTracking

HasSaveSlotsDataStore._setupPlaytimeTracking(selfHasSaveSlotsDataStore) → ()

Accrues per-slot playtime automatically. A "session" spans the time a slot is the active slot: selecting a slot begins one (bumping PlayCount), and deselecting, switching, or unbinding ends it. Elapsed wall time is folded into the slot's TimePlayed from a datastore saving callback, so it persists on exactly the cadence the data is written -- always fresh at save time, with no separate timer -- and again at each session boundary.

Skipped entirely when the owner opts out (TrackPlaytime = false), which is what offline admin tooling wants: editing a slot from a console is not someone playing it, and no session is ever begun, so _flushPlaytime stays a no-op for the object's whole life.

Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "Builds the slot system over a datastore that may not have loaded yet.",
            "params": [
                {
                    "name": "promiseDataStore",
                    "desc": "",
                    "lua_type": "Promise<DataStore>"
                },
                {
                    "name": "options",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStoreOptions"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 144,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetSlotFolder",
            "desc": "Returns the folder holding the slot's replicated metadata, or nil when there is no such slot.\nThe folder is owned by this object; do not parent or destroy it.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SlotId?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Folder?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 197,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetActiveSlotId",
            "desc": "Returns the active slot's id, or nil when nothing is selected.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "SlotId?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 209,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetLastActiveSlotId",
            "desc": "Returns the slot the player is on, or would resume on: the active slot when one is selected, and\nthe persisted \"Continue\" target otherwise. The synchronous twin of\n[HasSaveSlotsDataStore.PromiseLastActiveSlotId].\n\nThis is the one to read when acting on \"their current slot\" without a live session. Freshly opened\nagainst a datastore, nothing is selected yet -- the stored pointer loads as the last-active slot,\nand [HasSaveSlotsDataStore.GetActiveSlotId] stays nil until something selects.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "SlotId?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 224,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "IsActiveSlotEphemeral",
            "desc": "Returns whether the active slot is an ephemeral (session-only) one. False when nothing is active.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 233,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetSlotMetadata",
            "desc": "Returns the slot's metadata, or nil when there is no such slot.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SlotId?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "SaveSlotMetadata?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 243,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetActiveSlotMetadata",
            "desc": "Returns the active slot's metadata, or nil when nothing is selected. Unlike\n[HasSaveSlotsDataStore.GetSlotList] this does see an ephemeral slot, which is the only way to read\nthe metadata of a session in progress.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "SaveSlotMetadata?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 261,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetSlotList",
            "desc": "Returns the persisted slots, ordered by index. Ephemeral slots are excluded, matching\n[SaveSlotDataService.GetSlotList] -- read the active slot directly with\n[HasSaveSlotsDataStore.GetActiveSlotMetadata] to see one.\n\nOrdered because the underlying map is not: an unordered listing would shuffle between calls, and\nthe tooling reading this prints it.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "{ SaveSlotMetadata }"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 275,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetSlotIdFromIndex",
            "desc": "Returns the id of the persisted slot at the given index, or nil when there is none. Ephemeral\nslots are never addressable by index.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotIndex",
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "SlotId?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 298,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "GetSlotStore",
            "desc": "Returns the [DataStoreStage] backing the slot's saved data. For the default slot this is the\nplayer's root store; for an ephemeral slot it is an in-memory store.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SlotId"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "DataStoreStage"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 314,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "ObserveActiveSlotStoreBrio",
            "desc": "Observes the [DataStoreStage] for the active slot as a [Brio]",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable.Observable<\n\tBrio.Brio<DataStoreStage.DataStoreStage>\n>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 324,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseActiveSlotStore",
            "desc": "Returns the [DataStoreStage] for the active slot",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<DataStoreStage.DataStoreStage?>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 345,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSlotsLoaded",
            "desc": "Promises that all slots have loaded",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<any>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 359,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseHasSlot",
            "desc": "Returns whether the slot with the given ID exists",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SaveSlotData.SlotId?\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<boolean>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 366,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSelectSlot",
            "desc": "Selects the slot with the given ID",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SaveSlotData.SlotId\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<any>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 392,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseDeselectSlot",
            "desc": "Clears the active slot selection, returning the player to a no-slot state --\nthe counterpart to [HasSaveSlotsDataStore.PromiseSelectSlot], backing a \"back to menu\"\naffordance. The active slot's progress is flushed first (mirroring the save\nPromiseSelectSlot runs when switching away), and the last-active slot is\nremembered, so [HasSaveSlotsDataStore.PromiseSelectLastSaveSlot] can resume it later.\nA no-op when no slot is active.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<()>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 444,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseCreateSlot",
            "desc": "Creates a slot at the given index",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotIndex",
                    "desc": "",
                    "lua_type": "number"
                },
                {
                    "name": "metadata",
                    "desc": "",
                    "lua_type": "SaveSlotCreateMetadata?\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 465,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseExportSlot",
            "desc": "Exports a slot's saved data into a plain, serializable [SaveSlotExportUtils.SaveSlotExport].\nRejects the main/default slot by default: its store is the player's shared root datastore, so\nexporting it would leak the SaveSlots system data and universe-scoped global data living\nalongside it. Only isolated non-main slot substores are exportable.\n\n`allowMainSlot` opts out of that refusal for trusted admin tooling (see [SaveSlotCmdrService]).\nThe SaveSlots system data is always stripped from the result, so the export never carries the\nslot roster or the other slots' saved data. Universe-scoped global data sharing the root store\nis indistinguishable from the main slot's own data and is still carried, which is why this is\nnot exposed through [SaveSlotService].",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SlotId"
                },
                {
                    "name": "allowMainSlot",
                    "desc": "defaults to false",
                    "lua_type": "boolean?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<SaveSlotExportUtils.SaveSlotExport>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 515,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseImportSlot",
            "desc": "Imports an exported slot into a fresh slot, seeding the new slot's store with the exported data.\nThe destination defaults to the lowest free non-main index; passing `targetSlotIndex` puts the\nimport at that index instead, which must be free (delete or reset what is there first). Never uses\nthe main/default index either way -- importing onto the shared root store would wipe the player's\nglobal data. Resolves to the new slot's id. Rejects a malformed export, a taken or main-slot\ndestination, or when no non-main index is free.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "export",
                    "desc": "",
                    "lua_type": "SaveSlotExportUtils.SaveSlotExport"
                },
                {
                    "name": "targetSlotIndex",
                    "desc": "defaults to the lowest free non-main index",
                    "lua_type": "number?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<SlotId>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 564,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSaveSlotToSharedDataStore",
            "desc": "Exports a non-main slot (see [HasSaveSlotsDataStore.PromiseExportSlot]) and writes it to the shared\nsave slot store under the given key, tagged as a share code (see [SaveSlotExportUtils.Kind]) so the\nteleport arrival path will not load it.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SlotId"
                },
                {
                    "name": "key",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "allowMainSlot",
                    "desc": "defaults to false, see [HasSaveSlotsDataStore.PromiseExportSlot]",
                    "lua_type": "boolean?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<boolean>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 631,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseImportSlotFromSharedDataStore",
            "desc": "Reads a share code's export from the shared save slot store and imports it into a fresh non-main\nslot (see [HasSaveSlotsDataStore.PromiseImportSlot]). Rejects when no export is stored under the\nkey, or when the entry there is a transfer snapshot rather than a share code -- a transfer key is\nreplicated to every client (see the arrival path in\n[HasSaveSlotsDataStore.PromiseSelectTransferableEphemeralSlot]), so redeeming one into a kept slot\nwould turn a public handle into a permanent copy of someone else's save.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "key",
                    "desc": "",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<SlotId>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 664,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSelectTransferableEphemeralSlot",
            "desc": "Resumes a transfer: loads the snapshot stored under the given shared-store key into a fresh\nephemeral slot and selects it, keeping the key so the next teleport carries the slot forward again\n(see the transferable-ephemeral teleport provider in [SaveSlotService]). Like every ephemeral slot it\nis never persisted, stays out of the slot list, and is torn down on deselect.\n\n:::warning\nThe key comes from the arriving client's teleport band, so this loads whatever a client asks for.\nOnly entries written as transfers are accepted -- a share code, which players hand to each other, is\nrefused here and redeemed through [HasSaveSlotsDataStore.PromiseImportEphemeralSaveSlotFromCode]\ninstead. Entries predating that tag are refused too; see [SaveSlotExportUtils.canLoadAs].\n:::",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "key",
                    "desc": "",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<SlotId>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 705,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseImportEphemeralSaveSlotFromCode",
            "desc": "Redeems a share code into a fresh transferable ephemeral slot and selects it (see\n[HasSaveSlotsDataStore.PromiseSelectTransferableEphemeralSlot] for what that slot is).\n\nThe slot transfers onward under a freshly minted key rather than the code it came from: the transfer\nkey is handed to the client to carry across teleports, so reusing the code as that key would publish\nthe code and hand every holder of it a slot the arrival path would load. The code entry is left\nuntouched, so the same code still redeems for whoever else holds it.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "code",
                    "desc": "",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<SlotId>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 724,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseBuildEphemeralTransferSlice",
            "desc": "Builds this player's teleport slice for a transferable ephemeral slot: re-saves the active slot's\n*current live* data to the shared store under its key and returns a slice carrying that key. Resolves\nnil when the active slot is not a transferable ephemeral slot. A failed re-save degrades to nil so a\nteleport is never blocked (the destination then re-loads the last saved state). Asynchronous -- it is\nconsumed through [TeleportDataService.PromiseBuildTeleportData].",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<{ [string]: any }?>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 793,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "SetCodeGenerator",
            "desc": "Overrides the share-code generator for this player's exports (see [SaveSlotCodeUtils.CodeGenerator]).\nGames inject a custom format; the default is [SaveSlotCodeUtils.generateDefaultCode]. Usually set\ngame-wide via [SaveSlotService.SetCodeGenerator] rather than per player.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "generator",
                    "desc": "",
                    "lua_type": "CodeGenerator"
                }
            ],
            "returns": [],
            "function_type": "static",
            "source": {
                "line": 832,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseExportSaveSlotToCode",
            "desc": "Exports a slot to the shared store under a fresh generated code and resolves to that code. The code\nis a shareable handle other sessions load with\n[HasSaveSlotsDataStore.PromiseImportEphemeralSaveSlotFromCode]. Defaults to the active slot. Refuses\nthe main slot unless `allowMainSlot` is set (see [HasSaveSlotsDataStore.PromiseExportSlot]). The code\nformat comes from the configured generator (see [HasSaveSlotsDataStore.SetCodeGenerator]).",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "defaults to the active slot",
                    "lua_type": "SlotId?"
                },
                {
                    "name": "allowMainSlot",
                    "desc": "defaults to false, see [HasSaveSlotsDataStore.PromiseExportSlot]",
                    "lua_type": "boolean?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<string>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 866,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseExportSaveSlotToJson",
            "desc": "Exports a slot as a raw JSON string (no shared store), for direct inspection or attaching to a bug\nreport. Defaults to the active slot. Refuses the main slot unless `allowMainSlot` is set (see\n[HasSaveSlotsDataStore.PromiseExportSlot]).",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "defaults to the active slot",
                    "lua_type": "SlotId?"
                },
                {
                    "name": "allowMainSlot",
                    "desc": "defaults to false, see [HasSaveSlotsDataStore.PromiseExportSlot]",
                    "lua_type": "boolean?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<string>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 893,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseDuplicateSlot",
            "desc": "Duplicates the slot with the given ID into a new slot at the lowest free index,\ncopying its saved data and accrued playtime. Resolves to the new slot's id. The copy is not\nselected, its timestamps and session counters start fresh, and its name is suffixed with\n\" (Copy)\". Rejects when the source slot is missing or every index is in use.\n\nAn ephemeral slot may be duplicated: the copy is a real, persisted slot seeded with the ephemeral\nslot's live in-memory data, which is how a throwaway session is turned into a save. It keeps the\nsource's name unsuffixed (the copy is the first real slot for that session, not a second copy of an\nexisting save) and, like any duplicate, is not selected -- see\n[HasSaveSlotsDataStore.PromisePersistEphemeralSlot] for the version that continues play on the new slot.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SaveSlotData.SlotId\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 922,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromisePersistEphemeralSlot",
            "desc": "Turns an ephemeral slot into a real save: duplicates it into a fresh persisted slot at the lowest free\nindex (see [HasSaveSlotsDataStore.PromiseDuplicateSlot]) and selects that slot, so play continues on\ndata that is now being written. Defaults to the active slot, which in practice is the only ephemeral\nslot there is -- one stops existing the moment it stops being active. Resolves to the new slot's id.\n\nThe copy is taken from the ephemeral slot's live in-memory data at the moment this runs, and selecting\nthe new slot retires the ephemeral one, so anything written to the old store between the copy and the\nselection is dropped. Rejects when no slot is active, the slot is missing, the slot is not ephemeral,\nor every index is in use.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "defaults to the active slot",
                    "lua_type": "SlotId?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<SlotId>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1007,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseDeleteSlot",
            "desc": "Deletes the slot with the given ID. Deleting an ephemeral slot ends that session -- it is deselected\nand retired along with its in-memory store -- rather than being refused for being the active slot.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SaveSlotData.SlotId\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<any>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1037,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseDeleteAllSlots",
            "desc": "Deletes every slot for the player and clears the active/last-active\nselection, resetting the player to a fresh state. Resolves once all slots\nare gone.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<any>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1103,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseResetSlot",
            "desc": "Resets the slot with the given id to a fresh empty one -- equivalent to deleting the slot\nand creating a new one at the same index. The slot keeps its index and name; its saved data\nand metadata (timestamps) start fresh. Resolves to the new slot id.\n\nWhen the reset slot is the active slot, the selection clears and then reselects the fresh\nslot: everything bound to [HasSaveSlotsDataStore.ObserveActiveSlotStoreBrio] tears down as the\nselection clears and rebuilds against the empty store on reselect, so consumers reset\nreactively without wiping their own state. A non-active slot is left unselected, and its\n\"Continue\" pointer (when it was the last-active slot) is carried across to the fresh id so\nthe reset slot stays resumable. Rejects when the slot is missing.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SaveSlotData.SlotId\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1138,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseResetActiveSlot",
            "desc": "Resets the active slot to a fresh empty one -- see [HasSaveSlotsDataStore.PromiseResetSlot]. The slot\nkeeps its index and name; its saved data and metadata (timestamps) start fresh, and the fresh\nslot stays selected. Resolves to the new slot id, or nil when no slot is active.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId?>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1193,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSetSlotMetadata",
            "desc": "Sets the metadata for the slot with the given ID",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SaveSlotData.SlotId"
                },
                {
                    "name": "data",
                    "desc": "",
                    "lua_type": "SaveSlotData.SaveSlotMetadata\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<any>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1209,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseGetSlotMetadata",
            "desc": "Gets the metadata for the slot with the given ID",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotId",
                    "desc": "",
                    "lua_type": "SaveSlotData.SlotId\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SaveSlotMetadata?>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1233,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSlotIdFromIndex",
            "desc": "Returns the slot ID from the given index",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "slotIndex",
                    "desc": "",
                    "lua_type": "number\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId?>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1246,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseLastActiveSlotId",
            "desc": "Gets the last active slot ID",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId?>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1266,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSelectLastSaveSlot",
            "desc": "Selects the player's last active slot if one still exists, resolving to the\nselected slot id -- or nil when there is no slot to continue on. Backs a\n\"Continue\" affordance that every save-slot consumer tends to need.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId?>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1279,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSelectNewSaveSlot",
            "desc": "Creates a new slot at the lowest free index and selects it, resolving to the\nnew slot id -- or nil when every slot is already in use. Backs a \"New Game\"\naffordance.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise.Promise<SaveSlotData.SlotId?>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1304,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "PromiseSelectEphemeralSlot",
            "desc": "Creates a fresh ephemeral slot and selects it, resolving to its id. An ephemeral slot is selectable and\nactive exactly like a real one -- it drives [HasSaveSlotsDataStore.ObserveActiveSlotStoreBrio],\nsummaries, and playtime the same way, and its metadata replicates to the client like any other slot's,\nso UI can render the active session's name and summary -- but it is never persisted: no metadata is\nwritten, its data store is in-memory, and it is torn down the moment it stops being the active slot. It\nis also excluded from the save list ([SaveSlotDataService.GetSlotList] /\n[SaveSlotDataService.ObserveSlotList]), so it never shows up as something the player can return to.\nSelecting it never disturbs the persisted active-slot pointer or the \"Continue\" target, so the real slot\nthe player came from resumes untouched afterward. Backs a throwaway session (e.g. exploring a lobby)\nthat must leave no trace on save data.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                },
                {
                    "name": "metadata",
                    "desc": "optional SlotName/Summary for the in-memory slot",
                    "lua_type": "SaveSlotCreateMetadata?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<SlotId>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 1351,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        },
        {
            "name": "_setupPlaytimeTracking",
            "desc": "Accrues per-slot playtime automatically. A \"session\" spans the time a slot is the active slot:\nselecting a slot begins one (bumping PlayCount), and deselecting, switching, or unbinding ends\nit. Elapsed wall time is folded into the slot's TimePlayed from a datastore saving callback, so\nit persists on exactly the cadence the data is written -- always fresh at save time, with no\nseparate timer -- and again at each session boundary.\n\nSkipped entirely when the owner opts out (`TrackPlaytime = false`), which is what offline admin\ntooling wants: editing a slot from a console is not someone playing it, and no session is ever\nbegun, so `_flushPlaytime` stays a no-op for the object's whole life.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "HasSaveSlotsDataStore"
                }
            ],
            "returns": [],
            "function_type": "static",
            "source": {
                "line": 1582,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        }
    ],
    "properties": [],
    "types": [
        {
            "name": "HasSaveSlotsDataStoreOptions",
            "desc": "The state and collaborators this class cannot derive from a datastore alone.\n\nThe four value objects are *borrowed*, never owned: the player path passes the ones backed by\nreplicated player attributes, so writing them replicates, while offline tooling passes detached\nones. Either way this class only reads and writes them, and never destroys them.",
            "fields": [
                {
                    "name": "ActiveSlotId",
                    "lua_type": "ValueObject<SlotId?>",
                    "desc": ""
                },
                {
                    "name": "LastActiveSlotId",
                    "lua_type": "ValueObject<SlotId?>",
                    "desc": ""
                },
                {
                    "name": "ActiveTransferableEphemeralKey",
                    "lua_type": "ValueObject<string?>",
                    "desc": ""
                },
                {
                    "name": "MaxSlotCount",
                    "lua_type": "ValueObject<number>",
                    "desc": ""
                },
                {
                    "name": "SharedDataStoreService",
                    "lua_type": "any",
                    "desc": "SaveSlotSharedDataStoreService"
                },
                {
                    "name": "PromisePreSelect",
                    "lua_type": "((SlotId) -> Promise<boolean>)?",
                    "desc": "veto hook, defaults to allowing every selection"
                },
                {
                    "name": "UserId",
                    "lua_type": "number?",
                    "desc": "identity for generated share codes"
                },
                {
                    "name": "UserName",
                    "lua_type": "string?",
                    "desc": "identity for generated share codes"
                },
                {
                    "name": "TrackPlaytime",
                    "lua_type": "boolean?",
                    "desc": "accrue play sessions from selection changes, defaults to true"
                }
            ],
            "source": {
                "line": 75,
                "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
            }
        }
    ],
    "name": "HasSaveSlotsDataStore",
    "desc": "The save slot system over a [DataStore], with no [Player] attached.\n\nThis is the whole slot model -- the roster, the per-slot stores, selection, create/delete/reset,\nexport/import, ephemeral slots and playtime -- expressed against an injected datastore rather than\nagainst a bound player. [HasSaveSlots] is the binder that owns one of these for a live player and\nsupplies the player-shaped parts (replication, remotes, teleport data, summary providers).\n\nSplitting it out is what makes a slot reachable for a player who is not in this server: admin\ntooling borrows that player's datastore (see `PlayerDataStoreHandle`) and builds one of these over\nit, getting the same slot semantics with no [Player] instance in sight.\n\nThe slot roster is still modelled as Folders with attributes, because that representation is what\nthe client reads. Offline, those folders simply live in an unparented container and replicate to\nnobody.\n\n:::info\nConstructed with a *promise* of a datastore rather than a datastore, so every method can gate on\nthe same load promise the player path always gated on. Callers do not have to wait before using it.\n:::",
    "realm": [
        "Server"
    ],
    "source": {
        "line": 26,
        "path": "src/saveslot/src/Server/HasSaveSlotsDataStore.lua"
    }
}