bool FMinimalReplicationTagCountMap::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { const int32 CountBits = UAbilitySystemGlobals::Get().MinimalReplicationTagCountBits; const int32 MaxCount = ((1 << CountBits)-1); if (Ar.IsSaving()) { int32 Count = TagMap.Num(); if (Count > MaxCount) { ABILITY_LOG(Error, TEXT("FMinimapReplicationTagCountMap has too many tags (%d). This will cause tags to not replicate. See FMinimapReplicationTagCountMap::NetSerialize"), TagMap.Num()); Count = MaxCount; } Ar.SerializeBits(&Count, CountBits); for(auto& It : TagMap) { FGameplayTag& Tag = It.Key; Tag.NetSerialize(Ar, Map, bOutSuccess); if (--Count <= 0) { break; } } } else { int32 Count = TagMap.Num(); Ar.SerializeBits(&Count, CountBits); // Reset our local map for(auto& It : TagMap) { It.Value = 0; } // See what we have while(Count-- > 0) { FGameplayTag Tag; Tag.NetSerialize(Ar, Map, bOutSuccess); TagMap.FindOrAdd(Tag) = 1; } if (Owner) { // Update our tags with owner tags for(auto& It : TagMap) { Owner->SetTagMapCount(It.Key, It.Value); } } } bOutSuccess = true; return true; }
bool FGameplayTag::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { SCOPE_CYCLE_COUNTER(STAT_FGameplayTag_NetSerialize); UGameplayTagsManager& TagManager = IGameplayTagsModule::GetGameplayTagsManager(); uint8 bHasName = (TagName != NAME_None); uint8 bHasNetIndex = 0; FGameplayTagNetIndex NetIndex = INVALID_TAGNETINDEX; if (Ar.IsSaving()) { NetIndex = TagManager.GetNetIndexFromTag(*this); if (NetIndex != INVALID_TAGNETINDEX) { // If we have a valid net index, serialize with that bHasNetIndex = true; } } // Serialize if we have a name at all or are empty Ar.SerializeBits(&bHasName, 1); if (bHasName) { Ar.SerializeBits(&bHasNetIndex, 1); // If we have a net index serialize that, otherwise serialize as a name if (bHasNetIndex) { Ar << NetIndex; } else { Ar << TagName; } if (Ar.IsLoading() && bHasNetIndex) { TagName = TagManager.GetTagNameFromNetIndex(NetIndex); } } else { TagName = NAME_None; } bOutSuccess = true; return true; }
bool UPackageMap::SerializeName(FArchive& Ar, FName& Name) { if (Ar.IsLoading()) { uint8 bHardcoded = 0; Ar.SerializeBits(&bHardcoded, 1); if (bHardcoded) { // replicated by hardcoded index uint32 NameIndex; Ar.SerializeInt(NameIndex, MAX_NETWORKED_HARDCODED_NAME + 1); Name = EName(NameIndex); // hardcoded names never have a Number } else { // replicated by string FString InString; int32 InNumber; Ar << InString << InNumber; Name = FName(*InString, InNumber); } } else if (Ar.IsSaving()) { uint8 bHardcoded = Name.GetIndex() <= MAX_NETWORKED_HARDCODED_NAME; Ar.SerializeBits(&bHardcoded, 1); if (bHardcoded) { // send by hardcoded index checkSlow(Name.GetNumber() <= 0); // hardcoded names should never have a Number uint32 NameIndex = uint32(Name.GetIndex()); Ar.SerializeInt(NameIndex, MAX_NETWORKED_HARDCODED_NAME + 1); } else { // send by string FString OutString = Name.GetPlainNameString(); int32 OutNumber = Name.GetNumber(); Ar << OutString << OutNumber; } } return true; }
bool FPredictionKey::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { // Read bit for server initiated first uint8 ServerInitiatedByte = bIsServerInitiated; Ar.SerializeBits(&ServerInitiatedByte, 1); bIsServerInitiated = ServerInitiatedByte & 1; if (Ar.IsLoading()) { Ar << Current; if (Current > 0) { Ar << Base; } if (!bIsServerInitiated) { PredictiveConnection = Map; } } else { /** * Only serialize the payload if we have no owning connection (Client sending to server) * or if the owning connection is this connection (Server only sends the prediction key to the client who gave it to us) * or if this is a server initiated key (valid on all connections) */ if (PredictiveConnection == nullptr || (Map == PredictiveConnection) || bIsServerInitiated) { Ar << Current; if (Current > 0) { Ar << Base; } } else { int16 Payload = 0; Ar << Payload; } } bOutSuccess = true; return true; }
bool FGameplayEffectContextHandle::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { bool ValidData = Data.IsValid(); Ar.SerializeBits(&ValidData,1); if (ValidData) { if (Ar.IsLoading()) { // For now, just always reset/reallocate the data when loading. // Longer term if we want to generalize this and use it for property replication, we should support // only reallocating when necessary if (Data.IsValid() == false) { Data = TSharedPtr<FGameplayEffectContext>(UAbilitySystemGlobals::Get().AllocGameplayEffectContext()); } } void* ContainerPtr = Data.Get(); UScriptStruct* ScriptStruct = Data->GetScriptStruct(); if (ScriptStruct->StructFlags & STRUCT_NetSerializeNative) { ScriptStruct->GetCppStructOps()->NetSerialize(Ar, Map, bOutSuccess, Data.Get()); } else { // This won't work since UStructProperty::NetSerializeItem is deprecrated. // 1) we have to manually crawl through the topmost struct's fields since we don't have a UStructProperty for it (just the UScriptProperty) // 2) if there are any UStructProperties in the topmost struct's fields, we will assert in UStructProperty::NetSerializeItem. ABILITY_LOG(Fatal, TEXT("FGameplayEffectContextHandle::NetSerialize called on data struct %s without a native NetSerialize"), *ScriptStruct->GetName()); } } bOutSuccess = true; return true; }
bool UByteProperty::NetSerializeItem( FArchive& Ar, UPackageMap* Map, void* Data, TArray<uint8> * MetaData ) const { // -1 because the last item in the enum is the autogenerated _MAX item Ar.SerializeBits( Data, Enum ? FMath::CeilLogTwo(Enum->NumEnums() - 1) : 8 ); return 1; }
bool UByteProperty::NetSerializeItem( FArchive& Ar, UPackageMap* Map, void* Data, TArray<uint8> * MetaData ) const { Ar.SerializeBits( Data, Enum ? FMath::CeilLogTwo(Enum->GetMaxEnumValue()) : 8 ); return 1; }
bool FGameplayEffectContext::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { uint8 RepBits = 0; if (Ar.IsSaving()) { if (Instigator.IsValid() ) { RepBits |= 1 << 0; } if (EffectCauser.IsValid() ) { RepBits |= 1 << 1; } if (SourceObject.IsValid() ) { RepBits |= 1 << 2; } if (Actors.Num() > 0) { RepBits |= 1 << 3; } if (HitResult.IsValid()) { RepBits |= 1 << 4; } if (bHasWorldOrigin) { RepBits |= 1 << 5; } } Ar.SerializeBits(&RepBits, 6); if (RepBits & (1 << 0)) { Ar << Instigator; } if (RepBits & (1 << 1)) { Ar << EffectCauser; } if (RepBits & (1 << 2)) { Ar << SourceObject; } if (RepBits & (1 << 3)) { Ar << Actors;; } if (RepBits & (1 << 4)) { if (Ar.IsLoading()) { if (!HitResult.IsValid()) { HitResult = TSharedPtr<FHitResult>(new FHitResult()); } } HitResult->NetSerialize(Ar, Map, bOutSuccess); } if (RepBits & (1 << 5)) { Ar << WorldOrigin; bHasWorldOrigin = true; } else { bHasWorldOrigin = false; } if (Ar.IsLoading()) { AddInstigator(Instigator.Get(), EffectCauser.Get()); // Just to initialize InstigatorAbilitySystemComponent } bOutSuccess = true; return true; }
bool FGameplayCueParameters::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { static const uint8 NUM_LEVEL_BITS = 4; static const uint8 MAX_LEVEL = (1 << NUM_LEVEL_BITS) - 1; enum RepFlag { REP_NormalizedMagnitude = 0, REP_RawMagnitude, REP_EffectContext, REP_Location, REP_Normal, REP_Instigator, REP_EffectCauser, REP_SourceObject, REP_TargetAttachComponent, REP_PhysMaterial, REP_GELevel, REP_AbilityLevel, REP_MAX }; uint16 RepBits = 0; if (Ar.IsSaving()) { if (NormalizedMagnitude != 0.f) { RepBits |= (1 << REP_NormalizedMagnitude); } if (RawMagnitude != 0.f) { RepBits |= (1 << REP_RawMagnitude); } if (EffectContext.IsValid()) { RepBits |= (1 << REP_EffectContext); } if (Location.IsNearlyZero() == false) { RepBits |= (1 << REP_Location); } if (Normal.IsNearlyZero() == false) { RepBits |= (1 << REP_Normal); } if (Instigator.IsValid()) { RepBits |= (1 << REP_Instigator); } if (EffectCauser.IsValid()) { RepBits |= (1 << REP_EffectCauser); } if (SourceObject.IsValid()) { RepBits |= (1 << REP_SourceObject); } if (TargetAttachComponent.IsValid()) { RepBits |= (1 << REP_TargetAttachComponent); } if (PhysicalMaterial.IsValid()) { RepBits |= (1 << REP_PhysMaterial); } if (GameplayEffectLevel != 1) { RepBits |= (1 << REP_GELevel); } if (AbilityLevel != 1) { RepBits |= (1 << REP_AbilityLevel); } } Ar.SerializeBits(&RepBits, REP_MAX); // Tag containers serialize empty containers with 1 bit, so no need to serialize this in the RepBits field. AggregatedSourceTags.NetSerialize(Ar, Map, bOutSuccess); AggregatedTargetTags.NetSerialize(Ar, Map, bOutSuccess); if (RepBits & (1 << REP_NormalizedMagnitude)) { Ar << NormalizedMagnitude; } if (RepBits & (1 << REP_RawMagnitude)) { Ar << RawMagnitude; } if (RepBits & (1 << REP_EffectContext)) { EffectContext.NetSerialize(Ar, Map, bOutSuccess); } if (RepBits & (1 << REP_Location)) { Location.NetSerialize(Ar, Map, bOutSuccess); } if (RepBits & (1 << REP_Normal)) { Normal.NetSerialize(Ar, Map, bOutSuccess); } if (RepBits & (1 << REP_Instigator)) { Ar << Instigator; } if (RepBits & (1 << REP_EffectCauser)) { Ar << EffectCauser; } if (RepBits & (1 << REP_SourceObject)) { Ar << SourceObject; } if (RepBits & (1 << REP_TargetAttachComponent)) { Ar << TargetAttachComponent; } if (RepBits & (1 << REP_PhysMaterial)) { Ar << PhysicalMaterial; } if (RepBits & (1 << REP_GELevel)) { ensureMsgf(GameplayEffectLevel <= MAX_LEVEL, TEXT("FGameplayCueParameters::NetSerialize trying to serialize GC parameters with a GameplayEffectLevel of %d"), GameplayEffectLevel); if (Ar.IsLoading()) { GameplayEffectLevel = 0; } Ar.SerializeBits(&GameplayEffectLevel, NUM_LEVEL_BITS); } if (RepBits & (1 << REP_AbilityLevel)) { ensureMsgf(AbilityLevel <= MAX_LEVEL, TEXT("FGameplayCueParameters::NetSerialize trying to serialize GC parameters with an AbilityLevel of %d"), AbilityLevel); if (Ar.IsLoading()) { AbilityLevel = 0; } Ar.SerializeBits(&AbilityLevel, NUM_LEVEL_BITS); } bOutSuccess = true; return true; }
bool FHitResult::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { // Most of the time the vectors are the same values, use that as an optimization bool bImpactPointEqualsLocation = 0, bImpactNormalEqualsNormal = 0; if (Ar.IsSaving()) { bImpactPointEqualsLocation = (ImpactPoint == Location); bImpactNormalEqualsNormal = (ImpactNormal == Normal); } // pack bitfield with flags uint8 Flags = (bBlockingHit << 0) | (bStartPenetrating << 1) | (bImpactPointEqualsLocation << 2) | (bImpactNormalEqualsNormal << 3); Ar.SerializeBits(&Flags, 4); bBlockingHit = (Flags & (1 << 0)) ? 1 : 0; bStartPenetrating = (Flags & (1 << 1)) ? 1 : 0; bImpactPointEqualsLocation = (Flags & (1 << 2)) ? 1 : 0; bImpactNormalEqualsNormal = (Flags & (1 << 3)) ? 1 : 0; Ar << Time; bOutSuccess = true; bool bOutSuccessLocal = true; Location.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; Normal.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; if (!bImpactPointEqualsLocation) { ImpactPoint.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; } else if (Ar.IsLoading()) { ImpactPoint = Location; } if (!bImpactNormalEqualsNormal) { ImpactNormal.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; } else if (Ar.IsLoading()) { ImpactNormal = Normal; } TraceStart.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; TraceEnd.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; Ar << PenetrationDepth; Ar << Item; Ar << PhysMaterial; Ar << Actor; // Skipping component on purpose Ar << BoneName; Ar << FaceIndex; return true; }
bool FHitResult::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { // Most of the time the vectors are the same values, use that as an optimization bool bImpactPointEqualsLocation = 0, bImpactNormalEqualsNormal = 0; // Often times the indexes are invalid, use that as an optimization bool bInvalidItem = 0, bInvalidFaceIndex = 0, bNoPenetrationDepth = 0; if (Ar.IsSaving()) { bImpactPointEqualsLocation = (ImpactPoint == Location); bImpactNormalEqualsNormal = (ImpactNormal == Normal); bInvalidItem = (Item == INDEX_NONE); bInvalidFaceIndex = (FaceIndex == INDEX_NONE); bNoPenetrationDepth = (PenetrationDepth == 0.0f); } // pack bitfield with flags uint8 Flags = (bBlockingHit << 0) | (bStartPenetrating << 1) | (bImpactPointEqualsLocation << 2) | (bImpactNormalEqualsNormal << 3) | (bInvalidItem << 4) | (bInvalidFaceIndex << 5) | (bInvalidFaceIndex << 6); Ar.SerializeBits(&Flags, 7); bBlockingHit = (Flags & (1 << 0)) ? 1 : 0; bStartPenetrating = (Flags & (1 << 1)) ? 1 : 0; bImpactPointEqualsLocation = (Flags & (1 << 2)) ? 1 : 0; bImpactNormalEqualsNormal = (Flags & (1 << 3)) ? 1 : 0; bInvalidItem = (Flags & (1 << 4)) ? 1 : 0; bInvalidFaceIndex = (Flags & (1 << 5)) ? 1 : 0; bNoPenetrationDepth = (Flags & (1 << 6)) ? 1 : 0; Ar << Time; bOutSuccess = true; bool bOutSuccessLocal = true; Location.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; Normal.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; if (!bImpactPointEqualsLocation) { ImpactPoint.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; } else if (Ar.IsLoading()) { ImpactPoint = Location; } if (!bImpactNormalEqualsNormal) { ImpactNormal.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; } else if (Ar.IsLoading()) { ImpactNormal = Normal; } TraceStart.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; TraceEnd.NetSerialize(Ar, Map, bOutSuccessLocal); bOutSuccess &= bOutSuccessLocal; if (!bNoPenetrationDepth) { Ar << PenetrationDepth; } else if(Ar.IsLoading()) { PenetrationDepth = 0.0f; } if (!bInvalidItem) { Ar << Item; } else if (Ar.IsLoading()) { Item = INDEX_NONE; } Ar << PhysMaterial; Ar << Actor; Ar << Component; Ar << BoneName; if (!bInvalidFaceIndex) { Ar << FaceIndex; } else if (Ar.IsLoading()) { FaceIndex = INDEX_NONE; } return true; }