Keep
Keep is Cluaupp player data: ProfileStore session locking, tagged replication buffers, path tokens, transient overlays, ordered lists, and trade escrow. Server code uses Keep.Server; clients use Keep.Client. Low-level DataStore access uses Keep.Store; player-to-player trades use Keep.Trade. Paths are generated into Keep.Paths / Keep.Server.Paths from your template.
Header: #include <clpp/libs/keep.clh>. Runtime: CluauppLibs.Keep.
- Session-safe saves with mock mode, key prefixes, and buffer stats for tuning replication.
- Merged reads (
Get) vs persisted-only (GetPersisted) vs session-only transient layers. - Signals per path for UI (Gleam) and gameplay without polling.
When not to use: global non-player state (use Keep.Store directly or a custom store), or cross-place inventory without understanding ProfileStore limits.
Example
Section titled “Example”#include <clpp/roblox.clh>#include <clpp/libs/keep.clh>
[[server]]void initServer() { Keep.Server.Init(DataServiceOptions { .Template = myDefaultData, .StoreName = "PlayerData_v1", }); Data data = Keep.Server.WaitFor(player); data.Set(Keep.Server.Paths.Currencies.Coins, 100);}
[[client]]void initClient() { Keep.Client.Init(); Data data = Keep.Client.WaitForData(); int coins = data.Get(Keep.Client.Paths.Currencies.Coins); // replicated value}API — Keep (statics)
Section titled “API — Keep (statics)”Keep.Server
Section titled “Keep.Server”Returns: DataServiceServer — server-only API (Init, WaitFor, Get, …). Unavailable stubs on client builds.
When: Authoritative data in [[server]] scripts.
Example
Keep.Server.Init(opts);Keep.Client
Section titled “Keep.Client”Returns: DataServiceClient — client API (Init, WaitForData, Get, …).
When: Local player data mirror in [[client]] scripts.
Example
Keep.Client.Init();Keep.Paths
Section titled “Keep.Paths”Returns: DataPath tree — path tokens for the active context (server or client compile).
When: Typed Get / Set without string paths.
Example
DataPath p = Keep.Paths.Currencies.Coins;Keep.Enum
Section titled “Keep.Enum”Returns: DataServiceEnum — e.g. Keep.Enum.OrderList.Asc / Desc for ordered lists.
When: GetOrderedList options.
Example
string asc = Keep.Enum.OrderList.Asc;Keep.Store
Section titled “Keep.Store”Returns: KeepStore module — ProfileStore-style StartSessionAsync, globals, messaging.
When: Non-player keys, tooling, or custom session logic.
Example
KeepStore store = KeepStore.New("Meta", tmpl);Keep.Trade
Section titled “Keep.Trade”Returns: KeepTrade — escrow Begin / Reserve / Commit / Abort / SendOffline. Reserve deducts into a per-trade vault; Commit credits with receipts and SaveWaits both profiles (rollback if either save fails).
When: Atomic trades between two loaded profiles.
Example
string id = Keep.Trade.Begin(profileA, profileB);API — DataServiceServer
Section titled “API — DataServiceServer”DataServiceServer.Paths
Section titled “DataServiceServer.Paths”Returns: DataPath tree for the server template.
When: Same as Keep.Server.Paths after Init.
Example
DataPath coins = Keep.Server.Paths.Currencies.Coins;DataServiceServer::Init
Section titled “DataServiceServer::Init”Returns: DataServiceServer — this after starting replication and store binding.
When: Once per server experience with DataServiceOptions.
Example
Keep.Server.Init(DataServiceOptions { .Template = tmpl, .StoreName = "v1" });DataServiceServer::WaitFor
Section titled “DataServiceServer::WaitFor”Returns: Data — blocks until the player’s profile is loaded and replicated.
When: Join handlers that must not race empty data.
Example
Data data = Keep.Server.WaitFor(player);DataServiceServer::Get
Section titled “DataServiceServer::Get”Returns: Data or Luau nil if no session.
When: Non-yielding lookup after you know data exists.
Example
Data data = Keep.Server.Get(player);DataServiceServer::HasData
Section titled “DataServiceServer::HasData”Returns: bool — true when a live Data object exists for the player.
When: Guards before Get.
Example
bool ok = Keep.Server.HasData(player);DataServiceServer::GetProfile
Section titled “DataServiceServer::GetProfile”Returns: DataProfile — underlying store profile (save, release, trade APIs).
When: Keep.Trade or direct Profile:Save().
Example
DataProfile profile = Keep.Server.GetProfile(player);DataServiceServer::GetBufferStats
Section titled “DataServiceServer::GetBufferStats”Returns: DataBufferStats — aggregate replication metrics.
When: Server-wide bandwidth tuning.
Example
DataBufferStats s = Keep.Server.GetBufferStats();DataServiceServer::GetBufferStats (player)
Section titled “DataServiceServer::GetBufferStats (player)”Returns: DataBufferStats — per-player replication metrics.
When: Diagnosing one heavy client.
Example
DataBufferStats s = Keep.Server.GetBufferStats(player);DataServiceServer::Destroy
Section titled “DataServiceServer::Destroy”Returns: Luau nil. Tears down the server data service.
When: Test shutdown or place cleanup.
Example
Keep.Server.Destroy();API — DataServiceClient
Section titled “API — DataServiceClient”DataServiceClient.Paths
Section titled “DataServiceClient.Paths”Returns: DataPath tree for the client template.
When: Client Get / signals.
Example
auto path = Keep.Client.Paths.Currencies.Coins;DataServiceClient::Init
Section titled “DataServiceClient::Init”Returns: Data — local player data facade after starting client replication.
When: Once in client bootstrap (often before WaitForData).
Example
Data data = Keep.Client.Init();DataServiceClient::WaitForData
Section titled “DataServiceClient::WaitForData”Returns: Data — yields until the first full snapshot arrives.
When: HUD and input that need non-nil paths.
Example
Data data = Keep.Client.WaitForData();DataServiceClient::Get
Section titled “DataServiceClient::Get”Returns: Data or nil if not ready.
When: Polling without yield.
Example
Data data = Keep.Client.Get();DataServiceClient::GetBufferStats
Section titled “DataServiceClient::GetBufferStats”Returns: DataBufferStats — client receive stats.
When: Debugging replication volume locally.
Example
DataBufferStats s = Keep.Client.GetBufferStats();DataServiceClient::Destroy
Section titled “DataServiceClient::Destroy”Returns: Luau nil. Stops client data service.
When: Teardown.
Example
Keep.Client.Destroy();API — Data
Section titled “API — Data”Data.Changed
Section titled “Data.Changed”Returns: RBXScriptSignal — fires on any persisted/merged change (runtime Spark-backed).
When: Whole-profile UI refresh.
Example
data.Changed~>Connect(func () { refresh(); });Data.Destroyed
Section titled “Data.Destroyed”Returns: bool field — true after Destroy.
When: Ignoring signals after release.
Example
if (!data.Destroyed) { /* use data */ }Data::Get
Section titled “Data::Get”Returns: auto — merged view (persisted + transient) at optional path, or root table when omitted.
When: Gameplay reads that should see session overlays.
Example
int coins = data.Get(Keep.Client.Paths.Currencies.Coins); // 100Data::Get (path)
Section titled “Data::Get (path)”Returns: auto — value at DataPath path.
When: Typed path tokens.
Example
auto v = data.Get(path);Data::GetPersisted
Section titled “Data::GetPersisted”Returns: auto — saved ProfileStore slice only.
When: Auditing what will flush to DataStore.
Example
int saved = data.GetPersisted(path);Data::GetPersisted (path)
Section titled “Data::GetPersisted (path)”Returns: auto at path.
When: Persisted subtree.
Example
auto v = data.GetPersisted(path);Data::GetTransient
Section titled “Data::GetTransient”Returns: auto — transient overlay value or nil.
When: Buffs, round-only state not in save template.
Example
auto buff = data.GetTransient(path);Data::GetTransient (path)
Section titled “Data::GetTransient (path)”Returns: auto at path.
When: Addressed transient reads.
Example
auto t = data.GetTransient(path);Data::HasTransient
Section titled “Data::HasTransient”Returns: bool — any transient layer present (root or subtree).
When: Branching UI for temporary stats.
Example
bool has = data.HasTransient();Data::HasTransient (path)
Section titled “Data::HasTransient (path)”Returns: bool at path.
When: Specific transient key.
Example
bool has = data.HasTransient(path);Data::Set
Section titled “Data::Set”Returns: Luau nil. Writes persisted path (replicates, saves).
When: Authoritative progression on server.
Example
data.Set(path, 50); // coins become 50Data::SetTransient
Section titled “Data::SetTransient”Returns: Luau nil. Overlay only until cleared or session ends.
When: Round modifiers.
Example
data.SetTransient(path, 2);Data::Update
Section titled “Data::Update”Returns: auto — new value after fn(old) (persisted).
When: Atomic read-modify-write.
Example
data.Update(path, func (int old) { return old + 1; }); // incrementsData::UpdateTransient
Section titled “Data::UpdateTransient”Returns: auto — new transient value after fn.
When: Mutable session-only fields.
Example
data.UpdateTransient(path, func (int old) { return old + 1; });Data::ClearTransient
Section titled “Data::ClearTransient”Returns: Luau nil. Drops all transient overlays.
When: Round end.
Example
data.ClearTransient();Data::ClearTransient (path)
Section titled “Data::ClearTransient (path)”Returns: Luau nil. Clears one transient path.
When: Remove one buff.
Example
data.ClearTransient(path);Data::ArrayInsert
Section titled “Data::ArrayInsert”Returns: Luau nil. Appends or inserts into persisted array path.
When: Inventory lines, quest lists.
Example
data.ArrayInsert(path, item);Data::ArrayInsert (path, value, index)
Section titled “Data::ArrayInsert (path, value, index)”Returns: Luau nil. Inserts at index.
When: Ordered insert.
Example
data.ArrayInsert(path, item, 1);Data::ArrayInsertTransient
Section titled “Data::ArrayInsertTransient”Returns: Luau nil. Transient array append.
When: Session-only lists.
Example
data.ArrayInsertTransient(path, item);Data::ArrayInsertTransient (path, value, index)
Section titled “Data::ArrayInsertTransient (path, value, index)”Returns: Luau nil. Indexed transient insert.
When: Ordered transient arrays.
Example
data.ArrayInsertTransient(path, item, 2);Data::ArrayRemove
Section titled “Data::ArrayRemove”Returns: auto — removed element from persisted array.
When: Consume stack items.
Example
auto removed = data.ArrayRemove(path, 1);Data::ArrayRemoveTransient
Section titled “Data::ArrayRemoveTransient”Returns: auto — removed transient element.
When: Session list edits.
Example
auto removed = data.ArrayRemoveTransient(path, 1);Data::GetOrderedList
Section titled “Data::GetOrderedList”Returns: auto — ordered entries per OrderedListOptions (key, order, limit).
When: Leaderboards stored in data.
Example
auto rows = data.GetOrderedList(path, OrderedListOptions { .key = "Score", .order = Keep.Enum.OrderList.Desc, .limit = 10 });Data::GetOrderedListWithPriority
Section titled “Data::GetOrderedListWithPriority”Returns: auto — ordered list sorted by key ascending.
When: Priority queues in data.
Example
auto list = data.GetOrderedListWithPriority(path, "Priority");Data::GetOrderedListWithPriority (path, key, order)
Section titled “Data::GetOrderedListWithPriority (path, key, order)”Returns: auto — with explicit order string (Asc / Desc).
When: Custom sort direction.
Example
auto list = data.GetOrderedListWithPriority(path, "Priority", Keep.Enum.OrderList.Asc);Data::GetChangedSignal
Section titled “Data::GetChangedSignal”Returns: RBXScriptSignal — value changes at path.
When: Binding one stat to UI.
Example
data.GetChangedSignal(path)~>Connect(func (auto newV, auto oldV) {});Data::GetPathChangedSignal
Section titled “Data::GetPathChangedSignal”Returns: RBXScriptSignal — subtree path changes.
When: Nested tables.
Example
data.GetPathChangedSignal(path)~>Connect(func () {});Data::GetIndexChangedSignal
Section titled “Data::GetIndexChangedSignal”Returns: RBXScriptSignal — dictionary key or index updates.
When: Map-like data.
Example
data.GetIndexChangedSignal(path)~>Connect(func (auto key, auto newV, auto oldV) {});Data::GetArrayInsertedSignal
Section titled “Data::GetArrayInsertedSignal”Returns: RBXScriptSignal — (index, value) on insert.
When: List UI append animations.
Example
data.GetArrayInsertedSignal(path)~>Connect(func (int i, auto v) {});Data::GetArrayRemovedSignal
Section titled “Data::GetArrayRemovedSignal”Returns: RBXScriptSignal — (index, value) on remove.
When: List UI removals.
Example
data.GetArrayRemovedSignal(path)~>Connect(func (int i, auto v) {});Data::Typed
Section titled “Data::Typed”Returns: DataPath — typed path token for IntelliSense.
When: Feeding generics from a base path.
Example
DataPath typed = data.Typed(Keep.Server.Paths.Currencies.Coins);Data::Destroy
Section titled “Data::Destroy”Returns: Luau nil. Ends session and disconnects listeners.
When: Player leaving custom handlers before engine teardown.
Example
data.Destroy();API — KeepStore
Section titled “API — KeepStore”KeepStore.New
Section titled “KeepStore.New”Returns: KeepStore — named store with template tmpl for reconciliation.
When: Custom keys outside the player service.
Example
KeepStore store = KeepStore.New("Global", defaultTable);KeepStore.SetConstant
Section titled “KeepStore.SetConstant”Returns: Luau nil. Registers a global constant on the store module.
When: Shared configuration values referenced by store logic.
Example
KeepStore.SetConstant("Season", 2);KeepStore::StartSessionAsync
Section titled “KeepStore::StartSessionAsync”Returns: DataProfile — loaded session for key (yields).
When: Manual profile lifecycle.
Example
DataProfile profile = store.StartSessionAsync("Player_123");KeepStore::GetAsync
Section titled “KeepStore::GetAsync”Returns: auto — raw DataStore value for key (yields).
When: One-off reads without session.
Example
auto raw = store.GetAsync("Player_123");KeepStore::MessageAsync
Section titled “KeepStore::MessageAsync”Returns: bool — true if MessagingService publish succeeded.
When: Cross-server messages (trades, mail).
Example
bool sent = store.MessageAsync(key, payload);KeepStore::RemoveAsync
Section titled “KeepStore::RemoveAsync”Returns: bool — true if removal succeeded.
When: GDPR wipe or reset key.
Example
bool ok = store.RemoveAsync(key);API — KeepVersionQuery
Section titled “API — KeepVersionQuery”Returned from store version listing helpers in the runtime; CL++ type exposes iteration.
KeepVersionQuery::Get
Section titled “KeepVersionQuery::Get”Returns: auto — version metadata at index.
When: Random access in a version list.
Example
auto info = query.Get(1);KeepVersionQuery::List
Section titled “KeepVersionQuery::List”Returns: auto — array of all version entries collected.
When: Bulk inspection.
Example
auto all = query.List();KeepVersionQuery::Next
Section titled “KeepVersionQuery::Next”Returns: auto — next version entry, or nil when exhausted.
When: Sequential walk.
Example
auto item = query.Next();API — KeepTrade
Section titled “API — KeepTrade”KeepTrade::Begin
Section titled “KeepTrade::Begin”Returns: string — trade id, or empty string if either profile already has an active trade.
When: Starting a two-player escrow session.
Example
string tradeId = Keep.Trade.Begin(profileA, profileB); // non-empty guidKeepTrade::Reserve
Section titled “KeepTrade::Reserve”Returns: bool — true if amount of kind/ref was deducted from spendable data into the trade vault. A second reserve on the same kind|ref for this trade fails.
When: Locking currencies/items before commit. Spendable Get after Reserve already shows the lower balance, so a second spend cannot duplicate.
Example
bool ok = Keep.Trade.Reserve(profile, "Currency", "Coins", 10, tradeId);KeepTrade::Commit
Section titled “KeepTrade::Commit”Returns: bool — true if both offer lists moved from escrow with receipt ids and both SaveWaits succeeded. A failed save restores both in-memory snapshots and retries persist so a crash cannot duplicate.
When: Finalizing a trade on one server.
Example
bool done = Keep.Trade.Commit(store, profileA, profileB, offersA, offersB);KeepTrade::Abort
Section titled “KeepTrade::Abort”Returns: Luau nil. Refunds remaining reserved rows for tradeId and clears ActiveTradeId.
When: Cancel or disconnect mid-trade. EndSession / player leave also call AbortIfActive before the last save.
Example
Keep.Trade.Abort(profile, tradeId);KeepTrade::AbortIfActive
Section titled “KeepTrade::AbortIfActive”Returns: Luau nil. Aborts whatever ActiveTradeId is set.
When: Leave handlers; you usually do not call this yourself.
Keep.Trade.AbortIfActive(profile);KeepTrade::SendOffline
Section titled “KeepTrade::SendOffline”Returns: bool — true if trade payload was messaged to offline key.
When: Completing credit when recipient is not in-server.
Example
bool sent = Keep.Trade.SendOffline(store, key, payload);Supporting types (fields)
Section titled “Supporting types (fields)”DataBufferStats: Bytes, Messages, LastPacketBytes, LastUtilization (numbers). OrderedListOptions: key, order, limit. KeepTradeOffer: Kind, Ref, Amount. DataPath is an opaque path token. DataProfile is the session handle: IsActive, Reconcile, AddUserId, Save (async), SaveWait (blocks until the DataStore write finishes), EndSession.