Easy Chapter Generator
EnglishEspañol

Choose context before choosing an event

NeedPreferContext
Inspector response to readiness/load/failureManager UnityEventsParameterless
Failure reason and affected objectsChapterFailedChapterFailureInfo
Accepted Objective index before actionsChapter.ObjectiveCompletedint index
Scene detector accepted completionObjective.OnCompletedComponent-local, after Chapter acceptance
Chapter/Objective configured lifecycleSerialized row eventsAuthored in product window

Own the subscription lifetime

Cache the exact publisher instance, subscribe once, and remove the same delegate before discarding it. A later singleton lookup may return null or a replacement instance during scene teardown. For Chapter-specific events, detach from the old Chapter before observing a newly selected one.

Use OnEnable/OnDisable for scene components whose enabled lifetime matches observation. A persistent integration may instead subscribe after scene load and explicitly rebind when Managers change. Never add an anonymous lambda that cannot be removed unless the publisher has the same or shorter guaranteed lifetime.

Notifications are not state synchronization

Subscriptions receive future transitions only. After attaching, read current public properties once to render the initial state. This is especially important after persistence hydration, which intentionally does not replay historical completion or failure.

OnManagerReady means startup selection was attempted, not that it succeeded. Check CurrentChapter or HasActiveChapter in the listener. OnBeforeSceneLoad means the Manager already locked the transition; keep the callback short and synchronous.

Diagnose duplicated responses

Callback runs twice after re-enabling UI

The listener was added repeatedly without removal. Pair AddListener/RemoveListener and inspect persistent Inspector listeners separately.

Failure listener survives scene change

A persistent receiver may still reference the old Manager. Unsubscribe before unload and bind to the new instance.

No initial completion events after load

Expected: hydration does not replay them. Read state after OnManagerReady.

Wrong Objective appears in a detector OnCompleted callback

The Chapter may already have advanced; use the typed pre-action event or capture the ID before calling completion.

Observe Manager readiness and Objective completion

Where to place it
Add the observer to a persistent integration object in the same scene as the Manager.
When to call it
OnEnable subscribes; Manager readiness selects the current Chapter; ObjectiveCompleted reports an accepted completion index.
Behavior
Chapter start and completion UnityEvents are configured in the Inspector. ObjectiveCompleted is raised before the Objective completion action list.
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 LifecycleSubscriptionExample : MonoBehaviour
{
    private ChapterManager manager;
    private Chapter observedChapter;

    private void OnEnable()
    {
        manager = ChapterManager.Instance;
        if (manager == null)
        {
            return;
        }

        manager.OnManagerReady.AddListener(HandleManagerReady);
        ObserveCurrentChapter();
    }

    private void OnDisable()
    {
        manager?.OnManagerReady.RemoveListener(HandleManagerReady);
        StopObservingChapter();
        manager = null;
    }

    private void HandleManagerReady()
    {
        ObserveCurrentChapter();
    }

    private void ObserveCurrentChapter()
    {
        StopObservingChapter();
        observedChapter = manager != null ? manager.CurrentChapter : null;
        if (observedChapter != null)
        {
            observedChapter.ObjectiveCompleted += HandleObjectiveCompleted;
        }
    }

    private void StopObservingChapter()
    {
        if (observedChapter != null)
        {
            observedChapter.ObjectiveCompleted -= HandleObjectiveCompleted;
        }

        observedChapter = null;
    }

    private void HandleObjectiveCompleted(int objectiveIndex)
    {
        Debug.Log($"Completed objective index: {objectiveIndex}", this);
    }
}

Remove a typed event subscription

Where to place it
Place the listener on the object that owns the response to Chapter failure.
When to call it
OnEnable attaches to ChapterFailed and OnDisable removes the exact same delegate.
Behavior
Cache the Manager used for the subscription. Looking up a different singleton during teardown can leave the original event subscribed.
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 FailureSubscriptionExample : MonoBehaviour
{
    private ChapterManager manager;

    private void OnEnable()
    {
        manager = ChapterManager.Instance;
        if (manager != null)
        {
            manager.ChapterFailed += HandleChapterFailed;
        }
    }

    private void OnDisable()
    {
        if (manager != null)
        {
            manager.ChapterFailed -= HandleChapterFailed;
        }

        manager = null;
    }

    private void HandleChapterFailed(ChapterFailureInfo information)
    {
        Debug.Log($"{information.Chapter?.Identifier}: {information.Reason}", this);
    }
}