Appearance
Server Functions
Server-side PlayerState API for data management and persistence.
Server Only - Security
Server scripts only. No built-in RemoteEvents - create your own with validation.
Never trust client data!
Initialization Functions
Init()
Init(player, existingData?)
Initializes PlayerState for a player. Must be called when a player joins.
Parameters:
player: Player
- The player to initializeexistingData?: PlayerData
- Optional existing data (not currently supported)
Returns: boolean
- Success status
Example:
lua
local success = PlayerState.Init(player)
if success then
print("Player data loaded successfully")
else
warn("Failed to load player data")
-- Player will be kicked automatically
end
Notes:
- Automatically loads data from ProfileStore
- Creates Replica for client synchronization
- Handles ProfileStore session management
- NEW: Automatic leaderstats integration if configured
- NEW: Enhanced data validation and cleanup
- Player will be kicked if data fails to load
Status Functions
IsPlayerDataReady()
IsPlayerDataReady(player)
Checks if player data is fully loaded and ready for operations.
Parameters:
player: Player
- Target player
Returns: boolean
- True if data is ready, false otherwise
Example:
lua
if PlayerState.IsPlayerDataReady(player) then
PlayerState.Set(player, "Coins", 1000)
else
warn("Player data not ready yet")
end
Notes:
- NEW: Optional check - all functions already validate internally
- NEW: Useful for conditional logic or bulk operations
- NEW: More reliable than checking individual components
Basic Data Functions
Set()
Set(player, key, value)
Sets a top-level data value with enhanced validation.
Parameters:
player: Player
- Target playerkey: string
- Data keyvalue: any
- New value
Returns: boolean
- Success status
Example:
lua
local success = PlayerState.Set(player, "Coins", 1000)
if success then
print("Coins updated successfully")
else
warn("Failed to update coins")
end
Notes:
- NEW: Returns success status instead of void
- NEW: Prevents direct leaderstats modification
- NEW: Enhanced validation and error handling
- NEW: Warns about path syntax usage in Set()
Get()
Get(player, key)
Gets a top-level data value with validation.
Parameters:
player: Player
- Target playerkey: string
- Data key
Returns: any
- The value, or nil
if not found
Example:
lua
local coins = PlayerState.Get(player, "Coins")
local level = PlayerState.Get(player, "Level")
print(`Player {player.Name} has {coins or 0} coins and is level {level or 1}`)
Notes:
- NEW: Enhanced validation for player and replica status
- Returns
nil
safely if player data isn't ready - Thread-safe operation
Path-based Functions
SetPath()
SetPath(player, path, value)
Sets a nested data value using dot notation with enhanced validation.
Parameters:
player: Player
- Target playerpath: ValuePath
- Dot-separated path (e.g., "Plot.Likes")value: any
- New value
Returns: boolean
- Success status
Example:
lua
local success = PlayerState.SetPath(player, "Plot.Likes", 50)
if success then
print("Plot likes updated")
end
PlayerState.SetPath(player, "Settings.MusicEnabled", false)
PlayerState.SetPath(player, "Stats.HighScore", 1200)
Notes:
- NEW: Returns success status for better error handling
- NEW: Optimized path parsing with caching
- NEW: Prevents direct leaderstats path modification
- NEW: Enhanced nested value setting
GetPath()
GetPath(player, path)
Gets a nested data value using dot notation with optimized performance.
Parameters:
player: Player
- Target playerpath: ValuePath
- Dot-separated path
Returns: any
- The value, or nil
if not found
Example:
lua
local likes = PlayerState.GetPath(player, "Plot.Likes")
local musicEnabled = PlayerState.GetPath(player, "Settings.MusicEnabled")
local highScore = PlayerState.GetPath(player, "Stats.HighScore")
Notes:
- NEW: Optimized nested value retrieval
- NEW: Enhanced path caching system
- Safe handling of nil values in path traversal
Batch Operation Functions
SetValues()
SetValues(player, values)
Sets multiple top-level values at once with leaderstats protection.
Parameters:
player: Player
- Target playervalues: {[string]: any}
- Dictionary of key-value pairs
Returns: boolean
- Success status
Example:
lua
local success = PlayerState.SetValues(player, {
Coins = 1000,
Level = 5,
Experience = 750
})
if success then
print("Batch update successful")
end
Notes:
- NEW: Returns success status
- NEW: Prevents leaderstats modification in batch
- NEW: Enhanced error handling and validation
Performance
Use SetValues()
instead of multiple Set()
calls for better performance!
BatchSetValues()
BatchSetValues(player, operations)
Queues multiple path-based operations for optimized batch processing.
Parameters:
player: Player
- Target playeroperations: {BatchOperation}
- Array of batch operations
Returns: boolean
- Success status
lua
local success = PlayerState.BatchSetValues(player, {
{path = "Coins", value = 1000},
{path = "Level", value = 5},
{path = "Plot.Likes", value = 50}
})
lua
local operations = {
{path = "Coins", value = 2000},
{path = "Experience", value = 500},
{path = "Plot.Likes", value = 100},
{path = "Settings.MusicEnabled", value = true},
{path = "Stats.GamesPlayed", value = 25}
}
PlayerState.BatchSetValues(player, operations)
Notes:
- NEW: High-performance batch processing system
- NEW: Automatic optimization based on path structure
- NEW: Configurable batch delay and size limits
- NEW: Auto-flush when batch size reaches limit
- NEW: Prevents leaderstats modification
Batch Performance
- Operations are grouped by path structure for optimal performance
- Root-level operations are batched together
- Nested operations are intelligently grouped
- Auto-flush occurs at 20 operations or 0.03s delay
FlushBatch()
FlushBatch(player)
Immediately processes all queued batch operations for a player.
Parameters:
player: Player
- Target player
Returns: boolean
- Success status
Example:
lua
-- Queue operations
PlayerState.BatchSetValues(player, {
{path = "Coins", value = 1000},
{path = "Level", value = 5}
})
-- Force immediate processing
PlayerState.FlushBatch(player)
Notes:
- NEW: Manual batch processing control
- Useful for critical operations that need immediate processing
- Cancels any scheduled delayed processing
Array Operation Functions
AddToArray()
AddToArray(player, arrayPath, item)
Adds an item to the end of an array with validation.
Parameters:
player: Player
- Target playerarrayPath: ArrayPath
- Path to the arrayitem: any
- Item to add
Returns: boolean
- Success status
Example:
lua
-- Add item to inventory
local success = PlayerState.AddToArray(player, "Inventory", {
Id = "sword_001",
Name = "Iron Sword",
Rarity = "Common"
})
if success then
print("Item added to inventory")
end
-- Add achievement
PlayerState.AddToArray(player, "Achievements", "first_kill")
Notes:
- NEW: Enhanced array operation with success return
- NEW: Validates array path and player status
- Triggers appropriate change events for client synchronization
Array Indexing
Arrays are 1-indexed in Lua. Index 1 is the first item!
RemoveFromArray()
RemoveFromArray(player, arrayPath, index)
Removes an item from an array by index with bounds checking.
Parameters:
player: Player
- Target playerarrayPath: ArrayPath
- Path to the arrayindex: number
- Index to remove (1-based)
Returns: boolean
- Success status
Example:
lua
-- Remove first item from inventory
local success = PlayerState.RemoveFromArray(player, "Inventory", 1)
if not success then
warn("Failed to remove item")
end
-- Remove specific achievement
PlayerState.RemoveFromArray(player, "Achievements", 3)
Notes:
- NEW: Safe index-based removal with bounds checking
- NEW: Enhanced error handling and validation
- Returns
false
if index is invalid or operation fails
UpdateArrayItem()
UpdateArrayItem(player, arrayPath, index, newItem)
Updates an item in an array by index with validation.
Parameters:
player: Player
- Target playerarrayPath: ArrayPath
- Path to the arrayindex: number
- Index to update (1-based)newItem: any
- New item value
Returns: boolean
- Success status
Example:
lua
-- Update inventory item
local success = PlayerState.UpdateArrayItem(player, "Inventory", 1, {
Id = "sword_002",
Name = "Steel Sword",
Rarity = "Rare",
Enchantments = {"Sharpness", "Durability"}
})
if success then
print("Item upgraded successfully")
end
Notes:
- NEW: Safe array item modification
- NEW: Index validation and bounds checking
- Useful for upgrading or modifying existing array elements
Dictionary Operation Functions
SetInDict()
SetInDict(player, dictPath, key, value)
Sets a value in a dictionary/table with path validation.
Parameters:
player: Player
- Target playerdictPath: DictPath
- Path to the dictionarykey: string
- Dictionary keyvalue: any
- Value to set
Returns: boolean
- Success status
Example:
lua
-- Set building data
local success = PlayerState.SetInDict(player, "Plot.Buildings", "House", {
Level = 2,
Material = "Wood",
Position = Vector3.new(10, 0, 10)
})
-- Set game setting
PlayerState.SetInDict(player, "Settings", "GraphicsQuality", "High")
-- Set player stat
PlayerState.SetInDict(player, "Stats", "BestTime", 120.5)
Notes:
- NEW: Safe dictionary manipulation
- NEW: Enhanced path validation and error handling
- Creates nested structure if it doesn't exist
GetFromDict()
GetFromDict(player, dictPath, key)
Gets a value from a dictionary using a key with automatic type conversion.
Parameters:
player: Player
- Target playerdictPath: DictPath
- Path to the dictionarykey: string | number
- Dictionary key (numbers are converted to strings)
Returns: any
- The value, or nil
if not found
Example:
lua
-- Get building data
local houseData = PlayerState.GetFromDict(player, "Plot.Buildings", "House")
if houseData then
print("House level:", houseData.Level)
print("House material:", houseData.Material)
end
-- Get with numeric key (automatically converted to string)
local item = PlayerState.GetFromDict(player, "Inventory.Equipped", 1)
-- Get setting
local quality = PlayerState.GetFromDict(player, "Settings", "GraphicsQuality")
print("Graphics quality:", quality or "Default")
Notes:
- Automatically converts number keys to strings for consistency
- Returns
nil
if the dictionary or key doesn't exist - NEW: Safe dictionary value retrieval with validation
- NEW: Enhanced type handling for keys
RemoveFromDict()
RemoveFromDict(player, dictPath, key)
Removes a key from a dictionary with validation.
Parameters:
player: Player
- Target playerdictPath: DictPath
- Path to the dictionarykey: string
- Key to remove
Returns: boolean
- Success status
Example:
lua
-- Remove building
local success = PlayerState.RemoveFromDict(player, "Plot.Buildings", "OldHouse")
if success then
print("Building removed")
end
-- Remove obsolete setting
PlayerState.RemoveFromDict(player, "Settings", "ObsoleteOption")
Notes:
- NEW: Safe key removal from dictionaries
- Sets the key value to
nil
effectively removing it - NEW: Enhanced validation and error reporting
Cache Management Functions
ClearPathCache()
ClearPathCache()
Clears the global path parsing cache for memory management.
Parameters: None
Returns: Nothing
Example:
lua
-- Clear path cache during server maintenance
PlayerState.ClearPathCache()
-- Useful for debugging path-related issues
Notes:
- NEW: Global cache management for path parsing
- NEW: Automatic cache size management (max 1000 entries)
- Use for debugging or memory optimization
- Cache rebuilds automatically on next path access
Utility Functions
GetAll()
GetAll(player)
Gets all player data with validation.
Parameters:
player: Player
- Target player
Returns: PlayerData?
- Complete data table, or nil
if not found
Example:
lua
local allData = PlayerState.GetAll(player)
if allData then
print("Player has", allData.Coins, "coins")
-- Safely iterate through data
for key, value in pairs(allData) do
print(`{key}: {value}`)
end
end
Notes:
- NEW: Enhanced validation and nil safety
- Returns reference to actual data (be careful with modifications)
GetReplica()
GetReplica(player)
Gets the raw Replica instance for advanced operations.
Parameters:
player: Player
- Target player
Returns: ReplicaInstance?
- Replica instance, or nil
if not found
Example:
lua
local replica = PlayerState.GetReplica(player)
if replica then
-- Advanced Replica operations
replica:OnChange(function(action, path, ...)
print(`Data changed: {action} at {table.concat(path, ".")}`)
end)
-- Check replica status
print("Replica is active:", replica:IsActive())
end
Notes:
- NEW: Enhanced validation ensures replica is active
- Provides access to low-level Replica functionality
GetProfile()
GetProfile(player)
Gets the raw ProfileStore profile for advanced operations.
Parameters:
player: Player
- Target player
Returns: ProfileStoreProfile?
- Profile instance, or nil
if not found
Example:
lua
local profile = PlayerState.GetProfile(player)
if profile then
-- Advanced ProfileStore operations
print("Profile is active:", profile:IsActive())
-- Access profile metadata
print("Profile tags:", profile.Tags)
end
Notes:
- NEW: Enhanced validation ensures profile is active
- Use for advanced ProfileStore features
SaveData()
SaveData(player)
Forces data save validation check.
Parameters:
player: Player
- Target player
Returns: boolean
- Profile active status
Example:
lua
-- Check if save will succeed before critical operation
local canSave = PlayerState.SaveData(player)
if canSave then
-- Proceed with critical operation
PlayerState.Set(player, "ImportantData", value)
else
warn("Cannot save data - profile inactive")
end
Notes:
- NEW: Returns profile active status for validation
- Data is automatically saved on player leave and server shutdown
- Use for validation before critical operations
Leaderstats Integration
🏆 Automatic Leaderstats
PlayerState now automatically creates and manages leaderstats based on your data configuration:
lua
-- In your DefaultData module, add leaderstats configuration:
local DefaultData = {
Coins = 0,
Level = 1,
Experience = 0,
Plot = {
Likes = 0
},
-- Leaderstats configuration
leaderstats = {
["💰 Coins"] = "Coins",
["⭐ Level"] = "Level",
["👍 Likes"] = "Plot.Likes"
}
}
Features:
- Automatic Creation: Leaderstats are created when player data loads
- Real-time Sync: Updates automatically when data changes
- Type-Safe: Numbers use IntValue, others use StringValue
- Path Support: Supports nested paths like
"Plot.Likes"
Leaderstats Protection
Direct modification of leaderstats paths is prevented. Change the source data instead!
lua
-- ❌ This will fail
PlayerState.Set(player, "leaderstats", {...})
-- ✅ This updates the leaderstat automatically
PlayerState.Set(player, "Coins", 1000)
Usage Examples
💰 Currency Management with Validation
lua
-- Award coins (validation handled internally)
local function awardCoins(player, amount, source)
local currentCoins = PlayerState.Get(player, "Coins") or 0
local success = PlayerState.Set(player, "Coins", currentCoins + amount)
if success then
print(`Awarded {amount} coins to {player.Name} from {source}`)
return true
else
warn(`Failed to award coins to {player.Name}`)
return false
end
end
-- Spend coins with validation
local function spendCoins(player, amount, item)
local currentCoins = PlayerState.Get(player, "Coins") or 0
if currentCoins < amount then
return false, "Insufficient coins"
end
local success = PlayerState.Set(player, "Coins", currentCoins - amount)
if success then
print(`{player.Name} spent {amount} coins on {item}`)
return true, "Purchase successful"
else
return false, "Transaction failed"
end
end
📈 Level System with Batch Operations
lua
-- Level up player with batch operations
local function levelUp(player)
local currentLevel = PlayerState.Get(player, "Level") or 1
local currentCoins = PlayerState.Get(player, "Coins") or 0
local bonusCoins = currentLevel * 100
local success = PlayerState.BatchSetValues(player, {
{path = "Level", value = currentLevel + 1},
{path = "Experience", value = 0},
{path = "Coins", value = currentCoins + bonusCoins}
})
if success then
print(`{player.Name} leveled up to {currentLevel + 1}!`)
return true
end
return false
end
-- Add experience with level up check
local function addExperience(player, amount)
local currentExp = PlayerState.Get(player, "Experience") or 0
local currentLevel = PlayerState.Get(player, "Level") or 1
local expNeeded = currentLevel * 100
local newExp = currentExp + amount
if newExp >= expNeeded then
-- Level up
levelUp(player)
else
-- Just add experience
PlayerState.Set(player, "Experience", newExp)
end
end
🎒 Enhanced Inventory Management
lua
local MAX_INVENTORY_SIZE = 50
-- Add item with validation and limits
local function addItem(player, item)
local inventory = PlayerState.GetPath(player, "Inventory") or {}
if #inventory >= MAX_INVENTORY_SIZE then
return false, "Inventory full"
end
-- Add timestamp to item
item.AcquiredTime = os.time()
local success = PlayerState.AddToArray(player, "Inventory", item)
if success then
print(`Added {item.Name} to {player.Name}'s inventory`)
return true, "Item added"
end
return false, "Failed to add item"
end
-- Remove item by ID
local function removeItemById(player, itemId)
local inventory = PlayerState.GetPath(player, "Inventory") or {}
for index, item in ipairs(inventory) do
if item.Id == itemId then
local success = PlayerState.RemoveFromArray(player, "Inventory", index)
if success then
print(`Removed {item.Name} from {player.Name}'s inventory`)
return true
end
break
end
end
return false
end
-- Upgrade item in inventory
local function upgradeItem(player, itemIndex, newStats)
local inventory = PlayerState.GetPath(player, "Inventory") or {}
local item = inventory[itemIndex]
if not item then
return false, "Item not found"
end
-- Merge new stats
for key, value in pairs(newStats) do
item[key] = value
end
-- Update upgraded time
item.UpgradedTime = os.time()
local success = PlayerState.UpdateArrayItem(player, "Inventory", itemIndex, item)
if success then
print(`Upgraded {item.Name} for {player.Name}`)
return true
end
return false, "Upgrade failed"
end
🏠 Plot Building System
lua
-- Build structure on plot
local function buildStructure(player, buildingType, position)
local buildingData = {
Type = buildingType,
Level = 1,
Position = position,
BuiltTime = os.time(),
Health = 100
}
local buildingId = `{buildingType}_{os.time()}`
local success = PlayerState.SetInDict(player, "Plot.Buildings", buildingId, buildingData)
if success then
print(`{player.Name} built {buildingType} at {position}`)
return true, buildingId
end
return false, "Build failed"
end
-- Upgrade building
local function upgradeBuilding(player, buildingId)
local building = PlayerState.GetPath(player, `Plot.Buildings.{buildingId}`)
if not building then
return false, "Building not found"
end
building.Level = building.Level + 1
building.UpgradedTime = os.time()
local success = PlayerState.SetInDict(player, "Plot.Buildings", buildingId, building)
if success then
print(`{player.Name} upgraded {building.Type} to level {building.Level}`)
return true
end
return false, "Upgrade failed"
end
-- Remove building
local function removeBuilding(player, buildingId)
local success = PlayerState.RemoveFromDict(player, "Plot.Buildings", buildingId)
if success then
print(`{player.Name} removed building {buildingId}`)
return true
end
return false, "Removal failed"
end
Performance Tips
🚀 Optimization Strategies
- Use Batch Operations:
BatchSetValues()
for multiple changes - Check Data Readiness:
IsPlayerDataReady()
before operations - Cache Management:
ClearPathCache()
for memory optimization - Return Status Checking: Always check success returns
- Path Optimization: Reuse path strings when possible
🛡️ Best Practices
- Functions validate automatically - no manual readiness checks needed
- Use batch operations for multiple simultaneous changes
- Handle return values - most functions now return success status
- Avoid direct leaderstats modification - change source data instead
- Use proper error handling and user feedback
- Leverage automatic leaderstats for player progression display
- Monitor cache performance and clear when necessary