Skip to main content

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 nameUsually contains
Entities / NPCs / Mobs / EnemiesNPC characters
Map / World / LevelStatic terrain and structures
Items / DropsCollectible objects
Effects / VFXVisual effects (particles, etc.)
Zones / RegionsTrigger 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
tip

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.