Appearance
Types
PlayerState uses TypeScript-style type annotations for better code safety and IntelliSense support.
Core Data Types
PlayerData
The main data structure for player information, based on your DefaultData module.
lua
export type PlayerData = typeof(DefaultData)
Example DefaultData structure:
lua
{
Coins = 0,
Level = 1,
Experience = 0,
Inventory = {},
Settings = {
MusicEnabled = true,
SoundEnabled = true,
},
Plot = {
Likes = 0,
Size = 1,
Buildings = {},
},
Stats = {
TotalPlayTime = 0,
GamesPlayed = 0,
HighScore = 0,
},
Achievements = {},
-- NEW: Leaderstats configuration
leaderstats = {
["💰 Coins"] = "Coins",
["⭐ Level"] = "Level",
["👍 Likes"] = "Plot.Likes"
}
}
Path Types
ValuePath
String type for dot-separated data paths.
lua
export type ValuePath = string
Examples:
lua
"Coins" -- Top-level access
"Plot.Likes" -- Nested access
"Settings.MusicEnabled" -- Deep nesting
"Stats.HighScore" -- Any depth
"Plot.Buildings.House.Level" -- Complex nesting
ArrayPath
String type for paths to array/list data structures.
lua
export type ArrayPath = string
Examples:
lua
"Inventory" -- Top-level array
"Plot.Buildings" -- Nested array
"Achievements" -- List of achievements
"Stats.RecentScores" -- Nested score array
DictPath
String type for paths to dictionary/table data structures.
lua
export type DictPath = string
Examples:
lua
"Settings" -- Settings dictionary
"Plot.Buildings" -- Building configuration
"Stats" -- Player statistics
"Inventory.Equipped" -- Equipment slots
Batch Operation Types
BatchOperation
Type for individual batch operations used in BatchSetValues()
.
lua
export type BatchOperation = {
path: ValuePath,
value: any,
}
Example:
lua
local operations: {BatchOperation} = {
{path = "Coins", value = 1000},
{path = "Level", value = 5},
{path = "Plot.Likes", value = 50},
{path = "Settings.MusicEnabled", value = true}
}
Change Information Types
ChangeInfo
Enhanced type for change information in client listeners.
lua
export type ChangeInfo = {
action: "Set" | "SetValues" | "TableInsert" | "TableRemove",
path: {string},
index: number?,
}
Action Types:
"Set"
: Single value change"SetValues"
: Multiple values changed"TableInsert"
: Item added to array"TableRemove"
: Item removed from array
Properties:
action
: The type of change that occurredpath
: Array of path segments that changedindex
: Optional index for array operations
Example Usage:
lua
PlayerState.OnChanged(".", function(newValue, oldValue, info)
if info and info.action == "TableInsert" then
print(`Item added at index {info.index} to {table.concat(info.path, ".")}`)
end
end)
Server Interface Types
PlayerStateServer
The enhanced server module interface with all available functions.
lua
export type PlayerStateServer = {
-- Initialization
Init: (player: Player, existingData: PlayerData?) -> boolean,
-- Status checking
IsPlayerDataReady: (player: Player) -> boolean,
-- Basic operations
Set: (player: Player, key: string, value: any) -> boolean,
Get: (player: Player, key: string) -> any,
-- Path operations
SetPath: (player: Player, path: ValuePath, value: any) -> boolean,
GetPath: (player: Player, path: ValuePath) -> any,
-- Batch operations
SetValues: (player: Player, values: {[string]: any}) -> boolean,
BatchSetValues: (player: Player, operations: {BatchOperation}) -> boolean,
FlushBatch: (player: Player) -> boolean,
-- Array operations
AddToArray: (player: Player, arrayPath: ArrayPath, item: any) -> boolean,
RemoveFromArray: (player: Player, arrayPath: ArrayPath, index: number) -> boolean,
UpdateArrayItem: (player: Player, arrayPath: ArrayPath, index: number, newItem: any) -> boolean,
-- Dictionary operations
SetInDict: (player: Player, dictPath: DictPath, key: string, value: any) -> boolean,
GetFromDict: (player: Player, dictPath: DictPath, key: string | number) -> any,
RemoveFromDict: (player: Player, dictPath: DictPath, key: string) -> boolean,
-- Cache management
ClearPathCache: () -> (),
-- Utility functions
GetReplica: (player: Player) -> ReplicaInstance?,
GetProfile: (player: Player) -> ProfileStoreProfile?,
GetAll: (player: Player) -> PlayerData?,
SaveData: (player: Player) -> boolean,
}
ProfileStoreProfile
Enhanced ProfileStore profile interface for data persistence.
lua
export type ProfileStoreProfile = {
Data: PlayerData,
OnSessionEnd: RBXScriptSignal,
AddUserId: (self: ProfileStoreProfile, userId: number) -> (),
Reconcile: (self: ProfileStoreProfile) -> (),
EndSession: (self: ProfileStoreProfile) -> (),
IsActive: (self: ProfileStoreProfile) -> boolean,
}
Key Properties:
Data
: The actual player dataOnSessionEnd
: Event fired when profile session endsAddUserId()
: Associates user ID with profileReconcile()
: Merges template changes with existing dataEndSession()
: Manually end the profile sessionIsActive()
: Check if profile is still active
Notes:
- NEW: Enhanced validation for active status
- NEW: Better session management
- NEW: Automatic cleanup on session end
Client Interface Types
PlayerStateClient
The enhanced client module interface with all available functions.
lua
export type PlayerStateClient = {
-- Data access
Get: (key: string) -> any,
GetPath: (path: ValuePath) -> any,
GetFromDict: (dictPath: ValuePath, key: string | number) -> any,
GetAll: () -> PlayerData?,
-- Status checking
IsReady: () -> boolean,
-- Cache management
ClearCache: () -> (),
-- Change listeners
OnChanged: (pathOrKey: string, callback: (newValue: any, oldValue: any, changeInfo: ChangeInfo | {string}?) -> ()) -> ReplicaClient.Connection?,
-- Advanced access
GetReplica: () -> ReplicaInstance?,
}
Key Changes:
- NEW:
IsReady()
for status checking - NEW:
ClearCache()
for manual cache management - NEW: Enhanced
OnChanged()
withChangeInfo
support - NEW: Better error handling and validation
Enhanced Change Callback
Type for change listener callback functions with enhanced information.
lua
type ChangeCallback = (newValue: any, oldValue: any, changeInfo: ChangeInfo | {string}?) -> ()
Parameters:
newValue
: The new value after the changeoldValue
: The previous value before the changechangeInfo
: Enhanced change information with action details OR simple path array
Example with Action Handling:
lua
local connection = PlayerState.OnChanged("Inventory", function(newValue, oldValue, info)
if info and typeof(info) == "table" and info.action then
-- Enhanced change info
if info.action == "TableInsert" then
print(`Item added at index {info.index}`)
elseif info.action == "TableRemove" then
print(`Item removed from index {info.index}`)
end
else
-- Simple path info
print("Inventory changed")
end
end)
Replica System Types
ReplicaInstance
The Replica object used for real-time synchronization.
lua
export type ReplicaInstance = ReplicaServer.Replica -- or ReplicaClient.Replica
Common Properties:
Data
: The synchronized dataTags
: Metadata tags (UserId, PlayerName, etc.)OnChange
: Advanced change listenerSubscribe/Unsubscribe
: Client subscription management- NEW: Enhanced validation methods
- NEW: Better error handling
ReplicaConnection
Connection object returned by change listeners.
lua
export type ReplicaConnection = ReplicaClient.Connection
Methods:
Disconnect()
: Remove the listener and clean up
Notes:
- NEW: Enhanced connection validation
- NEW: Automatic cleanup on disconnect
- NEW: Better memory management
Configuration Types
Enhanced Profile Configuration
lua
type ProfileConfig = {
Key: string, -- Base key for ProfileStore
Template: PlayerData, -- Default data template
GlobalUpdates: boolean, -- Enable global updates
}
Enhanced DataStore Configuration
lua
type DataStoreConfig = {
Name: string, -- DataStore name
Scope: "Production" | "Testing", -- Environment scope
}
Complete Configuration with New Options
lua
type PlayerStateConfig = {
Profile: ProfileConfig,
DataStore: DataStoreConfig,
CleanExtraFields: boolean, -- NEW: Clean unused fields
BatchDelay: number, -- NEW: Batch processing delay
BatchSize: number, -- NEW: Auto-flush batch size
MaxCacheSize: number, -- NEW: Maximum cache entries
}
Default Configuration:
lua
-- PlayerStateConfig.lua
local Config = {
Server = {
Profile = {
Key = "PlayerData",
Template = DefaultData,
},
DataStore = {
Name = "PlayerData_ALPHA_0.02",
Scope = "Production",
},
CleanExtraFields = true,
BatchDelay = 0.03, -- 30ms batch delay
BatchSize = 20, -- Auto-flush at 20 operations
MaxCacheSize = 1000, -- Maximum cache entries
},
Client = {
CacheDuration = 0.1,
MaxCacheSize = 1000,
},
}
Leaderstats Types
LeaderstatsConfig
Configuration type for automatic leaderstats integration.
lua
export type LeaderstatsConfig = {
[string]: ValuePath -- Display name -> data path
}
Example:
lua
local leaderstatsConfig: LeaderstatsConfig = {
["💰 Coins"] = "Coins",
["⭐ Level"] = "Level",
["👍 Likes"] = "Plot.Likes",
["🏆 High Score"] = "Stats.HighScore"
}
Notes:
- Keys are the display names shown in leaderstats
- Values are paths to the actual data
- Supports nested paths with dot notation
- Numbers automatically use IntValue, others use StringValue
Type-Safe Usage Examples
Server Type Safety
lua
local PlayerState: PlayerStateServer = require(...)
-- Type-safe function with proper return types
local function awardCoins(player: Player, amount: number, source: string): boolean
if not PlayerState.IsPlayerDataReady(player) then
warn(`Cannot award coins to {player.Name} - data not ready`)
return false
end
local currentCoins: number = PlayerState.Get(player, "Coins") or 0
if amount <= 0 then
warn(`Invalid coin amount: {amount}`)
return false
end
local success = PlayerState.Set(player, "Coins", currentCoins + amount)
if success then
print(`Awarded {amount} coins to {player.Name} from {source}`)
end
return success
end
-- Type-safe batch operations
local function levelUpPlayer(player: Player): boolean
local operations: {BatchOperation} = {
{path = "Level", value = (PlayerState.Get(player, "Level") or 1) + 1},
{path = "Experience", value = 0},
{path = "Coins", value = (PlayerState.Get(player, "Coins") or 0) + 500}
}
return PlayerState.BatchSetValues(player, operations)
end
-- Type-safe data retrieval
local function getPlayerStats(player: Player): {Level: number, Experience: number, Coins: number}?
if not PlayerState.IsPlayerDataReady(player) then
return nil
end
local allData: PlayerData? = PlayerState.GetAll(player)
if not allData then
return nil
end
return {
Level = allData.Level or 1,
Experience = allData.Experience or 0,
Coins = allData.Coins or 0
}
end
Client Type Safety
lua
local PlayerState: PlayerStateClient = require(...)
-- Type-safe change listeners with enhanced info
local function setupCoinDisplay(label: TextLabel): ReplicaConnection?
return PlayerState.OnChanged("Coins", function(newValue: any, oldValue: any, info: ChangeInfo | {string}?)
local coins: number = newValue or 0
label.Text = tostring(coins)
-- Handle enhanced change info
if info and typeof(info) == "table" and info.action then
if oldValue and coins > oldValue then
showCoinGainEffect(coins - oldValue)
end
end
end)
end
-- Type-safe global change listener
local function setupGlobalListener(): ReplicaConnection?
return PlayerState.OnChanged(".", function(newValue: any, oldValue: any, info: ChangeInfo | {string}?)
if info and typeof(info) == "table" and info.action then
local changeInfo = info :: ChangeInfo
local pathString = table.concat(changeInfo.path, ".")
if changeInfo.action == "TableInsert" then
print(`Item added to {pathString} at index {changeInfo.index}`)
elseif changeInfo.action == "TableRemove" then
print(`Item removed from {pathString} at index {changeInfo.index}`)
end
end
end)
end
-- Type-safe data access with readiness check
local function getInventoryCount(): number?
if not PlayerState.IsReady() then
return nil
end
local inventory: {any} = PlayerState.GetPath("Inventory") or {}
return #inventory
end
Custom Type Extensions
Custom Item Types
You can extend these types for your specific use case:
lua
-- Custom item type for inventory
export type InventoryItem = {
Id: string,
Name: string,
Rarity: "Common" | "Rare" | "Epic" | "Legendary",
Level: number,
Attributes: {[string]: any}?,
AcquiredTime: number?,
UpgradedTime: number?,
}
-- Custom plot building type
export type PlotBuilding = {
Type: string,
Level: number,
Position: Vector3,
Rotation: number,
Upgrades: {string},
BuiltTime: number,
Health: number,
}
-- Extended player data with custom types
export type ExtendedPlayerData = PlayerData & {
Inventory: {InventoryItem},
Plot: {
Likes: number,
Size: number,
Buildings: {[string]: PlotBuilding},
},
Stats: {
TotalPlayTime: number,
GamesPlayed: number,
HighScore: number,
RecentScores: {number},
}
}
-- Batch operation with custom validation
export type ValidatedBatchOperation = BatchOperation & {
validate: () -> boolean,
description: string,
}
Type Guards and Validation
Runtime Type Checking
Utility functions for runtime type checking:
lua
-- Check if value is a valid inventory item
local function isInventoryItem(value: any): boolean
return typeof(value) == "table"
and typeof(value.Id) == "string"
and typeof(value.Name) == "string"
and typeof(value.Rarity) == "string"
and typeof(value.Level) == "number"
end
-- Check if change info is enhanced
local function isChangeInfo(value: any): boolean
return typeof(value) == "table"
and typeof(value.action) == "string"
and typeof(value.path) == "table"
end
-- Type-safe array access
local function getInventoryItem(index: number): InventoryItem?
if not PlayerState.IsReady() then
return nil
end
local inventory = PlayerState.GetPath("Inventory")
if typeof(inventory) ~= "table" or not inventory[index] then
return nil
end
local item = inventory[index]
return isInventoryItem(item) and item or nil
end
-- Validate batch operations
local function validateBatchOperations(operations: {BatchOperation}): boolean
for _, operation in operations do
if typeof(operation.path) ~= "string" or operation.value == nil then
return false
end
-- Check for leaderstats paths
if operation.path == "leaderstats" or string.sub(operation.path, 1, 12) == "leaderstats." then
warn(`Invalid batch operation: cannot modify leaderstats path {operation.path}`)
return false
end
end
return true
end
Performance Type Considerations
Caching Types
lua
-- Cache entry types
type CacheEntry<T> = {
value: T,
timestamp: number,
}
type PathCache = {[string]: {string}}
type ValueCache<T> = {[string]: CacheEntry<T>}
Connection Management Types
lua
-- Connection manager types
type ConnectionManager = {
connections: {[string]: ReplicaConnection},
add: (name: string, connection: ReplicaConnection) -> (),
remove: (name: string) -> (),
cleanup: () -> (),
}
These enhanced types provide better IntelliSense support, catch potential errors at development time, and make the codebase more maintainable with clear interfaces and expectations.