Reading time: ~30 minutes
The Unreal system is CORP’s game packaging and management framework. It provides a modular approach to organizing your game through Gamepacks - self-contained packages of assets, components, macros, and scripts.
Table of Contents
What is Unreal?
The Unreal system is CORP’s solution for:
- Modular Game Organization: Package features into independent Gamepacks
- Asset Management: Centralized asset loading and validation
- Component Registration: Automatic component discovery and mapping
- Script Management: Organized client and server script execution
- Game Configuration: Flexible authority and boot configuration
Key Features
- 📦 Gamepack System: Modular package organization
- 🎮 Authority Models: Client or server-authoritative games
- 🔧 Export Mappings: Components, Macros, and ScriptableObjects
- 📜 Script Management: Automatic client/server script placement
- 🚀 Bootstrap System: Configurable game initialization
Gamepacks
Gamepacks are the fundamental building blocks of the Unreal system. Each Gamepack is a self-contained module that can export:
- Components
- Macros
- ScriptableObjects
- Assets
- Client Scripts
- Server Scripts
- Boot Configuration
Gamepack Structure
MyGamepack/
├── metadata.ts # Gamepack configuration
├── exports/
│ ├── components.ts # Component mappings
│ ├── macros.ts # Macro mappings
│ ├── scriptableobjects.ts # ScriptableObject mappings
│ ├── bootconfig.ts # Boot configuration
│ └── scripts/
│ ├── client/ # Client scripts
│ └── server/ # Server scripts
├── assets/ # Asset folder
└── src/ # Source code
Project Structure
Typical CORP Project with Unreal
your-game/
├── CORP/ # Git submodule (must be named "CORP")
├── GAMECONFIG/
│ └── gameinfo.ts # Game configuration
├── GAMEPACKS/
│ ├── CorePack/ # Git submodule - core game systems
│ │ ├── metadata.ts
│ │ ├── exports/
│ │ └── assets/
│ ├── PlayerPack/ # Git submodule - player systems
│ │ ├── metadata.ts
│ │ └── exports/
│ └── EnemyPack/ # Git submodule - enemy systems
│ ├── metadata.ts
│ └── exports/
└── src/
├── client/
├── server/
└── shared/
Important: The CORP source code must be a git submodule named “CORP” in your repository. Each Gamepack should also be a git submodule for modularity and version control.
Setting Up Submodules
# Add CORP as a submodule
git submodule add <CORP-repo-url> CORP
# Add Gamepacks as submodules
git submodule add <gamepack-repo-url> GAMEPACKS/CorePack
git submodule add <gamepack-repo-url> GAMEPACKS/PlayerPack
Configuration
Game Info Configuration
Create GAMECONFIG/gameinfo.ts:
import { Unreal } from "CORP/shared/unreal";
const gameinfo: Unreal.Gameinfo = {
rootPack: "CorePack", // Root Gamepack to boot
authority: Unreal.Authority.SERVER // Authority model
};
export = gameinfo;
Authority Models
// Server-Authoritative (recommended for multiplayer)
authority: Unreal.Authority.SERVER
// Client-Authoritative (for single-player experiences)
authority: Unreal.Authority.CLIENT
Important: Workspace.StreamingEnabled should be disabled for client-authoritative games to ensure all game content is loaded immediately.
Create metadata.ts in your Gamepack:
import { Gamepacks } from "CORP/shared/unreal/gamepacks";
const metadata: Gamepacks.Config.Metadata = {
name: "MyGamepack",
// Development options
development: {
npm: {
includeLockfile: true,
includePackageJson: true
}
},
// Packaging options
packaging: {
npm: {
packageDependencies: true
},
obfuscation: {
engine: "luraph"
}
},
// Gamepack structure
options: {
assets: {}, // Include assets folder
source: {}, // Include source code
exports: {
components: {}, // Export components
macros: {}, // Export macros
scriptableObjects: {}, // Export ScriptableObjects
scripts: {
client: {}, // Export client scripts
server: {} // Export server scripts
},
boot: {} // Export boot config
}
}
};
export = metadata;
Bootstrap Process
How Unreal Bootstraps Your Game
- Load Game Info: Reads
GAMECONFIG/gameinfo.ts
- Parse Gamepacks: Discovers and parses all Gamepacks in
GAMEPACKS/
- Build Manifest: Creates game manifest with all exports
- Setup Assets: Organizes assets into centralized location
- Register Scripts: Places client/server scripts
- Execute Boot Config: Runs root Gamepack’s boot configuration
Using Bootstrap
In your client and server entry points:
// client/index.client.ts
import { Unreal } from "CORP/shared/unreal";
Unreal.bootstrap();
// server/index.server.ts
import { Unreal } from "CORP/shared/unreal";
Unreal.bootstrap();
Boot Configuration
Create exports/bootconfig.ts in your root Gamepack:
import { Boot } from "CORP/shared/unreal/gamepacks/boot";
const bootConfig: Boot.Config = {
// Start game from existing workspace instances
startFromWorkspace: true
};
export = bootConfig;
Boot Options:
startFromWorkspace: Load GameObjects from workspace with tags:
GameObjectSceneRoot: Main scene container
GameObjectContainer: Additional containers
Exports System
Exporting Components
Create exports/components.ts:
import { Config } from "CORP/shared/unreal/gamepacks/config";
import { PlayerController } from "../src/components/PlayerController";
import { EnemyAI } from "../src/components/EnemyAI";
import { HealthSystem } from "../src/components/HealthSystem";
import { NetworkObject } from "CORP/shared/networking/network-object";
const components: Config.Components = {
mappings: {
// Use snake_case for mapping names
"player_controller": PlayerController,
"enemy_ai": EnemyAI,
"health_system": HealthSystem,
// Core CORP components use $ prefix
"$network_object": NetworkObject
}
};
export = components;
Naming Convention: Use snake_case for all mapping names (components, macros, ScriptableObjects). Core CORP components are prefixed with $ (e.g., $network_object).
Exporting Macros
Create exports/macros.ts:
import { Config } from "CORP/shared/unreal/gamepacks/config";
import { PlayerMacro } from "../src/macros/PlayerMacro";
import { SpawnPointMacro } from "../src/macros/SpawnPointMacro";
const macros: Config.Macros = {
mappings: {
// Use snake_case for macro names
"player_macro": PlayerMacro,
"spawn_point_macro": SpawnPointMacro
}
};
export = macros;
Note: See Macros for detailed information about creating and using macros.
Exporting ScriptableObjects
Create exports/scriptableobjects.ts:
import { Config } from "CORP/shared/unreal/gamepacks/config";
import { WeaponData } from "../src/scriptableobjects/WeaponData";
import { EnemyData } from "../src/scriptableobjects/EnemyData";
const scriptableObjects: Config.ScriptableObjects = {
mappings: {
// Use snake_case for ScriptableObject names
"weapon_data": WeaponData,
"enemy_data": EnemyData
}
};
export = scriptableObjects;
Note: See ScriptableObjects for detailed information about creating and using ScriptableObjects.
Authority Models
Server-Authoritative
Best for multiplayer games where server controls game state.
// GAMECONFIG/gameinfo.ts
authority: Unreal.Authority.SERVER
Characteristics:
- Server spawns and manages NetworkObjects
- Server validates all game logic
- Clients replicate server state
- Ideal for competitive multiplayer
Example:
export class GameManager extends Behavior {
public onStart(): void {
if (Unreal.isAuthority()) {
// Server-side initialization
this.spawnEnemies();
this.setupGameLogic();
} else {
// Client-side initialization
this.setupUI();
}
}
protected getSourceScript(): ModuleScript {
return script as ModuleScript;
}
public willRemove(): void {}
}
Client-Authoritative
Best for single-player or cooperative games.
// GAMECONFIG/gameinfo.ts
authority: Unreal.Authority.CLIENT
Characteristics:
- Client controls game state
- Reduced server validation
- Lower network overhead
- Ideal for single-player or trusted environments
Warning: Set Workspace.StreamingEnabled = false for client-authoritative games.
Checking Authority
import { Unreal } from "CORP/shared/unreal";
export class GameController extends Behavior {
public onStart(): void {
if (Unreal.isAuthority()) {
// Authority (server or client based on config)
this.initializeGameState();
} else {
// Non-authority
this.waitForReplication();
}
}
protected getSourceScript(): ModuleScript {
return script as ModuleScript;
}
public willRemove(): void {}
}
Working with the Manifest
Accessing the Game Manifest
import { Unreal } from "CORP/shared/unreal";
// Get the complete manifest
const manifest = Unreal.getManifest();
// Access component mappings
const components = manifest.components;
// Access macro mappings
const macros = manifest.macros;
// Access ScriptableObject mappings
const scriptableObjects = manifest.scriptableObjects;
// Access game info
const gameinfo = manifest.gameinfo;
Getting Registered Classes
import { Unreal } from "CORP/shared/unreal";
// Get a component class by name
const PlayerClass = Unreal.getComponentClass("PlayerController");
// Get a macro class by name
const SpawnMacro = Unreal.getMacroClass("SpawnPointMacro");
// Get a ScriptableObject class by name
const WeaponDataClass = Unreal.getScriptableObjectClass("WeaponData");
Managing Scripts
Client Scripts
Place client scripts in exports/scripts/client/:
// exports/scripts/client/ClientSetup.client.ts
import { Players } from "@rbxts/services";
print("Client script loaded!");
Players.LocalPlayer.CharacterAdded.Connect((character) => {
print("Character spawned!");
});
These scripts are automatically placed in PlayerScripts.
Server Scripts
Place server scripts in exports/scripts/server/:
// exports/scripts/server/ServerSetup.server.ts
import { Players } from "@rbxts/services";
print("Server script loaded!");
Players.PlayerAdded.Connect((player) => {
print(`Player ${player.Name} joined!`);
});
These scripts are automatically placed in ServerScriptService.
Asset Management
Adding Assets to a Gamepack
- Create an
assets/ folder in your Gamepack
- Enable assets in metadata:
- Place asset folders in
assets/:
MyGamepack/
├── assets/
│ ├── Models/
│ │ ├── Player.rbxm
│ │ └── Enemy.rbxm
│ ├── Sounds/
│ └── UI/
- During bootstrap, assets are collapsed - all Gamepack assets are collected and organized into a centralized location in the game for easy access
Accessing Assets
Assets are accessed through the Virtual File System (VFS), which provides a unified path interface:
import { vfs } from "CORP/shared/utilities/vfs";
// Read an asset using the %assets% shorthand
const model = vfs.read<Model>("%assets%/Models/Player", {
classname: "Model"
});
// %assets% is equivalent to $collapsed/$assets in the VFS
// Both paths reference the same centralized asset location
VFS Path Convention: Use %assets% as a shorthand for the collapsed assets directory. The VFS automatically resolves this to the actual location where all Gamepack assets are stored.
Complete Example
Example Gamepack Setup
1. Game Configuration
// GAMECONFIG/gameinfo.ts
import { Unreal } from "CORP/shared/unreal";
const gameinfo: Unreal.Gameinfo = {
rootPack: "CoreGamepack",
authority: Unreal.Authority.SERVER
};
export = gameinfo;
// GAMEPACKS/CoreGamepack/metadata.ts
import { Gamepacks } from "CORP/shared/unreal/gamepacks";
const metadata: Gamepacks.Config.Metadata = {
name: "CoreGamepack",
options: {
assets: {},
exports: {
components: {},
boot: {}
}
}
};
export = metadata;
3. Component Exports
// GAMEPACKS/CoreGamepack/exports/components.ts
import { Config } from "CORP/shared/unreal/gamepacks/config";
import { PlayerController } from "../src/PlayerController";
import { GameManager } from "../src/GameManager";
const components: Config.Components = {
mappings: {
"PlayerController": PlayerController,
"GameManager": GameManager
}
};
export = components;
4. Boot Configuration
// GAMEPACKS/CoreGamepack/exports/bootconfig.ts
import { Boot } from "CORP/shared/unreal/gamepacks/boot";
const bootConfig: Boot.Config = {
startFromWorkspace: true
};
export = bootConfig;
5. Bootstrap
// client/index.client.ts & server/index.server.ts
import { Unreal } from "CORP/shared/unreal";
Unreal.bootstrap();
Best Practices
1. Organize by Feature
Create separate Gamepacks for major features:
GAMEPACKS/
├── CorePack/ # Core systems
├── PlayerPack/ # Player mechanics
├── CombatPack/ # Combat systems
├── UIPack/ # UI components
└── MapPack/ # Level assets
2. Use snake_case for Mapping Names
// ✓ Good - snake_case, clear and descriptive
mappings: {
"player_controller": PlayerController,
"enemy_ai": EnemyAI,
"health_system": HealthSystem,
"$network_object": NetworkObject // Core CORP components use $ prefix
}
// ✗ Bad - inconsistent casing
mappings: {
"PlayerController": PlayerController,
"enemyAI": EnemyAI
}
// ✗ Bad - unclear abbreviations
mappings: {
"pc": PlayerController,
"ai": EnemyAI
}
3. Choose Appropriate Authority
// ✓ Good for multiplayer
authority: Unreal.Authority.SERVER
// ✓ Good for single-player
authority: Unreal.Authority.CLIENT
// Note: Consider security and game type
4. Validate Gamepack Structure
Ensure your Gamepack has proper metadata before adding exports:
// Always include name
name: "MyGamepack",
// Enable options you use
options: {
assets: {}, // Only if you have assets
exports: {
components: {}, // Only if exporting components
// etc.
}
}
5. Keep Root Gamepack Minimal
The root Gamepack should primarily handle bootstrapping:
// Root Gamepack - minimal boot config
const bootConfig: Boot.Config = {
startFromWorkspace: true
};
// Other Gamepacks - feature implementation
6. Use Authority Checks
export class MyComponent extends Behavior {
public onStart(): void {
if (Unreal.isAuthority()) {
// Authority-only logic
} else {
// Replication logic
}
}
}
Troubleshooting
Common Issues
“Root gamepack not found”
- Ensure
rootPack name matches a Gamepack’s metadata name
- Check Gamepack is in
GAMEPACKS/ folder
“No scene root found in workspace”
- Tag a container with
GameObjectSceneRoot
- Ensure
startFromWorkspace: true in boot config
“Component mapping conflict”
- Different Gamepacks export same component name
- Use unique names across Gamepacks
Streaming warning with client authority
- Set
Workspace.StreamingEnabled = false in Roblox Studio
- This ensures all content loads immediately for client authority
- Or switch to
Unreal.Authority.SERVER
Next Steps
Master the Unreal system for modular, scalable game organization! 📦