UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
NetSerialization.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 NetworkSerialization.h:
5 Contains custom network serialization functionality.
6=============================================================================*/
7
8#pragma once
9
10#include "Stats/Stats.h"
12#include "UObject/Class.h"
13#include "Misc/NetworkVersion.h"
14#include "UObject/CoreNet.h"
15#include "EngineLogs.h"
17
18#include <type_traits>
19
20#include "NetSerialization.generated.h"
21
27template<typename ValueType>
28bool SerializeOptionalValue(const bool bIsSaving, FArchive& Ar, ValueType& Value, const ValueType& DefaultValue)
29{
30 bool bNotDefault = (bIsSaving && (Value != DefaultValue));
32 if (bNotDefault)
33 {
34 // Non-default value, need to save or load it.
35 Ar << Value;
36 }
37 else if (!bIsSaving)
38 {
39 // Loading, and should use default
40 Value = DefaultValue;
41 }
42
43 return bNotDefault;
44}
45
51template<typename ValueType>
52bool NetSerializeOptionalValue(const bool bIsSaving, FArchive& Ar, ValueType& Value, const ValueType& DefaultValue, class UPackageMap* PackageMap)
53{
54 bool bNotDefault = (bIsSaving && (Value != DefaultValue));
56 if (bNotDefault)
57 {
58 // Non-default value, need to save or load it.
59 bool bLocalSuccess = true;
60 Value.NetSerialize(Ar, PackageMap, bLocalSuccess);
61 }
62 else if (!bIsSaving)
63 {
64 // Loading, and should use default
65 Value = DefaultValue;
66 }
67
68 return bNotDefault;
69}
70
81#if 0
82
83USTRUCT()
85{
87
88
99 bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
100 {
101 // Your code here!
102 return true;
103 }
104
115 {
116 // Your code here!
117 return true;
118 }
119}
120
121template<>
122struct TStructOpsTypeTraits< FExampleStruct > : public TStructOpsTypeTraitsBase2< FExampleStruct >
123{
124 enum
125 {
126 WithNetSerializer = true,
128 };
129};
130
131#endif
132
172namespace UE::Net::Private
173{
174
175// ScaleFactor is multiplied before send and divided by post receive. A higher ScaleFactor means more precision.
176// MaxBitsPerComponent is the maximum number of bits to use per component. This is only a maximum. A header is
177// written (size = Log2 (MaxBitsPerComponent)) to indicate how many bits are actually used.
178template<int32 ScaleFactor, int32 MaxBitsPerComponent>
180{
181 uint32 Bits = 0;
182
183 // Serialize how many bits each component will have
185
186 int32 Bias = 1<<(Bits+1);
187 uint32 Max = 1<<(Bits+2);
188 uint32 DX = 0;
189 uint32 DY = 0;
190 uint32 DZ = 0;
191
192 Ar.SerializeInt( DX, Max );
193 Ar.SerializeInt( DY, Max );
194 Ar.SerializeInt( DZ, Max );
195
196 float fact = (float)ScaleFactor;
197
198 Value.X = (float)(static_cast<int32>(DX)-Bias) / fact;
199 Value.Y = (float)(static_cast<int32>(DY)-Bias) / fact;
200 Value.Z = (float)(static_cast<int32>(DZ)-Bias) / fact;
201
202 return true;
203}
204
205}
206
207template<int32 ScaleFactor, int32 MaxBitsPerComponent>
209{
210 return UE::Net::WriteQuantizedVector(ScaleFactor, Value, Ar);
211}
212
213template<int32 ScaleFactor, int32 MaxBitsPerComponent>
215{
216 return UE::Net::WriteQuantizedVector(ScaleFactor, Vector, Ar);
217}
218
219template<int32 ScaleFactor, int32 MaxBitsPerComponent>
221{
223 {
224 return UE::Net::ReadQuantizedVector(ScaleFactor, Value, Ar);
225 }
226 else
227 {
228 return UE::Net::Private::LegacyReadPackedVector<ScaleFactor, MaxBitsPerComponent>(Value, Ar);
229 }
230}
231
232template<int32 ScaleFactor, int32 MaxBitsPerComponent>
234{
236 {
237 return UE::Net::ReadQuantizedVector(ScaleFactor, Value, Ar);
238 }
239 else
240 {
241 FVector3f AsFloat;
242 const bool bRet = UE::Net::Private::LegacyReadPackedVector<ScaleFactor, MaxBitsPerComponent>(AsFloat, Ar);
243 Value = FVector3d(AsFloat);
244 return bRet;
245 }
246}
247
248template<int32 ScaleFactor, int32 MaxBitsPerComponent>
250{
252
254 {
255 return UE::Net::SerializeQuantizedVector<ScaleFactor>(Value, Ar);
256 }
257 else
258 {
259 check(Ar.IsLoading());
260 return UE::Net::Private::LegacyReadPackedVector<ScaleFactor, MaxBitsPerComponent>(Value, Ar);
261 }
262}
263
264template<int32 ScaleFactor, int32 MaxBitsPerComponent>
266{
268
270 {
271 return UE::Net::SerializeQuantizedVector<ScaleFactor>(Value, Ar);
272 }
273 else
274 {
275 check(Ar.IsLoading());
276 FVector3f AsFloat(Value);
277 const bool bRet = UE::Net::Private::LegacyReadPackedVector<ScaleFactor, MaxBitsPerComponent>(AsFloat, Ar);
278 Value = FVector3d(AsFloat);
279 return bRet;
280 }
281}
282
283// --------------------------------------------------------------
284
285template<int32 MaxValue, uint32 NumBits>
287{
288 // NumBits = 8:
289 static constexpr int32 MaxBitValue = (1 << (NumBits - 1)) - 1; // 0111 1111 - Max abs value we will serialize
290 static constexpr int32 Bias = (1 << (NumBits - 1)); // 1000 0000 - Bias to pivot around (in order to support signed values)
291 static constexpr int32 SerIntMax = (1 << (NumBits - 0)); // 1 0000 0000 - What we pass into SerializeInt
292 static constexpr int32 MaxDelta = (1 << (NumBits - 0)) - 1; // 1111 1111 - Max delta is
293};
294
295template<int32 MaxValue, uint32 NumBits, typename T UE_REQUIRES(std::is_floating_point_v<T> && NumBits < 32)>
296bool WriteFixedCompressedFloat(const T Value, FArchive& Ar)
297{
298 using Details = TFixedCompressedFloatDetails<MaxValue, NumBits>;
299
300 bool clamp = false;
301 int64 ScaledValue;
302 if ( MaxValue > Details::MaxBitValue )
303 {
304 // We have to scale this down
305 const T Scale = T(Details::MaxBitValue)/MaxValue;
306 ScaledValue = FMath::TruncToInt(Scale * Value);
307 }
308 else
309 {
310 // We will scale up to get extra precision. But keep is a whole number preserve whole values
311 constexpr int32 Scale = Details::MaxBitValue / MaxValue;
312 ScaledValue = FMath::RoundToInt( Scale * Value );
313 }
314
315 uint32 Delta = static_cast<uint32>(ScaledValue + Details::Bias);
316
317 if (Delta > Details::MaxDelta)
318 {
319 clamp = true;
320 Delta = static_cast<int32>(Delta) > 0 ? Details::MaxDelta : 0;
321 }
322
323 Ar.SerializeInt( Delta, Details::SerIntMax );
324
325 return !clamp;
326}
327
328template<int32 MaxValue, uint32 NumBits, typename T UE_REQUIRES(std::is_floating_point_v<T> && NumBits < 32)>
329bool ReadFixedCompressedFloat(T& Value, FArchive& Ar)
330{
331 using Details = TFixedCompressedFloatDetails<MaxValue, NumBits>;
332
333 uint32 Delta;
334 Ar.SerializeInt(Delta, Details::SerIntMax);
335 T UnscaledValue = static_cast<T>( static_cast<int32>(Delta) - Details::Bias );
336
337 if constexpr (MaxValue > Details::MaxBitValue)
338 {
339 // We have to scale down, scale needs to be a float:
340 constexpr T InvScale = MaxValue / (T)Details::MaxBitValue;
341 Value = UnscaledValue * InvScale;
342 }
343 else
344 {
345 constexpr int32 Scale = Details::MaxBitValue / MaxValue;
346 constexpr T InvScale = T(1) / (T)Scale;
347
348 Value = UnscaledValue * InvScale;
349 }
350
351 return true;
352}
353
354// --------------------------------------------------------------
355// MaxValue is the max abs value to serialize. If abs value of any vector components exceeds this, the serialized value will be clamped.
356// NumBits is the total number of bits to use - this includes the sign bit!
357//
358// So passing in NumBits = 8, and MaxValue = 2^8, you will scale down to fit into 7 bits so you can leave 1 for the sign bit.
359template<int32 MaxValue, uint32 NumBits>
376
377template<int32 MaxValue, uint32 NumBits>
396// --------------------------------------------------------------
397
408USTRUCT(meta = (HasNativeMake = "/Script/Engine.KismetMathLibrary.MakeVector_NetQuantize", HasNativeBreak = "/Script/Engine.KismetMathLibrary.BreakVector_NetQuantize"))
410{
412
414
418
419 inline FVector_NetQuantize(double InX, double InY, double InZ)
420 : FVector(InX, InY, InZ)
421 {}
422
424 {
425 FVector::operator=(InVec);
426 }
427
428 bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
429 {
430 bOutSuccess = SerializePackedVector<1, 20>(*this, Ar);
431 return true;
432 }
433};
434
435template<>
437{
438 enum
439 {
442 };
443};
444
453USTRUCT(meta = (HasNativeMake = "/Script/Engine.KismetMathLibrary.MakeVector_NetQuantize10", HasNativeBreak = "/Script/Engine.KismetMathLibrary.BreakVector_NetQuantize10"))
455{
457
459
463
464 inline FVector_NetQuantize10(double InX, double InY, double InZ)
465 : FVector(InX, InY, InZ)
466 {}
467
469 {
470 FVector::operator=(InVec);
471 }
472
473 bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
474 {
475 bOutSuccess = SerializePackedVector<10, 24>(*this, Ar);
476 return true;
477 }
478};
479
480template<>
482{
483 enum
484 {
487 };
488};
489
498USTRUCT(meta = (HasNativeMake = "/Script/Engine.KismetMathLibrary.MakeVector_NetQuantize100", HasNativeBreak = "/Script/Engine.KismetMathLibrary.BreakVector_NetQuantize100"))
500{
502
504
508
509 inline FVector_NetQuantize100(double InX, double InY, double InZ)
510 : FVector(InX, InY, InZ)
511 {}
512
515
516 bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
517 {
518 bOutSuccess = SerializePackedVector<100, 30>(*this, Ar);
519 return true;
520 }
521};
522
523template<>
525{
526 enum
527 {
530 };
531};
532
539USTRUCT(meta = (HasNativeMake = "/Script/Engine.KismetMathLibrary.MakeVector_NetQuantizeNormal", HasNativeBreak = "/Script/Engine.KismetMathLibrary.BreakVector_NetQuantizeNormal"))
541{
543
545
549
550 inline FVector_NetQuantizeNormal(double InX, double InY, double InZ)
551 : FVector(InX, InY, InZ)
552 {}
553
555 {
556 FVector::operator=(InVec);
557 }
558
559 bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
560 {
561 bOutSuccess = SerializeFixedVector<1, 16>(*this, Ar);
562 return true;
563 }
564};
565
566template<>
567struct TStructOpsTypeTraits< FVector_NetQuantizeNormal > : public TStructOpsTypeTraitsBase2< FVector_NetQuantizeNormal >
568{
569 enum
570 {
573 };
574};
575
576// --------------------------------------------------------------
577
578
617template<int32 MaxNum, typename T, typename A>
619{
620 const uint32 NumBits = FMath::CeilLogTwo(MaxNum)+1;
621
622 int32 ArrayNum = 0;
623
624 // Clamp number of elements on saving side
625 if (Ar.IsSaving())
626 {
627 ArrayNum = Array.Num();
628 if (ArrayNum > MaxNum)
629 {
630 // Overflow. This is on the saving side, so the calling code is exceeding the limit and needs to be fixed.
631 bOutSuccess = false;
632 ArrayNum = MaxNum;
633 }
634 }
635
636 // Serialize num of elements
637 Ar.SerializeBits(&ArrayNum, NumBits);
638
639 // Preallocate new items on loading side
640 if (Ar.IsLoading())
641 {
642 if (ArrayNum > MaxNum)
643 {
644 // If MaxNum doesn't fully utilize all bits that are needed to send the array size we can receive a larger value.
645 bOutSuccess = false;
646 ArrayNum = MaxNum;
647 }
648 Array.Reset();
649 Array.AddDefaulted(ArrayNum);
650 }
651
652 return ArrayNum;
653}
654
655template<int32 MaxNum, typename T, typename A>
657{
658 bool bOutSuccess = true;
660
661 // Serialize each element in the array with the << operator
662 for (int32 idx=0; idx < ArrayNum && Ar.IsError() == false; ++idx)
663 {
664 Ar << Array[idx];
665 }
666
667 // Return
668 bOutSuccess &= !Ar.IsError();
669 return bOutSuccess;
670}
671
672template<int32 MaxNum, typename T, typename A>
674{
675 bool bOutSuccess = true;
677
678 // Serialize each element in the array with the << operator
679 for (int32 idx=0; idx < ArrayNum && Ar.IsError() == false; ++idx)
680 {
681 Array[idx].NetSerialize(Ar, PackageMap, bOutSuccess);
682 }
683
684 // Return
685 bOutSuccess &= !Ar.IsError();
686 return bOutSuccess;
687}
#define check(expr)
Definition AssertionMacros.h:314
EForceInit
Definition CoreMiscDefines.h:154
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::Math::TVector< double > FVector3d
Definition MathFwd.h:60
int32 SafeNetSerializeTArray_HeaderOnly(FArchive &Ar, TArray< T, A > &Array, bool &bOutSuccess)
Definition NetSerialization.h:618
bool NetSerializeOptionalValue(const bool bIsSaving, FArchive &Ar, ValueType &Value, const ValueType &DefaultValue, class UPackageMap *PackageMap)
Definition NetSerialization.h:52
bool SafeNetSerializeTArray_WithNetSerialize(FArchive &Ar, TArray< T, A > &Array, class UPackageMap *PackageMap)
Definition NetSerialization.h:673
bool SafeNetSerializeTArray_Default(FArchive &Ar, TArray< T, A > &Array)
Definition NetSerialization.h:656
bool SerializeFixedVector(FVector3f &Vector, FArchive &Ar)
Definition NetSerialization.h:360
bool SerializeOptionalValue(const bool bIsSaving, FArchive &Ar, ValueType &Value, const ValueType &DefaultValue)
Definition NetSerialization.h:28
bool SerializePackedVector(FVector3f &Value, FArchive &Ar)
Definition NetSerialization.h:249
bool WritePackedVector(FVector3f Value, FArchive &Ar)
Definition NetSerialization.h:208
bool ReadPackedVector(FVector3f &Value, FArchive &Ar)
Definition NetSerialization.h:220
const bool
Definition NetworkReplayStreaming.h:178
#define USTRUCT(...)
Definition ObjectMacros.h:746
#define GENERATED_USTRUCT_BODY(...)
Definition ObjectMacros.h:767
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Archive.h:1208
virtual void SerializeInt(uint32 &Value, uint32 Max)
Definition Archive.h:1717
virtual CORE_API uint32 EngineNetVer() const
Definition Archive.cpp:1497
virtual CORE_API void UsingCustomVersion(const struct FGuid &Guid)
Definition Archive.cpp:590
UE_FORCEINLINE_HINT bool IsLoading() const
Definition Archive.h:236
UE_FORCEINLINE_HINT bool IsSaving() const
Definition Archive.h:248
virtual void SerializeBits(void *V, int64 LengthBits)
Definition Archive.h:1707
UE_FORCEINLINE_HINT bool IsError() const
Definition Archive.h:362
Definition Array.h:670
Definition CoreNet.h:191
constexpr int32 MaxValue
Definition LandscapeDataAccess.h:26
bool NetDeltaSerialize(FNetDeltaSerializeInfo &DeltaParms, void *Data)
Definition Class.h:1314
Definition NetworkVersion.cpp:28
bool ReadQuantizedVector(const int32 Scale, T &Value, FArchive &Ar)
Definition QuantizedVectorSerialization.cpp:111
bool WriteQuantizedVector(const int32 Scale, const T &Value, FArchive &Ar)
Definition QuantizedVectorSerialization.cpp:38
bool LegacyReadPackedVector(FVector3f &Value, FArchive &Ar)
Definition NetSerialization.h:179
@ Max
Definition EscalationStates.h:607
CORE_API static const FGuid Guid
Definition EngineNetworkCustomVersion.h:106
@ Ver21AndViewPitchOnly_DONOTUSE
Definition EngineNetworkCustomVersion.h:81
@ PackedVectorLWCSupport
Definition EngineNetworkCustomVersion.h:78
Definition CoreNet.h:643
Definition NetSerialization.h:500
bool NetSerialize(FArchive &Ar, class UPackageMap *Map, bool &bOutSuccess)
Definition NetSerialization.h:516
FVector_NetQuantize100(const FVector3f &InVec)
Definition NetSerialization.h:513
FVector_NetQuantize100(double InX, double InY, double InZ)
Definition NetSerialization.h:509
FVector_NetQuantize100(const FVector3d &InVec)
Definition NetSerialization.h:514
Definition NetSerialization.h:455
FVector_NetQuantize10(double InX, double InY, double InZ)
Definition NetSerialization.h:464
FVector_NetQuantize10(const FVector &InVec)
Definition NetSerialization.h:468
bool NetSerialize(FArchive &Ar, class UPackageMap *Map, bool &bOutSuccess)
Definition NetSerialization.h:473
Definition NetSerialization.h:541
FVector_NetQuantizeNormal(const FVector &InVec)
Definition NetSerialization.h:554
bool NetSerialize(FArchive &Ar, class UPackageMap *Map, bool &bOutSuccess)
Definition NetSerialization.h:559
FVector_NetQuantizeNormal(double InX, double InY, double InZ)
Definition NetSerialization.h:550
Definition NetSerialization.h:410
bool NetSerialize(FArchive &Ar, class UPackageMap *Map, bool &bOutSuccess)
Definition NetSerialization.h:428
FVector_NetQuantize(double InX, double InY, double InZ)
Definition NetSerialization.h:419
FVector_NetQuantize(const FVector &InVec)
Definition NetSerialization.h:423
Definition NetSerialization.h:287
static constexpr int32 Bias
Definition NetSerialization.h:290
static constexpr int32 SerIntMax
Definition NetSerialization.h:291
static constexpr int32 MaxBitValue
Definition NetSerialization.h:289
static constexpr int32 MaxDelta
Definition NetSerialization.h:292
Definition StructOpsTypeTraits.h:11
@ WithNetSharedSerialization
Definition StructOpsTypeTraits.h:31
@ WithNetSerializer
Definition StructOpsTypeTraits.h:26
@ WithNetDeltaSerializer
Definition StructOpsTypeTraits.h:27
Definition StructOpsTypeTraits.h:46