← back to drstreit__Unreal-01-VaultInventory

Function bodies 468 total

All specs Real LLM only Function bodies
GetDefinitionsByTag method · cpp · L85-L104 (20 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
TArray<UItemDefinition*> UItemDefinitionRegistry::GetDefinitionsByTag(FGameplayTag FilterTag) const
{
	if (!FilterTag.IsValid())
	{
		return GetAllDefinitions();
	}

	FReadScopeLock ReadLock(RegistryLock);

	TArray<UItemDefinition*> Result;
	for (const auto& Pair : DefinitionMap)
	{
		if (IsValid(Pair.Value) && Pair.Value->ItemTags.HasTag(FilterTag))
		{
			Result.Add(Pair.Value.Get());
		}
	}
	return Result;
}
GetDefinitionCount method · cpp · L105-L110 (6 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
int32 UItemDefinitionRegistry::GetDefinitionCount() const
{
	FReadScopeLock ReadLock(RegistryLock);
	return DefinitionMap.Num();
}
ValidateRegistry method · cpp · L111-L163 (53 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
TArray<FString> UItemDefinitionRegistry::ValidateRegistry() const
{
	FReadScopeLock ReadLock(RegistryLock);

	// Collect all definitions into an array for ParallelFor
	TArray<TPair<FGameplayTag, const UItemDefinition*>> AllDefs;
	AllDefs.Reserve(DefinitionMap.Num());
	for (const auto& Pair : DefinitionMap)
	{
		AllDefs.Emplace(Pair.Key, Pair.Value.Get());
	}

	// Thread-safe collection of warnings
	FCriticalSection WarningLock;
	TArray<FString> Warnings;

	// ParallelFor for batch validation of large catalogs
	ParallelFor(AllDefs.Num(), [&](int32 Index)
	{
		const FGameplayTag& Tag = AllDefs[Index].Key;
		const UItemDefinition* Def = AllDefs[Index].Value;

		if (!IsValid(Def))
		{
			FScopeLock Lock(&WarningLock);
			Warnings.Add(FString::Printf(TEXT("Tag '%s': null definition"), *Tag.ToString()));
			return;
		}

		// Check for missing Visuals fragment
		const UItemFragment_Visuals* Visuals = Def->FindFragmentByClass<UItemFragment_Visuals>();
		if (!Visuals)
		{
			FScopeLock Lock(&W
RegisterDefinition method · cpp · L166-L201 (36 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
bool UItemDefinitionRegistry::RegisterDefinition(FGameplayTag Tag, UItemDefinition* Definition)
{
	if (!Tag.IsValid())
	{
		UE_LOG(LogVaultRegistry, Error, TEXT("RegisterDefinition: invalid tag"));
		return false;
	}

	if (!IsValid(Definition))
	{
		UE_LOG(LogVaultRegistry, Error, TEXT("RegisterDefinition: null definition for tag '%s'"),
			*Tag.ToString());
		return false;
	}

	FWriteScopeLock WriteLock(RegistryLock);

	if (bRegistryFinalized)
	{
		UE_LOG(LogVaultRegistry, Error,
			TEXT("RegisterDefinition: registry is finalized, rejecting '%s'"), *Tag.ToString());
		return false;
	}

	if (DefinitionMap.Contains(Tag))
	{
		UE_LOG(LogVaultRegistry, Error,
			TEXT("RegisterDefinition: duplicate tag '%s' — collision rejected"), *Tag.ToString());
		return false;
	}

	DefinitionMap.Add(Tag, Definition);
	UE_LOG(LogVaultRegistry, Verbose, TEXT("Registered '%s'"), *Tag.ToString());
	return true;
}
PopulateFromDataTable method · cpp · L202-L235 (34 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
void UItemDefinitionRegistry::PopulateFromDataTable(const UDataTable* DataTable)
{
	if (!DataTable)
	{
		return;
	}

	const FString ContextString(TEXT("ItemDefinitionRegistry::PopulateFromDataTable"));
	TArray<FItemDefinitionRow*> AllRows;
	DataTable->GetAllRows<FItemDefinitionRow>(ContextString, AllRows);

	UE_LOG(LogVaultRegistry, Display, TEXT("Populating from DataTable '%s' (%d rows)"),
		*DataTable->GetName(), AllRows.Num());

	int32 SuccessCount = 0;
	for (const FItemDefinitionRow* Row : AllRows)
	{
		if (!Row || !Row->ItemTag.IsValid())
		{
			UE_LOG(LogVaultRegistry, Warning, TEXT("Skipping row with invalid ItemTag"));
			continue;
		}

		UItemDefinition* Def = CreateDefinitionFromRow(*Row);
		if (Def && RegisterDefinition(Row->ItemTag, Def))
		{
			++SuccessCount;
		}
	}

	UE_LOG(LogVaultRegistry, Display, TEXT("DataTable: registered %d/%d definitions"),
		SuccessCount, AllRows.Num());
}
PopulateFromAssetManager method · cpp · L236-L282 (47 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
void UItemDefinitionRegistry::PopulateFromAssetManager()
{
	UAssetManager& AssetManager = UAssetManager::Get();

	TArray<FPrimaryAssetId> AssetIds;
	AssetManager.GetPrimaryAssetIdList(FPrimaryAssetType(TEXT("ItemDefinition")), AssetIds);

	if (AssetIds.Num() == 0)
	{
		UE_LOG(LogVaultRegistry, Display, TEXT("Asset Manager: no ItemDefinition assets found"));
		return;
	}

	UE_LOG(LogVaultRegistry, Display, TEXT("Asset Manager: found %d ItemDefinition assets"), AssetIds.Num());

	int32 SuccessCount = 0;
	for (const FPrimaryAssetId& AssetId : AssetIds)
	{
		FSoftObjectPath AssetPath = AssetManager.GetPrimaryAssetPath(AssetId);
		UItemDefinition* Def = Cast<UItemDefinition>(AssetPath.TryLoad());

		if (!IsValid(Def))
		{
			UE_LOG(LogVaultRegistry, Warning, TEXT("Failed to load ItemDefinition asset: %s"),
				*AssetId.ToString());
			continue;
		}

		if (Def->ItemTags.Num() == 0)
		{
			UE_LOG(LogVaultRegistry, Warning, TEXT("ItemDefinition '%s' has no ItemTags, skipping"),
				*Def->GetN
FinalizeRegistry method · cpp · L283-L299 (17 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
void UItemDefinitionRegistry::FinalizeRegistry()
{
	{
		FWriteScopeLock WriteLock(RegistryLock);
		bRegistryFinalized = true;
		IntegrityHash = ComputeIntegrityHash();
	}

	bRegistryReady = true;

	UE_LOG(LogVaultRegistry, Display,
		TEXT("Registry finalized: %d definitions, integrity hash 0x%08X"),
		DefinitionMap.Num(), IntegrityHash);

	OnRegistryReady.Broadcast();
}
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
CreateDefinitionFromRow method · cpp · L302-L368 (67 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
UItemDefinition* UItemDefinitionRegistry::CreateDefinitionFromRow(const FItemDefinitionRow& Row)
{
	if (!Row.ItemTag.IsValid())
	{
		return nullptr;
	}

	// Create the definition with a stable name derived from the tag
	// The outer is 'this' (the registry subsystem) so it stays alive for the session
	FName DefName(*FString::Printf(TEXT("ItemDef_%s"), *Row.ItemTag.ToString().Replace(TEXT("."), TEXT("_"))));
	UItemDefinition* Def = NewObject<UItemDefinition>(this, DefName);

	// Build ItemTags from primary + extras
	Def->ItemTags.AddTag(Row.ItemTag);
	Def->ItemTags.AppendTags(Row.ExtraTags);

	// Always create Visuals fragment — DisplayName is essential for UI
	UItemFragment_Visuals* Visuals = NewObject<UItemFragment_Visuals>(Def);
	Visuals->DisplayName = Row.DisplayName;
	Visuals->Description = Row.Description;
	Visuals->InventoryIcon = Row.InventoryIcon;
	Visuals->WorldDropActorClass = Row.WorldDropActorClass;
	Def->Fragments.Add(Visuals);

	// Conditional: Stackable (only if MaxStac
ComputeIntegrityHash method · cpp · L369-L390 (22 LOC)
Source/VaultCore/Private/Data/ItemDefinitionRegistry.cpp
int32 UItemDefinitionRegistry::ComputeIntegrityHash() const
{
	// Collect and sort all tag strings for deterministic hashing
	TArray<FString> TagStrings;
	TagStrings.Reserve(DefinitionMap.Num());
	for (const auto& Pair : DefinitionMap)
	{
		TagStrings.Add(Pair.Key.ToString());
	}
	TagStrings.Sort();

	// Build a single concatenated string and hash it
	FString Combined;
	for (const FString& TagStr : TagStrings)
	{
		Combined += TagStr;
		Combined += TEXT("|");
	}

	return static_cast<int32>(FCrc::StrCrc32(*Combined));
}
GetPreloadDependencies method · cpp · L4-L9 (6 LOC)
Source/VaultCore/Private/Data/ItemFragment.cpp
void UItemFragment::GetPreloadDependencies(TArray<UObject*>& OutDeps)
{
	Super::GetPreloadDependencies(OutDeps);
	// Subclasses override to register TSoftObjectPtr assets with the Asset Manager
}
GetFragmentDescription method · cpp · L12-L15 (4 LOC)
Source/VaultCore/Private/Data/ItemFragment.cpp
FText UItemFragment::GetFragmentDescription() const
{
	return FText::FromString(GetClass()->GetName());
}
ShouldCreateSubsystem method · cpp · L9-L18 (10 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
bool UInventoryDebugSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	// Never create in shipping builds — debug-only subsystem
#if UE_BUILD_SHIPPING
	return false;
#else
	return true;
#endif
}
Initialize method · cpp · L19-L58 (40 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);

	RecentEvents.Reserve(MaxEventCount);
	SessionStartTime = FPlatformTime::Seconds();

	// Register console command for toggling the HUD overlay.
	// During editor map transitions, the new world's subsystems initialize BEFORE
	// the old world's subsystems deinitialize. Unregister the stale command first
	// to prevent the console manager "already exists" warning and ensure the
	// delegate binds to THIS subsystem's weak lambda (not the dying one).
	IConsoleObject* Existing = IConsoleManager::Get().FindConsoleObject(TEXT("Vault.Debug.Toggle"), false);
	if (Existing)
	{
		IConsoleManager::Get().UnregisterConsoleObject(Existing, false);
	}
	ToggleCommand = MakeUnique<FAutoConsoleCommand>(
		TEXT("Vault.Debug.Toggle"),
		TEXT("Toggle the Vault Debug HUD overlay"),
		FConsoleCommandDelegate::CreateWeakLambda(this, [this]()
		{
			bHUDVisible = !bHUDVisible;
			OnDebugHUDToggled
CreateWeakLambda method · cpp · L40-L45 (6 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
		FConsoleCommandDelegate::CreateWeakLambda(this, [this]()
		{
			bHUDVisible = !bHUDVisible;
			OnDebugHUDToggled.Broadcast(bHUDVisible);
			UE_LOG(LogVaultDX, Display, TEXT("Debug HUD %s"), bHUDVisible ? TEXT("shown") : TEXT("hidden"));
		})
Deinitialize method · cpp · L59-L80 (22 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::Deinitialize()
{
	UnbindFromTrackedComponent();

	// Skip unsubscribing from AuditLogSubsystem during world teardown.
	// Subsystem deinit order is nondeterministic — AuditLogSubsystem may
	// already be destroyed. AddUObject bindings auto-invalidate when this
	// UObject is destroyed, so manual removal is unnecessary.

	// Release console command ownership without unregistering.
	// During editor map transitions the new subsystem's Initialize() already
	// unregistered the stale command and created a fresh one, so Reset() here
	// would accidentally unregister the NEW subsystem's command.
	// Intentional leak (~16 bytes per map transition, debug-only subsystem).
	FAutoConsoleCommand* Leaked = ToggleCommand.Release();
	(void)Leaked;

	UE_LOG(LogVaultDX, Display, TEXT("InventoryDebugSubsystem shut down."));

	Super::Deinitialize();
}
Repobility — same analyzer, your code, free for public repos · /scan/
RecordEvent method · cpp · L83-L99 (17 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::RecordEvent(const FAuditEvent& Event)
{
	// No-op while frozen — preserve the frozen state for inspection
	if (bFrozen)
	{
		return;
	}

	RecentEvents.Add(Event);

	// Evict oldest when exceeding capacity
	if (RecentEvents.Num() > MaxEventCount)
	{
		RecentEvents.RemoveAt(0);
	}
}
GetRecentEvents method · cpp · L100-L104 (5 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
const TArray<FAuditEvent>& UInventoryDebugSubsystem::GetRecentEvents() const
{
	return bFrozen ? FrozenEvents : RecentEvents;
}
CacheSnapshot method · cpp · L107-L116 (10 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::CacheSnapshot(const FInventorySnapshot& Snapshot)
{
	if (bFrozen)
	{
		return;
	}

	CachedSnapshot = Snapshot;
}
GetCachedSnapshot method · cpp · L117-L121 (5 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
const FInventorySnapshot& UInventoryDebugSubsystem::GetCachedSnapshot() const
{
	return bFrozen ? FrozenSnapshot : CachedSnapshot;
}
RefreshSnapshot method · cpp · L122-L134 (13 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::RefreshSnapshot()
{
	if (bFrozen)
	{
		return;
	}

	if (TrackedComponent.IsValid())
	{
		CachedSnapshot = TrackedComponent->CreateSnapshot();
	}
}
GetHealthMetrics method · cpp · L137-L170 (34 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
FDebugHealthMetrics UInventoryDebugSubsystem::GetHealthMetrics() const
{
	FDebugHealthMetrics Metrics;

	// Query storage metrics from the game instance subsystem
	if (const UWorld* World = GetWorld())
	{
		if (const UGameInstance* GI = World->GetGameInstance())
		{
			if (const UVaultStorageManager* StorageMgr = GI->GetSubsystem<UVaultStorageManager>())
			{
				Metrics.StorageLatencyP95 = StorageMgr->GetLatencyP95();
				Metrics.StorageOperationCount = StorageMgr->GetOperationCount();
				Metrics.StorageFailureRate = StorageMgr->GetFailureRate();
			}
		}

		// Query audit event count
		if (const UAuditLogSubsystem* AuditSub = World->GetSubsystem<UAuditLogSubsystem>())
		{
			Metrics.TotalAuditEvents = AuditSub->GetTotalEventsDispatched();
		}
	}

	// Calculate events per second from session lifetime
	const double ElapsedSeconds = FPlatformTime::Seconds() - SessionStartTime;
	if (ElapsedSeconds > 0.0)
	{
		Metrics.EventsPerSecond = static_cast<float>(Metrics.TotalAuditEvents / Elaps
SetFreezeFrame method · cpp · L173-L198 (26 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::SetFreezeFrame(bool bFreeze)
{
	if (bFreeze == bFrozen)
	{
		return;
	}

	if (bFreeze)
	{
		// Capture current state into frozen copies
		FrozenEvents = RecentEvents;
		FrozenSnapshot = CachedSnapshot;
		UE_LOG(LogVaultDX, Display, TEXT("Freeze-frame ON: captured %d events, hash=%d"),
			FrozenEvents.Num(), FrozenSnapshot.InventoryHash);
	}
	else
	{
		// Discard frozen copies
		FrozenEvents.Reset();
		FrozenSnapshot = FInventorySnapshot();
		UE_LOG(LogVaultDX, Display, TEXT("Freeze-frame OFF: resumed live updates."));
	}

	bFrozen = bFreeze;
}
TrackInventory method · cpp · L201-L226 (26 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::TrackInventory(UInventoryManagerComponent* InComponent)
{
	// Unbind from any previously tracked component
	UnbindFromTrackedComponent();

	if (!IsValid(InComponent))
	{
		TrackedComponent.Reset();
		return;
	}

	TrackedComponent = InComponent;

	// Bind to inventory delegates for automatic snapshot refresh
	InComponent->OnInventoryItemAdded.AddDynamic(this, &UInventoryDebugSubsystem::OnItemAdded);
	InComponent->OnInventoryItemRemoved.AddDynamic(this, &UInventoryDebugSubsystem::OnItemRemoved);
	InComponent->OnInventoryItemChanged.AddDynamic(this, &UInventoryDebugSubsystem::OnItemChanged);
	InComponent->OnCurrencyChanged.AddDynamic(this, &UInventoryDebugSubsystem::OnCurrencyChanged);

	// Capture initial snapshot
	RefreshSnapshot();

	UE_LOG(LogVaultDX, Display, TEXT("Now tracking inventory for ProfileID=%s"),
		*InComponent->ProfileID);
}
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
UnbindFromTrackedComponent method · cpp · L227-L239 (13 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::UnbindFromTrackedComponent()
{
	if (TrackedComponent.IsValid())
	{
		TrackedComponent->OnInventoryItemAdded.RemoveDynamic(this, &UInventoryDebugSubsystem::OnItemAdded);
		TrackedComponent->OnInventoryItemRemoved.RemoveDynamic(this, &UInventoryDebugSubsystem::OnItemRemoved);
		TrackedComponent->OnInventoryItemChanged.RemoveDynamic(this, &UInventoryDebugSubsystem::OnItemChanged);
		TrackedComponent->OnCurrencyChanged.RemoveDynamic(this, &UInventoryDebugSubsystem::OnCurrencyChanged);
	}

	TrackedComponent.Reset();
}
OnItemAdded method · cpp · L242-L246 (5 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::OnItemAdded(const FInventoryEntry& Entry)
{
	RefreshSnapshot();
}
OnItemRemoved method · cpp · L247-L251 (5 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::OnItemRemoved(const FGuid& InstanceID)
{
	RefreshSnapshot();
}
OnItemChanged method · cpp · L252-L256 (5 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::OnItemChanged(const FInventoryEntry& Entry)
{
	RefreshSnapshot();
}
OnCurrencyChanged method · cpp · L257-L261 (5 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::OnCurrencyChanged(FGameplayTag CurrencyType, int32 NewBalance)
{
	RefreshSnapshot();
}
SetReconciliationReport method · cpp · L262-L268 (7 LOC)
Source/VaultCore/Private/DX/InventoryDebugSubsystem.cpp
void UInventoryDebugSubsystem::SetReconciliationReport(const TArray<FReconciliationDiscrepancy>& Report)
{
	LastReconciliationReport = Report;
	UE_LOG(LogVault, Log, TEXT("DebugSubsystem: Reconciliation report updated with %d discrepancies"),
		Report.Num());
}
AsyncFetchConfig method · cpp · L8-L131 (124 LOC)
Source/VaultCore/Private/Economy/LocalEconomyConfigProvider.cpp
void ULocalEconomyConfigProvider::AsyncFetchConfig(FOnEconomyConfigLoaded OnComplete)
{
	CachedConfig = FVaultEconomyConfig();
	CachedConfig.ConfigVersion = 1;

	const UVaultSettings* Settings = UVaultSettings::Get();

	int32 LootEntryCount = 0;
	int32 RecipeCount = 0;
	int32 ParamCount = 0;

	// ── Load Loot Tables from DataTable ─────────────
	// Each row is one loot entry; rows sharing the same LootTableTag form a single table.
	if (Settings && !Settings->LootTablesDataTable.IsNull())
	{
		UDataTable* LootDT = Settings->LootTablesDataTable.LoadSynchronous();
		if (IsValid(LootDT))
		{
			TArray<FLootTableRow*> Rows;
			LootDT->GetAllRows<FLootTableRow>(TEXT("LocalEconomyConfigProvider"), Rows);

			for (const FLootTableRow* Row : Rows)
			{
				if (!Row || !Row->LootTableTag.IsValid()) continue;

				FLootEntry Entry;
				Entry.ItemDef = Row->ItemDef;
				Entry.MinQuantity = Row->MinQuantity;
				Entry.MaxQuantity = Row->MaxQuantity;
				Entry.Weight = Row->Weight;

				// Group en
GetCachedConfig method · cpp · L132-L136 (5 LOC)
Source/VaultCore/Private/Economy/LocalEconomyConfigProvider.cpp
const FVaultEconomyConfig& ULocalEconomyConfigProvider::GetCachedConfig() const
{
	return CachedConfig;
}
Repobility · code-quality intelligence platform · https://repobility.com
GetConfigVersion method · cpp · L137-L141 (5 LOC)
Source/VaultCore/Private/Economy/LocalEconomyConfigProvider.cpp
int32 ULocalEconomyConfigProvider::GetConfigVersion() const
{
	return CachedConfig.ConfigVersion;
}
ShouldCreateSubsystem method · cpp · L12-L18 (7 LOC)
Source/VaultCore/Private/Lifecycle/ItemExpirationSubsystem.cpp
bool UItemExpirationSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	const UWorld* World = Cast<UWorld>(Outer);
	if (!World) return false;
	return World->GetNetMode() != NM_Client;
}
Initialize method · cpp · L19-L38 (20 LOC)
Source/VaultCore/Private/Lifecycle/ItemExpirationSubsystem.cpp
void UItemExpirationSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);

	const UVaultSettings* Settings = UVaultSettings::Get();
	const float Interval = Settings ? Settings->ExpirationSweepIntervalSeconds : 60.0f;

	if (GetWorld())
	{
		GetWorld()->GetTimerManager().SetTimer(
			SweepTimerHandle,
			this,
			&UItemExpirationSubsystem::RunExpirationSweep,
			Interval,
			true);
	}

	UE_LOG(LogVault, Display, TEXT("ItemExpirationSubsystem initialized. Sweep interval: %.0fs"), Interval);
}
Deinitialize method · cpp · L39-L47 (9 LOC)
Source/VaultCore/Private/Lifecycle/ItemExpirationSubsystem.cpp
void UItemExpirationSubsystem::Deinitialize()
{
	if (GetWorld())
	{
		GetWorld()->GetTimerManager().ClearTimer(SweepTimerHandle);
	}
	Super::Deinitialize();
}
RunExpirationSweep method · cpp · L48-L105 (58 LOC)
Source/VaultCore/Private/Lifecycle/ItemExpirationSubsystem.cpp
void UItemExpirationSubsystem::RunExpirationSweep()
{
	const UVaultSettings* Settings = UVaultSettings::Get();
	if (!Settings) return;

	const FDateTime Now = FDateTime::UtcNow();
	const FTimespan WarningThreshold = FTimespan::FromMinutes(Settings->NearExpiryWarningMinutes);

	int32 ExpiredCount = 0;
	int32 WarningCount = 0;

	// Iterate all inventory components in the world
	for (TObjectIterator<UInventoryManagerComponent> It; It; ++It)
	{
		UInventoryManagerComponent* Comp = *It;
		if (!IsValid(Comp) || !Comp->GetOwner() || Comp->GetOwnerRole() != ROLE_Authority)
		{
			continue;
		}

		// Collect expired items (iterate backwards since we may remove)
		TArray<FGuid> ToRemove;
		for (const FInventoryEntry& Entry : Comp->InventoryArray.Entries)
		{
			if (!Entry.HasExpiry()) continue;

			if (Entry.IsExpired())
			{
				ToRemove.Add(Entry.InstanceID);
			}
			else if ((Entry.ExpiresAtUTC - Now) < WarningThreshold)
			{
				// Near-expiry warning — fire once per item
				if (!WarnedIns
GetPrimaryAssetId method · cpp · L4-L8 (5 LOC)
Source/VaultCore/Private/Lifecycle/ItemTransformationRule.cpp
FPrimaryAssetId UItemTransformationRule::GetPrimaryAssetId() const
{
	return FPrimaryAssetId(TEXT("TransformationRule"), GetFName());
}
ShouldCreateSubsystem method · cpp · L18-L23 (6 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
bool UMailSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	const UWorld* World = Cast<UWorld>(Outer);
	return World && World->GetNetMode() != NM_Client;
}
Initialize method · cpp · L24-L35 (12 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
void UMailSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	if (GetWorld())
	{
		GetWorld()->GetTimerManager().SetTimer(
			ExpirationTimerHandle, this, &UMailSubsystem::CleanupExpiredMail, 300.0f, true);
	}
	AsyncLoadMailStore();
	UE_LOG(LogVault, Display, TEXT("MailSubsystem initialized."));
}
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
SendMail method · cpp · L36-L63 (28 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
FGameplayTag UMailSubsystem::SendMail(const FMailMessage& Message)
{
	FMailMessage Msg = Message;
	Msg.MessageID = FGuid::NewGuid();
	Msg.SentAtUTC = FDateTime::UtcNow();
	if (Msg.ExpiresAtUTC.GetTicks() == 0)
	{
		Msg.ExpiresAtUTC = FDateTime::UtcNow() + FTimespan::FromDays(30);
	}
	if (Msg.IdempotencyKey.IsEmpty())
	{
		Msg.IdempotencyKey = Msg.MessageID.ToString();
	}

	// Check idempotency
	if (UsedIdempotencyKeys.Contains(Msg.IdempotencyKey))
	{
		return VaultTags::Validation_Error_AlreadyClaimed;
	}

	MailStore.Add(Msg);
	AsyncSaveMailStore();
	UE_LOG(LogVault, Log, TEXT("Mail sent: From=%s To=%s Subject=%s"),
		*Msg.SenderID, *Msg.RecipientID, *Msg.Subject.ToString());

	return VaultTags::Validation_Success;
}
GetMailbox method · cpp · L64-L76 (13 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
TArray<FMailMessage> UMailSubsystem::GetMailbox(const FString& RecipientID) const
{
	TArray<FMailMessage> Result;
	for (const FMailMessage& Msg : MailStore)
	{
		if (Msg.RecipientID == RecipientID && !Msg.bClaimed)
		{
			Result.Add(Msg);
		}
	}
	return Result;
}
ClaimAttachments method · cpp · L77-L116 (40 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
FGameplayTag UMailSubsystem::ClaimAttachments(const FGuid& MessageID, APlayerController* Recipient)
{
	FMailMessage* Msg = MailStore.FindByPredicate([&MessageID](const FMailMessage& M)
	{
		return M.MessageID == MessageID;
	});

	if (!Msg) return VaultTags::Validation_Error_ItemNotFound;
	if (Msg->bClaimed) return VaultTags::Validation_Error_AlreadyClaimed;

	UInventoryManagerComponent* Comp = Recipient->GetPawn()
		? Recipient->GetPawn()->FindComponentByClass<UInventoryManagerComponent>()
		: nullptr;
	if (!Comp) return VaultTags::Validation_Error_NotOwner;

	// Transfer item attachments
	for (const FMailAttachment& Att : Msg->Attachments)
	{
		if (IsValid(Att.ItemDef.Get()))
		{
			Comp->Authority_AddItem(Att.ItemDef, Att.Quantity, Att.InitialTags);
		}
	}

	// Transfer currency attachments
	for (const auto& Pair : Msg->CurrencyAttachments)
	{
		Comp->Authority_AddCurrency(Pair.Key, Pair.Value);
	}

	Msg->bClaimed = true;
	UsedIdempotencyKeys.Add(Msg->IdempotencyKey);
	AsyncSaveMail
DeleteMessage method · cpp · L117-L129 (13 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
void UMailSubsystem::DeleteMessage(const FGuid& MessageID)
{
	const int32 Removed = MailStore.RemoveAll([&MessageID](const FMailMessage& M)
	{
		return M.MessageID == MessageID && M.bClaimed;
	});

	if (Removed > 0)
	{
		AsyncSaveMailStore();
	}
}
GrantReward method · cpp · L130-L152 (23 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
FGameplayTag UMailSubsystem::GrantReward(
	const FString& RecipientID, const FString& RewardKey,
	const TArray<FMailAttachment>& Items, const TMap<FGameplayTag, int32>& Currency,
	const FString& SenderID)
{
	// Idempotency check
	if (UsedIdempotencyKeys.Contains(RewardKey))
	{
		UE_LOG(LogVault, Log, TEXT("GrantReward: RewardKey=%s already claimed, skipping."), *RewardKey);
		return VaultTags::Validation_Error_AlreadyClaimed;
	}

	FMailMessage Msg;
	Msg.SenderID = SenderID;
	Msg.RecipientID = RecipientID;
	Msg.Subject = FText::FromString(TEXT("Reward Delivery"));
	Msg.Attachments = Items;
	Msg.CurrencyAttachments = Currency;
	Msg.IdempotencyKey = RewardKey;

	return SendMail(Msg);
}
CleanupExpiredMail method · cpp · L153-L167 (15 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
void UMailSubsystem::CleanupExpiredMail()
{
	const FDateTime Now = FDateTime::UtcNow();
	const int32 Removed = MailStore.RemoveAll([&Now](const FMailMessage& M)
	{
		return M.ExpiresAtUTC.GetTicks() > 0 && Now > M.ExpiresAtUTC && !M.bClaimed;
	});

	if (Removed > 0)
	{
		UE_LOG(LogVault, Log, TEXT("Cleaned up %d expired unclaimed mail messages."), Removed);
		AsyncSaveMailStore();
	}
}
AsyncSaveMailStore method · cpp · L170-L220 (51 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
void UMailSubsystem::AsyncSaveMailStore()
{
	UWorld* World_Local = GetWorld();
	UGameInstance* GI = World_Local ? World_Local->GetGameInstance() : nullptr;
	UVaultStorageManager* SM = GI ? GI->GetSubsystem<UVaultStorageManager>() : nullptr;
	if (SM == nullptr) return;

	TScriptInterface<IInventoryStorageProvider> Provider = SM->GetActiveProvider();
	if (!Provider.GetObject()) return;

	// Serialize mail store to JSON
	TSharedRef<FJsonObject> Root = MakeShared<FJsonObject>();

	TArray<TSharedPtr<FJsonValue>> MessagesArray;
	for (const FMailMessage& Msg : MailStore)
	{
		TSharedRef<FJsonObject> MsgObj = MakeShared<FJsonObject>();
		MsgObj->SetStringField(TEXT("MessageID"), Msg.MessageID.ToString());
		MsgObj->SetStringField(TEXT("SenderID"), Msg.SenderID);
		MsgObj->SetStringField(TEXT("RecipientID"), Msg.RecipientID);
		MsgObj->SetStringField(TEXT("Subject"), Msg.Subject.ToString());
		MsgObj->SetStringField(TEXT("Body"), Msg.Body.ToString());
		MsgObj->SetStringField(TEXT("SentAtUTC")
AsyncLoadMailStore method · cpp · L221-L240 (20 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
void UMailSubsystem::AsyncLoadMailStore()
{
	UWorld* World_Local = GetWorld();
	UGameInstance* GI = World_Local ? World_Local->GetGameInstance() : nullptr;
	UVaultStorageManager* SM = GI ? GI->GetSubsystem<UVaultStorageManager>() : nullptr;
	if (SM == nullptr) return;

	TScriptInterface<IInventoryStorageProvider> Provider = SM->GetActiveProvider();
	if (!Provider.GetObject()) return;

	// Dynamic delegates cannot BindLambda — use an unbound delegate.
	// The load callback will fire on the game thread. For now, the mail store
	// starts empty each session and is populated by incoming SendMail/GrantReward calls.
	// Full deserialization from storage is deferred to a UFUNCTION callback approach.
	FOnStorageLoadComplete OnComplete;
	Provider->AsyncLoad(TEXT("System_Mail"), OnComplete);

	UE_LOG(LogVault, Log, TEXT("MailSubsystem: AsyncLoadMailStore dispatched for System_Mail"));
}
Repobility — same analyzer, your code, free for public repos · /scan/
BulkGrantRewards method · cpp · L243-L262 (20 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
TArray<FGameplayTag> UMailSubsystem::BulkGrantRewards(
	const TArray<FString>& RecipientIDs,
	const FString& RewardKey,
	const TArray<FMailAttachment>& Items,
	const TMap<FGameplayTag, int32>& Currency,
	const FString& SenderID)
{
	TArray<FGameplayTag> Results;
	Results.Reserve(RecipientIDs.Num());

	for (int32 i = 0; i < RecipientIDs.Num(); ++i)
	{
		// Each grant gets a unique idempotency key: BaseKey_Index
		const FString UniqueKey = FString::Printf(TEXT("%s_%d"), *RewardKey, i);
		Results.Add(GrantReward(RecipientIDs[i], UniqueKey, Items, Currency, SenderID));
	}

	return Results;
}
ProcessWebhookPayload method · cpp · L263-L309 (47 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
FGameplayTag UMailSubsystem::ProcessWebhookPayload(const FString& JSONPayload)
{
	TSharedPtr<FJsonObject> JsonObj;
	const TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JSONPayload);

	if (!FJsonSerializer::Deserialize(Reader, JsonObj) || !JsonObj.IsValid())
	{
		UE_LOG(LogVault, Warning, TEXT("MailSubsystem: Malformed webhook JSON payload"));
		return FGameplayTag(VaultTags::Validation_Error_MalformedPayload);
	}

	const FString Recipient = JsonObj->GetStringField(TEXT("recipient"));
	const FString RewardKey = JsonObj->GetStringField(TEXT("reward_key"));
	const FString Sender = JsonObj->HasField(TEXT("sender"))
		? JsonObj->GetStringField(TEXT("sender"))
		: TEXT("System_Webhook");

	if (Recipient.IsEmpty() || RewardKey.IsEmpty())
	{
		UE_LOG(LogVault, Warning, TEXT("MailSubsystem: Webhook missing recipient or reward_key"));
		return FGameplayTag(VaultTags::Validation_Error_MalformedPayload);
	}

	// Parse items array (simplified — real implementation would resolve I
GetUnclaimedMailCount method · cpp · L310-L322 (13 LOC)
Source/VaultCore/Private/Mail/MailSubsystem.cpp
int32 UMailSubsystem::GetUnclaimedMailCount(const FString& RecipientID) const
{
	int32 Count = 0;
	for (const FMailMessage& Msg : MailStore)
	{
		if (Msg.RecipientID == RecipientID && !Msg.bClaimed)
		{
			++Count;
		}
	}
	return Count;
}
‹ prevpage 4 / 10next ›