The Game Tree
Every Roblox game is a tree of objects rooted at game. Understanding where things live — and why — is the foundation of effective scripting. If you don't know where to look, you'll spend hours finding nothing.
The Service Layer
At the top level, game contains services — singletons managed by Roblox. The ones you care about:
game
├── Workspace ← the 3D world
├── Players ← connected players
├── ReplicatedStorage ← shared between server and client
├── ReplicatedFirst ← loads before anything else
├── Lighting ← visual effects and atmosphere
├── SoundService ← audio settings
├── Teams ← team objects
├── StarterGui ← GUI templates (not useful at runtime)
├── StarterPack ← tool templates (not useful at runtime)
├── CoreGui ← Roblox system UI (you can parent to this)
└── ...
As a client, you cannot see ServerScriptService, ServerStorage, or TextChatService's server components.
Workspace: The 3D World
Workspace is where everything physical lives:
Workspace
├── Camera ← the camera object
├── [PlayerName] ← your character model (added when you spawn)
│ ├── HumanoidRootPart
│ ├── Humanoid
│ ├── Head
│ ├── UpperTorso / Torso
│ ├── LowerTorso / HumanoidRootPart
│ └── [scripts, values, accessories]
├── [Other players' characters]
├── Baseplate / Map parts
└── [Game-specific folders]
The game-specific folders are what you need to discover. Common names you'll see:
| Folder name | Usually contains |
|---|---|
Entities / NPCs / Mobs / Enemies | NPC characters |
Map / World / Level | Static terrain and structures |
Items / Drops | Collectible objects |
Effects / VFX | Visual effects (particles, etc.) |
Zones / Regions | Trigger areas |
There's no standard — every game invents its own naming. That's why you need Dex.
ReplicatedStorage: Where Remotes Live
Almost every game puts its RemoteEvents and RemoteFunctions in ReplicatedStorage because both client and server can access it:
ReplicatedStorage
├── Remotes (folder)
│ ├── AttackRemote ← RemoteEvent
│ ├── GetPlayerData ← RemoteFunction
│ └── ShopRemote ← RemoteEvent or RemoteFunction
├── Modules (folder)
│ └── GameConfig ← ModuleScript
└── Assets
└── [models, sounds, etc.]
Some games scatter remotes directly in ReplicatedStorage instead of organizing them in a folder. Others put them in game.Players.LocalPlayer or deeply nested in workspace. Use rSpy to find them regardless of location — it captures all remote traffic.
The Players Service
Players
├── LocalPlayer ← you
│ ├── PlayerGui ← your UI (ScreenGuis live here)
│ ├── Backpack ← your tools
│ ├── PlayerScripts ← client-side scripts the game gave you
│ └── leaderstats ← common name for stat values (coins, level, etc.)
└── [OtherPlayer]
└── ...
PlayerScripts often contains ModuleScripts with game logic you can read. leaderstats (if it exists) is a folder with ValueBase instances for public stats.
Finding Instances by Class
When you know the type but not the location:
-- Find all RemoteEvents anywhere in the game
for _, v in game:GetDescendants() do
if v:IsA("RemoteEvent") then
print(v:GetFullName())
end
end
-- Find all Humanoids (living entities)
for _, v in workspace:GetDescendants() do
if v:IsA("Humanoid") and v.Health > 0 then
print(v.Parent.Name, v.Health)
end
end
-- Find a specific named remote anywhere
local function findRemote(name)
for _, v in game:GetDescendants() do
if (v:IsA("RemoteEvent") or v:IsA("RemoteFunction")) and v.Name == name then
return v
end
end
end
GetDescendants() on the whole game is slow. Narrow it down — search workspace for entities, ReplicatedStorage for remotes.
Common Patterns for NPC/Enemy Structure
Games that have enemies usually follow one of these patterns:
Pattern A: Folder of models
workspace.Enemies
├── Goblin1 (Model)
│ ├── HumanoidRootPart
│ ├── Humanoid
│ └── HP (NumberValue)
├── Goblin2 (Model)
└── ...
Pattern B: Tagged with CollectionService
local CollectionService = game:GetService("CollectionService")
for _, entity in CollectionService:GetTagged("Enemy") do
-- entity is any instance tagged "Enemy"
end
Pattern C: Replicated folder updated by server
The server adds/removes enemies from a folder; the client watches it with ChildAdded/ChildRemoved.
Look for patterns when exploring — if you find one enemy, the others are usually structured identically.
Detecting Folder Structure Without Dex
You can print the tree from your executor:
-- Print first two levels of workspace
local function printTree(parent, depth)
if depth > 2 then return end
for _, child in parent:GetChildren() do
print(string.rep(" ", depth) .. child.ClassName .. " " .. child.Name)
printTree(child, depth + 1)
end
end
printTree(workspace, 0)
This is handy when you don't have Dex available or want a quick scan.