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

# Scenario Data

> ScriptableObject asset that defines a VR training scenario's metadata, activities, and scene loading configuration.

**Product:** [Molca VR SDK](/overview/platforms) (paths assume **molca-sdk-vr**). Not used by the Digital Twin SDK (`_MolcaDT`).

**Script:** `Assets/_MolcaSDK/_VR/Scripts/Scenario/Data/ScenarioData.cs`\
**Type:** `ScriptableObject` (registered in [Scenario Data Config](/setup/scenario-data-config) collections)

## When to use

Use `ScenarioData` (or its subclasses `SimulationScenarioData` / `TourScenarioData`) to define a VR training scenario:

* **Scenario metadata** — name, description, image, tags, time limits
* **Activity definitions** — ordered list of `ScenarioActivityData` entries
* **Scene loading** — `SceneLoadPlan` for single-player and per-role multiplayer configurations
* **Launch options** — execution mode support (Training/Assessment), config options
* **Multiplayer roles** — role definitions and per-role scene plans

Each scenario asset is registered in [Scenario Data Config](/setup/scenario-data-config) collections and resolved at runtime by `ScenarioSessionManager` or Home UI.

## Role

`ScenarioData` is the **authoring asset** that defines everything about a scenario:

1. **Metadata** — displayed in Home UI, used for filtering/search
2. **Activities** — `ScenarioActivityData` entries matched to runtime `ScenarioActivity` components by `RefId`
3. **Scene loading** — `SceneLoadPlan` structure executed by `SceneLoadPlanExecutor` to load ordered multi-scene setups
4. **Multiplayer** — role definitions and per-role scene configurations
5. **Backend integration** — `ScenarioId` (org ID) links to backend scenario records

At runtime, [Scenario Manager](/vr/scenario-manager) reads this asset to configure the scenario state machine, activity sequence, and scene loading.

## Inspector setup

### Basic metadata

| Field                    | Purpose                                                                                        |
| ------------------------ | ---------------------------------------------------------------------------------------------- |
| **Ref Id**               | Stable unique identifier (auto-generated). Used for local lookups and localization keys.       |
| **Scenario Id**          | Organization scenario ID from backend (set via `SetOrgScenarioId`). Used for session creation. |
| **Scenario Name**        | Display name (DynamicLocalization). Shown in Home UI.                                          |
| **Scenario Description** | Description text (DynamicLocalization). Shown in scenario detail UI.                           |
| **Scenario Image**       | Thumbnail texture. Displayed in Home UI scenario cards.                                        |
| **Scenario Tags**        | Array of `ScenarioTag` for filtering/categorization.                                           |
| **Time Limit Seconds**   | Scenario time limit. `0` = no limit. Enforced by `ScenarioManager`.                            |
| **Supports Multiplayer** | Enable for multiplayer scenarios. Requires role definitions and role scene mappings.           |

### Launch configuration

| Field                   | Purpose                                                                                                          |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Supports Assessment** | Enable Assessment mode button in scenario detail UI. Training is always available.                               |
| **Config Options**      | Array of `ScenarioConfigOptionSO` — runtime-selectable options shown before launch (e.g., difficulty, language). |

### Activities

| Field                   | Purpose                                                                                                                                                                |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Scenario Activities** | Ordered array of `ScenarioActivityData`. Each entry defines an activity's metadata (name, description, RefId). Runtime `ScenarioActivity` components match by `RefId`. |

### Roles (multiplayer only)

| Field              | Purpose                                                                                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Scenario Roles** | Array of `ScenarioRole` definitions. Each role has a `RefId`, name, description, and optional icon. Used for role selection UI and role scene mapping. |

### Scene loading

#### Single Player Plan

| Field              | Purpose                                                                                                                                                                                               |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Preload Scenes** | Array of `SceneEntry` loaded before the scenario scene. Index 0 loads as **Single** (active scene); subsequent entries load **Additive**. Use for shared environments, lighting, or asset preloading. |
| **Scenario Scene** | The main scenario logic scene (required). Loads **Additive** when preloads exist, **Single** when no preloads.                                                                                        |

