Values & Configs
Roblox has a family of "Value" instances that store individual data values in the object tree. Games use them constantly to store player stats, game flags, and NPC states. Learning to find, read, watch, and write them gives you a window into the game's live state.
The Value Instance Types
| Type | Stores | Example use |
|---|---|---|
StringValue | A string | Player class, team name, status effect |
NumberValue | A float | Custom HP, multiplier, score |
IntValue | An integer | Level, coins, kills |
BoolValue | true/false | Is raging, is stunned, has shield |
ObjectValue | Any Instance | Current target, equipped item |
Vector3Value | Vector3 | Spawn position, destination |
CFrameValue | CFrame | Saved transform |
Color3Value | Color3 | Team color, UI theme |
All have a single .Value property that holds the data.
Reading Values
local char = Players.LocalPlayer.Character
-- Find a value on a character
local levelValue = char:FindFirstChild("Level")
if levelValue then
print("My level:", levelValue.Value)
end
-- Find value by type (when you know the type but not the name)
local strVal = char:FindFirstChildOfClass("StringValue")
if strVal then
print(strVal.Name, "=", strVal.Value)
end
-- Print ALL values on an NPC
local npc = workspace.Enemies:FindFirstChild("BossEnemy")
if npc then
for _, child in npc:GetDescendants() do
if child:IsA("ValueBase") then -- base class of all value types
print(child.ClassName, child.Name, "=", tostring(child.Value))
end
end
end
Writing Values
-- Attempt to modify a value
local speedMult = char:FindFirstChild("SpeedMultiplier")
if speedMult and speedMult:IsA("NumberValue") then
speedMult.Value = 3.0 -- client-side change
end
-- BoolValue toggle
local isRaging = char:FindFirstChild("IsRaging")
if isRaging then
isRaging.Value = true
end
Important: Writing values only changes them on your client. The server has its own copy. For values that drive server-side behavior (like damage dealt), changing the client copy does nothing to the actual gameplay — the server reads its own copy. Some games read values on the client to show UI (HP bar, stat display) — modifying those can fake UI state but doesn't affect real values.
Reacting to Value Changes
The .Changed event fires whenever .Value changes:
local rageValue = char:WaitForChild("IsRaging", 10)
if rageValue then
-- React immediately to current state
print("Currently raging:", rageValue.Value)
-- React to future changes
rageValue.Changed:Connect(function(newValue)
if newValue then
print("Entered rage!")
else
print("Rage ended")
end
end)
end
For precise property watching:
rageValue:GetPropertyChangedSignal("Value"):Connect(function()
print("New value:", rageValue.Value)
end)
Configuration Folders
Many games group settings in a Configuration instance or a plain Folder with values inside:
local config = game.ReplicatedStorage:FindFirstChild("GameConfig")
or game.Workspace:FindFirstChild("Settings")
if config then
for _, val in config:GetChildren() do
if val:IsA("ValueBase") then
print(val.Name, "=", val.Value)
end
end
end
Example structure in a game:
ReplicatedStorage
└── GameConfig (Configuration)
├── MaxPlayers (IntValue = 20)
├── RoundTime (NumberValue = 300)
├── Mode (StringValue = "Competitive")
└── DebugMode (BoolValue = false)
If DebugMode is a BoolValue you can write to, setting it true on your client might reveal debug info in the UI.
ObjectValue: Tracking Targets
ObjectValue is special — it holds a reference to another Instance:
-- A game might store the player's current target:
local targetValue = char:FindFirstChild("CurrentTarget")
if targetValue and targetValue:IsA("ObjectValue") then
local target = targetValue.Value -- this is the actual Instance
if target then
print("Targeting:", target:GetFullName())
end
-- Watch for target changes
targetValue.Changed:Connect(function(newTarget)
if newTarget then
print("New target:", newTarget.Name)
end
end)
end
leaderstats
leaderstats is a Roblox convention — a Folder named leaderstats on each player containing their public stats. Most games have it:
local player = Players.LocalPlayer
local stats = player:WaitForChild("leaderstats", 5)
if stats then
for _, stat in stats:GetChildren() do
print(stat.Name, "=", stat.Value)
end
-- Example output:
-- Coins = 1250
-- Level = 7
-- Kills = 43
end
Watch a stat change:
local coins = stats:WaitForChild("Coins")
coins.Changed:Connect(function(newAmount)
print("Coins changed to:", newAmount)
end)
Finding Values Across All Players
-- Print level of every connected player
for _, player in Players:GetPlayers() do
local stats = player:FindFirstChild("leaderstats")
if stats then
local level = stats:FindFirstChild("Level")
print(player.Name, "level:", level and level.Value or "?")
end
end
Using Values to Detect Game State
Values are often the simplest way to know what's happening:
-- Watch for a round state value
local roundState = workspace:WaitForChild("RoundState", 10)
if roundState then
roundState.Changed:Connect(function(state)
if state == "active" then
print("Round started!")
-- enable your script
elseif state == "intermission" then
print("Round over, waiting...")
-- disable your script
end
end)
end
This pattern lets your script automatically enable/disable based on the game's own state machine — no manual timing required.