#nullable enable using System; using System.Security.Cryptography; using System.Text; namespace ReplacedPerson.Core { public static class ReplacedStateHasher { public static string Compute(ReplacedMatchState state, Pcg32 random) { var text = new StringBuilder(2048); text.Append(state.Round).Append('|').Append(state.LeadPlayer).Append('|').Append(state.InitiativeRoll) .Append('|').Append((int)state.Phase).Append('|').Append((int)state.Winner).Append('|') .Append(state.IsLastStand ? 1 : 0).Append('|').Append(state.LastStandUsed ? 1 : 0).Append('|') .Append(state.ContentHash).Append('|').Append(random.State).Append('|').Append(random.Increment).Append('\n'); for (var index = 0; index < state.Players.Length; index++) { var player = state.Players[index]; text.Append(index).Append('|').Append(player.PlayerId).Append('|').Append(player.Health).Append('|') .Append(player.Cost).Append('|').Append(player.Defense).Append('|').Append(player.BonusNormalDraw) .Append('|').Append(player.GuaranteedDodge ? 1 : 0).Append('|').Append(player.SkipNextEndDraw ? 1 : 0) .Append('|').Append(player.SpentThisRound).Append('|').Append(player.EffectiveEffectsThisRound) .Append('|').Append(player.DamageThisRound).Append('\n'); AppendList(text, player.NormalDrawPile); AppendList(text, player.NormalDiscard); AppendList(text, player.NormalHand); AppendList(text, player.EndDrawPile); AppendList(text, player.EndDiscard); AppendList(text, player.EndHand); } for (var i = 0; i < state.LastAcceptedSequence.Length; i++) text.Append("S|").Append(i).Append('|').Append(state.LastAcceptedSequence[i]).Append('\n'); for (var i = 0; i < state.Submissions.Length; i++) { var submission = state.Submissions[i]; text.Append("C|").Append(i).Append('|'); if (submission == null) { text.Append("null\n"); continue; } text.Append(submission.Pass ? 1 : 0).Append('|').Append(submission.DiscardEndOnPass ? 1 : 0) .Append('|').Append(submission.RerollSlot).Append('|'); AppendList(text, submission.NormalCardIds); AppendList(text, submission.EndCardIds); } foreach (var resolution in state.LastResolution) { text.Append("R|").Append(resolution.SlotIndex).Append('|').Append((int)resolution.PlayerOneType).Append('|') .Append((int)resolution.PlayerTwoType).Append('|').Append(resolution.PlayerOneRoll).Append('|') .Append(resolution.PlayerTwoRoll).Append('|').Append(resolution.PlayerOneValue).Append('|') .Append(resolution.PlayerTwoValue).Append('|').Append(resolution.PlayerOneRerolled ? 1 : 0).Append('|') .Append(resolution.PlayerTwoRerolled ? 1 : 0).Append('|').Append(resolution.DamageToPlayerOne).Append('|') .Append(resolution.DamageToPlayerTwo).Append('|').Append(resolution.Summary).Append('\n'); } using var sha = SHA256.Create(); var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(text.ToString())); var result = new StringBuilder(bytes.Length * 2); foreach (var value in bytes) result.Append(value.ToString("x2")); return result.ToString(); } private static void AppendList(StringBuilder target, System.Collections.Generic.IEnumerable values) => target.Append('[').Append(string.Join(",", values)).Append("]\n"); } }