void UDataTable::LoadStructData(FArchive& Ar) { UScriptStruct* LoadUsingStruct = RowStruct; if (LoadUsingStruct == NULL) { UE_LOG(LogDataTable, Error, TEXT("Missing RowStruct while loading DataTable '%s'!"), *GetPathName()); LoadUsingStruct = FTableRowBase::StaticStruct(); } int32 NumRows; Ar << NumRows; for (int32 RowIdx = 0; RowIdx < NumRows; RowIdx++) { // Load row name FName RowName; Ar << RowName; // Load row data uint8* RowData = (uint8*)FMemory::Malloc(LoadUsingStruct->PropertiesSize); LoadUsingStruct->InitializeStruct(RowData); // And be sure to call DestroyScriptStruct later LoadUsingStruct->SerializeTaggedProperties(Ar, RowData, LoadUsingStruct, NULL); // Add to map RowMap.Add(RowName, RowData); } }
FGameplayAbilityTargetDataHandle UAbilitySystemBlueprintLibrary::FilterTargetData(FGameplayAbilityTargetDataHandle TargetDataHandle, FGameplayTargetDataFilterHandle FilterHandle) { FGameplayAbilityTargetDataHandle ReturnDataHandle; for (int32 i = 0; TargetDataHandle.IsValid(i); ++i) { FGameplayAbilityTargetData* UnfilteredData = TargetDataHandle.Get(i); check(UnfilteredData); if (UnfilteredData->GetActors().Num() > 0) { TArray<TWeakObjectPtr<AActor>> FilteredActors = UnfilteredData->GetActors().FilterByPredicate(FilterHandle); if (FilteredActors.Num() > 0) { //Copy the data first, since we don't understand the internals of it UScriptStruct* ScriptStruct = UnfilteredData->GetScriptStruct(); FGameplayAbilityTargetData* NewData = (FGameplayAbilityTargetData*)FMemory::Malloc(ScriptStruct->GetCppStructOps()->GetSize()); ScriptStruct->InitializeStruct(NewData); ScriptStruct->CopyScriptStruct(NewData, UnfilteredData); ReturnDataHandle.Data.Add(TSharedPtr<FGameplayAbilityTargetData>(NewData)); if (FilteredActors.Num() < UnfilteredData->GetActors().Num()) { //We have lost some, but not all, of our actors, so replace the array. This should only be possible with targeting types that permit actor-array setting. if (!NewData->SetActors(FilteredActors)) { //This is an error, though we could ignore it. We somehow filtered out part of a list, but the class doesn't support changing the list, so now it's all or nothing. check(false); } } } } } return ReturnDataHandle; }
bool FGameplayEffectContextHandle::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { UScriptStruct* ScriptStruct = Data.IsValid() ? Data->GetScriptStruct() : NULL; Ar << ScriptStruct; if (ScriptStruct) { 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 check(!Data.IsValid()); FGameplayEffectContext * NewData = (FGameplayEffectContext*)FMemory::Malloc(ScriptStruct->GetCppStructOps()->GetSize()); ScriptStruct->InitializeStruct(NewData); Data = TSharedPtr<FGameplayEffectContext>(NewData); } void* ContainerPtr = Data.Get(); 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()); for (TFieldIterator<UProperty> It(ScriptStruct); It; ++It) { if (It->PropertyFlags & CPF_RepSkip) { continue; } void * PropertyData = It->ContainerPtrToValuePtr<void*>(ContainerPtr); It->NetSerializeItem(Ar, Map, PropertyData); } } } bOutSuccess = true; return true; }
bool FGameplayAbilityTargetDataHandle::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { uint8 DataNum; if (Ar.IsSaving()) { UE_CLOG(Data.Num() > MAX_uint8, LogAbilitySystem, Warning, TEXT("Too many TargetData sources (%d!) to net serialize. Clamping to %d"), Data.Num(), MAX_uint8); DataNum = FMath::Min<int32>( Data.Num(), MAX_uint8 ); } Ar << DataNum; if (Ar.IsLoading()) { Data.SetNumZeroed(DataNum); } for (int32 i = 0; i < DataNum && !Ar.IsError(); ++i) { UScriptStruct* ScriptStruct = Data[i].IsValid() ? Data[i]->GetScriptStruct() : NULL; Ar << ScriptStruct; if (ScriptStruct) { 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 check(!Data[i].IsValid()); FGameplayAbilityTargetData * NewData = (FGameplayAbilityTargetData*)FMemory::Malloc(ScriptStruct->GetCppStructOps()->GetSize()); ScriptStruct->InitializeStruct(NewData); Data[i] = TSharedPtr<FGameplayAbilityTargetData>(NewData); } void* ContainerPtr = Data[i].Get(); if (ScriptStruct->StructFlags & STRUCT_NetSerializeNative) { ScriptStruct->GetCppStructOps()->NetSerialize(Ar, Map, bOutSuccess, Data[i].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("FGameplayAbilityTargetDataHandle::NetSerialize called on data struct %s without a native NetSerialize"), *ScriptStruct->GetName()); for (TFieldIterator<UProperty> It(ScriptStruct); It; ++It) { if (It->PropertyFlags & CPF_RepSkip) { continue; } void* PropertyData = It->ContainerPtrToValuePtr<void*>(ContainerPtr); It->NetSerializeItem(Ar, Map, PropertyData); } } } } //ABILITY_LOG(Warning, TEXT("FGameplayAbilityTargetDataHandle Serialized: %s"), ScriptStruct ? *ScriptStruct->GetName() : TEXT("NULL") ); bOutSuccess = true; return true; }