A modern player data management system for Roblox games featuring ProfileService integration, replica-based state replication, automatic leaderboards, and batched updates.
π Full Documentation - Complete API reference, guides, and examples
- β ProfileService Integration - Secure data persistence with session locking
- β Real-time Replication - Automatic client data sync with change tracking
- β Built-in Leaderboards - Automatic stat tracking and rankings
- β Batched Updates - Efficient DataStore writes
- β Path-Based Access - Access nested data with dot notation
- β Type-Safe API - Full Luau type coverage
- β Performance Optimized - Intelligent caching and rate limiting
Recommended for beginners - Download the latest .rbxm file from Releases and drag it into your ReplicatedStorage.
Clone or download this repository
git clone https://github.com/bellaouzo/PlayerState.git
Use the GitHub Cloning Plugin to clone directly into Roblox Studio.
Edit DefaultData.luau to define your player data:
return {
Coins = 0,
Level = 1,
Inventory = {
Weapons = {},
Items = {}
},
leaderstats = {
["π° Coins"] = "Coins",
["β Level"] = "Level"
}
}Edit PlayerStateConfig.luau for your game settings:
local Config = {
Server = {
DataStore = {
Name = "PlayerData_v1",
Scope = "Production"
},
Leaderboard = {
Enabled = true,
TrackedStats = {"Coins", "Level"}
}
}
}
return Configlocal Players = game:GetService("Players")
local PlayerState = require(ReplicatedStorage.PlayerState.PlayerStateServer)
Players.PlayerAdded:Connect(function(player)
local success = PlayerState.Init(player)
if success then
print(`[PlayerState] Loaded data for {player.Name}`)
end
end)
Players.PlayerRemoving:Connect(function(player)
PlayerState.SaveData(player)
end)local PlayerState = require(ReplicatedStorage.PlayerState.PlayerStateClient)
-- Wait for data to load
PlayerState.IsReady() -- Check if ready
-- Listen for changes
PlayerState.OnChanged("Coins", function(newValue, oldValue)
print(`Coins: {oldValue} β {newValue}`)
end)-- Set a value
PlayerState.Set(player, "Coins", 100)
-- Get a value
local coins = PlayerState.Get(player, "Coins")
-- Access nested data with dot notation
PlayerState.SetPath(player, "Inventory.Weapons[1].Durability", 95)
local durability = PlayerState.GetPath(player, "Inventory.Weapons[1].Durability")-- Increment by 1
PlayerState.Increment(player, "Coins")
-- Increment by custom amount
PlayerState.Increment(player, "Level", 5)
-- Decrement
PlayerState.Decrement(player, "Coins", 10)-- Add item to array
PlayerState.AddToArray(player, "Inventory.Weapons", {
Id = "sword_001",
Name = "Iron Sword",
Damage = 10
})
-- Update array item
PlayerState.UpdateArrayItem(player, "Inventory.Weapons", 1, {
Id = "sword_001",
Name = "Iron Sword",
Damage = 15
})
-- Remove from array
PlayerState.RemoveFromArray(player, "Inventory.Weapons", 1)-- Set dictionary value
PlayerState.SetInDict(player, "Inventory.Items", "health_potion", 5)
-- Get dictionary value
local quantity = PlayerState.GetFromDict(player, "Inventory.Items", "health_potion")
-- Remove from dictionary
PlayerState.RemoveFromDict(player, "Inventory.Items", "health_potion")-- Update multiple values at once
PlayerState.BatchSetValues(player, {
{path = "Coins", value = 200},
{path = "Level", value = 5},
{path = "Experience", value = 1000}
})
-- Manually flush batch (normally auto-flushes)
PlayerState.FlushBatch(player)-- Get top players
local topPlayers = PlayerState.GetLeaderboard("Coins", 10)
-- Returns: {{userId = 123, score = 5000, rank = 1}, ...}
-- Get player's rank
local rank = PlayerState.GetPlayerRank(player, "Coins")-- Before data is saved
PlayerState.BeforeSave:Connect(function(player, data)
-- Validate or modify data before saving
end)
-- When player data loads
PlayerState.ProfileLoaded:Connect(function(player, data)
print("Data loaded for", player.Name)
end)
-- When player leaves
PlayerState.ProfileUnloaded:Connect(function(player, data)
print("Data saved for", player.Name)
end)-- Get all player data
local allData = PlayerState.GetAll(player)
-- Check if data is ready
if PlayerState.IsPlayerDataReady(player) then
-- Safe to use data
end
-- Save data manually
PlayerState.SaveData(player)
-- Admin: Wipe player data
PlayerState.WipePlayerData(player)-- Get value
local coins = PlayerState.Get("Coins")
-- Get nested value
local durability = PlayerState.GetPath("Inventory.Weapons[1].Durability")
-- Get dictionary value
local quantity = PlayerState.GetFromDict("Inventory.Items", "health_potion")
-- Get all data
local allData = PlayerState.GetAll()-- Listen to any path
PlayerState.OnChanged("Coins", function(newValue, oldValue)
print(`Coins changed: {oldValue} β {newValue}`)
end)
PlayerState.OnChanged("Inventory.Weapons", function(newValue, oldValue)
print("Weapons updated!")
end)-- Check if data is ready
if PlayerState.IsReady() then
-- Data loaded
end
-- Clear cache (advanced)
PlayerState.ClearCache()
-- Get underlying Replica (advanced)
local replica = PlayerState.GetReplica()This library uses the following third-party dependencies (included):
- ProfileStore by MAD STUDIO (loleris) - DataStore session management
- Replica by MAD STUDIO (loleris) - State replication system
- Maid, Signal, Remote, RateLimit by MAD STUDIO - Supporting utilities
See individual file headers for full attribution details.
MIT License - See LICENSE file for details
- π¬ DevForum Post
- π Report Issues