Skip to content

Commit 2060511

Browse files
committed
feat(ReplayEvent): add serialization and deserialization for combat replay events
- Implemented ReplayEventSerialize and ReplayEventDeserialize patches to handle RitsuLib-managed actions within combat replay events. - Updated RitsuLibManagedNetActions to allow actions to be recordable for replay by changing RecordableToReplay to true. - Enhanced PatcherSetup to register the new serialization and deserialization patches, improving replay functionality.
1 parent f4ead41 commit 2060511

3 files changed

Lines changed: 108 additions & 1 deletion

File tree

Networking/ManagedActions/Patches/RitsuLibManagedNetActionMessagePatches.cs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using MegaCrit.Sts2.Core.Entities.Multiplayer;
12
using MegaCrit.Sts2.Core.GameActions.Multiplayer;
23
using MegaCrit.Sts2.Core.Multiplayer.Messages.Game;
4+
using MegaCrit.Sts2.Core.Multiplayer.Replay;
35
using MegaCrit.Sts2.Core.Multiplayer.Serialization;
46
using MegaCrit.Sts2.Core.Runs;
57
using STS2RitsuLib.Patching.Models;
@@ -119,5 +121,108 @@ public static bool Prefix(ref ActionEnqueuedMessage __instance, PacketReader rea
119121
return false;
120122
}
121123
}
124+
125+
internal sealed class ReplayEventSerialize : IPatchMethod
126+
{
127+
public static string PatchId => "ritsulib_managed_net_action_replay_event_serialize";
128+
public static bool IsCritical => true;
129+
130+
public static string Description =>
131+
"Serialize RitsuLib-managed actions inside combat replay events";
132+
133+
public static ModPatchTarget[] GetTargets()
134+
{
135+
return
136+
[
137+
new(typeof(CombatReplayEvent),
138+
nameof(CombatReplayEvent.Serialize),
139+
[typeof(PacketWriter)]),
140+
];
141+
}
142+
143+
// ReSharper disable once InconsistentNaming
144+
public static bool Prefix(CombatReplayEvent __instance, PacketWriter writer)
145+
{
146+
writer.WriteInt((int)__instance.eventType, 3);
147+
switch (__instance.eventType)
148+
{
149+
case CombatReplayEventType.GameAction:
150+
writer.WriteULong(__instance.playerId!.Value);
151+
var action = __instance.action ??
152+
throw new InvalidOperationException(
153+
"Combat replay game action event has no action.");
154+
if (RitsuLibManagedNetActions.TryWriteNetAction(writer, action)) return false;
155+
writer.WriteByte((byte)action.ToId());
156+
writer.Write(action);
157+
break;
158+
case CombatReplayEventType.HookAction:
159+
writer.WriteULong(__instance.playerId!.Value);
160+
writer.WriteUInt(__instance.hookId!.Value);
161+
writer.WriteEnum(__instance.gameActionType!.Value);
162+
break;
163+
case CombatReplayEventType.ResumeAction:
164+
writer.WriteUInt(__instance.actionId!.Value);
165+
break;
166+
case CombatReplayEventType.PlayerChoice:
167+
writer.WriteULong(__instance.playerId!.Value);
168+
writer.WriteUInt(__instance.choiceId!.Value);
169+
writer.Write(__instance.playerChoiceResult!.Value);
170+
break;
171+
default:
172+
throw new ArgumentOutOfRangeException(nameof(__instance.eventType));
173+
}
174+
175+
return false;
176+
}
177+
}
178+
179+
internal sealed class ReplayEventDeserialize : IPatchMethod
180+
{
181+
public static string PatchId => "ritsulib_managed_net_action_replay_event_deserialize";
182+
public static bool IsCritical => true;
183+
184+
public static string Description =>
185+
"Deserialize RitsuLib-managed actions inside combat replay events";
186+
187+
public static ModPatchTarget[] GetTargets()
188+
{
189+
return
190+
[
191+
new(typeof(CombatReplayEvent),
192+
nameof(CombatReplayEvent.Deserialize),
193+
[typeof(PacketReader)]),
194+
];
195+
}
196+
197+
// ReSharper disable once InconsistentNaming
198+
public static bool Prefix(ref CombatReplayEvent __instance, PacketReader reader)
199+
{
200+
__instance.eventType = (CombatReplayEventType)reader.ReadInt(3);
201+
switch (__instance.eventType)
202+
{
203+
case CombatReplayEventType.GameAction:
204+
__instance.playerId = reader.ReadULong();
205+
__instance.action = RitsuLibManagedNetActions.ReadNetAction(reader);
206+
break;
207+
case CombatReplayEventType.HookAction:
208+
__instance.playerId = reader.ReadULong();
209+
__instance.hookId = reader.ReadUInt();
210+
__instance.gameActionType = reader.ReadEnum<GameActionType>();
211+
break;
212+
case CombatReplayEventType.ResumeAction:
213+
__instance.actionId = reader.ReadUInt();
214+
break;
215+
case CombatReplayEventType.PlayerChoice:
216+
__instance.playerId = reader.ReadULong();
217+
__instance.choiceId = reader.ReadUInt();
218+
__instance.playerChoiceResult = reader.Read<NetPlayerChoiceResult>();
219+
break;
220+
default:
221+
throw new ArgumentOutOfRangeException();
222+
}
223+
224+
return false;
225+
}
226+
}
122227
}
123228
}

Networking/ManagedActions/RitsuLibManagedNetActions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ public sealed class RitsuLibManagedGameAction(
380380
public override GameActionType ActionType { get; } = actionType;
381381

382382
/// <inheritdoc />
383-
public override bool RecordableToReplay => false;
383+
public override bool RecordableToReplay => true;
384384

385385
/// <inheritdoc />
386386
protected override async Task ExecuteAction()

RitsuLibFramework.PatcherSetup.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ private static void RegisterLifecyclePatches()
175175
patcher.RegisterPatch<RitsuLibManagedNetActionMessagePatches.RequestDeserialize>();
176176
patcher.RegisterPatch<RitsuLibManagedNetActionMessagePatches.AnnouncementSerialize>();
177177
patcher.RegisterPatch<RitsuLibManagedNetActionMessagePatches.AnnouncementDeserialize>();
178+
patcher.RegisterPatch<RitsuLibManagedNetActionMessagePatches.ReplayEventSerialize>();
179+
patcher.RegisterPatch<RitsuLibManagedNetActionMessagePatches.ReplayEventDeserialize>();
178180
patcher.RegisterPatch<ModModelIdentityRunStateCreatePatch>();
179181
patcher.RegisterPatch<ModModelIdentityPlayerRunStatePatch>();
180182
patcher.RegisterPatch<ModModelIdentityRunStateAddCardPatch>();

0 commit comments

Comments
 (0)