Easy Chapter Generator
EnglishEspañol

Observe public state without changing it

DebugDemo is a development pattern for logging Manager readiness, current Chapter/Objective identity, transition state, and typed failure context. It is valuable when integrating UI, save, dialogue, or movement because it distinguishes “the external signal never arrived” from “Core rejected a stale or wrong-ID request.”

The observer should never call completion, selection, failure, or transition from its logging callbacks. That separation keeps diagnostics from altering the problem being measured.

Signals and properties to expose

SourceRecordInterpretation
OnManagerReadyCurrentChapterId, CurrentObjectiveId, statesInitial selection attempted
Chapter.ObjectiveCompletedChapter ID and accepted indexPre-completion-action boundary
ChapterFailedChapter, Objective, ReasonAccepted final failure state
OnBeforeSceneLoadIsTransitioningAccepted transition is about to persist handoff/load
Periodic snapshotActive flags and IDsCurrent observation, not event history

Use the observer during an integration test

  1. 1
    Add the observer to a Demo-only GameObject and ensure it subscribes after the Manager exists.
  2. 2
    Run the intended external action and record the state immediately before its callback.
  3. 3
    Inspect the callback's completion result. If false, compare its expected ID with CurrentObjectiveId.
  4. 4
    Test one duplicate callback and one scene unload. Confirm no duplicate listener or stale singleton remains.
  5. 5
    Disable verbose diagnostics in a release player.

Diagnostic limits

  • Logging does not prove a physics callback or vendor event is configured correctly; instrument that source too.
  • Hydrated state has no historical events to replay.
  • OnBeforeSceneLoad is parameterless and does not identify the destination.
  • A polling UI can see the next Objective by the time a component OnCompleted callback runs.
  • High-frequency Console logging allocates and can distort performance measurements.

The compiled observer below demonstrates safe subscription and cleanup using only public API.

Build a public-API diagnostic observer

Where to place it
Use this only on a Demo or development diagnostics GameObject and exclude it from production staging if unnecessary.
When to call it
It records Manager readiness, accepted transitions and failures while the component is enabled.
Behavior
The observer never changes progression. Logging every event may be noisy and should remain disabled in a release player.
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 DebugDemoObserverExample : MonoBehaviour
{
    private ChapterManager manager;

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

        manager.OnManagerReady.AddListener(LogState);
        manager.OnBeforeSceneLoad.AddListener(LogState);
        manager.ChapterFailed += LogFailure;
    }

    private void OnDisable()
    {
        if (manager == null)
        {
            return;
        }

        manager.OnManagerReady.RemoveListener(LogState);
        manager.OnBeforeSceneLoad.RemoveListener(LogState);
        manager.ChapterFailed -= LogFailure;
        manager = null;
    }

    private void LogState()
    {
        if (manager != null)
        {
            Debug.Log(
                $"Chapter={manager.CurrentChapterId}, " +
                $"Objective={manager.CurrentObjectiveId}, " +
                $"Transitioning={manager.IsTransitioning}",
                this);
        }
    }

    private void LogFailure(ChapterFailureInfo information)
    {
        Debug.Log($"Failure: {information.Reason}", this);
    }
}