From 247e896815526c61846186d2d90b6a4346ff2abe Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 26 Aug 2026 11:14:48 +0200 Subject: [PATCH] chore(replay): scaffold project with machine builder and frame types --- src/Chip8.Replay/Chip8.Replay.csproj | 16 ++++++++++++++ src/Chip8.Replay/MachineBuilder.cs | 31 +++++++++++++++++++++++++++ src/Chip8.Replay/MovieFrame.cs | 32 ++++++++++++++++++++++++++++ src/Chip8.Replay/RomHash.cs | 28 ++++++++++++++++++++++++ src/Chip8.Replay/TimelineSnapshot.cs | 17 +++++++++++++++ 5 files changed, 124 insertions(+) create mode 100644 src/Chip8.Replay/Chip8.Replay.csproj create mode 100644 src/Chip8.Replay/MachineBuilder.cs create mode 100644 src/Chip8.Replay/MovieFrame.cs create mode 100644 src/Chip8.Replay/RomHash.cs create mode 100644 src/Chip8.Replay/TimelineSnapshot.cs diff --git a/src/Chip8.Replay/Chip8.Replay.csproj b/src/Chip8.Replay/Chip8.Replay.csproj new file mode 100644 index 0000000..c64a386 --- /dev/null +++ b/src/Chip8.Replay/Chip8.Replay.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + disable + enable + Chip8.Replay + Chip8.Replay + 10 + + + + + + + diff --git a/src/Chip8.Replay/MachineBuilder.cs b/src/Chip8.Replay/MachineBuilder.cs new file mode 100644 index 0000000..611abd8 --- /dev/null +++ b/src/Chip8.Replay/MachineBuilder.cs @@ -0,0 +1,31 @@ +using Chip8.Core; + +namespace Chip8.Replay; + +public static class MachineBuilder +{ + public static Machine fromMovie(InputMovie movie) + { + return new Machine(QuirksCodec.clone(movie.quirks), movie.randomSeed, movie.platform); + } + + public static Machine fromMovie(InputMovie movie, byte[] rom) + { + var machine = fromMovie(movie); + machine.loadRom(rom); + return machine; + } + + public static InputMovie headerFor(Machine machine, byte[] rom, string romName, int instructionsPerFrame, int? randomSeed) + { + var movie = new InputMovie + { + platform = machine.platform, + quirks = QuirksCodec.clone(machine.quirks), + randomSeed = randomSeed, + instructionsPerFrame = instructionsPerFrame, + }; + movie.setRom(rom, romName); + return movie; + } +} diff --git a/src/Chip8.Replay/MovieFrame.cs b/src/Chip8.Replay/MovieFrame.cs new file mode 100644 index 0000000..1d3afe9 --- /dev/null +++ b/src/Chip8.Replay/MovieFrame.cs @@ -0,0 +1,32 @@ +using System; + +namespace Chip8.Replay; + +public readonly struct MovieFrame : IEquatable +{ + public int index { get; } + public KeyMask keys { get; } + + public MovieFrame(int index, KeyMask keys) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index), "movie frame index cannot be negative"); + } + this.index = index; + this.keys = keys; + } + + public MovieFrame(int index, ushort keyBits) + : this(index, new KeyMask(keyBits)) + { + } + + public bool Equals(MovieFrame other) => index == other.index && keys == other.keys; + + public override bool Equals(object? obj) => obj is MovieFrame other && Equals(other); + + public override int GetHashCode() => (index * 397) ^ keys.bits; + + public override string ToString() => "frame " + index + " " + keys.toKeyList(); +} diff --git a/src/Chip8.Replay/RomHash.cs b/src/Chip8.Replay/RomHash.cs new file mode 100644 index 0000000..56e8d6d --- /dev/null +++ b/src/Chip8.Replay/RomHash.cs @@ -0,0 +1,28 @@ +using System; +using System.Globalization; + +namespace Chip8.Replay; + +public static class RomHash +{ + const ulong fnvOffsetBasis = 14695981039346656037UL; + const ulong fnvPrime = 1099511628211UL; + + public static ulong compute(byte[] rom) + { + ulong hash = fnvOffsetBasis; + foreach (byte value in rom) + { + hash ^= value; + hash *= fnvPrime; + } + return hash; + } + + public static string toHex(byte[] rom) => format(compute(rom)); + + public static string format(ulong hash) => hash.ToString("X16", CultureInfo.InvariantCulture); + + public static ulong parse(string hex) => + ulong.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture); +} diff --git a/src/Chip8.Replay/TimelineSnapshot.cs b/src/Chip8.Replay/TimelineSnapshot.cs new file mode 100644 index 0000000..2857f17 --- /dev/null +++ b/src/Chip8.Replay/TimelineSnapshot.cs @@ -0,0 +1,17 @@ +namespace Chip8.Replay; + +public sealed class TimelineSnapshot +{ + public int frameIndex { get; } + public byte[] state { get; } + + public TimelineSnapshot(int frameIndex, byte[] state) + { + this.frameIndex = frameIndex; + this.state = state; + } + + public int stateSize => state.Length; + + public override string ToString() => "snapshot frame=" + frameIndex + " bytes=" + state.Length; +}