#### Role Scene Mappings (multiplayer only)

| Field                   | Purpose                                                                                                                                         |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **Role Scene Mappings** | Array of `RoleSceneMapping`. Each entry maps a `roleId` (matching `ScenarioRole.RefId`) to a full `SceneLoadPlan` for that role in multiplayer. |

## SceneLoadPlan structure

The `SceneLoadPlan` defines ordered multi-scene loading with synchronization:

```csharp theme={null}
[Serializable]
public struct SceneLoadPlan
{
    public SceneEntry[] preloadScenes;  // Loaded before scenario scene
    public SceneEntry scenarioScene;    // Main scenario logic scene
}
```

### Load order

1. **`preloadScenes[0]`** loads as **Single** (becomes active scene)
2. Wait for `preloadScenes[0].waitForRefIds` (or 2 frames if empty)
3. **`preloadScenes[1..n]`** load as **Additive** (each waits for its RefIds)
4. **`scenarioScene`** loads as **Additive** (when preloads exist) or **Single** (no preloads)

### SceneEntry fields

Each scene entry has:

```csharp theme={null}
[Serializable]
public struct SceneEntry
{
    public string sceneName;              // Build-settings scene name
    public AssetReference sceneReference; // Addressable scene (takes priority)
    public string[] waitForRefIds;        // RefIds to wait for before next scene
}
```

| Field                | Purpose                                                                                                                                              |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Scene Name**       | Build-settings scene name. Used when **Scene Reference** is not set.                                                                                 |
| **Scene Reference**  | Addressable `AssetReference`. **Takes priority** over Scene Name when valid.                                                                         |
| **Wait For Ref Ids** | Array of RefIds that must be registered in `ReferenceManager` before the next scene loads. Leave empty to wait two frames only. Timeout: 15 seconds. |

## Code

### Get scene load plan

```csharp theme={null}
using MolcaSDK.VR.Scenario;

// Single-player
SceneLoadPlan plan = scenarioData.GetSceneLoadPlan(ScenarioPlayerMode.Single);

// Multiplayer (specific role)
SceneLoadPlan plan = scenarioData.GetSceneLoadPlan(ScenarioPlayerMode.Multiplayer, "operator");

if (plan.IsValid)
{
    Debug.Log($"Scenario scene: {plan.scenarioScene.sceneName}");
    Debug.Log($"Preload count: {(plan.HasPreloads ? plan.preloadScenes.Length : 0)}");
}
```

### Access metadata

```csharp theme={null}
// Basic info
string name = scenarioData.Name;
string description = scenarioData.Description;
float timeLimit = scenarioData.TimeLimitSeconds;
bool hasTimeLimit = scenarioData.HasTimeLimit;

// Activities
IReadOnlyList<ScenarioActivityData> activities = scenarioData.Activities;
foreach (var activity in activities)
{
    Debug.Log($"Activity: {activity.Name} (RefId: {activity.RefId})");
}

// Roles (multiplayer)
if (scenarioData.SupportsMultiplayer)
{
    IReadOnlyList<ScenarioRole> roles = scenarioData.Roles;
    foreach (var role in roles)
    {
        Debug.Log($"Role: {role.Name} (RefId: {role.RefId})");
    }
}
```

### Check for legacy data

```csharp theme={null}
// Check if asset has unmigrated legacy scene fields
if (scenarioData.HasLegacySceneData)
{
    Debug.LogWarning("Scenario has legacy scene data. Migration recommended.");
    
    // Migrate automatically (editor only)
    #if UNITY_EDITOR
    bool migrated = scenarioData.MigrateLegacySceneFields();
    if (migrated)
    {
        UnityEditor.EditorUtility.SetDirty(scenarioData);
        Debug.Log("Legacy scene data migrated to SceneLoadPlan.");
    }
    #endif
}
```

### Set organization scenario ID

```csharp theme={null}
// Called after fetching scenario metadata from backend
scenarioData.SetOrgScenarioId(orgScenarioId: 12345);
```

