> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monolisk.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced Topics

> Spawn management, observables, signals, performance optimization, and advanced patterns

<Note>**Reading time:** \~35 minutes</Note>

This guide covers advanced features and patterns in CORP for experienced developers.

## Table of Contents

* [Spawn Management](#spawn-management)
* [Observable System](#observable-system)
* [Signals](#signals)
* [Custom Serialization](#custom-serialization)
* [Performance Optimization](#performance-optimization)
* [Performance Namespace](#performance-namespace)
* [Advanced Networking Patterns](#advanced-networking-patterns)
* [Debugging and Logging](#debugging-and-logging)

## Spawn Management

The `SpawnManager` handles NetworkObject and NetworkBehavior spawning and synchronization.

### Understanding Spawn Lifecycle

When a NetworkObject is added to a GameObject on the server:

1. `addComponent(NetworkObject)` is called
2. NetworkObject automatically spawns and generates a unique network ID
3. GameObject is replicated to all clients
4. All NetworkBehaviors are registered
5. Clients reconstruct the GameObject and components
6. `onStart()` is called on both server and clients

> **Note**: You don't need to manually call `spawn()` - NetworkObjects spawn automatically when added with `addComponent()`. Manual `spawn()` is only needed when using the low-level `addComponentNoInit()` method.

### Working with SpawnManager

```typescript theme={null}
import { SpawnManager } from "CORP/shared/networking/spawn-manager";

// Get a NetworkBehavior by ID
const behavior = SpawnManager.getNetworkBehaviorById(behaviorId);

// Listen for NetworkBehavior spawns
SpawnManager.onNetworkBehaviorAdded.connect((behavior) => {
    print(`NetworkBehavior spawned: ${behavior.getId()}`);
});

// Listen for NetworkBehavior removals
SpawnManager.onNetworkBehaviorRemoved.connect((behavior) => {
    print(`NetworkBehavior removed: ${behavior.getId()}`);
});
```

### Dynamic Spawning Patterns

#### Spawn on Demand

```typescript theme={null}
export class EnemySpawner extends Behavior {
    private spawnedEnemies: GameObject[] = [];

    public spawnEnemy(position: Vector3): GameObject {
        const enemy = new GameObject("Enemy");
        enemy.setTransform(new CFrame(position));
        
        // NetworkObject automatically spawns when added
        enemy.addComponent(NetworkObject);
        enemy.addComponent(EnemyAI);
        enemy.addComponent(HealthSystem);

        if (RunService.IsServer()) {
            this.spawnedEnemies.push(enemy);
        }

        return enemy;
    }

    public despawnAll(): void {
        if (RunService.IsServer()) {
            for (const enemy of this.spawnedEnemies) {
                enemy.destroy();
            }
            this.spawnedEnemies = [];
        }
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

#### Object Pooling

```typescript theme={null}
export class ProjectilePool extends NetworkBehavior {
    private pool: GameObject[] = [];
    private active: Set<GameObject> = new Set();

    public onStart(): void {
        if (RunService.IsServer()) {
            // Pre-spawn projectiles
            for (let i = 0; i < 10; i++) {
                const projectile = this.createProjectile();
                this.pool.push(projectile);
            }
        }
    }

    private createProjectile(): GameObject {
        const proj = new GameObject("Projectile");
        const netObj = proj.addComponent(NetworkObject);
        proj.addComponent(Projectile);
        
        // Start inactive (no parent)
        proj.setParent(undefined);
        
        return proj;
    }

    public spawn(position: Vector3, direction: Vector3): GameObject | undefined {
        if (!RunService.IsServer()) return;

        // Get from pool
        const projectile = this.pool.pop();
        if (!projectile) return undefined;

        // Activate
        projectile.setTransform(new CFrame(position));
        projectile.setParent(SceneManager.currentScene);
        
        const proj = projectile.getComponent(Projectile);
        proj?.activate(direction);

        this.active.add(projectile);
        return projectile;
    }

    public despawn(projectile: GameObject): void {
        if (!RunService.IsServer()) return;

        // Deactivate - remove from scene
        projectile.setParent(undefined);
        
        this.active.delete(projectile);
        this.pool.push(projectile);
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

## Observable System

CORP uses an observable system for networked state management.

### NetworkedObservable Base Class

All networked collections inherit from `NetworkedObservable`:

```typescript theme={null}
export class CustomNetworkedType<T> extends NetworkedObservable<T, InternalVersionOf<T>> {
    protected encode(input: T): InternalVersionOf<T> {
        // Convert to network-safe format
        return input as InternalVersionOf<T>;
    }

    protected decode(input: InternalVersionOf<T>): T {
        // Convert from network format
        return input as T;
    }

    protected needsEncoding(value: T | InternalVersionOf<T>): value is T {
        // Check if value needs encoding
        return true;
    }
}
```

### Linking NetworkBehaviors

NetworkedVariables can reference NetworkBehaviors:

```typescript theme={null}
export class TargetingSystem extends NetworkBehavior {
    // References another NetworkBehavior
    public readonly currentTarget = new NetworkedVariable<EnemyAI | undefined>(undefined);

    public setTarget(enemy: EnemyAI): void {
        if (RunService.IsServer()) {
            // Automatically creates a network reference
            this.currentTarget.setValue(enemy);
        }
    }

    public onStart(): void {
        this.currentTarget.onValueChanged.connect((newTarget) => {
            if (newTarget) {
                print(`Now targeting: ${newTarget.getName()}`);
            }
        });
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

### Custom Observable Events

Create custom events for observables:

```typescript theme={null}
export class InventorySystem extends NetworkBehavior {
    public readonly items = new NetworkedList<string>();
    public readonly onItemEquipped = new Signal<[string]>("itemEquipped");

    public equipItem(itemName: string): void {
        if (RunService.IsServer()) {
            const index = this.items.getValue().indexOf(itemName);
            if (index !== -1) {
                // Move to front (equipped slot)
                this.items.remove(index);
                this.items.push(itemName);
                
                // Fire custom event
                this.onItemEquipped.fire(itemName);
            }
        }
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

## Signals

CORP uses a powerful Signal system for event-driven programming. Signals provide type-safe, memory-efficient event handling.

### Basic Signal Usage

```typescript theme={null}
import { Signal } from "CORP/shared/utilities/signal";

export class EventEmitter extends Behavior {
    // Create a signal with typed parameters
    public readonly onDamaged = new Signal<[number, Player]>("onDamaged");
    public readonly onHealed = new Signal<[number]>("onHealed");

    public takeDamage(amount: number, attacker: Player): void {
        // Fire the signal
        this.onDamaged.fire(amount, attacker);
    }

    public heal(amount: number): void {
        this.onHealed.fire(amount);
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

### Connecting to Signals

```typescript theme={null}
export class DamageListener extends Behavior {
    public onStart(): void {
        const emitter = this.getComponent(EventEmitter);

        if (emitter) {
            // Connect to signal
            const connection = emitter.onDamaged.connect((amount, attacker) => {
                print(`Took ${amount} damage from ${attacker.Name}`);
            });

            // Add to collector for automatic cleanup
            this.collector.add(connection);
        }
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {
        // Connections in collector are automatically cleaned up
    }
}
```

### One-Time Connections

```typescript theme={null}
export class OneShotListener extends Behavior {
    public onStart(): void {
        const emitter = this.getComponent(EventEmitter);

        if (emitter) {
            // Connect once, then disconnect
            const connection = emitter.onDamaged.connect((amount, attacker) => {
                print("First damage taken!");
                connection.disconnect();
            });
        }
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

### Custom Signals

```typescript theme={null}
export class GameStateManager extends Behavior {
    public readonly onGameStart = new Signal<[]>("onGameStart");
    public readonly onGameEnd = new Signal<[winner: string]>("onGameEnd");
    public readonly onRoundStart = new Signal<[roundNumber: number]>("onRoundStart");

    public startGame(): void {
        print("Game starting!");
        this.onGameStart.fire();
    }

    public endGame(winner: string): void {
        print(`Game ended! Winner: ${winner}`);
        this.onGameEnd.fire(winner);
    }

    public startRound(roundNumber: number): void {
        print(`Round ${roundNumber} starting!`);
        this.onRoundStart.fire(roundNumber);
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

## Custom Serialization

### Extending Behavior Serialization

Override serialization methods for custom types:

```typescript theme={null}
export class CustomData extends Behavior {
    @SerializeField
    public complexData: ComplexType = new ComplexType();

    protected override serializeProperty(datatable: dict, key: string): void {
        const value = (this as dict)[key];

        if (key === "complexData") {
            // Custom serialization for ComplexType
            datatable[key] = {
                type: "ComplexType",
                data: this.serializeComplexType(value as ComplexType)
            };
        } else {
            super.serializeProperty(datatable, key);
        }
    }

    private serializeComplexType(data: ComplexType): dict {
        return {
            // Serialize complex type to plain object
            field1: data.field1,
            field2: data.field2
        };
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

### Scene Serialization Hooks

```typescript theme={null}
export class SaveableComponent extends Behavior {
    private runtimeData: Map<string, number> = new Map();

    public saveToScene(): dict {
        const state = this.serializeState();
        
        // Add runtime data
        state.runtimeData = Object.fromEntries(this.runtimeData);
        
        return state;
    }

    public loadFromScene(data: dict): void {
        // Restore runtime data
        if (data.runtimeData) {
            this.runtimeData = new Map(Object.entries(data.runtimeData as dict) as [string, number][]);
        }
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

## Performance Optimization

### Batched Network Updates

Use batched replication (the default) for frequently changing values:

```typescript theme={null}
export class MovementSync extends NetworkBehavior {
    // BATCHED is the default replication behavior
    // Updates are sent on HeartBeat for efficiency
    public readonly position = new NetworkedVariable<Vector3>(Vector3.zero, {
        replicationBehavior: NetworkVariableReplicationBehavior.BATCHED // default
    });

    // For critical updates that must be sent immediately
    public readonly healthCritical = new NetworkedVariable<number>(100, {
        replicationBehavior: NetworkVariableReplicationBehavior.INSTANTANEOUS
    });

    public onStart(): void {
        if (RunService.IsServer()) {
            // Update position frequently - batched automatically
            RunService.Heartbeat.Connect(() => {
                this.position.setValue(this.getPosition());
            });
        }
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

> **Note**: `BATCHED` is the default replication behavior. It groups updates and sends them on HeartBeat for efficiency. Only use `INSTANTANEOUS` for critical updates that must be sent immediately.

### Execution Order Optimization

Control component initialization order:

```typescript theme={null}
// Initialize managers first
export class GameManager extends Behavior {
    public readonly executionOrder = -100;
    // ... implementation
}

// Initialize systems next
export class PhysicsSystem extends Behavior {
    public readonly executionOrder = -50;
    // ... implementation
}

// Initialize gameplay components last
export class PlayerController extends Behavior {
    public readonly executionOrder = 0; // Default
    // ... implementation
}
```

### Lazy Component Initialization

Defer expensive initialization:

```typescript theme={null}
export class ExpensiveComponent extends Behavior {
    private initialized: boolean = false;

    public onStart(): void {
        // Quick initialization
        this.setupBasics();
    }

    private setupBasics(): void {
        // Minimal setup
    }

    public performExpensiveInit(): void {
        if (this.initialized) return;

        // Expensive operations
        task.spawn(() => {
            this.loadAssets();
            this.buildDataStructures();
            this.initialized = true;
        });
    }

    private loadAssets(): void {
        // Load assets asynchronously
    }

    private buildDataStructures(): void {
        // Build complex data structures
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

## Advanced Networking Patterns

### Request-Response Pattern

```typescript theme={null}
export class DataProvider extends NetworkBehavior {
    private dataCache: Map<string, string> = new Map();

    @RPC.Method({
        endpoints: [RPC.Endpoint.CLIENT_TO_SERVER],
        returnMode: RPC.ReturnMode.RETURNS
    })
    public requestData(key: string): string | undefined {
        if (RunService.IsServer()) {
            return this.dataCache.get(key);
        }
        return undefined;
    }

    // Client usage
    public async getData(key: string): Promise<string | undefined> {
        // Call RPC and wait for response
        return this.requestData(key);
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

### Broadcast Pattern

```typescript theme={null}
export class ChatSystem extends NetworkBehavior {
    @RPC.Method({
        endpoints: [RPC.Endpoint.CLIENT_TO_SERVER]
    })
    public sendMessage(message: string): void {
        if (RunService.IsServer()) {
            // Validate message
            if (message.size() > 200) return;

            // Broadcast to all clients
            this.broadcastMessage(message);
        }
    }

    @RPC.Method({
        endpoints: [RPC.Endpoint.SERVER_TO_CLIENT]
    })
    private broadcastMessage(message: string): void {
        if (RunService.IsClient()) {
            print(`Chat: ${message}`);
            // Update UI
        }
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

### Ownership Transfer Pattern

Transfer ownership of NetworkObjects between players:

```typescript theme={null}
export class TransferableObject extends NetworkBehavior {
    public transferOwnership(newOwner: Player): void {
        if (RunService.IsServer()) {
            const netObj = this.getNetworkObject();
            
            // Transfer ownership
            netObj.changeOwnership(newOwner);
            
            // Notify clients
            this.notifyOwnershipChange(newOwner);
        }
    }

    @RPC.Method({
        endpoints: [RPC.Endpoint.SERVER_TO_CLIENT]
    })
    private notifyOwnershipChange(newOwner: Player): void {
        if (RunService.IsClient()) {
            print(`Ownership transferred to ${newOwner.Name}`);
            
            // Update client-side logic
            if (newOwner === Players.LocalPlayer) {
                this.enableLocalControl();
            } else {
                this.disableLocalControl();
            }
        }
    }

    private enableLocalControl(): void {
        // Enable input handling
    }

    private disableLocalControl(): void {
        // Disable input handling
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public onStart(): void {}
    public willRemove(): void {}
}
```

> **Note**: The term "ownership" is used for NetworkObject ownership. "Authority" is reserved for the Unreal system's authority model (client vs server authority).

## Performance Namespace

CORP includes a `Performance` namespace with utilities for monitoring and optimization.

### Using Performance Utilities

```typescript theme={null}
import { Performance } from "CORP/shared/utilities/performance";

export class PerformanceMonitor extends Behavior {
    public onStart(): void {
        // Monitor frame times
        const frameTime = Performance.getFrameTime();
        print(`Current frame time: ${frameTime}ms`);

        // Check if performance is degraded
        if (Performance.isPerformanceDegraded()) {
            warn("Performance is degraded!");
            this.reduceQuality();
        }

        // Measure operation performance
        const startTime = Performance.now();
        this.expensiveOperation();
        const duration = Performance.now() - startTime;
        print(`Operation took ${duration}ms`);
    }

    private expensiveOperation(): void {
        // Expensive code
    }

    private reduceQuality(): void {
        // Reduce graphics quality, particle effects, etc.
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

## Debugging and Logging

### Debug Utilities

CORP includes a debug system with log groups:

```typescript theme={null}
import { Debug, LogGroup } from "CORP/shared/utilities/logging";

const MyLogGroup: LogGroup = {
    prefix: "MY_SYSTEM",
    enabled: true,
    parent: undefined // Optional parent group
};

export class DebuggableComponent extends Behavior {
    public onStart(): void {
        Debug.log(MyLogGroup, "Component started");
        Debug.info(MyLogGroup, "Info message");
        Debug.warning(MyLogGroup, "Warning message");
        Debug.except(MyLogGroup, "Error message");
        Debug.special(MyLogGroup, "Special message");
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

### Network Debug Logging

```typescript theme={null}
const NetworkLogGroup: LogGroup = {
    prefix: "NETWORK",
    enabled: true
};

export class NetworkDebugger extends NetworkBehavior {
    public onStart(): void {
        const netObj = this.getNetworkObject();

        netObj.ownerChanged.connect((owner) => {
            Debug.log(NetworkLogGroup, `Ownership changed to ${owner?.Name ?? "server"}`);
        });

        this.health.onValueChanged.connect((newValue, oldValue) => {
            Debug.log(NetworkLogGroup, `Health: ${oldValue} -> ${newValue}`);
        });
    }

    public readonly health = new NetworkedVariable<number>(100);

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

### Performance Profiling

```typescript theme={null}
export class ProfiledComponent extends Behavior {
    public onStart(): void {
        debug.profilebegin("MyExpensiveOperation");
        
        this.expensiveOperation();
        
        debug.profileend();
    }

    private expensiveOperation(): void {
        // Expensive code
        // Shows up in Roblox MicroProfiler
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }

    public willRemove(): void {}
}
```

## Best Practices Summary

### 1. Use Appropriate Replication

* **Batched** for frequent updates (position, rotation)
* **Instantaneous** only for critical, infrequent updates

### 2. Optimize Component Lifecycle

* Use `executionOrder` for dependencies
* Defer expensive initialization
* Clean up resources in `willRemove()`

### 3. Design for Network Authority

* Server validates all inputs
* Clients predict locally
* Server corrects client state when needed

### 4. Pool Network Objects

* Pre-spawn frequently used objects
* Reuse instead of destroying
* Reduces network overhead

### 5. Profile and Debug

* Use log groups for debugging
* Profile expensive operations
* Monitor network bandwidth

## Next Steps

* **[API Reference](./api-reference)**: Complete API documentation
* **[Examples](./examples)**: Practical implementations
* **[Networking](./networking)**: Core networking concepts

***

Master advanced CORP features to build sophisticated games! 🎯
