69 lines
2.0 KiB
C#
69 lines
2.0 KiB
C#
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<string, long> 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:{Normalize(sender)}:{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();
|
|
}
|
|
}
|
|
} |