## Scene loading examples

### Simple single scene

```csharp theme={null}
// Inspector configuration:
singlePlayerPlan:
  preloadScenes: (empty)
  scenarioScene:
    sceneName: "FireSafetyTraining"
    sceneReference: null
    waitForRefIds: (empty)

// Result: Loads "FireSafetyTraining" as Single
```

### Environment + scenario (two scenes)

```csharp theme={null}
// Inspector configuration:
singlePlayerPlan:
  preloadScenes:
    [0] sceneName: "Environment_Factory"
        sceneReference: null
        waitForRefIds: ["factory_floor", "control_panel"]
  scenarioScene:
    sceneName: "Scenario_SafetyTraining"
    sceneReference: null
    waitForRefIds: (empty)

// Result:
// 1. Load "Environment_Factory" as Single
// 2. Wait for "factory_floor" and "control_panel" RefIds (15s timeout)
// 3. Load "Scenario_SafetyTraining" as Additive
```

### Addressable scenes

```csharp theme={null}
// Inspector configuration:
singlePlayerPlan:
  preloadScenes:
    [0] sceneName: ""
        sceneReference: AssetReference("Environments/Factory")
        waitForRefIds: (empty)
  scenarioScene:
    sceneName: ""
    sceneReference: AssetReference("Scenarios/SafetyTraining")
    waitForRefIds: (empty)

// Result: Loads both scenes via Addressables
// Scene Reference takes priority over Scene Name when valid
```

### Multiplayer with role-specific scenes

```csharp theme={null}
// Inspector configuration:
singlePlayerPlan:
  scenarioScene:
    sceneName: "Scenario_Operator_Solo"

roleSceneMappings:
  [0] roleId: "operator"
      plan:
        preloadScenes:
          [0] sceneName: "Environment_Factory"
        scenarioScene:
          sceneName: "Scenario_Operator_View"
  [1] roleId: "supervisor"
      plan:
        preloadScenes:
          [0] sceneName: "Environment_Factory"
        scenarioScene:
          sceneName: "Scenario_Supervisor_View"

// Usage:
var operatorPlan = scenarioData.GetSceneLoadPlan(ScenarioPlayerMode.Multiplayer, "operator");
var supervisorPlan = scenarioData.GetSceneLoadPlan(ScenarioPlayerMode.Multiplayer, "supervisor");
```

## API reference

### Properties

| Property              | Type                                    | Description                                   |
| --------------------- | --------------------------------------- | --------------------------------------------- |
| `RefId`               | `string`                                | Stable unique identifier (IReferenceable).    |
| `ScenarioId`          | `int`                                   | Organization scenario ID from backend.        |
| `Name`                | `string`                                | Display name (localized).                     |
| `Description`         | `string`                                | Description text (localized).                 |
| `SupportsMultiplayer` | `bool`                                  | Whether multiplayer is enabled.               |
| `Activities`          | `IReadOnlyList<ScenarioActivityData>`   | Activity definitions.                         |
| `Roles`               | `IReadOnlyList<ScenarioRole>`           | Role definitions (multiplayer).               |
| `Tags`                | `IReadOnlyList<ScenarioTag>`            | Scenario tags for filtering.                  |
| `Image`               | `Texture2D`                             | Thumbnail image.                              |
| `TimeLimitSeconds`    | `float`                                 | Time limit in seconds (`0` = no limit).       |
| `HasTimeLimit`        | `bool`                                  | Whether time limit is set.                    |
| `SupportsAssessment`  | `bool`                                  | Whether Assessment mode is available.         |
| `ConfigOptions`       | `IReadOnlyList<ScenarioConfigOptionSO>` | Launch configuration options.                 |
| `SinglePlayerPlan`    | `SceneLoadPlan`                         | Scene load plan for single-player.            |
| `RoleSceneMappings`   | `IReadOnlyList<RoleSceneMapping>`       | Per-role scene plans (multiplayer).           |
| `HasLegacySceneData`  | `bool`                                  | Whether unmigrated legacy scene fields exist. |

