From 4f7e8ec30a4e85df837b575316e9fdbec192d692 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 21 Jun 2026 19:55:40 +0200 Subject: [PATCH] =?UTF-8?q?feat(core/slice-1):=20TeleportAnimSequencer=20?= =?UTF-8?q?=E2=80=94=20define=20enums,=20record,=20event=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../World/TeleportAnimSequencer.cs | 37 ++++++++++++++++ .../World/TeleportAnimSequencerTests.cs | 43 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/AcDream.Core/World/TeleportAnimSequencer.cs create mode 100644 tests/AcDream.Core.Tests/World/TeleportAnimSequencerTests.cs diff --git a/src/AcDream.Core/World/TeleportAnimSequencer.cs b/src/AcDream.Core/World/TeleportAnimSequencer.cs new file mode 100644 index 00000000..d7980a78 --- /dev/null +++ b/src/AcDream.Core/World/TeleportAnimSequencer.cs @@ -0,0 +1,37 @@ +namespace AcDream.Core.World; + +// acclient.h:6871 — TeleportAnimState enum, verbatim order. +public enum TeleportAnimState +{ + Off = 0, + WorldFadeOut = 1, + TunnelFadeIn = 2, + Tunnel = 3, + TunnelContinue = 4, + TunnelFadeOut = 5, + WorldFadeIn = 6, +} + +/// Why the teleport was triggered — drives per-entry start state (spec §2.5). +public enum TeleportEntryKind { Portal, Login, Death, Logout } + +/// +/// Edge-triggered events the sequencer emits on the tick they first occur. +/// Consumers drive audio / placement / LoginComplete from these; the sequencer +/// has no dependency on any of those systems. +/// +public enum TeleportAnimEvent +{ + PlayEnterSound, // Begin(): sound_ui_enter_portal + EnterTunnel, // Off/WorldFade* -> Tunnel: world is now hidden + Place, // Tunnel -> TunnelContinue: world loaded; place the player + PlayExitSound, // TunnelFadeOut -> WorldFadeIn: sound_ui_exit_portal + FireLoginComplete, // WorldFadeIn -> Off: send GameAction 0xA1 +} + +/// Immutable per-frame snapshot from the sequencer. +public readonly record struct TeleportAnimSnapshot( + TeleportAnimState State, + float FadeAlpha, // 0 = clear world, 1 = full black + bool ShowTunnel, // true during TunnelFadeIn..TunnelFadeOut + bool ShowPleaseWait); // true during TunnelContinue only diff --git a/tests/AcDream.Core.Tests/World/TeleportAnimSequencerTests.cs b/tests/AcDream.Core.Tests/World/TeleportAnimSequencerTests.cs new file mode 100644 index 00000000..355b22f7 --- /dev/null +++ b/tests/AcDream.Core.Tests/World/TeleportAnimSequencerTests.cs @@ -0,0 +1,43 @@ +using AcDream.Core.World; +using Xunit; + +namespace AcDream.Core.Tests.World; + +public sealed class TeleportAnimSequencerTests +{ + // --- Task 1.1: type presence --- + + [Fact] + public void Enums_HaveExpectedValues() + { + Assert.Equal(0, (int)TeleportAnimState.Off); + Assert.Equal(1, (int)TeleportAnimState.WorldFadeOut); + Assert.Equal(2, (int)TeleportAnimState.TunnelFadeIn); + Assert.Equal(3, (int)TeleportAnimState.Tunnel); + Assert.Equal(4, (int)TeleportAnimState.TunnelContinue); + Assert.Equal(5, (int)TeleportAnimState.TunnelFadeOut); + Assert.Equal(6, (int)TeleportAnimState.WorldFadeIn); + + _ = TeleportEntryKind.Portal; + _ = TeleportEntryKind.Login; + _ = TeleportEntryKind.Death; + _ = TeleportEntryKind.Logout; + + _ = TeleportAnimEvent.PlayEnterSound; + _ = TeleportAnimEvent.PlayExitSound; + _ = TeleportAnimEvent.Place; + _ = TeleportAnimEvent.FireLoginComplete; + _ = TeleportAnimEvent.EnterTunnel; + } + + [Fact] + public void Snapshot_DefaultsAreOff_ClearAlpha() + { + var snap = new TeleportAnimSnapshot( + TeleportAnimState.Off, FadeAlpha: 0f, ShowTunnel: false, ShowPleaseWait: false); + Assert.Equal(TeleportAnimState.Off, snap.State); + Assert.Equal(0f, snap.FadeAlpha); + Assert.False(snap.ShowTunnel); + Assert.False(snap.ShowPleaseWait); + } +}