Skip to main content

Examples

Common workflows and use cases for Elys Asset Tools.

Example 1: Reorganizing Content Structure

Scenario: You want to move all character assets from scattered locations into a centralized /Game/Characters/ folder.

Steps:

  1. Analyze existing structure

    // Scan current character locations
    Subsystem->ScanFolder("/Game/Content/OldCharacters");
    Subsystem->ScanFolder("/Game/Legacy/Characters");
  2. Check dependencies

    • Right-click each folder → Analyze Dependencies
    • Note external references (maps, blueprints using these characters)
  3. Move assets

    TArray<FString> Sources = {
    "/Game/Content/OldCharacters",
    "/Game/Legacy/Characters"
    };
    Subsystem->StartMoveAssets(Sources, "/Game/Characters");
  4. Clean up

    // Delete now-empty source folders
    Subsystem->DeleteEmptyFolders("/Game/Content");
    Subsystem->DeleteEmptyFolders("/Game/Legacy");

Result: All character assets are now in /Game/Characters/ with references automatically updated.


Example 2: Pre-Release Cleanup

Scenario: Before shipping, clean up development assets and test content.

Steps:

  1. Identify unused test content

    // Scan test folder
    FERP_AssetDependencyScanResult Result = Subsystem->ScanFolder("/Game/Test");

    // Check for external referencers
    if (Result.Referencers.Num() == 0)
    {
    UE_LOG(LogElysAssetTools, Log, TEXT("Safe to delete Test folder"));
    }
  2. Safe delete unused folders

    // These will only delete if safe
    Subsystem->SafeDeleteFolder("/Game/Test");
    Subsystem->SafeDeleteFolder("/Game/Development");
    Subsystem->SafeDeleteFolder("/Game/Experiments");
  3. Clean up empty folders and redirectors

    Subsystem->DeleteEmptyFolders("/Game");
    Subsystem->FixRedirectorsInFolder("/Game");

Result: Project is clean, only shipping content remains.


Example 3: Safe Asset Migration

Scenario: Migrate assets from an old plugin to your game content.

Steps:

  1. Analyze plugin assets

    // Understand what the plugin assets depend on
    FERP_AssetDependencyScanResult Result = Subsystem->ScanFolder("/MyPlugin/Content");

    // Log dependencies
    for (const FAssetData& Dep : Result.Dependencies)
    {
    UE_LOG(LogElysAssetTools, Log, TEXT("Depends on: %s"), *Dep.PackageName.ToString());
    }
  2. Move to game content

    // Move assets from plugin to game
    TArray<FString> Sources = {"/MyPlugin/Content/Characters"};
    Subsystem->StartMoveAssets(Sources, "/Game/MigratedContent");
  3. Verify and clean up

    • Test that all references work
    • Remove the plugin if no longer needed
    • Delete empty folders

Result: Assets successfully migrated to game content.


Example 4: Batch Folder Operations

Scenario: You have multiple folders to move to a new structure.

Blueprint Example:

// Create an Editor Utility Widget
UCLASS()
class UBatchFolderMoveWidget : public UEditorUtilityWidget
{
UFUNCTION(BlueprintCallable)
void BatchMoveToNewStructure()
{
UERP_AssetToolsEditorSubsystem* Subsystem =
GEditor->GetEditorSubsystem<UERP_AssetToolsEditorSubsystem>();

// Define moves
TMap<FString, FString> Moves;
Moves.Add("/Game/Old/Characters", "/Game/Core/Characters");
Moves.Add("/Game/Old/Weapons", "/Game/Core/Weapons");
Moves.Add("/Game/Old/Maps", "/Game/Core/Maps");

// Execute moves
for (const auto& Move : Moves)
{
TArray<FString> Source = {Move.Key};
Subsystem->StartMoveAssets(Source, Move.Value);

// Wait for completion (in real widget, use async)
while (IsMoving())
{
FPlatformProcess::Sleep(0.1f);
}
}

// Final cleanup
Subsystem->DeleteEmptyFolders("/Game/Old");

UE_LOG(LogElysAssetTools, Log, TEXT("Batch move complete"));
}
};

Example 5: Automated Weekly Cleanup

