UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
IntNetSerializerBase.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
12#include <type_traits>
13
14namespace UE::Net::Private
15{
16
17// FIntNetSerializerBase is expected to work for both signed and unsigned integers.
18template<typename InSourceType, typename InConfigType>
20{
21 static const uint32 Version = 0;
22
24 // For convenience we'll use an unsigned type as the quantized type
25 using QuantizedType = std::make_unsigned_t<SourceType>;
27
29 {
30 const QuantizedType Value = *reinterpret_cast<const QuantizedType*>(Args.Source);
31
32 FNetBitStreamWriter* Writer = Context.GetBitStreamWriter();
33
34 const ConfigType* Config = static_cast<const ConfigType*>(Args.NetSerializerConfig);
35 const uint32 BitCount = Config->BitCount;
36
37 // Zero value optimization for larger bit counts
38 if (BitCount >= ZeroValueOptimizationBitCount)
39 {
40 if (Writer->WriteBool(Value == QuantizedType(0)))
41 {
42 return;
43 }
44 }
45
46 if constexpr (sizeof(SourceType) == 8)
47 {
48 Writer->WriteBits(static_cast<uint32>(Value), FMath::Min(BitCount, 32U));
49 if (BitCount > 32U)
50 {
51 Writer->WriteBits(static_cast<uint32>(Value >> 32U), BitCount - 32U); // sizeof(SourceType)*4 == 32 for 64-bit types. This is to prevent compiler warning for shorter types.
52 }
53 }
54 else
55 {
56 Writer->WriteBits(Value, BitCount);
57 }
58 }
59
61 {
62 QuantizedType* Target = reinterpret_cast<QuantizedType*>(Args.Target);
63
64 FNetBitStreamReader* Reader = Context.GetBitStreamReader();
65
66 const ConfigType* Config = static_cast<const ConfigType*>(Args.NetSerializerConfig);
67 const uint32 BitCount = Config->BitCount;
68
69 // Zero value optimization for larger bit counts
70 if (BitCount >= ZeroValueOptimizationBitCount)
71 {
72 if (Reader->ReadBool())
73 {
74 *Target = SourceType(0);
75 return;
76 }
77 }
78
80 if constexpr (sizeof(SourceType) == 8)
81 {
82 Value = Reader->ReadBits(FMath::Min(BitCount, 32U));
83 if (BitCount > 32U)
84 {
85 Value |= static_cast<QuantizedType>(Reader->ReadBits(BitCount - 32U)) << 32U;
86 }
87 }
88 else
89 {
90 Value = static_cast<QuantizedType>(Reader->ReadBits(BitCount));
91 }
92
93 // Sign-extend the value if needed
94 if constexpr (std::is_signed_v<SourceType>)
95 {
96 const QuantizedType SignMask = static_cast<QuantizedType>(QuantizedType(1) << (BitCount - 1U));
97 Value = (Value ^ SignMask) - SignMask;
98 }
99
100 *Target = Value;
101 }
102
104 {
105 // For this case we require the values to be properly signed as the helper function requires it.
106 const SourceType Value = *reinterpret_cast<const SourceType*>(Args.Source);
107 const SourceType PrevValue = *reinterpret_cast<const SourceType*>(Args.Prev);
108
109 const ConfigType* Config = static_cast<const ConfigType*>(Args.NetSerializerConfig);
110 const uint8 MaxBitCount = Config->BitCount;
111
112 if (MaxBitCount == 0)
113 {
114 return;
115 }
116
117 const uint32 IndexToBitCountEntries = GetDeltaBitCountTableIndex(MaxBitCount);
118 const uint8* BitCountTable = DeltaBitCountTable[IndexToBitCountEntries];
119 const uint32 BitCountTableEntryCount = DeltaBitCountTableEntryCount[IndexToBitCountEntries];
120
121 FNetBitStreamWriter* Writer = Context.GetBitStreamWriter();
122 if constexpr (std::is_signed_v<SourceType>)
123 {
125 }
126 else
127 {
129 }
130 }
131
133 {
134 SourceType& Target = *reinterpret_cast<SourceType*>(Args.Target);
135 const SourceType PrevValue = *reinterpret_cast<const SourceType*>(Args.Prev);
136
137 const ConfigType* Config = static_cast<const ConfigType*>(Args.NetSerializerConfig);
138 const uint8 MaxBitCount = Config->BitCount;
139
140 if (MaxBitCount == 0)
141 {
142 Target = SourceType(0);
143 return;
144 }
145
146 const uint32 IndexToBitCountEntries = GetDeltaBitCountTableIndex(MaxBitCount);
147 const uint8* BitCountTable = DeltaBitCountTable[IndexToBitCountEntries];
148 const uint32 BitCountTableEntryCount = DeltaBitCountTableEntryCount[IndexToBitCountEntries];
149
150 FNetBitStreamReader* Reader = Context.GetBitStreamReader();
151 if constexpr (std::is_signed_v<SourceType>)
152 {
154 }
155 else
156 {
158 }
159 }
160
162 {
163 const SourceType Source = *reinterpret_cast<const SourceType*>(Args.Source);
164
165 const ConfigType* Config = static_cast<const ConfigType*>(Args.NetSerializerConfig);
166 const uint32 BitCount = Config->BitCount;
167
169 if constexpr (std::is_signed_v<SourceType>)
170 {
171 const QuantizedType SignMask = static_cast<QuantizedType>(QuantizedType(1) << (BitCount - 1U));
172 const QuantizedType ValueMask = SignMask | (SignMask - QuantizedType(1));
173
174 Value = static_cast<QuantizedType>(Source) & ValueMask;
175 // Sign-extend
176 Value = (Value ^ SignMask) - SignMask;
177 }
178 else
179 {
181 const QuantizedType ValueMask = MaxValueForType >> (sizeof(QuantizedType)*8U - BitCount);
182 Value = Source & ValueMask;
183 }
184
185 QuantizedType& Target = *reinterpret_cast<QuantizedType*>(Args.Target);
186 Target = Value;
187 }
188
190 {
191 const SourceType& Source = *reinterpret_cast<const SourceType*>(Args.Source);
192 SourceType& Target = *reinterpret_cast<SourceType*>(Args.Target);
193
194 Target = Source;
195 }
196
198 {
199 if (Args.bStateIsQuantized)
200 {
201 const QuantizedType Value0 = *reinterpret_cast<const QuantizedType*>(Args.Source0);
202 const QuantizedType Value1 = *reinterpret_cast<const QuantizedType*>(Args.Source1);
203
204 return Value0 == Value1;
205 }
206 else
207 {
208 const ConfigType* Config = static_cast<const ConfigType*>(Args.NetSerializerConfig);
209 const uint32 BitCount = Config->BitCount;
210
212 const QuantizedType ValueMask = MaxValueForType >> (sizeof(SourceType)*8U - BitCount);
213
214 // Only the lower BitCount bits of the values are considered when quantizing.
215 const QuantizedType MaskedValue0 = *reinterpret_cast<const QuantizedType*>(Args.Source0) & ValueMask;
216 const QuantizedType MaskedValue1 = *reinterpret_cast<const QuantizedType*>(Args.Source1) & ValueMask;
217
218 return MaskedValue0 == MaskedValue1;
219 }
220 }
221
223 {
224 const ConfigType* Config = static_cast<const ConfigType*>(Args.NetSerializerConfig);
225 const uint32 BitCount = Config->BitCount;
226
227 // Detect invalid bit count
229 {
230 return false;
231 }
232
233 const SourceType Value = *reinterpret_cast<const SourceType*>(Args.Source);
234 const bool bIsValidValue = GetBitsNeeded(Value) <= BitCount;
235 return bIsValidValue;
236 }
237
238private:
239 static uint32 GetDeltaBitCountTableIndex(uint8 BitCount)
240 {
241 // Use a small lookup table.
242 // It's indexed via (BitCount-1)/8 which is in the range [0,7].
243 // In max BitCount: 65+ 64 56 48 40 32 24 16 8
244 // Index: 0 3 3 3 3 2 2 1 0
245 constexpr uint64 TableIndexLUT = 0b1111111110100100U;
246 constexpr uint32 MaxTableIndex = 3U;
247 const uint32 LUTShiftAmount = (uint8(BitCount - 1) >> 3U) << 1U;
248 const uint32 TableIndex = (TableIndexLUT >> LUTShiftAmount) & MaxTableIndex;
249 return TableIndex;
250 }
251
252 /* These are delta compression bit count tables for bitcounts <= 8, 16, 32 and 64 respectively.
253 * What they have in common is that they all allow for same value optimization,
254 * i.e. the delta to be serialized is zero. The index into the table must always be written
255 * so for bit counts > 8 the minimum number of bits written is 2.
256 * The bit counts are not scientifically nor empirically proven. They're mainly aiming to keep small changes cheap.
257 */
258 inline static const uint8 DeltaBitCountTable[4][3] =
259 {
260 {0, 0 /* unused */, 0 /* unused */},
261 {0, 4, 10},
262 {0, 4, 14},
263 {0, 14, 32},
264 };
265
266 inline static const uint32 DeltaBitCountTableEntryCount[4] = {1, 3, 3, 3};
267
268 static constexpr uint32 ZeroValueOptimizationBitCount = 16U;
269};
270
271}
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition NetBitStreamReader.h:11
IRISCORE_API uint32 ReadBits(uint32 BitCount)
Definition NetBitStreamReader.cpp:54
bool ReadBool()
Definition NetBitStreamReader.h:34
Definition NetBitStreamWriter.h:11
bool WriteBool(bool Value)
Definition NetBitStreamWriter.h:110
IRISCORE_API void WriteBits(uint32 Value, uint32 BitCount)
Definition NetBitStreamWriter.cpp:59
Definition NetSerializationContext.h:31
Definition NetworkVersion.cpp:28
uint32 GetBitsNeeded(const int32 Value)
Definition QuantizedVectorSerialization.cpp:13
void DeserializeUintDelta(FNetBitStreamReader &Reader, uint32 &OutValue, const uint32 PrevValue, const uint8 *SmallBitCountTable, const uint32 SmallBitCountTableEntryCount, uint8 LargeBitCount)
Definition BitPacking.cpp:194
void SerializeUintDelta(FNetBitStreamWriter &Writer, const uint32 Value, const uint32 PrevValue, const uint8 *SmallBitCountTable, const uint32 SmallBitCountTableEntryCount, uint8 LargeBitCount)
Definition BitPacking.cpp:189
void SerializeIntDelta(FNetBitStreamWriter &Writer, const int32 Value, const int32 PrevValue, const uint8 *SmallBitCountTable, const uint32 SmallBitCountTableEntryCount, uint8 LargeBitCount)
Definition BitPacking.cpp:177
void DeserializeIntDelta(FNetBitStreamReader &Reader, int32 &OutValue, const int32 PrevValue, const uint8 *SmallBitCountTable, const uint32 SmallBitCountTableEntryCount, uint8 LargeBitCount)
Definition BitPacking.cpp:182
Definition NetSerializer.h:259
NetSerializerValuePointer Source
Definition NetSerializer.h:261
NetSerializerValuePointer Target
Definition NetSerializer.h:263
Definition NetSerializer.h:194
NetSerializerValuePointer Target
Definition NetSerializer.h:195
Definition NetSerializer.h:222
NetSerializerValuePointer Prev
Definition NetSerializer.h:224
Definition NetSerializer.h:274
NetSerializerValuePointer Source1
Definition NetSerializer.h:278
NetSerializerValuePointer Source0
Definition NetSerializer.h:276
bool bStateIsQuantized
Definition NetSerializer.h:280
Definition NetSerializer.h:243
NetSerializerValuePointer Target
Definition NetSerializer.h:247
NetSerializerValuePointer Source
Definition NetSerializer.h:245
Definition NetSerializer.h:183
NetSerializerValuePointer Source
Definition NetSerializer.h:185
Definition NetSerializer.h:207
NetSerializerValuePointer Prev
Definition NetSerializer.h:209
NetSerializerConfigParam NetSerializerConfig
Definition NetSerializer.h:157
Definition NetSerializer.h:292
NetSerializerValuePointer Source
Definition NetSerializer.h:294
Definition IntNetSerializerBase.h:20
static bool Validate(FNetSerializationContext &Context, const FNetValidateArgs &Args)
Definition IntNetSerializerBase.h:222
static const uint32 Version
Definition IntNetSerializerBase.h:21
static bool IsEqual(FNetSerializationContext &Context, const FNetIsEqualArgs &Args)
Definition IntNetSerializerBase.h:197
InConfigType ConfigType
Definition IntNetSerializerBase.h:26
static void Dequantize(FNetSerializationContext &Context, const FNetDequantizeArgs &Args)
Definition IntNetSerializerBase.h:189
static void DeserializeDelta(FNetSerializationContext &Context, const FNetDeserializeDeltaArgs &Args)
Definition IntNetSerializerBase.h:132
static void Deserialize(FNetSerializationContext &Context, const FNetDeserializeArgs &Args)
Definition IntNetSerializerBase.h:60
static void SerializeDelta(FNetSerializationContext &Context, const FNetSerializeDeltaArgs &Args)
Definition IntNetSerializerBase.h:103
static void Serialize(FNetSerializationContext &Context, const FNetSerializeArgs &Args)
Definition IntNetSerializerBase.h:28
static void Quantize(FNetSerializationContext &Context, const FNetQuantizeArgs &Args)
Definition IntNetSerializerBase.h:161
std::make_unsigned_t< SourceType > QuantizedType
Definition IntNetSerializerBase.h:25
InSourceType SourceType
Definition IntNetSerializerBase.h:23