Easy Chapter Generator
EnglishEspañol

Four completion actions

ActionScene loadHandoff payload
NoneNoNone; project events own the next decision
Load SceneTarget SceneNone; destination uses its normal startup priority
Load Scene and Start ChapterTarget SceneNext Chapter ID and an empty Objective ID
Restore CheckpointTarget SceneNext Chapter ID plus Checkpoint Objective ID

The Editor shows only fields relevant to the selected action. Both destination IDs must resolve against the content expected in the target scene; a selector can help author current project content, but runtime still validates the exact IDs.

Accepted transition order

  1. Validate scene nameAn empty name warns and exits without setting transition state.
  2. Lock transitionIsTransitioning becomes true; later TransitionToScene calls are ignored and failure returns TransitionInProgress.
  3. NotifyOnBeforeSceneLoad runs.
  4. Write handoffWhen a Chapter ID is supplied, a versioned one-use JSON record is written and flushed.
  5. LoadSceneManager.LoadScene(sceneName) begins the synchronous scene change.

OnBeforeSceneLoad runs before handoff storage, so use it to close UI or record telemetry, not to read the just-written handoff or delay loading asynchronously.

Destination startup priority

The new Manager hydrates the one-use handoff and verifies that its Chapter exists and, when supplied, that the Objective belongs to it. A valid handoff has priority over the destination's Editor testing override and Default Chapter. It is deleted and flushed before the Chapter resumes, so a later unrelated scene reload cannot consume it again.

If the handoff is absent or invalid, the Manager tries the Editor-only test selection, then Default Chapter. A Load Scene action intentionally creates no handoff, so seeing the destination default start is expected. A Load Scene and Start Chapter action must name the target Chapter exactly.

What Restore Checkpoint restores

Restore Checkpoint selects the named Chapter and asks it to resume from the named Ordered Objective while respecting hydrated Completed and Skipped rows. It does not restore player position, inventory, health, instantiated world objects, or arbitrary save-game state. Use CheckpointPositionController, lifecycle events, or the project's save system for those responsibilities.

The destination starts its default Chapter

Confirm the source action writes a non-empty Next Chapter ID, the destination Manager contains that exact ID, and storage accepted and flushed the handoff.

The requested Objective is bypassed

A previously persisted terminal record may already mark it Completed or Skipped. Clear the intended profile or choose a nonterminal checkpoint.

Scene loads but OnBeforeSceneLoad did not run

Confirm the load went through ChapterManager. Direct SceneManager calls bypass this product event and handoff.

Listen immediately before scene load

Where to place it
Add the listener beside systems that must close UI or record telemetry before a load.
When to call it
OnBeforeSceneLoad runs after IsTransitioning becomes true and before handoff storage and SceneManager.LoadScene.
Behavior
The callback is a notification, not an asynchronous loading barrier. Do not start a second transition from it.
using System;
using System.Collections;
using System.Collections.Generic;
using OverFuture.ChapterObjectiveSystem.Chapters;
using OverFuture.ChapterObjectiveSystem.Events;
using OverFuture.ChapterObjectiveSystem.Objectives;
using OverFuture.ChapterObjectiveSystem.Persistence;
using OverFuture.ChapterObjectiveSystem.Progression;
using UnityEngine;

public sealed class BeforeSceneLoadExample : MonoBehaviour
{
    private ChapterManager manager;

    private void OnEnable()
    {
        manager = ChapterManager.Instance;
        manager?.OnBeforeSceneLoad.AddListener(HandleBeforeSceneLoad);
    }

    private void OnDisable()
    {
        manager?.OnBeforeSceneLoad.RemoveListener(HandleBeforeSceneLoad);
        manager = null;
    }

    private void HandleBeforeSceneLoad()
    {
        if (manager != null && manager.IsTransitioning)
        {
            Debug.Log("The accepted scene transition is about to load.", this);
        }
    }
}