Skip to content

tm.kvp ​

Typed, safe access to the resource key value store. Use it instead of calling the GetResourceKvp* / SetResourceKvp* natives directly. Shared: it works on the client (per install) and on the server (per server). Keys live in the calling resource's own KVP namespace, exactly like the raw natives. Client KVP is per install, so it suits UI preferences and never anything the server must trust.

lua
local store = tm.kvp.scope('emotes:')   -- optional, prefixes every key

store.set('volume', 5)                   -- picks the native by type: string, boolean, integer, float, table (json)
store.setInt('legacy', v)                -- force an int for a number from NUI or the database that might arrive as 5.0
store.setFloat('scale', 1)               -- force a float for a whole number
store.getInt('volume', 3)                -- the default is returned only when the key is missing, a stored 0 stays 0
store.getBool('hideHud', false)
store.getJson('favorites', {})           -- corrupt or missing json returns the default
store.setMany({ a = 1, b = 'x' })        -- one disk flush for the batch
store.setDebounced('position', pos)      -- sliders and drags: latest value, at most one write per 500 ms
store.list()  store.delete('volume')  store.clear()

Pair the getter with the type you stored:

StoredRead with
stringgetString(key, default?)
boolean (stored as the int 0 or 1)getBool(key, default?)
integergetInt(key, default?)
floatgetFloat(key, default?)
tablegetJson(key, default?) (a missing key, an empty string and corrupt json all return the default)

Ints and floats are 32 bit, so store larger numbers (millisecond timestamps, big ids) as a string or in json. An integer outside the 32 bit range is stored as a float by set.

Functions ​

FunctionNotes
has(key)True when the key exists, whatever its type. Does not read the value, so it never hits the "bad cast" error.
set(key, value)Stores by natural type. A nil value deletes the key. Errors for a type KVP cannot hold (functions, userdata). Writes to disk on every call.
setInt(key, value), setFloat(key, value)Force the type. setInt rounds.
delete(key)Removes a key.
setMany(values)Writes a table of key and value pairs with one disk flush. A nil cannot be expressed in a table, use delete.
setDebounced(key, value, delay?)Keeps only the latest value and writes at most once per delay ms (default 500), batched with one flush. Flushes on resource stop so nothing is lost. A nil value is a debounced delete.
flush()Writes any queued debounced values now.
list(prefix)Every stored key that starts with prefix.
clear(prefix)Deletes every key with the prefix using one flush and returns how many. An empty prefix is refused with an error.
scope(prefix)A handle with the same functions that prefixes every key. list returns keys without the prefix, clear() takes no argument, and scope(sub) nests.

Reading a key through tm.kvp always sees the newest value, including a pending debounced one. Plain set writes to disk on every call, so use setDebounced or setMany for anything that changes rapidly or in bulk.

Some builds do not expose the no-sync natives (the client in particular). In that case batched writes fall back to plain synced writes and the flush is a no-op.