diff --git a/src/Data/Replay/Events/AppearReplayEvent.cs b/src/Data/Replay/Events/AppearReplayEvent.cs index 8e7c438..8aaad9c 100644 --- a/src/Data/Replay/Events/AppearReplayEvent.cs +++ b/src/Data/Replay/Events/AppearReplayEvent.cs @@ -1,33 +1,44 @@ using AmongUs.GameOptions; -using BetterAmongUs.Utilities; using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class AppearReplayEvent : IReplayEvent<(int playerId, bool animate)> +internal sealed class AppearReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "player_appear"; [JsonPropertyName("eventData")] - public (int playerId, bool animate) EventData { get; set; } + public AppearReplayData? EventData { get; set; } public void Play() { - var player = Utils.PlayerFromPlayerId(EventData.playerId); + if (EventData == null) + return; + + var player = Utils.PlayerFromPlayerId(EventData.PlayerId); if (player == null) return; if (player.Data.RoleType != RoleTypes.Phantom) return; - player.SetRoleInvisibility(false, EventData.animate, true); + player.SetRoleInvisibility(false, EventData.Animate, true); } - public void Record(PlayerControl player, bool animate) + public void Undo() { - EventData = (player.PlayerId, animate); } -} + + public void Record(AppearReplayArgs args) + { + EventData = new AppearReplayData(args.Player.PlayerId, args.Animate); + } + + internal record AppearReplayData(int PlayerId, bool Animate) : IReplayEvent.Data; + + internal record AppearReplayArgs(PlayerControl Player, bool Animate) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/MurderReplayEvent.cs b/src/Data/Replay/Events/MurderReplayEvent.cs index 52a92da..707dd28 100644 --- a/src/Data/Replay/Events/MurderReplayEvent.cs +++ b/src/Data/Replay/Events/MurderReplayEvent.cs @@ -1,17 +1,17 @@ -using BetterAmongUs.Utilities; -using BetterAmongUs.Interfaces; +using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class MurderReplayEvent : IReplayEvent<(int killerId, int targetId)> +internal sealed class MurderReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "player_murder"; [JsonPropertyName("eventData")] - public (int killerId, int targetId) EventData { get; set; } + public MurderReplayData? EventData { get; set; } public void Play() { @@ -26,8 +26,16 @@ internal sealed class MurderReplayEvent : IReplayEvent<(int killerId, int target killer.MurderPlayer(target, MurderResultFlags.Succeeded); } - public void Record(PlayerControl killer, PlayerControl target) + public void Undo() { - EventData = (killer.PlayerId, target.PlayerId); } + + public void Record(MurderReplayArgs murderReplayArgs) + { + EventData = new MurderReplayData(murderReplayArgs.killer.PlayerId, murderReplayArgs.target.PlayerId); + } + + internal record MurderReplayData(int killerId, int targetId) : IReplayEvent.Data; + + internal record MurderReplayArgs(PlayerControl killer, PlayerControl target) : IReplayEvent.Args; } diff --git a/src/Data/Replay/Events/ProtectReplayEvent.cs b/src/Data/Replay/Events/ProtectReplayEvent.cs index 2f8a7e1..8bed4b4 100644 --- a/src/Data/Replay/Events/ProtectReplayEvent.cs +++ b/src/Data/Replay/Events/ProtectReplayEvent.cs @@ -1,26 +1,29 @@ using AmongUs.GameOptions; -using BetterAmongUs.Utilities; using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class ProtectReplayEvent : IReplayEvent<(int playerId, int targetId)> +internal sealed class ProtectReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "protect_player"; [JsonPropertyName("eventData")] - public (int playerId, int targetId) EventData { get; set; } + public ProtectReplayData? EventData { get; set; } public void Play() { - var player = Utils.PlayerFromPlayerId(EventData.playerId); + if (EventData == null) + return; + + var player = Utils.PlayerFromPlayerId(EventData.PlayerId); if (player == null) return; - var target = Utils.PlayerFromPlayerId(EventData.targetId); + var target = Utils.PlayerFromPlayerId(EventData.TargetId); if (target == null) return; @@ -30,8 +33,16 @@ internal sealed class ProtectReplayEvent : IReplayEvent<(int playerId, int targe player.ProtectPlayer(target, player.Data.DefaultOutfit.ColorId); } - public void Record(PlayerControl player, PlayerControl target) + public void Undo() { - EventData = (player.PlayerId, target.PlayerId); } -} + + public void Record(ProtectReplayArgs args) + { + EventData = new ProtectReplayData(args.Player.PlayerId, args.Target.PlayerId); + } + + internal record ProtectReplayData(int PlayerId, int TargetId) : IReplayEvent.Data; + + internal record ProtectReplayArgs(PlayerControl Player, PlayerControl Target) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/ProtectedReplayEvent.cs b/src/Data/Replay/Events/ProtectedReplayEvent.cs index c169fa5..22634db 100644 --- a/src/Data/Replay/Events/ProtectedReplayEvent.cs +++ b/src/Data/Replay/Events/ProtectedReplayEvent.cs @@ -1,29 +1,42 @@ -using BetterAmongUs.Utilities; -using BetterAmongUs.Interfaces; +using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class ProtectedReplayEvent : IReplayEvent<(int killerId, int targetId)> +internal sealed class ProtectedReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "player_protected"; [JsonPropertyName("eventData")] - public (int killerId, int targetId) EventData { get; set; } + public ProtectedReplayData? EventData { get; set; } public void Play() { - var target = Utils.PlayerFromPlayerId(EventData.targetId); + if (EventData == null) + return; + + var target = Utils.PlayerFromPlayerId(EventData.TargetId); + if (target == null) + return; RoleEffectAnimation roleEffectAnimation = UnityEngine.Object.Instantiate(RoleManager.Instance.protectAnim, target.transform); roleEffectAnimation.SetMaskLayerBasedOnWhoShouldSee(true); roleEffectAnimation.Play(target, null, target.cosmetics.FlipX, RoleEffectAnimation.SoundType.Global, 0f, true, 0f); } - public void Record(PlayerControl killer, PlayerControl target) + public void Undo() { - EventData = (killer.PlayerId, target.PlayerId); } -} + + public void Record(ProtectedReplayArgs args) + { + EventData = new ProtectedReplayData(args.Killer.PlayerId, args.Target.PlayerId); + } + + internal record ProtectedReplayData(int KillerId, int TargetId) : IReplayEvent.Data; + + internal record ProtectedReplayArgs(PlayerControl Killer, PlayerControl Target) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/SetRoleEvent.cs b/src/Data/Replay/Events/SetRoleEvent.cs index 32a5620..78da4db 100644 --- a/src/Data/Replay/Events/SetRoleEvent.cs +++ b/src/Data/Replay/Events/SetRoleEvent.cs @@ -1,31 +1,42 @@ using AmongUs.GameOptions; -using BetterAmongUs.Utilities; using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class SetRoleEvent : IReplayEvent<(int playerId, int roleType)> +internal sealed class SetRoleEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "set_role"; [JsonPropertyName("eventData")] - public (int playerId, int roleType) EventData { get; set; } + public SetRoleReplayData? EventData { get; set; } public void Play() { - var player = Utils.PlayerFromPlayerId(EventData.playerId); - if (player != null) - { - var roleType = (RoleTypes)EventData.roleType; - player.RpcSetRole(roleType, true); - } + if (EventData == null) + return; + + var player = Utils.PlayerFromPlayerId(EventData.PlayerId); + if (player == null) + return; + + var roleType = (RoleTypes)EventData.RoleType; + player.RpcSetRole(roleType, true); } - public void Record(PlayerControl player, RoleTypes roleType) + public void Undo() { - EventData = (player.Data.PlayerId, (int)roleType); } -} + + public void Record(SetRoleReplayArgs args) + { + EventData = new SetRoleReplayData(args.Player.PlayerId, (int)args.RoleType); + } + + internal record SetRoleReplayData(int PlayerId, int RoleType) : IReplayEvent.Data; + + internal record SetRoleReplayArgs(PlayerControl Player, RoleTypes RoleType) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/ShapeshiftReplayEvent.cs b/src/Data/Replay/Events/ShapeshiftReplayEvent.cs index 57fe3b9..4495607 100644 --- a/src/Data/Replay/Events/ShapeshiftReplayEvent.cs +++ b/src/Data/Replay/Events/ShapeshiftReplayEvent.cs @@ -1,37 +1,48 @@ using AmongUs.GameOptions; -using BetterAmongUs.Utilities; using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class ShapeshiftReplayEvent : IReplayEvent<(int playerId, int targetId, bool animate)> +internal sealed class ShapeshiftReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "player_shapeshift"; [JsonPropertyName("eventData")] - public (int playerId, int targetId, bool animate) EventData { get; set; } + public ShapeshiftReplayData? EventData { get; set; } public void Play() { - var player = Utils.PlayerFromPlayerId(EventData.playerId); + if (EventData == null) + return; + + var player = Utils.PlayerFromPlayerId(EventData.PlayerId); if (player == null) return; - var target = Utils.PlayerFromPlayerId(EventData.targetId); + var target = Utils.PlayerFromPlayerId(EventData.TargetId); if (target == null) return; if (player.Data.RoleType != RoleTypes.Shapeshifter) return; - player.Shapeshift(target, EventData.animate); + player.Shapeshift(target, EventData.Animate); } - public void Record(PlayerControl killer, PlayerControl target, bool animate) + public void Undo() { - EventData = (killer.PlayerId, target.PlayerId, animate); } -} + + public void Record(ShapeshiftReplayArgs args) + { + EventData = new ShapeshiftReplayData(args.Player.PlayerId, args.Target.PlayerId, args.Animate); + } + + internal record ShapeshiftReplayData(int PlayerId, int TargetId, bool Animate) : IReplayEvent.Data; + + internal record ShapeshiftReplayArgs(PlayerControl Player, PlayerControl Target, bool Animate) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/StartMeetingReplayEvent.cs b/src/Data/Replay/Events/StartMeetingReplayEvent.cs index fbd81e7..991476c 100644 --- a/src/Data/Replay/Events/StartMeetingReplayEvent.cs +++ b/src/Data/Replay/Events/StartMeetingReplayEvent.cs @@ -4,20 +4,30 @@ using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class StartMeetingReplayEvent : IReplayEvent<(int playerId, int targetId)> +internal sealed class StartMeetingReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "start_meeting"; [JsonPropertyName("eventData")] - public (int playerId, int targetId) EventData { get; set; } + public StartMeetingReplayData? EventData { get; set; } public void Play() { + if (EventData == null) + return; } - public void Record(PlayerControl player, PlayerControl? target) + public void Undo() { - EventData = (player.PlayerId, target?.PlayerId ?? -1); } -} + + public void Record(StartMeetingReplayArgs args) + { + EventData = new StartMeetingReplayData(args.Player.PlayerId, args.Target?.PlayerId ?? -1); + } + + internal record StartMeetingReplayData(int PlayerId, int TargetId) : IReplayEvent.Data; + + internal record StartMeetingReplayArgs(PlayerControl Player, PlayerControl? Target) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/UpdateSystemReplayEvent.cs b/src/Data/Replay/Events/UpdateSystemReplayEvent.cs index a3ccf4f..6fad9ef 100644 --- a/src/Data/Replay/Events/UpdateSystemReplayEvent.cs +++ b/src/Data/Replay/Events/UpdateSystemReplayEvent.cs @@ -1,32 +1,43 @@ -using BetterAmongUs.Utilities; -using BetterAmongUs.Interfaces; +using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class UpdateSystemReplayEvent : IReplayEvent<(byte systemType, int playerId, byte amount)> +internal sealed class UpdateSystemReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "update_system"; [JsonPropertyName("eventData")] - public (byte systemType, int playerId, byte amount) EventData { get; set; } + public UpdateSystemReplayData? EventData { get; set; } public void Play() { - var player = Utils.PlayerFromPlayerId(EventData.playerId); + if (EventData == null) + return; + + var player = Utils.PlayerFromPlayerId(EventData.PlayerId); if (player == null) return; if (ShipStatus.Instance == null) return; - ShipStatus.Instance?.UpdateSystem((SystemTypes)EventData.systemType, player, EventData.amount); + ShipStatus.Instance.UpdateSystem((SystemTypes)EventData.SystemType, player, EventData.Amount); } - public void Record(SystemTypes system, PlayerControl player, byte amount) + public void Undo() { - EventData = (checked((byte)system), player.PlayerId, amount); } -} + + public void Record(UpdateSystemReplayArgs args) + { + EventData = new UpdateSystemReplayData(checked((byte)args.System), args.Player.PlayerId, args.Amount); + } + + internal record UpdateSystemReplayData(byte SystemType, int PlayerId, byte Amount) : IReplayEvent.Data; + + internal record UpdateSystemReplayArgs(SystemTypes System, PlayerControl Player, byte Amount) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/VanishReplayEvent.cs b/src/Data/Replay/Events/VanishReplayEvent.cs index fb87860..f880442 100644 --- a/src/Data/Replay/Events/VanishReplayEvent.cs +++ b/src/Data/Replay/Events/VanishReplayEvent.cs @@ -1,22 +1,25 @@ using AmongUs.GameOptions; -using BetterAmongUs.Utilities; using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class VanishReplayEvent : IReplayEvent +internal sealed class VanishReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "player_vanish"; [JsonPropertyName("eventData")] - public int EventData { get; set; } + public VanishReplayData? EventData { get; set; } public void Play() { - var player = Utils.PlayerFromPlayerId(EventData); + if (EventData == null) + return; + + var player = Utils.PlayerFromPlayerId(EventData.PlayerId); if (player == null) return; @@ -26,8 +29,16 @@ internal sealed class VanishReplayEvent : IReplayEvent player.SetRoleInvisibility(true, true, true); } - public void Record(PlayerControl player) + public void Undo() { - EventData = player.PlayerId; } -} + + public void Record(VanishReplayArgs args) + { + EventData = new VanishReplayData(args.Player.PlayerId); + } + + internal record VanishReplayData(int PlayerId) : IReplayEvent.Data; + + internal record VanishReplayArgs(PlayerControl Player) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Data/Replay/Events/VentReplayEvent.cs b/src/Data/Replay/Events/VentReplayEvent.cs index bd50e11..32108bd 100644 --- a/src/Data/Replay/Events/VentReplayEvent.cs +++ b/src/Data/Replay/Events/VentReplayEvent.cs @@ -1,37 +1,51 @@ -using BetterAmongUs.Utilities; -using BetterAmongUs.Interfaces; +using BetterAmongUs.Interfaces; +using BetterAmongUs.Utilities; using System.Text.Json.Serialization; namespace BetterAmongUs.Data.Replay.Events; [Serializable] -internal sealed class VentReplayEvent : IReplayEvent<(int playerId, bool exit, int ventId)> +internal sealed class VentReplayEvent : IReplayEvent { [JsonPropertyName("id")] public string Id => "player_vent"; [JsonPropertyName("eventData")] - public (int playerId, bool exit, int ventId) EventData { get; set; } + public VentReplayData? EventData { get; set; } public void Play() { - var vent = ShipStatus.Instance.AllVents.First(v => v.Id == EventData.ventId); - var player = Utils.PlayerFromPlayerId(EventData.playerId); - if (vent != null && player != null) + if (EventData == null) + return; + + var player = Utils.PlayerFromPlayerId(EventData.PlayerId); + if (player == null) + return; + + var vent = ShipStatus.Instance.AllVents.FirstOrDefault(v => v.Id == EventData.VentId); + if (vent == null) + return; + + if (EventData.Exit) { - if (EventData.exit) - { - vent.ExitVent(player); - } - else - { - vent.EnterVent(player); - } + vent.ExitVent(player); + } + else + { + vent.EnterVent(player); } } - public void Record(PlayerControl player, bool exit, int ventId) + public void Undo() { - EventData = (player.PlayerId, exit, ventId); } -} + + public void Record(VentReplayArgs args) + { + EventData = new VentReplayData(args.Player.PlayerId, args.Exit, args.VentId); + } + + internal record VentReplayData(int PlayerId, bool Exit, int VentId) : IReplayEvent.Data; + + internal record VentReplayArgs(PlayerControl Player, bool Exit, int VentId) : IReplayEvent.Args; +} \ No newline at end of file diff --git a/src/Interfaces/IReplayEvent.cs b/src/Interfaces/IReplayEvent.cs index 460f554..d2677f7 100644 --- a/src/Interfaces/IReplayEvent.cs +++ b/src/Interfaces/IReplayEvent.cs @@ -1,29 +1,55 @@ namespace BetterAmongUs.Interfaces; /// -/// Interface for replay events in BetterAmongUs. +/// Base interface for all replay events. /// public interface IReplayEvent { /// - /// Gets the unique identifier for the replay event. + /// Base record for all replay event data. /// - string Id { get; } + public abstract record Data; /// - /// Plays or executes the replay event. + /// Base record for all replay event arguments. /// - void Play(); + public abstract record Args; } /// -/// Generic interface for replay events with associated data. +/// Generic interface for replay events with typed data and arguments. /// -/// The type of data associated with the event. -public interface IReplayEvent : IReplayEvent +/// The type of event data. Must inherit from . +/// The type of event arguments. Must inherit from . +public interface IReplayEvent : IReplayEvent + where EventDataType : IReplayEvent.Data + where EventArgType : IReplayEvent.Args { /// - /// Gets or sets the event data. + /// Gets the unique identifier for the event type. /// - T? EventData { get; set; } + /// A string that uniquely identifies this type of event. + string Id { get; } + + /// + /// Gets the stored event data. + /// + /// The event data of type , or null if not recorded. + EventDataType? EventData { get; } + + /// + /// Records the event using the provided arguments. + /// + /// The arguments used to construct the event data. + void Record(EventArgType replayEventArg); + + /// + /// Replays the event using the stored event data. + /// + void Play(); + + /// + /// Undoes the effects of the replayed event. + /// + void Undo(); } \ No newline at end of file