Scenario: Run automatic cleanup every week to keep the project tidy.

Editor Utility Widget:

UCLASS()
class UWeeklyCleanupWidget : public UEditorUtilityWidget
{
UFUNCTION(BlueprintCallable)
void RunWeeklyCleanup()
{
UERP_AssetToolsEditorSubsystem* Subsystem =
GEditor->GetEditorSubsystem<UERP_AssetToolsEditorSubsystem>();

UE_LOG(LogElysAssetTools, Log, TEXT("Starting weekly cleanup..."));

// 1. Delete empty folders
Subsystem->DeleteEmptyFolders("/Game");
UE_LOG(LogElysAssetTools, Log, TEXT("✓ Deleted empty folders"));

// 2. Fix redirectors
Subsystem->FixRedirectorsInFolder("/Game");
UE_LOG(LogElysAssetTools, Log, TEXT("✓ Fixed redirectors"));

// 3. Scan for unused test assets
FERP_AssetDependencyScanResult TestResult = Subsystem->ScanFolder("/Game/Test");
if (TestResult.Referencers.Num() == 0)
{
Subsystem->SafeDeleteFolder("/Game/Test");
UE_LOG(LogElysAssetTools, Log, TEXT("✓ Removed unused test content"));
}

UE_LOG(LogElysAssetTools, Log, TEXT("Weekly cleanup complete!"));
}
};

Example 6: Finding Circular Dependencies

Scenario: Detect circular dependencies that could cause issues.

void FindCircularDependencies(const FString& FolderPath)
{
UERP_AssetToolsEditorSubsystem* Subsystem =
GEditor->GetEditorSubsystem<UERP_AssetToolsEditorSubsystem>();

// Scan folder
FERP_AssetDependencyScanResult Result = Subsystem->ScanFolder(FolderPath);

// Check each asset
for (const FAssetData& Asset : Result.ScannedAssets)
{
FString AssetPath = Asset.PackageName.ToString();

// Does this asset depend on something that depends on it?
for (const FAssetData& Dependency : Result.Dependencies)
{
// Scan the dependency
FERP_AssetDependencyScanResult DepResult =
Subsystem->ScanAsset(Dependency.PackageName.ToString());

// Check if dependency references us back
for (const FAssetData& DepReferencer : DepResult.Referencers)
{
if (DepReferencer.PackageName == Asset.PackageName)
{
UE_LOG(LogElysAssetTools, Warning,
TEXT("Circular dependency: %s <-> %s"),
*Asset.AssetName.ToString(),
*Dependency.AssetName.ToString());
}
}
}
}
}

Example 7: Pre-Move Validation

Scenario: Validate a move operation before executing it.

bool ValidateMoveOperation(const TArray<FString>& Sources, const FString& Destination)
{
UERP_AssetToolsEditorSubsystem* Subsystem =
GEditor->GetEditorSubsystem<UERP_AssetToolsEditorSubsystem>();

// Check 1: Destination exists
if (!FPaths::DirectoryExists(Destination))
{
UE_LOG(LogElysAssetTools, Error, TEXT("Destination folder does not exist"));
return false;
}

// Check 2: No conflicts
for (const FString& Source : Sources)
{
FString FolderName = FPaths::GetCleanFilename(Source);
FString TargetPath = FPaths::Combine(Destination, FolderName);

TArray<FAssetData> ExistingAssets;
AssetRegistry.GetAssetsByPath(*TargetPath, ExistingAssets, false);

if (ExistingAssets.Num() > 0)
{
UE_LOG(LogElysAssetTools, Error, TEXT("Conflict: %s already exists at destination"), *FolderName);
return false;
}
}

// Check 3: Sources have no external critical dependencies
for (const FString& Source : Sources)
{
FERP_AssetDependencyScanResult Result = Subsystem->ScanFolder(Source);

// Check for engine content dependencies (can't be moved)
for (const FAssetData& Dep : Result.Dependencies)
{
if (Dep.PackageName.ToString().StartsWith("/Engine"))
{
// Engine dependencies are OK
continue;
}
}
}

UE_LOG(LogElysAssetTools, Log, TEXT("Move validation passed"));
return true;
}

More Examples

For more examples and community contributions, visit:

Next Steps