Client LuaCsForBarotrauma
NetStructBitField.cs
1 #nullable enable
2 
3 using System;
4 using System.Collections.Generic;
5 using System.Collections.Immutable;
7 using Lidgren.Network;
8 
9 namespace Barotrauma
10 {
11  sealed class WriteOnlyBitField : IDisposable
12  {
13  private const int AmountOfBoolsInByte = 7; // Reserve last bit for end marker
14  private readonly List<byte> Buffer = new List<byte>();
15  private int index;
16  private bool disposed;
17 
18  public void WriteBoolean(bool b)
19  {
20  ThrowIfDisposed();
21 
22  int arrayIndex = (int)Math.Floor(index / (float)AmountOfBoolsInByte);
23  if (arrayIndex >= Buffer.Count) { Buffer.Add(0); }
24 
25  int bitIndex = index % AmountOfBoolsInByte;
26  Buffer[arrayIndex] |= (byte)(b ? 1u << bitIndex : 0);
27  index++;
28  }
29 
30  public void WriteInteger(int value, int min, int max)
31  {
32  ThrowIfDisposed();
33 
34  uint range = (uint)(max - min);
35  int numberOfBits = NetUtility.BitsToHoldUInt(range);
36 
37  uint writeValue = (uint)(value - min);
38 
39  for (int i = 0; i < numberOfBits; i++)
40  {
41  WriteBoolean((writeValue & (1u << i)) != 0);
42  }
43  }
44 
45  public void WriteFloat(float value, float min, float max, int numberOfBits)
46  {
47  ThrowIfDisposed();
48 
49  float range = max - min;
50  float unit = (value - min) / range;
51  uint maxVal = (1u << numberOfBits) - 1;
52 
53  uint writeValue = (uint)(maxVal * unit);
54  for (int i = 0; i < numberOfBits; i++)
55  {
56  WriteBoolean((writeValue & (1u << i)) != 0);
57  }
58  }
59 
60  public void WriteToMessage(IWriteMessage msg)
61  {
62  ThrowIfDisposed();
63 
64  if (Buffer.Count == 0) { Buffer.Add(0); }
65 
66  Buffer[^1] |= 1 << AmountOfBoolsInByte; // mark the last byte so we know when to stop reading
67 
68  foreach (byte b in Buffer)
69  {
70  msg.WriteByte(b);
71  }
72 
73  Dispose();
74  }
75 
76  public void Dispose()
77  {
78  disposed = true;
79  }
80 
81  private void ThrowIfDisposed()
82  {
83  if (disposed) { throw new ObjectDisposedException(nameof(WriteOnlyBitField)); }
84  }
85  }
86 
87  sealed class ReadOnlyBitField
88  {
89  private const int AmountOfBoolsInByte = 7; // Reserve last bit for end marker
90  private readonly ImmutableArray<byte> buffer;
91  private int index;
92 
94  {
95  List<byte> bytes = new List<byte>();
96  byte currentByte;
97 
98  do
99  {
100  if (inc.BitPosition >= inc.LengthBits)
101  {
102  throw new Exception("Failed to find the end of the bit field: end of the message reached.");
103  }
104  currentByte = inc.ReadByte();
105  bytes.Add(currentByte);
106  }
107  while (!IsBitSet(currentByte, AmountOfBoolsInByte));
108 
109  buffer = bytes.ToImmutableArray();
110  }
111 
112  public bool ReadBoolean()
113  {
114  int arrayIndex = (int)MathF.Floor(index / (float)AmountOfBoolsInByte);
115  int bitIndex = index % AmountOfBoolsInByte;
116  index++;
117  return IsBitSet(buffer[arrayIndex], bitIndex);
118  }
119 
120  public int ReadInteger(int min, int max)
121  {
122  uint range = (uint)(max - min);
123  int numberOfBits = NetUtility.BitsToHoldUInt(range);
124 
125  uint value = 0;
126  for (int i = 0; i < numberOfBits; i++)
127  {
128  value |= ReadBoolean() ? 1u << i : 0u;
129  }
130 
131  return (int)(min + value);
132  }
133 
134  public float ReadFloat(float min, float max, int numberOfBits)
135  {
136  int maxInt = (1 << numberOfBits) - 1;
137 
138  uint value = 0;
139  for (int i = 0; i < numberOfBits; i++)
140  {
141  value |= ReadBoolean() ? 1u << i : 0u;
142  }
143 
144  float range = max - min;
145  return min + range * value / maxInt;
146  }
147 
148  private static bool IsBitSet(byte b, int bitIndex) => (b & (1u << bitIndex)) != 0;
149  }
150 }
int ReadInteger(int min, int max)
float ReadFloat(float min, float max, int numberOfBits)
ReadOnlyBitField(IReadMessage inc)
void WriteInteger(int value, int min, int max)
void WriteFloat(float value, float min, float max, int numberOfBits)
void WriteToMessage(IWriteMessage msg)