Skip to content

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 initialize
  • existingData?: 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 player
  • key: string - Data key
  • value: 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 player
  • key: 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 player
  • path: 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 player
  • path: 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 player
  • values: {[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 player
  • operations: {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 player
  • arrayPath: ArrayPath - Path to the array
  • item: 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 player
  • arrayPath: ArrayPath - Path to the array
  • index: 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 player
  • arrayPath: ArrayPath - Path to the array
  • index: 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 player
  • dictPath: DictPath - Path to the dictionary
  • key: string - Dictionary key
  • value: 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 player
  • dictPath: DictPath - Path to the dictionary
  • key: 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 player
  • dictPath: DictPath - Path to the dictionary
  • key: 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

  1. Use Batch Operations: BatchSetValues() for multiple changes
  2. Check Data Readiness: IsPlayerDataReady() before operations
  3. Cache Management: ClearPathCache() for memory optimization
  4. Return Status Checking: Always check success returns
  5. Path Optimization: Reuse path strings when possible

🛡️ Best Practices

  1. Functions validate automatically - no manual readiness checks needed
  2. Use batch operations for multiple simultaneous changes
  3. Handle return values - most functions now return success status
  4. Avoid direct leaderstats modification - change source data instead
  5. Use proper error handling and user feedback
  6. Leverage automatic leaderstats for player progression display
  7. Monitor cache performance and clear when necessary

PlayerState - High-Performance Roblox Data Management