98 lines
3.5 KiB
C#
98 lines
3.5 KiB
C#
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Text.Json;
|
|
using SideScrollerGame.Sim.Math;
|
|
using SideScrollerGame.Sim.Runtime;
|
|
|
|
namespace SideScrollerGame.Sim.Serialization;
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
internal static class SimulationStateSerializer
|
|
{
|
|
[ExcludeFromCodeCoverage]
|
|
private sealed record SimulationStateDocument
|
|
{
|
|
public int Version { get; init; }
|
|
|
|
public int Tick { get; init; }
|
|
|
|
public int Seed { get; init; }
|
|
|
|
public ulong RandomState { get; init; }
|
|
|
|
public ulong LastRandomValue { get; init; }
|
|
|
|
public ImmutableArray<PlayerStateDocument> Players { get; init; }
|
|
|
|
public ImmutableArray<string> ActivatedTriggerIds { get; init; }
|
|
}
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
private sealed record PlayerStateDocument
|
|
{
|
|
public int PlayerId { get; init; }
|
|
|
|
public int PositionX { get; init; }
|
|
|
|
public int PositionY { get; init; }
|
|
|
|
public sbyte MoveAxisX { get; init; }
|
|
|
|
public sbyte MoveAxisY { get; init; }
|
|
|
|
public short AimAxisX { get; init; }
|
|
|
|
public short AimAxisY { get; init; }
|
|
|
|
public int SelectedWeaponSlot { get; init; }
|
|
|
|
public int ButtonMask { get; init; }
|
|
|
|
public int Health { get; init; }
|
|
}
|
|
|
|
public static byte[] Serialize(SimulationState state)
|
|
{
|
|
List<PlayerStateDocument> players = new(state.Players.Length);
|
|
foreach (var player in state.Players)
|
|
{
|
|
players.Add(new()
|
|
{
|
|
PlayerId = player.PlayerId.Value,
|
|
PositionX = player.Position.m_X.m_Value,
|
|
PositionY = player.Position.m_Y.m_Value,
|
|
MoveAxisX = player.MoveAxisX,
|
|
MoveAxisY = player.MoveAxisY,
|
|
AimAxisX = player.AimAxisX,
|
|
AimAxisY = player.AimAxisY,
|
|
SelectedWeaponSlot = player.SelectedWeaponSlot,
|
|
ButtonMask = player.ButtonMask,
|
|
Health = player.Health
|
|
});
|
|
}
|
|
|
|
return JsonSerializer.SerializeToUtf8Bytes(new SimulationStateDocument
|
|
{
|
|
Version = SimulationDefaults.StateFormatVersion,
|
|
Tick = state.Tick,
|
|
Seed = state.Seed,
|
|
RandomState = state.RandomState,
|
|
LastRandomValue = state.LastRandomValue,
|
|
Players = players.ToImmutableArray(),
|
|
ActivatedTriggerIds = state.ActivatedTriggerIds.Order(StringComparer.Ordinal).ToImmutableArray()
|
|
});
|
|
}
|
|
|
|
public static SimulationState Deserialize(byte[] data)
|
|
{
|
|
var document = JsonSerializer.Deserialize<SimulationStateDocument>(data) ?? throw new InvalidOperationException("Simulation state payload was empty.");
|
|
if (document.Version != SimulationDefaults.StateFormatVersion)
|
|
throw new NotSupportedException($"Unsupported simulation state version {document.Version}.");
|
|
|
|
var players = ImmutableArray.CreateBuilder<PlayerState>(document.Players.Length);
|
|
foreach (var player in document.Players)
|
|
players.Add(new(new(player.PlayerId), new(new() { m_Value = player.PositionX }, new FixPoint16 { m_Value = player.PositionY }), player.MoveAxisX, player.MoveAxisY, player.AimAxisX, player.AimAxisY, player.SelectedWeaponSlot, player.ButtonMask, player.Health));
|
|
|
|
return new(document.Tick, document.Seed, document.RandomState, document.LastRandomValue, players.MoveToImmutable(), document.ActivatedTriggerIds.ToImmutableHashSet(StringComparer.Ordinal));
|
|
}
|
|
} |