using System.Collections.Generic; using System.Net; using Network.Defines; namespace Network.NetworkApplication { public sealed class SyncSequenceTracker { private readonly object gate = new(); private readonly Dictionary latestSequenceByStream = new(); public bool ShouldAccept(MessageType messageType, byte[] payload, IPEndPoint sender) { if (!TryResolveSequence(messageType, payload, sender, out var streamKey, out var sequence)) { return true; } lock (gate) { if (latestSequenceByStream.TryGetValue(streamKey, out var latestSequence) && sequence < latestSequence) { return false; } latestSequenceByStream[streamKey] = sequence; return true; } } private static bool TryResolveSequence( MessageType messageType, byte[] payload, IPEndPoint sender, out string streamKey, out long sequence) { switch (messageType) { case MessageType.MoveInput: { var input = MoveInput.Parser.ParseFrom(payload); streamKey = $"input:{input.PlayerId}"; sequence = input.Tick; return true; } case MessageType.PlayerState: { var state = PlayerState.Parser.ParseFrom(payload); streamKey = $"state:{state.PlayerId}"; sequence = state.Tick; return true; } default: streamKey = null; sequence = 0; return false; } } private static string Normalize(IPEndPoint sender) { return sender == null ? "unknown" : sender.ToString(); } } }