Function bodies 468 total
ExecuteMigrationPipeline method · cpp · L21-L64 (44 LOC)Source/VaultCore/Private/Migration/VaultMigrationUtility.cpp
bool UVaultMigrationUtility::ExecuteMigrationPipeline(
const FString& RawPayload,
int32 LoadedVersion,
FString& OutPayload)
{
const UVaultSettings* Settings = UVaultSettings::Get();
if (!Settings)
{
UE_LOG(LogVault, Error, TEXT("Migration: UVaultSettings not available"));
OutPayload = RawPayload;
return false;
}
const int32 TargetVersion = Settings->CurrentGameSchemaVersion;
if (LoadedVersion >= TargetVersion)
{
// Already current — no migration needed
OutPayload = RawPayload;
return true;
}
UE_LOG(LogVault, Display, TEXT("Migration: Upgrading payload from V%d to V%d"),
LoadedVersion, TargetVersion);
FString WorkingPayload = RawPayload;
// Apply migrations sequentially: V1→V2→V3→...
for (int32 Version = LoadedVersion; Version < TargetVersion; ++Version)
{
if (!ApplyMigration(Version, WorkingPayload))
{
UE_LOG(LogVault, Error, TEXT("Migration: Failed at V%d→V%d"), Version, Version + 1);
OutPayload = RawPayload; // Return original on failure NeedsMigration method · cpp · L80-L85 (6 LOC)Source/VaultCore/Private/Migration/VaultMigrationUtility.cpp
bool UVaultMigrationUtility::NeedsMigration(int32 LoadedVersion) const
{
const UVaultSettings* Settings = UVaultSettings::Get();
return Settings && LoadedVersion < Settings->CurrentGameSchemaVersion;
}ApplyMigration method · cpp · L86-L111 (26 LOC)Source/VaultCore/Private/Migration/VaultMigrationUtility.cpp
bool UVaultMigrationUtility::ApplyMigration(int32 FromVersion, FString& InOutPayload)
{
const TFunction<FString(const FString&)>* MigrationFunc = MigrationRegistry.Find(FromVersion);
if (!MigrationFunc || !(*MigrationFunc))
{
UE_LOG(LogVault, Warning,
TEXT("Migration: No migration registered for V%d→V%d — passing through unchanged"),
FromVersion, FromVersion + 1);
// No registered migration = identity transform (data format compatible)
return true;
}
const FString Result = (*MigrationFunc)(InOutPayload);
if (Result.IsEmpty())
{
UE_LOG(LogVault, Error,
TEXT("Migration: V%d→V%d returned empty payload"), FromVersion, FromVersion + 1);
return false;
}
InOutPayload = Result;
return true;
}TriggerPostMigrationSave method · cpp · L112-L140 (29 LOC)Source/VaultCore/Private/Migration/VaultMigrationUtility.cpp
void UVaultMigrationUtility::TriggerPostMigrationSave(
const FString& ProfileID, const FString& MigratedPayload, UObject* WorldContextObject)
{
if (!IsValid(WorldContextObject)) return;
UWorld* World = WorldContextObject->GetWorld();
if (!World) return;
UGameInstance* GI = World->GetGameInstance();
UVaultStorageManager* SM = GI ? GI->GetSubsystem<UVaultStorageManager>() : nullptr;
if (SM == nullptr) return;
TScriptInterface<IInventoryStorageProvider> Provider = SM->GetActiveProvider();
if (!Provider.GetObject()) return;
const UVaultSettings* Settings = UVaultSettings::Get();
FVaultStoragePayload Payload;
Payload.ProfileID = ProfileID;
Payload.SchemaVersion = Settings ? Settings->CurrentGameSchemaVersion : 1;
Payload.LockVersion = 0;
Payload.InventoryJSON = MigratedPayload;
FOnStorageSaveComplete OnComplete;
Provider->AsyncSave(Payload, OnComplete);
UE_LOG(LogVault, Display, TEXT("Migration: Triggered post-migration save for ProfileID=%s"), *ProfileID);
}BP_RegisterMigration method · cpp · L141-L157 (17 LOC)Source/VaultCore/Private/Migration/VaultMigrationUtility.cpp
void UVaultMigrationUtility::BP_RegisterMigration(
int32 FromVersion, FBlueprintMigrationDelegate MigrationDelegate)
{
if (!MigrationDelegate.IsBound())
{
UE_LOG(LogVault, Warning,
TEXT("BP_RegisterMigration: Delegate not bound for V%d — registration skipped."),
FromVersion);
return;
}
RegisterMigration(FromVersion, [MigrationDelegate](const FString& RawPayload) -> FString
{
return MigrationDelegate.Execute(RawPayload);
});
}PreReplicatedRemove method · cpp · L12-L25 (14 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
void FInventoryArray::PreReplicatedRemove(const TArrayView<int32> RemovedIndices, int32 FinalSize)
{
if (UInventoryManagerComponent* Comp = OwningComponent.Get())
{
for (int32 Index : RemovedIndices)
{
if (Entries.IsValidIndex(Index))
{
Comp->NotifyItemRemoved(Entries[Index].InstanceID);
}
}
}
}PostReplicatedAdd method · cpp · L26-L66 (41 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
void FInventoryArray::PostReplicatedAdd(const TArrayView<int32> AddedIndices, int32 FinalSize)
{
// Resolve ItemDefTag → ItemDef for newly replicated entries (client-side)
// ItemDef is NotReplicated — clients resolve from their local registry
UItemDefinitionRegistry* Registry = nullptr;
if (UInventoryManagerComponent* Comp = OwningComponent.Get())
{
if (UWorld* World = Comp->GetWorld())
{
if (UGameInstance* GI = World->GetGameInstance())
{
Registry = GI->GetSubsystem<UItemDefinitionRegistry>();
}
}
for (int32 Index : AddedIndices)
{
if (Entries.IsValidIndex(Index))
{
FInventoryEntry& Entry = Entries[Index];
// Client-side tag resolution: ItemDef is NotReplicated, resolve from tag
if (!IsValid(Entry.ItemDef.Get()) && Entry.ItemDefTag.IsValid() && Registry)
{
Entry.ItemDef = const_cast<UItemDefinition*>(
Registry->ResolveDefinition(Entry.ItemDefTag));
if (!IsValid(Entry.ItemDef.Get()))
{
UE_LOG(LogVaultNetwRepobility — same analyzer, your code, free for public repos · /scan/
PostReplicatedChange method · cpp · L67-L98 (32 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
void FInventoryArray::PostReplicatedChange(const TArrayView<int32> ChangedIndices, int32 FinalSize)
{
if (UInventoryManagerComponent* Comp = OwningComponent.Get())
{
// Resolve ItemDef if it's null (can happen after tag-based replication)
UItemDefinitionRegistry* Registry = nullptr;
if (UWorld* World = Comp->GetWorld())
{
if (UGameInstance* GI = World->GetGameInstance())
{
Registry = GI->GetSubsystem<UItemDefinitionRegistry>();
}
}
for (int32 Index : ChangedIndices)
{
if (Entries.IsValidIndex(Index))
{
FInventoryEntry& Entry = Entries[Index];
if (!IsValid(Entry.ItemDef.Get()) && Entry.ItemDefTag.IsValid() && Registry)
{
Entry.ItemDef = const_cast<UItemDefinition*>(
Registry->ResolveDefinition(Entry.ItemDefTag));
}
Comp->NotifyItemChanged(Entry);
}
}
}
}AddEntry method · cpp · L101-L110 (10 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
int32 FInventoryArray::AddEntry(FInventoryEntry&& NewEntry)
{
int32 NewIndex = Entries.Add(MoveTemp(NewEntry));
// Structural change — must dirty the entire array so replication picks up the new entry
MarkArrayDirty();
UE_LOG(LogVaultNetwork, Verbose, TEXT("AddEntry: Index=%d, InstanceID=%s"),
NewIndex, *Entries[NewIndex].InstanceID.ToString());
return NewIndex;
}RemoveEntry method · cpp · L111-L127 (17 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
void FInventoryArray::RemoveEntry(int32 Index)
{
if (!Entries.IsValidIndex(Index))
{
UE_LOG(LogVaultNetwork, Warning, TEXT("RemoveEntry: Invalid index %d (Entries.Num=%d)"),
Index, Entries.Num());
return;
}
UE_LOG(LogVaultNetwork, Verbose, TEXT("RemoveEntry: Index=%d, InstanceID=%s"),
Index, *Entries[Index].InstanceID.ToString());
// RemoveAtSwap is O(1) and Iris-friendly — does not trigger full-array re-replication
Entries.RemoveAtSwap(Index);
MarkArrayDirty();
}FindByInstanceID method · cpp · L128-L135 (8 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
FInventoryEntry* FInventoryArray::FindByInstanceID(const FGuid& InstanceID)
{
return Entries.FindByPredicate([&InstanceID](const FInventoryEntry& Entry)
{
return Entry.InstanceID == InstanceID;
});
}FindByInstanceID method · cpp · L136-L143 (8 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
const FInventoryEntry* FInventoryArray::FindByInstanceID(const FGuid& InstanceID) const
{
return Entries.FindByPredicate([&InstanceID](const FInventoryEntry& Entry)
{
return Entry.InstanceID == InstanceID;
});
}FindIndexByInstanceID method · cpp · L144-L151 (8 LOC)Source/VaultCore/Private/Network/InventoryArray.cpp
int32 FInventoryArray::FindIndexByInstanceID(const FGuid& InstanceID) const
{
return Entries.IndexOfByPredicate([&InstanceID](const FInventoryEntry& Entry)
{
return Entry.InstanceID == InstanceID;
});
}PostInitProperties method · cpp · L13-L45 (33 LOC)Source/VaultCore/Private/Settings/VaultSettings.cpp
void UVaultSettings::PostInitProperties()
{
Super::PostInitProperties();
// Auto-load secrets from environment variables.
// Transient fields start empty — env vars populate them at startup.
// Command-line args take precedence over env vars.
auto LoadSecret = [](FString& OutValue, const TCHAR* EnvVarName, const TCHAR* FieldName)
{
if (!OutValue.IsEmpty()) return; // Already set (e.g., editor manual input)
FString Value = FPlatformMisc::GetEnvironmentVariable(EnvVarName);
if (!Value.IsEmpty())
{
OutValue = Value;
UE_LOG(LogVaultSettings, Display, TEXT("Loaded %s from env var %s"), FieldName, EnvVarName);
}
};
LoadSecret(SupabaseSecretKey, TEXT("VAULT_SUPABASE_KEY"), TEXT("SupabaseSecretKey"));
LoadSecret(AWSApiGatewayKey, TEXT("VAULT_AWS_API_KEY"), TEXT("AWSApiGatewayKey"));
LoadSecret(RemoteEconomyConfigAuthToken, TEXT("VAULT_ECONOMY_TOKEN"), TEXT("RemoteEconomyConfigAuthToken"));
LoadSecret(EconomyConfigSigningKey, TEXT("VAULT_ECONOMY_SIGNING_KEY"), TEXGet method · cpp · L46-L50 (5 LOC)Source/VaultCore/Private/Settings/VaultSettings.cpp
const UVaultSettings* UVaultSettings::Get()
{
return GetDefault<UVaultSettings>();
}Repobility analyzer · published findings · https://repobility.com
AsyncLoad method · cpp · L5-L33 (29 LOC)Source/VaultCore/Private/Storage/NullStorageProvider.cpp
void UNullStorageProvider::AsyncLoad(const FString& ProfileID, FOnStorageLoadComplete OnComplete)
{
const double Start = FPlatformTime::Seconds();
FVaultStoragePayload Payload;
bool bSuccess = true;
if (const FVaultStoragePayload* Found = InMemoryStore.Find(ProfileID))
{
Payload = *Found;
}
else
{
// Empty load — valid, just means new player
Payload.ProfileID = ProfileID;
}
LastMetrics.LatencyMs = (FPlatformTime::Seconds() - Start) * 1000.0;
LastMetrics.PayloadSizeBytes = Payload.InventoryJSON.Len() + Payload.WalletJSON.Len();
LastMetrics.bSuccess = bSuccess;
LastMetrics.ErrorMessage.Empty();
LastMetrics.HttpStatusCode = 0;
UE_LOG(LogVaultStorage, Verbose, TEXT("NullProvider::AsyncLoad: ProfileID=%s, Found=%s"),
*ProfileID, InMemoryStore.Contains(ProfileID) ? TEXT("true") : TEXT("false"));
OnComplete.ExecuteIfBound(bSuccess, Payload);
}AsyncSave method · cpp · L34-L70 (37 LOC)Source/VaultCore/Private/Storage/NullStorageProvider.cpp
void UNullStorageProvider::AsyncSave(const FVaultStoragePayload& Payload, FOnStorageSaveComplete OnComplete)
{
const double Start = FPlatformTime::Seconds();
bool bSuccess = true;
FString ErrorMessage;
// OCC check: if we have an existing record, verify LockVersion
if (const FVaultStoragePayload* Existing = InMemoryStore.Find(Payload.ProfileID))
{
if (Payload.LockVersion != Existing->LockVersion)
{
bSuccess = false;
ErrorMessage = FString::Printf(
TEXT("OCC conflict: expected LockVersion=%d, got=%d"),
Existing->LockVersion, Payload.LockVersion);
UE_LOG(LogVaultStorage, Warning, TEXT("NullProvider::AsyncSave: %s"), *ErrorMessage);
}
}
if (bSuccess)
{
FVaultStoragePayload SavedPayload = Payload;
SavedPayload.LockVersion++; // Increment on successful save
SavedPayload.LastSyncedUTC = FDateTime::UtcNow().ToIso8601();
InMemoryStore.Add(Payload.ProfileID, SavedPayload);
}
LastMetrics.LatencyMs = (FPlatformTime::Seconds() - Start) * 1000.0;
LastAsyncDelete method · cpp · L71-L79 (9 LOC)Source/VaultCore/Private/Storage/NullStorageProvider.cpp
void UNullStorageProvider::AsyncDelete(const FString& ProfileID, FOnStorageSaveComplete OnComplete)
{
InMemoryStore.Remove(ProfileID);
UE_LOG(LogVaultStorage, Verbose, TEXT("NullProvider::AsyncDelete: ProfileID=%s"), *ProfileID);
OnComplete.ExecuteIfBound(true, TEXT(""));
}GetLastOperationMetrics method · cpp · L80-L84 (5 LOC)Source/VaultCore/Private/Storage/NullStorageProvider.cpp
FStorageOperationMetrics UNullStorageProvider::GetLastOperationMetrics() const
{
return LastMetrics;
}SerializeInventory function · cpp · L16-L87 (72 LOC)Source/VaultCore/Private/Storage/VaultSerializationHelpers.cpp
FString SerializeInventory(const FInventoryArray& Inventory, const FWalletContainer& Wallet)
{
// Use UE's JSON object converter for USTRUCT serialization.
// This handles UPROPERTY reflection automatically.
// For production, this should use FObjectAndNameAsStringProxyArchive
// to convert hard object refs to string names.
TSharedRef<FJsonObject> Root = MakeShareable(new FJsonObject());
// Serialize entries as JSON array
TArray<TSharedPtr<FJsonValue>> EntriesArray;
for (const FInventoryEntry& Entry : Inventory.Entries)
{
TSharedPtr<FJsonObject> EntryObj = MakeShareable(new FJsonObject());
EntryObj->SetStringField(TEXT("InstanceID"), Entry.InstanceID.ToString());
EntryObj->SetNumberField(TEXT("StackCount"), Entry.StackCount);
EntryObj->SetStringField(TEXT("BindingPolicy"), Entry.BindingPolicy.ToString());
EntryObj->SetStringField(TEXT("BoundToOwnerID"), Entry.BoundToOwnerID);
if (Entry.HasExpiry())
{
EntryObj->SetStringField(TEXT("ExpiresAtUTC"), Entry.ExpDeserializeInventory function · cpp · L88-L240 (153 LOC)Source/VaultCore/Private/Storage/VaultSerializationHelpers.cpp
bool DeserializeInventory(const FString& JSON, FInventoryArray& OutInventory, FWalletContainer& OutWallet,
const UItemDefinitionRegistry* Registry)
{
if (JSON.IsEmpty())
{
// Empty payload = new player, valid
return true;
}
TSharedPtr<FJsonObject> Root;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JSON);
if (!FJsonSerializer::Deserialize(Reader, Root) || !Root.IsValid())
{
UE_LOG(LogVaultStorage, Error, TEXT("DeserializeInventory: Failed to parse JSON"));
return false;
}
// Deserialize entries
OutInventory.Entries.Reset();
const TArray<TSharedPtr<FJsonValue>>* EntriesArray = nullptr;
if (Root->TryGetArrayField(TEXT("Entries"), EntriesArray))
{
for (const TSharedPtr<FJsonValue>& EntryVal : *EntriesArray)
{
const TSharedPtr<FJsonObject>* EntryObj = nullptr;
if (!EntryVal->TryGetObject(EntryObj) || !EntryObj) continue;
FInventoryEntry Entry;
FString InstanceIDStr;
if ((*EntryObj)->TryGetStringField(TEXT("InstanceID"), InstaInitialize method · cpp · L13-L44 (32 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
void UVaultStorageManager::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// Default to NullStorageProvider until a concrete provider registers
UNullStorageProvider* NullProvider = NewObject<UNullStorageProvider>(this);
ActiveProvider.SetObject(NullProvider);
ActiveProvider.SetInterface(Cast<IInventoryStorageProvider>(NullProvider));
LatencyHistory.Reserve(MetricsWindowSize);
SuccessHistory.Reserve(MetricsWindowSize);
// If Local_DataTable economy config is selected and no server module overrides,
// set up the local provider directly (no HTTP needed)
const UVaultSettings* Settings = UVaultSettings::Get();
if (Settings && Settings->EconomyConfigProvider == EVaultEconomyConfigProvider::Local_DataTable)
{
ULocalEconomyConfigProvider* LocalProvider = NewObject<ULocalEconomyConfigProvider>(this);
EconomyConfigProviderObject = LocalProvider;
FOnEconomyConfigLoaded OnConfigLoaded;
OnConfigLoaded.BindUObject(this, &UVaultStorageManagRegisterStorageProvider method · cpp · L47-L60 (14 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
void UVaultStorageManager::RegisterStorageProvider(TScriptInterface<IInventoryStorageProvider> Provider)
{
if (!Provider.GetObject())
{
UE_LOG(LogVaultStorage, Warning, TEXT("RegisterStorageProvider: null provider, keeping NullStorageProvider"));
return;
}
ActiveProvider = Provider;
UE_LOG(LogVaultStorage, Display, TEXT("VaultStorageManager: Registered storage provider %s"),
*Provider.GetObject()->GetClass()->GetName());
}Repobility · severity-and-effort ranking · https://repobility.com
RegisterEconomyConfigProvider method · cpp · L61-L82 (22 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
void UVaultStorageManager::RegisterEconomyConfigProvider(UObject* ProviderObj)
{
if (!IsValid(ProviderObj))
{
UE_LOG(LogVaultEconomy, Warning, TEXT("RegisterEconomyConfigProvider: null provider"));
return;
}
EconomyConfigProviderObject = ProviderObj;
IVaultEconomyConfigProvider* Provider = Cast<IVaultEconomyConfigProvider>(ProviderObj);
if (Provider)
{
FOnEconomyConfigLoaded OnConfigLoaded;
OnConfigLoaded.BindUObject(this, &UVaultStorageManager::OnEconomyConfigLoaded);
Provider->AsyncFetchConfig(OnConfigLoaded);
UE_LOG(LogVaultEconomy, Display, TEXT("VaultStorageManager: Registered economy config provider %s"),
*ProviderObj->GetClass()->GetName());
}
}GetActiveProvider method · cpp · L85-L89 (5 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
TScriptInterface<IInventoryStorageProvider> UVaultStorageManager::GetActiveProvider() const
{
return ActiveProvider;
}GetEconomyConfigProvider method · cpp · L90-L98 (9 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
IVaultEconomyConfigProvider* UVaultStorageManager::GetEconomyConfigProvider() const
{
if (!IsValid(EconomyConfigProviderObject))
{
return nullptr;
}
return Cast<IVaultEconomyConfigProvider>(EconomyConfigProviderObject);
}GetEconomyConfig method · cpp · L99-L108 (10 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
const FVaultEconomyConfig& UVaultStorageManager::GetEconomyConfig() const
{
IVaultEconomyConfigProvider* Provider = GetEconomyConfigProvider();
if (Provider && bEconomyConfigReady)
{
return Provider->GetCachedConfig();
}
return EmptyConfig;
}OnEconomyConfigLoaded method · cpp · L109-L131 (23 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
void UVaultStorageManager::OnEconomyConfigLoaded(bool bSuccess)
{
bEconomyConfigReady = bSuccess;
if (bSuccess)
{
IVaultEconomyConfigProvider* Provider = GetEconomyConfigProvider();
if (Provider)
{
const FVaultEconomyConfig& Config = Provider->GetCachedConfig();
UE_LOG(LogVaultEconomy, Display,
TEXT("VaultStorageManager: Economy config ready (Version=%d, LootTables=%d, Recipes=%d, Params=%d)"),
Config.ConfigVersion, Config.LootTables.Num(),
Config.CraftingRecipes.Num(), Config.BalanceParameters.Num());
}
}
else
{
UE_LOG(LogVaultEconomy, Error,
TEXT("VaultStorageManager: Economy config failed to load. bEconomyConfigReady remains false."));
}
}RecordOperationMetrics method · cpp · L134-L153 (20 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
void UVaultStorageManager::RecordOperationMetrics(const FStorageOperationMetrics& Metrics)
{
TotalOperations++;
if (LatencyHistory.Num() >= MetricsWindowSize)
{
LatencyHistory.RemoveAt(0);
SuccessHistory.RemoveAt(0);
}
LatencyHistory.Add(Metrics.LatencyMs);
SuccessHistory.Add(Metrics.bSuccess);
if (!Metrics.bSuccess)
{
UE_LOG(LogVaultStorage, Warning, TEXT("Storage operation failed: %s (Latency=%.1fms)"),
*Metrics.ErrorMessage, Metrics.LatencyMs);
}
}GetLatencyP95 method · cpp · L154-L164 (11 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
float UVaultStorageManager::GetLatencyP95() const
{
if (LatencyHistory.Num() == 0) return 0.0f;
TArray<float> Sorted = LatencyHistory;
Sorted.Sort();
const int32 P95Index = FMath::FloorToInt(Sorted.Num() * 0.95f);
return Sorted.IsValidIndex(P95Index) ? Sorted[P95Index] : Sorted.Last();
}GetFailureRate method · cpp · L165-L177 (13 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
float UVaultStorageManager::GetFailureRate() const
{
if (SuccessHistory.Num() == 0) return 0.0f;
int32 Failures = 0;
for (bool bSuccess : SuccessHistory)
{
if (!bSuccess) Failures++;
}
return (static_cast<float>(Failures) / SuccessHistory.Num()) * 100.0f;
}Open data scored by Repobility · https://repobility.com
CheckStorageHealth method · cpp · L180-L196 (17 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
void UVaultStorageManager::CheckStorageHealth(bool& bOutHealthy, float& OutLatencyMs, FGameplayTag& OutErrorTag) const
{
bOutHealthy = false;
OutLatencyMs = 0.0f;
OutErrorTag = FGameplayTag();
if (!ActiveProvider.GetObject())
{
OutErrorTag = VaultTags::Validation_Error_ServerNotReady;
return;
}
// Provider exists — report as healthy with current P95 latency
bOutHealthy = true;
OutLatencyMs = GetLatencyP95();
}GetMetricsSnapshot method · cpp · L197-L204 (8 LOC)Source/VaultCore/Private/Storage/VaultStorageManager.cpp
bool UVaultStorageManager::GetMetricsSnapshot(int32& OutTotalOps, float& OutFailureRate, float& OutLatencyP95) const
{
OutTotalOps = TotalOperations;
OutFailureRate = GetFailureRate();
OutLatencyP95 = GetLatencyP95();
return true;
}CreateBasicDef function · cpp · L49-L52 (4 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
UItemDefinition* CreateBasicDef()
{
return NewObject<UItemDefinition>();
}CreateStackableDef function · cpp · L55-L63 (9 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
UItemDefinition* CreateStackableDef(int32 MaxStack = 20)
{
UItemDefinition* Def = NewObject<UItemDefinition>();
UItemFragment_Stackable* Frag = NewObject<UItemFragment_Stackable>(Def);
Frag->MaxStackSize = MaxStack;
Frag->bAllowPartialStacks = true;
Def->Fragments.Add(Frag);
return Def;
}CreateWeightedDef function · cpp · L66-L73 (8 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
UItemDefinition* CreateWeightedDef(float Weight = 2.5f)
{
UItemDefinition* Def = NewObject<UItemDefinition>();
UItemFragment_Weight* Frag = NewObject<UItemFragment_Weight>(Def);
Frag->PerItemWeight = Weight;
Def->Fragments.Add(Frag);
return Def;
}CreateStackableWeightedDef function · cpp · L76-L87 (12 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
UItemDefinition* CreateStackableWeightedDef(int32 MaxStack = 20, float Weight = 1.0f)
{
UItemDefinition* Def = NewObject<UItemDefinition>();
UItemFragment_Stackable* SFrag = NewObject<UItemFragment_Stackable>(Def);
SFrag->MaxStackSize = MaxStack;
SFrag->bAllowPartialStacks = true;
Def->Fragments.Add(SFrag);
UItemFragment_Weight* WFrag = NewObject<UItemFragment_Weight>(Def);
WFrag->PerItemWeight = Weight;
Def->Fragments.Add(WFrag);
return Def;
}CreateBindableDef function · cpp · L90-L95 (6 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
UItemDefinition* CreateBindableDef(FGameplayTag BindingPolicy)
{
UItemDefinition* Def = NewObject<UItemDefinition>();
Def->DefaultBindingPolicy = BindingPolicy;
return Def;
}TestRemoveItem function · cpp · L122-L128 (7 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool TestRemoveItem(UInventoryManagerComponent* Comp, const FGuid& InstanceID)
{
const int32 Idx = Comp->InventoryArray.FindIndexByInstanceID(InstanceID);
if (Idx == INDEX_NONE) return false;
Comp->InventoryArray.RemoveEntry(Idx);
return true;
}Repobility — same analyzer, your code, free for public repos · /scan/
PopulateInventory function · cpp · L131-L142 (12 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
TArray<FGuid> PopulateInventory(UInventoryManagerComponent* Comp, int32 Count, UItemDefinition* Def = nullptr)
{
TArray<FGuid> IDs;
IDs.Reserve(Count);
for (int32 i = 0; i < Count; ++i)
{
UItemDefinition* ItemDef = Def ? Def : CreateBasicDef();
FGuid ID = TestAddItem(Comp, ItemDef);
IDs.Add(ID);
}
return IDs;
}TotalItemQuantity function · cpp · L145-L153 (9 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
int32 TotalItemQuantity(const UInventoryManagerComponent* Comp)
{
int32 Total = 0;
for (const FInventoryEntry& Entry : Comp->GetEntries())
{
Total += Entry.StackCount;
}
return Total;
}RunTest method · cpp · L167-L233 (67 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S1_MassLogin::RunTest(const FString& Parameters)
{
// Simulate 50 players each saving 100 items, then loading them back
UNullStorageProvider* Provider = NewObject<UNullStorageProvider>();
constexpr int32 PlayerCount = 50;
constexpr int32 ItemsPerPlayer = 100;
// Phase 1: Save 50 inventories
for (int32 P = 0; P < PlayerCount; ++P)
{
UInventoryManagerComponent* Comp = NewObject<UInventoryManagerComponent>();
Comp->ProfileID = FString::Printf(TEXT("Player_%03d"), P);
UItemDefinition* Def = CreateStackableDef(99);
for (int32 I = 0; I < ItemsPerPlayer; ++I)
{
TestAddItem(Comp, Def);
}
// Serialize and save
FString InvJSON;
InvJSON = VaultSerialization::SerializeInventory(Comp->InventoryArray, Comp->Wallet);
FVaultStoragePayload Payload;
Payload.ProfileID = Comp->ProfileID;
Payload.SchemaVersion = 1;
Payload.LockVersion = 0;
Payload.InventoryJSON = InvJSON;
Payload.WalletJSON = TEXT("");
bool bSaved = false;
FOnStorageSaveComplRunTest method · cpp · L237-L284 (48 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S1_SaveOnMutation::RunTest(const FString& Parameters)
{
// Verify that Authority_AddItem triggers a save (via serialization roundtrip)
UNullStorageProvider* Provider = NewObject<UNullStorageProvider>();
UInventoryManagerComponent* Comp = NewObject<UInventoryManagerComponent>();
Comp->ProfileID = TEXT("SaveMutationPlayer");
UItemDefinition* Def = CreateBasicDef();
// Add item
FGuid ID = TestAddItem(Comp, Def);
TestTrue(TEXT("Item added"), ID.IsValid());
TestEqual(TEXT("Component has 1 entry"), Comp->GetEntryCount(), 1);
// Serialize state after mutation
FString InvJSON;
InvJSON = VaultSerialization::SerializeInventory(Comp->InventoryArray, Comp->Wallet);
TestFalse(TEXT("InventoryJSON not empty after add"), InvJSON.IsEmpty());
// Save and reload — verify state persists
FVaultStoragePayload Payload;
Payload.ProfileID = TEXT("SaveMutationPlayer");
Payload.SchemaVersion = 1;
Payload.LockVersion = 0;
Payload.InventoryJSON = InvJSON;
Payload.WalletJSON RunTest method · cpp · L288-L353 (66 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S1_OCCConflict::RunTest(const FString& Parameters)
{
// Two sessions load same profile, both try to save — second must fail
UNullStorageProvider* Provider = NewObject<UNullStorageProvider>();
// Initial save
FVaultStoragePayload InitPayload;
InitPayload.ProfileID = TEXT("OCCPlayer");
InitPayload.SchemaVersion = 1;
InitPayload.LockVersion = 0;
InitPayload.InventoryJSON = TEXT("{}");
InitPayload.WalletJSON = TEXT("{}");
bool bOk = false;
FOnStorageSaveComplete CB;
CB.BindLambda([&bOk](bool b, const FString&) { bOk = b; });
Provider->AsyncSave(InitPayload, CB);
TestTrue(TEXT("Initial save ok"), bOk);
// Session A loads (gets LockVersion=1)
int32 SessionAVersion = -1;
FOnStorageLoadComplete LoadA;
LoadA.BindLambda([&SessionAVersion](bool, const FVaultStoragePayload& P) { SessionAVersion = P.LockVersion; });
Provider->AsyncLoad(TEXT("OCCPlayer"), LoadA);
TestEqual(TEXT("Session A LockVersion=1"), SessionAVersion, 1);
// Session B loads (also gets LocRunTest method · cpp · L357-L408 (52 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S1_BatchSave::RunTest(const FString& Parameters)
{
// 50 players save simultaneously, then verify all load back
UNullStorageProvider* Provider = NewObject<UNullStorageProvider>();
constexpr int32 PlayerCount = 50;
// Save all
for (int32 P = 0; P < PlayerCount; ++P)
{
UInventoryManagerComponent* Comp = NewObject<UInventoryManagerComponent>();
Comp->ProfileID = FString::Printf(TEXT("Batch_%03d"), P);
PopulateInventory(Comp, 10);
Comp->Wallet.AddCurrency(GoldTag(), (P + 1) * 100);
FString InvJSON;
InvJSON = VaultSerialization::SerializeInventory(Comp->InventoryArray, Comp->Wallet);
FVaultStoragePayload Payload;
Payload.ProfileID = Comp->ProfileID;
Payload.SchemaVersion = 1;
Payload.LockVersion = 0;
Payload.InventoryJSON = InvJSON;
Payload.WalletJSON = TEXT("");
bool bOk = false;
FOnStorageSaveComplete CB;
CB.BindLambda([&bOk](bool b, const FString&) { bOk = b; });
Provider->AsyncSave(Payload, CB);
TestTrue(FString::Printf(TEXT("BRunTest method · cpp · L412-L435 (24 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S1_StorageMetrics::RunTest(const FString& Parameters)
{
// Verify storage operation metrics are populated after operations
UNullStorageProvider* Provider = NewObject<UNullStorageProvider>();
FVaultStoragePayload Payload;
Payload.ProfileID = TEXT("MetricsPlayer");
Payload.SchemaVersion = 1;
Payload.LockVersion = 0;
Payload.InventoryJSON = TEXT("{\"test\":1}");
Payload.WalletJSON = TEXT("{}");
FOnStorageSaveComplete CB;
CB.BindLambda([](bool, const FString&) {});
Provider->AsyncSave(Payload, CB);
// Check metrics after save
FStorageOperationMetrics Metrics = Provider->GetLastOperationMetrics();
TestTrue(TEXT("Metrics success"), Metrics.bSuccess);
TestTrue(TEXT("Metrics latency >= 0"), Metrics.LatencyMs >= 0.0f);
return true;
}RunTest method · cpp · L443-L466 (24 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S2_RapidAddBurst::RunTest(const FString& Parameters)
{
UInventoryManagerComponent* Comp = NewObject<UInventoryManagerComponent>();
constexpr int32 BurstCount = 100;
UItemDefinition* Def = CreateBasicDef();
TSet<FGuid> UniqueIDs;
const double Start = FPlatformTime::Seconds();
for (int32 i = 0; i < BurstCount; ++i)
{
FGuid ID = TestAddItem(Comp, Def);
TestTrue(FString::Printf(TEXT("Item %d has valid ID"), i), ID.IsValid());
UniqueIDs.Add(ID);
}
const double Elapsed = (FPlatformTime::Seconds() - Start) * 1000.0;
TestEqual(TEXT("100 entries in inventory"), Comp->GetEntryCount(), BurstCount);
TestEqual(TEXT("100 unique IDs"), UniqueIDs.Num(), BurstCount);
UE_LOG(LogTemp, Display, TEXT("Scenario S2: 100 item adds in %.2f ms"), Elapsed);
return true;
}Repobility analyzer · published findings · https://repobility.com
RunTest method · cpp · L470-L501 (32 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S2_RapidRemoveBurst::RunTest(const FString& Parameters)
{
UInventoryManagerComponent* Comp = NewObject<UInventoryManagerComponent>();
TArray<FGuid> IDs = PopulateInventory(Comp, 100);
TestEqual(TEXT("Starting with 100 items"), Comp->GetEntryCount(), 100);
// Remove first 50
for (int32 i = 0; i < 50; ++i)
{
bool bRemoved = TestRemoveItem(Comp, IDs[i]);
TestTrue(FString::Printf(TEXT("Remove %d succeeded"), i), bRemoved);
}
TestEqual(TEXT("50 items remain"), Comp->GetEntryCount(), 50);
// Verify removed items are gone
for (int32 i = 0; i < 50; ++i)
{
const FInventoryEntry* Found = Comp->FindEntryByID(IDs[i]);
TestNull(FString::Printf(TEXT("Removed item %d not found"), i), Found);
}
// Verify remaining items exist
for (int32 i = 50; i < 100; ++i)
{
const FInventoryEntry* Found = Comp->FindEntryByID(IDs[i]);
TestNotNull(FString::Printf(TEXT("Remaining item %d found"), i), Found);
}
return true;
}RunTest method · cpp · L505-L528 (24 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S2_StackMerge::RunTest(const FString& Parameters)
{
// Test stacking mechanics: add items and verify total quantity is conserved.
// TestAddItem creates separate entries (merging is Authority_AddItem behavior
// that requires actor context). We verify the data structures support stacking.
UInventoryManagerComponent* Comp = NewObject<UInventoryManagerComponent>();
UItemDefinition* Def = CreateStackableDef(20);
// Add 20 stacks of 5
for (int32 i = 0; i < 20; ++i)
{
TestAddItem(Comp, Def, 5);
}
// Total quantity should be 100
int32 TotalQty = TotalItemQuantity(Comp);
TestEqual(TEXT("Total quantity is 100"), TotalQty, 100);
// 20 separate entries (no merging without Authority context)
TestEqual(TEXT("20 entries created"), Comp->GetEntryCount(), 20);
return true;
}RunTest method · cpp · L532-L550 (19 LOC)Source/VaultCore/Private/Tests/VaultScenarioTests.cpp
bool FScenario_S2_InventoryFullRejection::RunTest(const FString& Parameters)
{
UInventoryManagerComponent* Comp = NewObject<UInventoryManagerComponent>();
UInventoryValidationSubsystem* V = NewObject<UInventoryValidationSubsystem>();
// Fill to default capacity (40 slots)
const UVaultSettings* Settings = UVaultSettings::Get();
const int32 MaxSlots = Settings ? Settings->DefaultMaxInventorySlots : 40;
PopulateInventory(Comp, MaxSlots);
TestEqual(TEXT("At max capacity"), Comp->GetEntryCount(), MaxSlots);
// Validate that capacity check fails
FGameplayTag Result = V->CheckSlotCapacity(Comp);
TestEqual(TEXT("SlotCapacity returns InventoryFull"),
Result, FGameplayTag(VaultTags::Validation_Error_InventoryFull));
return true;
}