Client LuaCsForBarotrauma
NetIdUtils.cs
1 using System;
2 using System.Diagnostics;
3 
4 namespace Barotrauma.Networking
5 {
9  static class NetIdUtils
10  {
14  public static bool IdMoreRecent(ushort newID, ushort oldID)
15  {
16  uint id1 = newID;
17  uint id2 = oldID;
18 
19  return
20  (id1 > id2) && (id1 - id2 <= ushort.MaxValue / 2)
21  ||
22  (id2 > id1) && (id2 - id1 > ushort.MaxValue / 2);
23  }
24 
28  public static bool IdMoreRecentOrMatches(ushort newId, ushort oldId)
29  => !IdMoreRecent(oldId, newId);
30 
35  public static ushort GetIdOlderThan(ushort id)
36 #if DEBUG
37  // Debug implementation has some RNG to discourage bad assumptions about the return value
38  => unchecked((ushort)(id - 1 - Rand.Int(500, sync: Rand.RandSync.Unsynced)));
39 #else
40  // Release implementation favors performance
41  => unchecked((ushort)(id - 1));
42 #endif
43 
44  public static ushort Difference(ushort id1, ushort id2)
45  {
46  int diff = id2 > id1 ? id2 - id1 : id1 - id2;
47  return (ushort)(diff > ushort.MaxValue / 2 ? ushort.MaxValue - diff : diff);
48  }
49 
50  public static ushort Clamp(ushort id, ushort min, ushort max)
51  {
52  if (IdMoreRecent(min, max))
53  {
54  throw new ArgumentException($"Min cannot be larger than max ({min}, {max})");
55  }
56 
57  if (!IdMoreRecent(id, min))
58  {
59  return min;
60  }
61  else if (IdMoreRecent(id, max))
62  {
63  return max;
64  }
65 
66  return id;
67  }
68 
72  public static bool IsValidId(ushort currentId, ushort previousId, ushort latestPossibleId)
73  {
74  //cannot be valid if more recent than the latest Id
75  if (IdMoreRecent(currentId, latestPossibleId)) { return false; }
76 
77  //normally the id needs to be more recent than the previous id,
78  //but there's a special case when the previous id was 0:
79  // if a client reconnects mid-round and tries to jump from the unitialized state (0) back to some previous high id (> ushort.MaxValue / 2),
80  // this would normally get interpreted as trying to jump backwards, but in this case we'll allow it
81  return IdMoreRecent(currentId, previousId) || (previousId == 0 && currentId > ushort.MaxValue / 2);
82  }
83 
84 #if DEBUG
85  public static void Test()
86  {
87  Debug.Assert(IdMoreRecent((ushort)2, (ushort)1));
88  Debug.Assert(IdMoreRecent((ushort)2, (ushort)(ushort.MaxValue - 5)));
89  Debug.Assert(!IdMoreRecent((ushort)ushort.MaxValue, (ushort)5));
90 
91  Debug.Assert(Clamp((ushort)5, (ushort)1, (ushort)10) == 5);
92  Debug.Assert(Clamp((ushort)(ushort.MaxValue - 5), (ushort)(ushort.MaxValue - 2), (ushort)3) == (ushort)(ushort.MaxValue - 2));
93 
94  Debug.Assert(IsValidId((ushort)10, (ushort)1, (ushort)10));
95  Debug.Assert(!IsValidId((ushort)11, (ushort)1, (ushort)10));
96 
97  Debug.Assert(IsValidId((ushort)1, (ushort)(ushort.MaxValue - 5), (ushort)10));
98  Debug.Assert(!IsValidId((ushort)(ushort.MaxValue - 6), (ushort)(ushort.MaxValue - 5), (ushort)10));
99 
100  Debug.Assert(IsValidId((ushort)0, (ushort)(ushort.MaxValue - 100), (ushort)5));
101  Debug.Assert(!IsValidId((ushort)(ushort.MaxValue - 101), (ushort)(ushort.MaxValue - 100), (ushort)ushort.MaxValue));
102 
103  Debug.Assert(Difference((ushort)0, (ushort)56) == 56);
104  Debug.Assert(Difference((ushort)56, (ushort)0) == 56);
105  Debug.Assert(Difference((ushort)5, (ushort)(ushort.MaxValue - 101)) == 106);
106  Debug.Assert(Difference((ushort)(ushort.MaxValue - 101), (ushort)5) == 106);
107  }
108 #endif
109  }
110 }