### Methods

| Method                                 | Returns         | Description                                                                                                                    |
| -------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `GetSceneLoadPlan(playerMode, roleId)` | `SceneLoadPlan` | Returns the scene load plan for the given player mode and optional role. Returns `default` (invalid) if no plan is configured. |
| `SetOrgScenarioId(id)`                 | `void`          | Sets the organization scenario ID (called after backend fetch).                                                                |
| `MigrateLegacySceneFields()`           | `bool`          | Migrates legacy flat scene fields to `SceneLoadPlan`. Returns `true` if migration was performed. Editor only.                  |
| `Initialize()`                         | `void`          | Initializes localization and nested data (activities, tags, roles). Called by `ScenarioDataConfig`.                            |

## Troubleshooting

* **Scenario not found at runtime:** verify the asset is registered in [Scenario Data Config](/setup/scenario-data-config) collections. Check `RefId` matches the lookup key.
* **Scene doesn't load:** confirm `scenarioScene` has either `sceneName` or `sceneReference` set. For Addressables, verify the scene is marked as Addressable and the key is valid. Check `SceneLoadPlan.IsValid`.
* **Preload scenes load out of order:** preload scenes load sequentially by array index. Index 0 always loads as Single (active scene); subsequent entries load Additive.
* **Scene loads but objects missing:** check `waitForRefIds` on preload scenes. The executor waits up to 15 seconds for those RefIds to be registered in `ReferenceManager`. Check console for timeout warnings.
* **Multiplayer role scene not found:** verify `roleSceneMappings` contains an entry with matching `roleId`. Check that the role's `SceneLoadPlan.IsValid`.
* **Activities don't match runtime components:** ensure `ScenarioActivity` components in the scene have `activityId` matching `ScenarioActivityData.RefId`. Mismatches log warnings.
* **Legacy scene fields not migrating:** call `MigrateLegacySceneFields()` in editor. Check that `singlePlayerPlan` is empty before migration (migration only runs when plan is invalid).
* **Time limit not enforced:** verify `TimeLimitSeconds > 0` and [Scenario Manager](/vr/scenario-manager) is active. Time limit is checked in `ScenarioManager.Update()`.

## Related

* [Scenario Data Config](/setup/scenario-data-config) — SettingModule that registers scenario collections
* [Scenario Manager](/vr/scenario-manager) — runtime state machine that executes scenarios
* [New scenario quick start](/setup/new-scenario-quickstart) — step-by-step guide for creating scenarios
* [Recipe: Set up a VR scenario](/recipes/setup-vr-scenario) — complete scenario setup workflow
* [Session loading and events](/vr/session-loading-and-events) — how sessions load scenario scenes
* [Scenario Activity](/vr/scenario-activity) — runtime activity component that matches `ScenarioActivityData`

## Unity Editor

<Frame caption="ScenarioData Inspector — metadata, activities, and scene loading configuration">
  <img src="https://mintcdn.com/ptmolcateknologinusantara/qXrgFMk4QevJTANv/images/features/setup/scenario-data-config-inspector.png?fit=max&auto=format&n=qXrgFMk4QevJTANv&q=85&s=be203d4ed7ee5bf7b3e8c27e20a03915" alt="Scenario Data Inspector" width="885" height="254" data-path="images/features/setup/scenario-data-config-inspector.png" />
</Frame>

<Info>
  **Migration from legacy fields:** If you have existing scenario assets created before the `SceneLoadPlan` refactoring, they contain hidden legacy fields (`sceneName`, `singlePlayerSceneName`, `environmentSceneName`, etc.). These are automatically migrated to `singlePlayerPlan` when accessed at runtime. For editor migration, call `MigrateLegacySceneFields()` in a custom editor script or inspector.
</Info>

<Warning>
  **Addressable priority:** When both `sceneName` and `sceneReference` are set on a `SceneEntry`, the Addressable reference takes priority. If the Addressable key is invalid, the scene load will fail — it does NOT fall back to `sceneName`. Set only one field to avoid confusion.
</Warning>
