examples/MusicDirectorExample.cs

Example helper that wires a MusicDirectorCore authority to a MusicRuntime and audio sink. It constructs cue/configuration and an event catalog, ticks the authority, applies decisions to the runtime, and forwards runtime actions to an IMusicAudioSink.

Networking
using SboxDirector;

namespace AdaptiveDirectorExamples;

/// <summary>A local example. A network game sends MusicDecisionBatch to the owning client before applying it to MusicRuntime.</summary>
public sealed class MusicDirectorExample
{
    readonly MusicDirectorCore _authority;
    readonly MusicRuntime _runtime;
    readonly IMusicAudioSink _audio;

    public MusicDirectorExample(string participantId, IMusicAudioSink audio)
    {
        _audio = audio;
        var cues = new MusicCueConfiguration
        {
            CombatIntroEvents = new[] { "mygame.combat.intro" },
            CombatSecondaryEvent = "mygame.combat.secondary",
            CombatCloseEvent = "mygame.combat.close",
            CombatTrackIds = new[] { "combat", "combat_secondary", "combat_close" },
            BossApproachingEvent = "mygame.boss.approach",
            BossTrackId = "boss",
            SafeAtmosphereEvent = "mygame.atmosphere.safe",
            DangerAtmosphereEvent = "mygame.atmosphere.danger",
            PositionalStingerEvent = ""
        };
        _authority = new MusicDirectorCore(RecoveredMusicDirectorDefaults.CreateConfiguration(cues, seed: 123));
        _runtime = new MusicRuntime(participantId, new MusicEventCatalog(new[]
        {
            Event("mygame.combat.intro", "combat", MusicPriority.Critical),
            Event("mygame.combat.secondary", "combat_secondary", MusicPriority.Critical),
            Event("mygame.combat.close", "combat_close", MusicPriority.Critical),
            Event("mygame.boss.approach", "boss", MusicPriority.Critical, blocks: new[] { "combat", "combat_secondary", "combat_close" }),
            Event("mygame.atmosphere.safe", "ambient", MusicPriority.Low),
            Event("mygame.atmosphere.danger", "ambient", MusicPriority.Medium)
        }));
    }

    public MusicHostRunResult Tick(MusicWorldSnapshot world, IReadOnlyList<MusicGameplayEvent>? events = null)
    {
        var decisions = _authority.Tick(world, events); // Replicate this batch here when authority and listener are separate.
        var runtime = _runtime.Apply(decisions); foreach (var action in runtime.Actions) _audio.Apply(action); return new(decisions, runtime);
    }

    static MusicEventDefinition Event(string eventId, string trackId, MusicPriority priority, IReadOnlyList<string>? blocks = null) => new() { EventId = eventId, TrackId = trackId, Priority = priority, BlockTrackList = blocks ?? Array.Empty<string>() };
}